Update ooo320-m1
[ooovba.git] / sw / source / core / docnode / ndtbl1.cxx
blob7dbf247500b64dd3ec07830705900365bad7558f
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: ndtbl1.cxx,v $
10 * $Revision: 1.25 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
35 #ifdef WTC
36 #define private public
37 #endif
39 #include "hintids.hxx"
40 #include <svx/lrspitem.hxx>
41 #include <svx/boxitem.hxx>
42 #include <svx/brshitem.hxx>
43 #include <svx/frmdiritem.hxx>
44 #include <fmtornt.hxx>
45 #include <fmtfsize.hxx>
46 #include <fmtlsplt.hxx>
47 #include <fmtrowsplt.hxx>
48 #include <tabcol.hxx>
49 #include <frmatr.hxx>
50 #include <cellfrm.hxx>
51 #include <tabfrm.hxx>
52 #include <cntfrm.hxx>
53 #include <txtfrm.hxx>
55 #include "doc.hxx"
56 #include "pam.hxx"
57 #include "swcrsr.hxx"
58 #include "viscrs.hxx"
59 #include "swtable.hxx"
60 #include "htmltbl.hxx"
61 #include "tblsel.hxx"
62 #include "swtblfmt.hxx"
63 #include "docary.hxx"
64 #include "ndindex.hxx"
65 #include "undobj.hxx"
67 using namespace ::com::sun::star;
70 extern void ClearFEShellTabCols();
72 //siehe auch swtable.cxx
73 #define COLFUZZY 20L
75 inline BOOL IsSame( long nA, long nB ) { return Abs(nA-nB) <= COLFUZZY; }
77 class SwTblFmtCmp
79 public:
80 SwFrmFmt *pOld,
81 *pNew;
82 INT16 nType;
84 SwTblFmtCmp( SwFrmFmt *pOld, SwFrmFmt *pNew, INT16 nType );
86 static SwFrmFmt *FindNewFmt( SvPtrarr &rArr, SwFrmFmt*pOld, INT16 nType );
87 static void Delete( SvPtrarr &rArr );
91 SwTblFmtCmp::SwTblFmtCmp( SwFrmFmt *pO, SwFrmFmt *pN, INT16 nT )
92 : pOld ( pO ), pNew ( pN ), nType( nT )
96 SwFrmFmt *SwTblFmtCmp::FindNewFmt( SvPtrarr &rArr, SwFrmFmt *pOld, INT16 nType )
98 for ( USHORT i = 0; i < rArr.Count(); ++i )
100 SwTblFmtCmp *pCmp = (SwTblFmtCmp*)rArr[i];
101 if ( pCmp->pOld == pOld && pCmp->nType == nType )
102 return pCmp->pNew;
104 return 0;
107 void SwTblFmtCmp::Delete( SvPtrarr &rArr )
109 for ( USHORT i = 0; i < rArr.Count(); ++i )
110 delete (SwTblFmtCmp*)rArr[i];
113 void lcl_GetStartEndCell( const SwCursor& rCrsr,
114 SwLayoutFrm *&prStart, SwLayoutFrm *&prEnd )
116 ASSERT( rCrsr.GetCntntNode() && rCrsr.GetCntntNode( FALSE ),
117 "Tabselection nicht auf Cnt." );
119 Point aPtPos, aMkPos;
120 const SwShellCrsr* pShCrsr = dynamic_cast<const SwShellCrsr*>(&rCrsr);
121 if( pShCrsr )
123 aPtPos = pShCrsr->GetPtPos();
124 aMkPos = pShCrsr->GetMkPos();
127 // robust:
128 SwCntntNode* pPointNd = rCrsr.GetCntntNode();
129 SwCntntNode* pMarkNd = rCrsr.GetCntntNode(FALSE);
131 SwFrm* pPointFrm = pPointNd ? pPointNd->GetFrm( &aPtPos ) : 0;
132 SwFrm* pMarkFrm = pMarkNd ? pMarkNd->GetFrm( &aMkPos ) : 0;
134 prStart = pPointFrm ? pPointFrm->GetUpper() : 0;
135 prEnd = pMarkFrm ? pMarkFrm->GetUpper() : 0;
138 BOOL lcl_GetBoxSel( const SwCursor& rCursor, SwSelBoxes& rBoxes,
139 BOOL bAllCrsr = FALSE )
141 const SwTableCursor* pTblCrsr =
142 dynamic_cast<const SwTableCursor*>(&rCursor);
143 if( pTblCrsr )
144 ::GetTblSelCrs( *pTblCrsr, rBoxes );
145 else
147 const SwPaM *pCurPam = &rCursor, *pSttPam = pCurPam;
148 do {
149 const SwNode* pNd = pCurPam->GetNode()->FindTableBoxStartNode();
150 if( pNd )
152 SwTableBox* pBox = (SwTableBox*)pNd->FindTableNode()->GetTable().
153 GetTblBox( pNd->GetIndex() );
154 rBoxes.Insert( pBox );
156 } while( bAllCrsr &&
157 pSttPam != ( pCurPam = (SwPaM*)pCurPam->GetNext()) );
159 return 0 != rBoxes.Count();
162 /***********************************************************************
163 #* Class : SwDoc
164 #* Methoden : SetRowHeight(), GetRowHeight()
165 #* Datum : MA 17. May. 93
166 #* Update : JP 28.04.98
167 #***********************************************************************/
168 //Die Zeilenhoehe wird ausgehend von der Selektion ermittelt/gesetzt.
169 //Ausgehend von jeder Zelle innerhalb der Selektion werden nach oben alle
170 //Zeilen abgeklappert, die oberste Zeile erhaelt den gewuenschten Wert alle
171 //tieferliegenden Zeilen einen entsprechenden Wert der sich aus der
172 //Relation der alten und neuen Groesse der obersten Zeile und ihrer
173 //eigenen Groesse ergiebt.
174 //Alle veraenderten Zeilen erhalten ggf. ein eigenes FrmFmt.
175 //Natuerlich darf jede Zeile nur einmal angefasst werden.
177 inline void InsertLine( SvPtrarr& rLineArr, SwTableLine* pLine )
179 if( USHRT_MAX == rLineArr.GetPos( (void*&)pLine ) )
180 rLineArr.Insert( (void*&)pLine, rLineArr.Count() );
183 //-----------------------------------------------------------------------------
185 BOOL lcl_IsAnLower( const SwTableLine *pLine, const SwTableLine *pAssumed )
187 const SwTableLine *pTmp = pAssumed->GetUpper() ?
188 pAssumed->GetUpper()->GetUpper() : 0;
189 while ( pTmp )
191 if ( pTmp == pLine )
192 return TRUE;
193 pTmp = pTmp->GetUpper() ? pTmp->GetUpper()->GetUpper() : 0;
195 return FALSE;
197 //-----------------------------------------------------------------------------
199 struct LinesAndTable
201 SvPtrarr &rLines;
202 const SwTable &rTable;
203 BOOL bInsertLines;
205 LinesAndTable( SvPtrarr &rL, const SwTable &rTbl ) :
206 rLines( rL ), rTable( rTbl ), bInsertLines( TRUE ) {}
210 BOOL _FindLine( const _FndLine*& rpLine, void* pPara );
212 BOOL _FindBox( const _FndBox*& rpBox, void* pPara )
214 if ( rpBox->GetLines().Count() )
216 ((LinesAndTable*)pPara)->bInsertLines = TRUE;
217 ((_FndBox*)rpBox)->GetLines().ForEach( _FindLine, pPara );
218 if ( ((LinesAndTable*)pPara)->bInsertLines )
220 const SwTableLines &rLines = rpBox->GetBox()
221 ? rpBox->GetBox()->GetTabLines()
222 : ((LinesAndTable*)pPara)->rTable.GetTabLines();
223 if ( rpBox->GetLines().Count() == rLines.Count() )
225 for ( USHORT i = 0; i < rLines.Count(); ++i )
226 ::InsertLine( ((LinesAndTable*)pPara)->rLines,
227 (SwTableLine*)rLines[i] );
229 else
230 ((LinesAndTable*)pPara)->bInsertLines = FALSE;
233 else if ( rpBox->GetBox() )
234 ::InsertLine( ((LinesAndTable*)pPara)->rLines,
235 (SwTableLine*)rpBox->GetBox()->GetUpper() );
236 return TRUE;
239 BOOL _FindLine( const _FndLine*& rpLine, void* pPara )
241 ((_FndLine*)rpLine)->GetBoxes().ForEach( _FindBox, pPara );
242 return TRUE;
245 void lcl_CollectLines( SvPtrarr &rArr, const SwCursor& rCursor, bool bRemoveLines )
247 //Zuerst die selektierten Boxen einsammeln.
248 SwSelBoxes aBoxes;
249 if( !::lcl_GetBoxSel( rCursor, aBoxes ))
250 return ;
252 //Die selektierte Struktur kopieren.
253 const SwTable &rTable = aBoxes[0]->GetSttNd()->FindTableNode()->GetTable();
254 LinesAndTable aPara( rArr, rTable );
255 _FndBox aFndBox( 0, 0 );
257 _FndPara aTmpPara( aBoxes, &aFndBox );
258 ((SwTableLines&)rTable.GetTabLines()).ForEach( &_FndLineCopyCol, &aTmpPara );
261 //Diejenigen Lines einsammeln, die nur selektierte Boxen enthalten.
262 const _FndBox *pTmp = &aFndBox;
263 ::_FindBox( pTmp, &aPara );
265 // Remove lines, that have a common superordinate row.
266 // (Not for row split)
267 if ( bRemoveLines )
269 for ( USHORT i = 0; i < rArr.Count(); ++i )
271 SwTableLine *pUpLine = (SwTableLine*)rArr[i];
272 for ( USHORT k = 0; k < rArr.Count(); ++k )
274 if ( k != i && ::lcl_IsAnLower( pUpLine, (SwTableLine*)rArr[k] ) )
276 rArr.Remove( k );
277 if ( k <= i )
278 --i;
279 --k;
286 //-----------------------------------------------------------------------------
288 void lcl_ProcessRowAttr( SvPtrarr& rFmtCmp, SwTableLine* pLine, const SfxPoolItem& rNew )
290 SwFrmFmt *pNewFmt;
291 if ( 0 != (pNewFmt = SwTblFmtCmp::FindNewFmt( rFmtCmp, pLine->GetFrmFmt(), 0 )))
292 pLine->ChgFrmFmt( (SwTableLineFmt*)pNewFmt );
293 else
295 SwFrmFmt *pOld = pLine->GetFrmFmt();
296 SwFrmFmt *pNew = pLine->ClaimFrmFmt();
297 pNew->SetFmtAttr( rNew );
298 rFmtCmp.Insert( new SwTblFmtCmp( pOld, pNew, 0 ), rFmtCmp.Count());
302 //-----------------------------------------------------------------------------
304 void lcl_ProcessBoxSize( SvPtrarr &rFmtCmp, SwTableBox *pBox, const SwFmtFrmSize &rNew );
306 void lcl_ProcessRowSize( SvPtrarr &rFmtCmp, SwTableLine *pLine, const SwFmtFrmSize &rNew )
308 lcl_ProcessRowAttr( rFmtCmp, pLine, rNew );
309 SwTableBoxes &rBoxes = pLine->GetTabBoxes();
310 for ( USHORT i = 0; i < rBoxes.Count(); ++i )
311 ::lcl_ProcessBoxSize( rFmtCmp, rBoxes[i], rNew );
314 //-----------------------------------------------------------------------------
316 void lcl_ProcessBoxSize( SvPtrarr &rFmtCmp, SwTableBox *pBox, const SwFmtFrmSize &rNew )
318 SwTableLines &rLines = pBox->GetTabLines();
319 if ( rLines.Count() )
321 SwFmtFrmSize aSz( rNew );
322 aSz.SetHeight( rNew.GetHeight() ? rNew.GetHeight() / rLines.Count() : 0 );
323 for ( USHORT i = 0; i < rLines.Count(); ++i )
324 ::lcl_ProcessRowSize( rFmtCmp, rLines[i], aSz );
328 //-----------------------------------------------------------------------------
330 /******************************************************************************
331 * void SwDoc::SetRowSplit()
332 ******************************************************************************/
333 void SwDoc::SetRowSplit( const SwCursor& rCursor, const SwFmtRowSplit &rNew )
335 SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
336 if( pTblNd )
338 SvPtrarr aRowArr( 25, 50 ); //Zum sammeln Lines.
339 ::lcl_CollectLines( aRowArr, rCursor, false );
341 if( aRowArr.Count() )
343 if( DoesUndo() )
345 ClearRedo();
346 AppendUndo( new SwUndoAttrTbl( *pTblNd ));
349 SvPtrarr aFmtCmp( Max( BYTE(255), BYTE(aRowArr.Count()) ), 255 );
351 for( USHORT i = 0; i < aRowArr.Count(); ++i )
352 ::lcl_ProcessRowAttr( aFmtCmp, (SwTableLine*)aRowArr[i], rNew );
354 SwTblFmtCmp::Delete( aFmtCmp );
355 SetModified();
361 /******************************************************************************
362 * SwTwips SwDoc::GetRowSplit() const
363 ******************************************************************************/
364 void SwDoc::GetRowSplit( const SwCursor& rCursor, SwFmtRowSplit *& rpSz ) const
366 rpSz = 0;
368 SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
369 if( pTblNd )
371 SvPtrarr aRowArr( 25, 50 ); //Zum sammeln der Lines.
372 ::lcl_CollectLines( aRowArr, rCursor, false );
374 if( aRowArr.Count() )
376 rpSz = &(SwFmtRowSplit&)((SwTableLine*)aRowArr[0])->
377 GetFrmFmt()->GetRowSplit();
379 for ( USHORT i = 1; i < aRowArr.Count() && rpSz; ++i )
381 if ( (*rpSz).GetValue() != ((SwTableLine*)aRowArr[i])->GetFrmFmt()->GetRowSplit().GetValue() )
382 rpSz = 0;
384 if ( rpSz )
385 rpSz = new SwFmtRowSplit( *rpSz );
391 /******************************************************************************
392 * void SwDoc::SetRowHeight( SwTwips nNew )
393 ******************************************************************************/
394 void SwDoc::SetRowHeight( const SwCursor& rCursor, const SwFmtFrmSize &rNew )
396 SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
397 if( pTblNd )
399 SvPtrarr aRowArr( 25, 50 ); //Zum sammeln Lines.
400 ::lcl_CollectLines( aRowArr, rCursor, true );
402 if( aRowArr.Count() )
404 if( DoesUndo() )
406 ClearRedo();
407 AppendUndo( new SwUndoAttrTbl( *pTblNd ));
410 SvPtrarr aFmtCmp( Max( BYTE(255), BYTE(aRowArr.Count()) ), 255 );
411 for ( USHORT i = 0; i < aRowArr.Count(); ++i )
412 ::lcl_ProcessRowSize( aFmtCmp, (SwTableLine*)aRowArr[i], rNew );
413 SwTblFmtCmp::Delete( aFmtCmp );
415 SetModified();
421 /******************************************************************************
422 * SwTwips SwDoc::GetRowHeight() const
423 ******************************************************************************/
424 void SwDoc::GetRowHeight( const SwCursor& rCursor, SwFmtFrmSize *& rpSz ) const
426 rpSz = 0;
428 SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
429 if( pTblNd )
431 SvPtrarr aRowArr( 25, 50 ); //Zum sammeln der Lines.
432 ::lcl_CollectLines( aRowArr, rCursor, true );
434 if( aRowArr.Count() )
436 rpSz = &(SwFmtFrmSize&)((SwTableLine*)aRowArr[0])->
437 GetFrmFmt()->GetFrmSize();
439 for ( USHORT i = 1; i < aRowArr.Count() && rpSz; ++i )
441 if ( *rpSz != ((SwTableLine*)aRowArr[i])->GetFrmFmt()->GetFrmSize() )
442 rpSz = 0;
444 if ( rpSz )
445 rpSz = new SwFmtFrmSize( *rpSz );
450 BOOL SwDoc::BalanceRowHeight( const SwCursor& rCursor, BOOL bTstOnly )
452 BOOL bRet = FALSE;
453 SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
454 if( pTblNd )
456 SvPtrarr aRowArr( 25, 50 ); //Zum sammeln der Lines.
457 ::lcl_CollectLines( aRowArr, rCursor, true );
459 if( 1 < aRowArr.Count() )
461 if( !bTstOnly )
463 long nHeight = 0;
464 USHORT i;
466 for ( i = 0; i < aRowArr.Count(); ++i )
468 SwClientIter aIter( *((SwTableLine*)aRowArr[i])->GetFrmFmt() );
469 SwFrm* pFrm = (SwFrm*)aIter.First( TYPE(SwFrm) );
470 while ( pFrm )
472 nHeight = Max( nHeight, pFrm->Frm().Height() );
473 pFrm = (SwFrm*)aIter.Next();
476 SwFmtFrmSize aNew( ATT_MIN_SIZE, 0, nHeight );
478 if( DoesUndo() )
480 ClearRedo();
481 AppendUndo( new SwUndoAttrTbl( *pTblNd ));
484 SvPtrarr aFmtCmp( Max( BYTE(255), BYTE(aRowArr.Count()) ), 255 );
485 for( i = 0; i < aRowArr.Count(); ++i )
486 ::lcl_ProcessRowSize( aFmtCmp, (SwTableLine*)aRowArr[i], aNew );
487 SwTblFmtCmp::Delete( aFmtCmp );
489 SetModified();
491 bRet = TRUE;
494 return bRet;
497 /******************************************************************************
498 * void SwDoc::SetRowBackground()
499 ******************************************************************************/
500 void SwDoc::SetRowBackground( const SwCursor& rCursor, const SvxBrushItem &rNew )
502 SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
503 if( pTblNd )
505 SvPtrarr aRowArr( 25, 50 ); //Zum sammeln Lines.
506 ::lcl_CollectLines( aRowArr, rCursor, true );
508 if( aRowArr.Count() )
510 if( DoesUndo() )
512 ClearRedo();
513 AppendUndo( new SwUndoAttrTbl( *pTblNd ));
516 SvPtrarr aFmtCmp( Max( BYTE(255), BYTE(aRowArr.Count()) ), 255 );
518 for( USHORT i = 0; i < aRowArr.Count(); ++i )
519 ::lcl_ProcessRowAttr( aFmtCmp, (SwTableLine*)aRowArr[i], rNew );
521 SwTblFmtCmp::Delete( aFmtCmp );
522 SetModified();
527 /******************************************************************************
528 * SwTwips SwDoc::GetRowBackground() const
529 ******************************************************************************/
530 BOOL SwDoc::GetRowBackground( const SwCursor& rCursor, SvxBrushItem &rToFill ) const
532 BOOL bRet = FALSE;
533 SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
534 if( pTblNd )
536 SvPtrarr aRowArr( 25, 50 ); //Zum sammeln Lines.
537 ::lcl_CollectLines( aRowArr, rCursor, true );
539 if( aRowArr.Count() )
541 rToFill = ((SwTableLine*)aRowArr[0])->GetFrmFmt()->GetBackground();
543 bRet = TRUE;
544 for ( USHORT i = 1; i < aRowArr.Count(); ++i )
545 if ( rToFill != ((SwTableLine*)aRowArr[i])->GetFrmFmt()->GetBackground() )
547 bRet = FALSE;
548 break;
552 return bRet;
555 /***********************************************************************
556 #* Class : SwDoc
557 #* Methoden : SetTabBorders(), GetTabBorders()
558 #* Datum : MA 18. May. 93
559 #* Update : JP 29.04.98
560 #***********************************************************************/
561 inline void InsertCell( SvPtrarr& rCellArr, SwCellFrm* pCellFrm )
563 if( USHRT_MAX == rCellArr.GetPos( (void*&)pCellFrm ) )
564 rCellArr.Insert( (void*&)pCellFrm, rCellArr.Count() );
567 //-----------------------------------------------------------------------------
568 void lcl_CollectCells( SvPtrarr &rArr, const SwRect &rUnion,
569 SwTabFrm *pTab )
571 SwLayoutFrm *pCell = pTab->FirstCell();
574 // Wenn in der Zelle ein spaltiger Bereich sitzt, muessen wir
575 // uns erst wieder zur Zelle hochhangeln
576 while ( !pCell->IsCellFrm() )
577 pCell = pCell->GetUpper();
578 ASSERT( pCell, "Frame ist keine Zelle." );
579 if ( rUnion.IsOver( pCell->Frm() ) )
580 ::InsertCell( rArr, (SwCellFrm*)pCell );
581 //Dafuer sorgen, dass die Zelle auch verlassen wird (Bereiche)
582 SwLayoutFrm *pTmp = pCell;
584 { pTmp = pTmp->GetNextLayoutLeaf();
585 } while ( pCell->IsAnLower( pTmp ) );
586 pCell = pTmp;
587 } while( pCell && pTab->IsAnLower( pCell ) );
590 void SwDoc::SetTabBorders( const SwCursor& rCursor, const SfxItemSet& rSet )
592 SwCntntNode* pCntNd = rCursor.GetPoint()->nNode.GetNode().GetCntntNode();
593 SwTableNode* pTblNd = pCntNd ? pCntNd->FindTableNode() : 0;
594 if( !pTblNd )
595 return ;
597 SwLayoutFrm *pStart, *pEnd;
598 ::lcl_GetStartEndCell( rCursor, pStart, pEnd );
600 SwSelUnions aUnions;
601 ::MakeSelUnions( aUnions, pStart, pEnd );
603 if( aUnions.Count() )
605 SwTable& rTable = pTblNd->GetTable();
606 if( DoesUndo() )
608 ClearRedo();
609 AppendUndo( new SwUndoAttrTbl( *pTblNd ));
612 SvPtrarr aFmtCmp( 255, 255 );
613 const SvxBoxItem* pSetBox;
614 const SvxBoxInfoItem *pSetBoxInfo;
616 const SvxBorderLine* pLeft = 0;
617 const SvxBorderLine* pRight = 0;
618 const SvxBorderLine* pTop = 0;
619 const SvxBorderLine* pBottom = 0;
620 const SvxBorderLine* pHori = 0;
621 const SvxBorderLine* pVert = 0;
622 BOOL bHoriValid = TRUE, bVertValid = TRUE,
623 bTopValid = TRUE, bBottomValid = TRUE,
624 bLeftValid = TRUE, bRightValid = TRUE;
626 // JP 21.07.95: die Flags im BoxInfo-Item entscheiden, wann eine
627 // BorderLine gueltig ist!!
628 if( SFX_ITEM_SET == rSet.GetItemState( SID_ATTR_BORDER_INNER, FALSE,
629 (const SfxPoolItem**)&pSetBoxInfo) )
631 pHori = pSetBoxInfo->GetHori();
632 pVert = pSetBoxInfo->GetVert();
634 bHoriValid = pSetBoxInfo->IsValid(VALID_HORI);
635 bVertValid = pSetBoxInfo->IsValid(VALID_VERT);
637 // wollen wir die auswerten ??
638 bTopValid = pSetBoxInfo->IsValid(VALID_TOP);
639 bBottomValid = pSetBoxInfo->IsValid(VALID_BOTTOM);
640 bLeftValid = pSetBoxInfo->IsValid(VALID_LEFT);
641 bRightValid = pSetBoxInfo->IsValid(VALID_RIGHT);
644 if( SFX_ITEM_SET == rSet.GetItemState( RES_BOX, FALSE,
645 (const SfxPoolItem**)&pSetBox) )
647 pLeft = pSetBox->GetLeft();
648 pRight = pSetBox->GetRight();
649 pTop = pSetBox->GetTop();
650 pBottom = pSetBox->GetBottom();
652 else
654 // nicht gesetzt, also keine gueltigen Werte
655 bTopValid = bBottomValid = bLeftValid = bRightValid = FALSE;
656 pSetBox = 0;
659 BOOL bFirst = TRUE;
660 for ( USHORT i = 0; i < aUnions.Count(); ++i )
662 SwSelUnion *pUnion = aUnions[i];
663 SwTabFrm *pTab = pUnion->GetTable();
664 const SwRect &rUnion = pUnion->GetUnion();
665 const BOOL bLast = i == aUnions.Count() - 1 ? TRUE : FALSE;
667 SvPtrarr aCellArr( 255, 255 );
668 ::lcl_CollectCells( aCellArr, pUnion->GetUnion(), pTab );
670 //Alle Zellenkanten, die mit dem UnionRect uebereinstimmen oder
671 //darueber hinausragen sind Aussenkanten. Alle anderen sind
672 //Innenkanten.
673 //neu: Die Aussenkanten koennen abhaengig davon, ob es sich um eine
674 //Start/Mittlere/Folge -Tabelle (bei Selektionen ueber FollowTabs)
675 //handelt doch keine Aussenkanten sein.
676 //Aussenkanten werden links, rechts, oben und unten gesetzt.
677 //Innenkanten werden nur oben und links gesetzt.
678 for ( USHORT j = 0; j < aCellArr.Count(); ++j )
680 SwCellFrm *pCell = (SwCellFrm*)aCellArr[j];
681 const sal_Bool bVert = pTab->IsVertical();
682 const sal_Bool bRTL = pTab->IsRightToLeft();
683 sal_Bool bTopOver, bLeftOver, bRightOver, bBottomOver;
684 if ( bVert )
686 bTopOver = pCell->Frm().Right() >= rUnion.Right();
687 bLeftOver = pCell->Frm().Top() <= rUnion.Top();
688 bRightOver = pCell->Frm().Bottom() >= rUnion.Bottom();
689 bBottomOver = pCell->Frm().Left() <= rUnion.Left();
691 else
693 bTopOver = pCell->Frm().Top() <= rUnion.Top();
694 bLeftOver = pCell->Frm().Left() <= rUnion.Left();
695 bRightOver = pCell->Frm().Right() >= rUnion.Right();
696 bBottomOver = pCell->Frm().Bottom() >= rUnion.Bottom();
699 if ( bRTL )
701 sal_Bool bTmp = bRightOver;
702 bRightOver = bLeftOver;
703 bLeftOver = bTmp;
706 //Grundsaetzlich nichts setzen in HeadlineRepeats.
707 if ( pTab->IsFollow() &&
708 ( pTab->IsInHeadline( *pCell ) ||
709 // --> FME 2006-02-07 #126092# Same holds for follow flow rows.
710 pCell->IsInFollowFlowRow() ) )
711 // <--
712 continue;
714 SvxBoxItem aBox( pCell->GetFmt()->GetBox() );
716 INT16 nType = 0;
718 //Obere Kante
719 if( bTopValid )
721 if ( bFirst && bTopOver )
723 aBox.SetLine( pTop, BOX_LINE_TOP );
724 nType |= 0x0001;
726 else if ( bHoriValid )
728 aBox.SetLine( 0, BOX_LINE_TOP );
729 nType |= 0x0002;
733 //Linke Kante
734 if ( bLeftOver )
736 if( bLeftValid )
738 aBox.SetLine( pLeft, BOX_LINE_LEFT );
739 nType |= 0x0004;
742 else if( bVertValid )
744 aBox.SetLine( pVert, BOX_LINE_LEFT );
745 nType |= 0x0008;
748 //Rechte Kante
749 if( bRightValid )
751 if ( bRightOver )
753 aBox.SetLine( pRight, BOX_LINE_RIGHT );
754 nType |= 0x0010;
756 else if ( bVertValid )
758 aBox.SetLine( 0, BOX_LINE_RIGHT );
759 nType |= 0x0020;
763 //Untere Kante
764 if ( bLast && bBottomOver )
766 if( bBottomValid )
768 aBox.SetLine( pBottom, BOX_LINE_BOTTOM );
769 nType |= 0x0040;
772 else if( bHoriValid )
774 aBox.SetLine( pHori, BOX_LINE_BOTTOM );
775 nType |= 0x0080;
778 if( pSetBox )
780 static USHORT __READONLY_DATA aBorders[] = {
781 BOX_LINE_BOTTOM, BOX_LINE_TOP,
782 BOX_LINE_RIGHT, BOX_LINE_LEFT };
783 const USHORT* pBrd = aBorders;
784 for( int k = 0; k < 4; ++k, ++pBrd )
785 aBox.SetDistance( pSetBox->GetDistance( *pBrd ), *pBrd );
788 SwTableBox *pBox = (SwTableBox*)pCell->GetTabBox();
789 SwFrmFmt *pNewFmt;
790 if ( 0 != (pNewFmt = SwTblFmtCmp::FindNewFmt( aFmtCmp, pBox->GetFrmFmt(), nType )))
791 pBox->ChgFrmFmt( (SwTableBoxFmt*)pNewFmt );
792 else
794 SwFrmFmt *pOld = pBox->GetFrmFmt();
795 SwFrmFmt *pNew = pBox->ClaimFrmFmt();
796 pNew->SetFmtAttr( aBox );
797 aFmtCmp.Insert( new SwTblFmtCmp( pOld, pNew, nType ), aFmtCmp.Count());
801 bFirst = FALSE;
804 SwHTMLTableLayout *pTableLayout = rTable.GetHTMLTableLayout();
805 if( pTableLayout )
807 SwCntntFrm* pFrm = rCursor.GetCntntNode()->GetFrm();
808 SwTabFrm* pTabFrm = pFrm->ImplFindTabFrm();
810 pTableLayout->BordersChanged(
811 pTableLayout->GetBrowseWidthByTabFrm( *pTabFrm ), TRUE );
813 SwTblFmtCmp::Delete( aFmtCmp );
814 ::ClearFEShellTabCols();
815 SetModified();
819 void lcl_SetLineStyle( SvxBorderLine *pToSet,
820 const Color *pColor, const SvxBorderLine *pBorderLine)
822 if ( pBorderLine )
824 if ( !pColor )
826 Color aTmp( pToSet->GetColor() );
827 *pToSet = *pBorderLine;
828 pToSet->SetColor( aTmp );
830 else
831 *pToSet = *pBorderLine;
833 if ( pColor )
834 pToSet->SetColor( *pColor );
837 void SwDoc::SetTabLineStyle( const SwCursor& rCursor,
838 const Color* pColor, BOOL bSetLine,
839 const SvxBorderLine* pBorderLine )
841 SwCntntNode* pCntNd = rCursor.GetPoint()->nNode.GetNode().GetCntntNode();
842 SwTableNode* pTblNd = pCntNd ? pCntNd->FindTableNode() : 0;
843 if( !pTblNd )
844 return ;
846 SwLayoutFrm *pStart, *pEnd;
847 ::lcl_GetStartEndCell( rCursor, pStart, pEnd );
849 SwSelUnions aUnions;
850 ::MakeSelUnions( aUnions, pStart, pEnd );
852 if( aUnions.Count() )
854 SwTable& rTable = pTblNd->GetTable();
855 if( DoesUndo() )
857 ClearRedo();
858 AppendUndo( new SwUndoAttrTbl( *pTblNd ));
861 for( USHORT i = 0; i < aUnions.Count(); ++i )
863 SwSelUnion *pUnion = aUnions[i];
864 SwTabFrm *pTab = pUnion->GetTable();
865 SvPtrarr aCellArr( 255, 255 );
866 ::lcl_CollectCells( aCellArr, pUnion->GetUnion(), pTab );
868 for ( USHORT j = 0; j < aCellArr.Count(); ++j )
870 SwCellFrm *pCell = ( SwCellFrm* )aCellArr[j];
872 //Grundsaetzlich nichts setzen in HeadlineRepeats.
873 if ( pTab->IsFollow() && pTab->IsInHeadline( *pCell ) )
874 continue;
876 ((SwTableBox*)pCell->GetTabBox())->ClaimFrmFmt();
877 SwFrmFmt *pFmt = pCell->GetFmt();
878 SvxBoxItem aBox( pFmt->GetBox() );
880 if ( !pBorderLine && bSetLine )
881 aBox = *(SvxBoxItem*)::GetDfltAttr( RES_BOX );
882 else
884 if ( aBox.GetTop() )
885 ::lcl_SetLineStyle( (SvxBorderLine*)aBox.GetTop(),
886 pColor, pBorderLine );
887 if ( aBox.GetBottom() )
888 ::lcl_SetLineStyle( (SvxBorderLine*)aBox.GetBottom(),
889 pColor, pBorderLine );
890 if ( aBox.GetLeft() )
891 ::lcl_SetLineStyle( (SvxBorderLine*)aBox.GetLeft(),
892 pColor, pBorderLine );
893 if ( aBox.GetRight() )
894 ::lcl_SetLineStyle( (SvxBorderLine*)aBox.GetRight(),
895 pColor, pBorderLine );
897 pFmt->SetFmtAttr( aBox );
901 SwHTMLTableLayout *pTableLayout = rTable.GetHTMLTableLayout();
902 if( pTableLayout )
904 SwCntntFrm* pFrm = rCursor.GetCntntNode()->GetFrm();
905 SwTabFrm* pTabFrm = pFrm->ImplFindTabFrm();
907 pTableLayout->BordersChanged(
908 pTableLayout->GetBrowseWidthByTabFrm( *pTabFrm ), TRUE );
910 ::ClearFEShellTabCols();
911 SetModified();
915 void SwDoc::GetTabBorders( const SwCursor& rCursor, SfxItemSet& rSet ) const
917 SwCntntNode* pCntNd = rCursor.GetPoint()->nNode.GetNode().GetCntntNode();
918 SwTableNode* pTblNd = pCntNd ? pCntNd->FindTableNode() : 0;
919 if( !pTblNd )
920 return ;
922 SwLayoutFrm *pStart, *pEnd;
923 ::lcl_GetStartEndCell( rCursor, pStart, pEnd );
925 SwSelUnions aUnions;
926 ::MakeSelUnions( aUnions, pStart, pEnd );
928 if( aUnions.Count() )
930 SvxBoxItem aSetBox ((const SvxBoxItem &) rSet.Get(RES_BOX ));
931 SvxBoxInfoItem aSetBoxInfo((const SvxBoxInfoItem&) rSet.Get(SID_ATTR_BORDER_INNER));
933 BOOL bTopSet = FALSE,
934 bBottomSet = FALSE,
935 bLeftSet = FALSE,
936 bRightSet = FALSE,
937 bHoriSet = FALSE,
938 bVertSet = FALSE,
939 bDistanceSet = FALSE;
941 aSetBoxInfo.ResetFlags();
943 for ( USHORT i = 0; i < aUnions.Count(); ++i )
945 SwSelUnion *pUnion = aUnions[i];
946 const SwTabFrm *pTab = pUnion->GetTable();
947 const SwRect &rUnion = pUnion->GetUnion();
948 const BOOL bFirst = i == 0 ? TRUE : FALSE;
949 const BOOL bLast = i == aUnions.Count() - 1 ? TRUE : FALSE;
951 SvPtrarr aCellArr( 255, 255 );
952 ::lcl_CollectCells( aCellArr, rUnion, (SwTabFrm*)pTab );
954 for ( USHORT j = 0; j < aCellArr.Count(); ++j )
956 const SwCellFrm *pCell = (const SwCellFrm*)aCellArr[j];
957 const sal_Bool bVert = pTab->IsVertical();
958 const sal_Bool bRTL = pTab->IsRightToLeft();
959 sal_Bool bTopOver, bLeftOver, bRightOver, bBottomOver;
960 if ( bVert )
962 bTopOver = pCell->Frm().Right() >= rUnion.Right();
963 bLeftOver = pCell->Frm().Top() <= rUnion.Top();
964 bRightOver = pCell->Frm().Bottom() >= rUnion.Bottom();
965 bBottomOver = pCell->Frm().Left() <= rUnion.Left();
967 else
969 bTopOver = pCell->Frm().Top() <= rUnion.Top();
970 bLeftOver = pCell->Frm().Left() <= rUnion.Left();
971 bRightOver = pCell->Frm().Right() >= rUnion.Right();
972 bBottomOver = pCell->Frm().Bottom() >= rUnion.Bottom();
975 if ( bRTL )
977 sal_Bool bTmp = bRightOver;
978 bRightOver = bLeftOver;
979 bLeftOver = bTmp;
982 const SwFrmFmt *pFmt = pCell->GetFmt();
983 const SvxBoxItem &rBox = pFmt->GetBox();
985 //Obere Kante
986 if ( bFirst && bTopOver )
988 if (aSetBoxInfo.IsValid(VALID_TOP))
990 if ( !bTopSet )
991 { bTopSet = TRUE;
992 aSetBox.SetLine( rBox.GetTop(), BOX_LINE_TOP );
994 else if ((aSetBox.GetTop() && rBox.GetTop() &&
995 !(*aSetBox.GetTop() == *rBox.GetTop())) ||
996 ((!aSetBox.GetTop()) ^ (!rBox.GetTop()))) // XOR-Ausdruck ist TRUE, wenn genau einer der beiden Pointer 0 ist
998 aSetBoxInfo.SetValid(VALID_TOP, FALSE );
999 aSetBox.SetLine( 0, BOX_LINE_TOP );
1004 //Linke Kante
1005 if ( bLeftOver )
1007 if (aSetBoxInfo.IsValid(VALID_LEFT))
1009 if ( !bLeftSet )
1010 { bLeftSet = TRUE;
1011 aSetBox.SetLine( rBox.GetLeft(), BOX_LINE_LEFT );
1013 else if ((aSetBox.GetLeft() && rBox.GetLeft() &&
1014 !(*aSetBox.GetLeft() == *rBox.GetLeft())) ||
1015 ((!aSetBox.GetLeft()) ^ (!rBox.GetLeft())))
1017 aSetBoxInfo.SetValid(VALID_LEFT, FALSE );
1018 aSetBox.SetLine( 0, BOX_LINE_LEFT );
1022 else
1024 if (aSetBoxInfo.IsValid(VALID_VERT))
1026 if ( !bVertSet )
1027 { bVertSet = TRUE;
1028 aSetBoxInfo.SetLine( rBox.GetLeft(), BOXINFO_LINE_VERT );
1030 else if ((aSetBoxInfo.GetVert() && rBox.GetLeft() &&
1031 !(*aSetBoxInfo.GetVert() == *rBox.GetLeft())) ||
1032 ((!aSetBoxInfo.GetVert()) ^ (!rBox.GetLeft())))
1033 { aSetBoxInfo.SetValid( VALID_VERT, FALSE );
1034 aSetBoxInfo.SetLine( 0, BOXINFO_LINE_VERT );
1039 //Rechte Kante
1040 if ( aSetBoxInfo.IsValid(VALID_RIGHT) && bRightOver )
1042 if ( !bRightSet )
1043 { bRightSet = TRUE;
1044 aSetBox.SetLine( rBox.GetRight(), BOX_LINE_RIGHT );
1046 else if ((aSetBox.GetRight() && rBox.GetRight() &&
1047 !(*aSetBox.GetRight() == *rBox.GetRight())) ||
1048 (!aSetBox.GetRight() ^ !rBox.GetRight()))
1049 { aSetBoxInfo.SetValid( VALID_RIGHT, FALSE );
1050 aSetBox.SetLine( 0, BOX_LINE_RIGHT );
1054 //Untere Kante
1055 if ( bLast && bBottomOver )
1057 if ( aSetBoxInfo.IsValid(VALID_BOTTOM) )
1059 if ( !bBottomSet )
1060 { bBottomSet = TRUE;
1061 aSetBox.SetLine( rBox.GetBottom(), BOX_LINE_BOTTOM );
1063 else if ((aSetBox.GetBottom() && rBox.GetBottom() &&
1064 !(*aSetBox.GetBottom() == *rBox.GetBottom())) ||
1065 (!aSetBox.GetBottom() ^ !rBox.GetBottom()))
1066 { aSetBoxInfo.SetValid( VALID_BOTTOM, FALSE );
1067 aSetBox.SetLine( 0, BOX_LINE_BOTTOM );
1071 //in allen Zeilen ausser der letzten werden die
1072 // horiz. Linien aus der Bottom-Linie entnommen
1073 else
1075 if (aSetBoxInfo.IsValid(VALID_HORI))
1077 if ( !bHoriSet )
1078 { bHoriSet = TRUE;
1079 aSetBoxInfo.SetLine( rBox.GetBottom(), BOXINFO_LINE_HORI );
1081 else if ((aSetBoxInfo.GetHori() && rBox.GetBottom() &&
1082 !(*aSetBoxInfo.GetHori() == *rBox.GetBottom())) ||
1083 ((!aSetBoxInfo.GetHori()) ^ (!rBox.GetBottom())))
1085 aSetBoxInfo.SetValid( VALID_HORI, FALSE );
1086 aSetBoxInfo.SetLine( 0, BOXINFO_LINE_HORI );
1091 // Abstand zum Text
1092 if (aSetBoxInfo.IsValid(VALID_DISTANCE))
1094 static USHORT __READONLY_DATA aBorders[] = {
1095 BOX_LINE_BOTTOM, BOX_LINE_TOP,
1096 BOX_LINE_RIGHT, BOX_LINE_LEFT };
1097 const USHORT* pBrd = aBorders;
1099 if( !bDistanceSet ) // bei 1. Durchlauf erstmal setzen
1101 bDistanceSet = TRUE;
1102 for( int k = 0; k < 4; ++k, ++pBrd )
1103 aSetBox.SetDistance( rBox.GetDistance( *pBrd ),
1104 *pBrd );
1106 else
1108 for( int k = 0; k < 4; ++k, ++pBrd )
1109 if( aSetBox.GetDistance( *pBrd ) !=
1110 rBox.GetDistance( *pBrd ) )
1112 aSetBoxInfo.SetValid( VALID_DISTANCE, FALSE );
1113 aSetBox.SetDistance( (USHORT) 0 );
1114 break;
1120 rSet.Put( aSetBox );
1121 rSet.Put( aSetBoxInfo );
1125 /***********************************************************************
1126 #* Class : SwDoc
1127 #* Methoden : SetBoxAttr
1128 #* Datum : MA 18. Dec. 96
1129 #* Update : JP 29.04.98
1130 #***********************************************************************/
1131 void SwDoc::SetBoxAttr( const SwCursor& rCursor, const SfxPoolItem &rNew )
1133 SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
1134 SwSelBoxes aBoxes;
1135 if( pTblNd && ::lcl_GetBoxSel( rCursor, aBoxes, TRUE ) )
1137 SwTable& rTable = pTblNd->GetTable();
1138 if( DoesUndo() )
1140 ClearRedo();
1141 AppendUndo( new SwUndoAttrTbl( *pTblNd ));
1144 SvPtrarr aFmtCmp( Max( BYTE(255), BYTE(aBoxes.Count()) ), 255 );
1145 for ( USHORT i = 0; i < aBoxes.Count(); ++i )
1147 SwTableBox *pBox = aBoxes[i];
1149 SwFrmFmt *pNewFmt;
1150 if ( 0 != (pNewFmt = SwTblFmtCmp::FindNewFmt( aFmtCmp, pBox->GetFrmFmt(), 0 )))
1151 pBox->ChgFrmFmt( (SwTableBoxFmt*)pNewFmt );
1152 else
1154 SwFrmFmt *pOld = pBox->GetFrmFmt();
1155 SwFrmFmt *pNew = pBox->ClaimFrmFmt();
1156 pNew->SetFmtAttr( rNew );
1157 aFmtCmp.Insert( new SwTblFmtCmp( pOld, pNew, 0 ), aFmtCmp.Count());
1161 SwHTMLTableLayout *pTableLayout = rTable.GetHTMLTableLayout();
1162 if( pTableLayout )
1164 SwCntntFrm* pFrm = rCursor.GetCntntNode()->GetFrm();
1165 SwTabFrm* pTabFrm = pFrm->ImplFindTabFrm();
1167 pTableLayout->Resize(
1168 pTableLayout->GetBrowseWidthByTabFrm( *pTabFrm ), TRUE );
1170 SwTblFmtCmp::Delete( aFmtCmp );
1171 SetModified();
1175 /***********************************************************************
1176 #* Class : SwDoc
1177 #* Methoden : GetBoxAttr()
1178 #* Datum : MA 01. Jun. 93
1179 #* Update : JP 29.04.98
1180 #***********************************************************************/
1182 BOOL SwDoc::GetBoxAttr( const SwCursor& rCursor, SfxPoolItem& rToFill ) const
1184 BOOL bRet = FALSE;
1185 SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
1186 SwSelBoxes aBoxes;
1187 if( pTblNd && lcl_GetBoxSel( rCursor, aBoxes ))
1189 bRet = TRUE;
1190 BOOL bOneFound = FALSE;
1191 const USHORT nWhich = rToFill.Which();
1192 for( USHORT i = 0; i < aBoxes.Count(); ++i )
1194 switch ( nWhich )
1196 case RES_BACKGROUND:
1198 const SvxBrushItem &rBack =
1199 aBoxes[i]->GetFrmFmt()->GetBackground();
1200 if( !bOneFound )
1202 (SvxBrushItem&)rToFill = rBack;
1203 bOneFound = TRUE;
1205 else if( rToFill != rBack )
1206 bRet = FALSE;
1208 break;
1210 case RES_FRAMEDIR:
1212 const SvxFrameDirectionItem& rDir =
1213 aBoxes[i]->GetFrmFmt()->GetFrmDir();
1214 if( !bOneFound )
1216 (SvxFrameDirectionItem&)rToFill = rDir;
1217 bOneFound = TRUE;
1219 else if( rToFill != rDir )
1220 bRet = FALSE;
1224 if ( FALSE == bRet )
1225 break;
1228 return bRet;
1231 /***********************************************************************
1232 #* Class : SwDoc
1233 #* Methoden : SetBoxAlign, SetBoxAlign
1234 #* Datum : MA 18. Dec. 96
1235 #* Update : JP 29.04.98
1236 #***********************************************************************/
1237 void SwDoc::SetBoxAlign( const SwCursor& rCursor, USHORT nAlign )
1239 ASSERT( nAlign == text::VertOrientation::NONE ||
1240 nAlign == text::VertOrientation::CENTER ||
1241 nAlign == text::VertOrientation::BOTTOM, "wrong alignment" );
1242 SwFmtVertOrient aVertOri( 0, nAlign );
1243 SetBoxAttr( rCursor, aVertOri );
1246 USHORT SwDoc::GetBoxAlign( const SwCursor& rCursor ) const
1248 USHORT nAlign = USHRT_MAX;
1249 SwTableNode* pTblNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
1250 SwSelBoxes aBoxes;
1251 if( pTblNd && ::lcl_GetBoxSel( rCursor, aBoxes ))
1252 for( USHORT i = 0; i < aBoxes.Count(); ++i )
1254 const SwFmtVertOrient &rOri =
1255 aBoxes[i]->GetFrmFmt()->GetVertOrient();
1256 if( USHRT_MAX == nAlign )
1257 nAlign = static_cast<USHORT>(rOri.GetVertOrient());
1258 else if( rOri.GetVertOrient() != nAlign )
1260 nAlign = USHRT_MAX;
1261 break;
1264 return nAlign;
1268 /***********************************************************************
1269 #* Class : SwDoc
1270 #* Methoden : AdjustCellWidth()
1271 #* Datum : MA 20. Feb. 95
1272 #* Update : JP 29.04.98
1273 #***********************************************************************/
1274 USHORT lcl_CalcCellFit( const SwLayoutFrm *pCell )
1276 SwTwips nRet = 0;
1277 const SwFrm *pFrm = pCell->Lower(); //Die ganze Zelle.
1278 SWRECTFN( pCell )
1279 while ( pFrm )
1281 const SwTwips nAdd = (pFrm->Frm().*fnRect->fnGetWidth)() -
1282 (pFrm->Prt().*fnRect->fnGetWidth)();
1284 // --> FME 2005-12-02 #127801# pFrm does not necessarily have to be a SwTxtFrm!
1285 const SwTwips nCalcFitToContent = pFrm->IsTxtFrm() ?
1286 ((SwTxtFrm*)pFrm)->CalcFitToContent() :
1287 (pFrm->Prt().*fnRect->fnGetWidth)();
1288 // <--
1290 nRet = Max( nRet, nCalcFitToContent + nAdd );
1291 pFrm = pFrm->GetNext();
1293 //Umrandung und linker/rechter Rand wollen mit kalkuliert werden.
1294 nRet += (pCell->Frm().*fnRect->fnGetWidth)() -
1295 (pCell->Prt().*fnRect->fnGetWidth)();
1297 //Um Rechenungenauikeiten, die spaeter bei SwTable::SetTabCols enstehen,
1298 //auszugleichen, addieren wir noch ein bischen.
1299 nRet += COLFUZZY;
1300 return (USHORT)Max( long(MINLAY), nRet );
1303 /*Die Zelle ist in der Selektion, wird aber nicht von den TabCols beschrieben.
1304 *Das bedeutet, dass die Zelle aufgrund der zweidimensionalen Darstellung von
1305 *anderen Zellen "geteilt" wurde. Wir muessen also den Wunsch- bzw. Minimalwert
1306 *der Zelle auf die Spalten, durch die sie geteilt wurde verteilen.
1308 *Dazu sammeln wir zuerst die Spalten - nicht die Spaltentrenner! - ein, die
1309 *sich mit der Zelle ueberschneiden. Den Wunschwert der Zelle verteilen wir
1310 *dann anhand des Betrages der Ueberschneidung auf die Zellen.
1311 *Wenn eine Zelle bereits einen groesseren Wunschwert angemeldet hat, so bleibt
1312 *dieser erhalten, kleinere Wuensche werden ueberschrieben.
1315 void lcl_CalcSubColValues( SvUShorts &rToFill, const SwTabCols &rCols,
1316 const SwLayoutFrm *pCell, const SwLayoutFrm *pTab,
1317 BOOL bWishValues )
1319 const USHORT nWish = bWishValues ?
1320 ::lcl_CalcCellFit( pCell ) :
1321 MINLAY + USHORT(pCell->Frm().Width() - pCell->Prt().Width());
1323 SWRECTFN( pTab )
1325 for ( USHORT i = 0 ; i <= rCols.Count(); ++i )
1327 long nColLeft = i == 0 ? rCols.GetLeft() : rCols[i-1];
1328 long nColRight = i == rCols.Count() ? rCols.GetRight() : rCols[i];
1329 nColLeft += rCols.GetLeftMin();
1330 nColRight += rCols.GetLeftMin();
1332 //Werte auf die Verhaeltnisse der Tabelle (Follows) anpassen.
1333 if ( rCols.GetLeftMin() != USHORT((pTab->Frm().*fnRect->fnGetLeft)()) )
1335 const long nDiff = (pTab->Frm().*fnRect->fnGetLeft)() - rCols.GetLeftMin();
1336 nColLeft += nDiff;
1337 nColRight += nDiff;
1339 const long nCellLeft = (pCell->Frm().*fnRect->fnGetLeft)();
1340 const long nCellRight = (pCell->Frm().*fnRect->fnGetRight)();
1342 //Ueberschneidungsbetrag ermitteln.
1343 long nWidth = 0;
1344 if ( nColLeft <= nCellLeft && nColRight >= (nCellLeft+COLFUZZY) )
1345 nWidth = nColRight - nCellLeft;
1346 else if ( nColLeft <= (nCellRight-COLFUZZY) && nColRight >= nCellRight )
1347 nWidth = nCellRight - nColLeft;
1348 else if ( nColLeft >= nCellLeft && nColRight <= nCellRight )
1349 nWidth = nColRight - nColLeft;
1350 if ( nWidth && pCell->Frm().Width() )
1352 long nTmp = nWidth * nWish / pCell->Frm().Width();
1353 if ( USHORT(nTmp) > rToFill[i] )
1354 rToFill[i] = USHORT(nTmp);
1359 /*Besorgt neue Werte zu Einstellung der TabCols.
1360 *Es wird nicht ueber die Eintrage in den TabCols itereriert, sondern
1361 *quasi ueber die Zwischenraeume, die ja die Zellen beschreiben.
1363 *bWishValues == TRUE: Es werden zur aktuellen Selektion bzw. zur aktuellen
1364 * Zelle die Wunschwerte aller betroffen Zellen ermittelt.
1365 * Sind mehrere Zellen in einer Spalte, so wird der
1366 * groesste Wunschwert als Ergebnis geliefert.
1367 * Fuer die TabCol-Eintraege, zu denen keine Zellen
1368 * ermittelt wurden, werden 0-en eingetragen.
1370 *bWishValues == FALSE: Die Selektion wird senkrecht ausgedehnt. Zu jeder
1371 * Spalte in den TabCols, die sich mit der Selektion
1372 * schneidet wird der Minimalwert ermittelt.
1375 void lcl_CalcColValues( SvUShorts &rToFill, const SwTabCols &rCols,
1376 const SwLayoutFrm *pStart, const SwLayoutFrm *pEnd,
1377 BOOL bWishValues )
1379 SwSelUnions aUnions;
1380 ::MakeSelUnions( aUnions, pStart, pEnd,
1381 bWishValues ? nsSwTblSearchType::TBLSEARCH_NONE : nsSwTblSearchType::TBLSEARCH_COL );
1383 for ( USHORT i2 = 0; i2 < aUnions.Count(); ++i2 )
1385 SwSelUnion *pSelUnion = aUnions[i2];
1386 const SwTabFrm *pTab = pSelUnion->GetTable();
1387 const SwRect &rUnion = pSelUnion->GetUnion();
1389 SWRECTFN( pTab )
1390 sal_Bool bRTL = pTab->IsRightToLeft();
1392 const SwLayoutFrm *pCell = pTab->FirstCell();
1395 if ( pCell->IsCellFrm() && pCell->FindTabFrm() == pTab && ::IsFrmInTblSel( rUnion, pCell ) )
1397 const long nCLeft = (pCell->Frm().*fnRect->fnGetLeft)();
1398 const long nCRight = (pCell->Frm().*fnRect->fnGetRight)();
1400 BOOL bNotInCols = TRUE;
1402 for ( USHORT i = 0; i <= rCols.Count(); ++i )
1404 USHORT nFit = rToFill[i];
1405 long nColLeft = i == 0 ? rCols.GetLeft() : rCols[i-1];
1406 long nColRight = i == rCols.Count() ? rCols.GetRight() : rCols[i];
1408 if ( bRTL )
1410 long nTmpRight = nColRight;
1411 nColRight = rCols.GetRight() - nColLeft;
1412 nColLeft = rCols.GetRight() - nTmpRight;
1415 nColLeft += rCols.GetLeftMin();
1416 nColRight += rCols.GetLeftMin();
1418 //Werte auf die Verhaeltnisse der Tabelle (Follows) anpassen.
1419 long nLeftA = nColLeft;
1420 long nRightA = nColRight;
1421 if ( rCols.GetLeftMin() != USHORT((pTab->Frm().*fnRect->fnGetLeft)()) )
1423 const long nDiff = (pTab->Frm().*fnRect->fnGetLeft)() - rCols.GetLeftMin();
1424 nLeftA += nDiff;
1425 nRightA += nDiff;
1428 //Wir wollen nicht allzu genau hinsehen.
1429 if ( ::IsSame(nCLeft, nLeftA) && ::IsSame(nCRight, nRightA))
1431 bNotInCols = FALSE;
1432 if ( bWishValues )
1434 const USHORT nWish = ::lcl_CalcCellFit( pCell );
1435 if ( nWish > nFit )
1436 nFit = nWish;
1438 else
1439 { const USHORT nMin = MINLAY + USHORT(pCell->Frm().Width() -
1440 pCell->Prt().Width());
1441 if ( !nFit || nMin < nFit )
1442 nFit = nMin;
1444 if ( rToFill[i] < nFit )
1445 rToFill[i] = nFit;
1448 if ( bNotInCols )
1449 ::lcl_CalcSubColValues( rToFill, rCols, pCell, pTab, bWishValues );
1451 do {
1452 pCell = pCell->GetNextLayoutLeaf();
1453 }while( pCell && pCell->Frm().Width() == 0 );
1454 } while ( pCell && pTab->IsAnLower( pCell ) );
1459 void SwDoc::AdjustCellWidth( const SwCursor& rCursor, BOOL bBalance )
1461 // pruefe ob vom aktuellen Crsr der Point/Mark in einer Tabelle stehen
1462 SwCntntNode* pCntNd = rCursor.GetPoint()->nNode.GetNode().GetCntntNode();
1463 SwTableNode* pTblNd = pCntNd ? pCntNd->FindTableNode() : 0;
1464 if( !pTblNd )
1465 return ;
1467 SwLayoutFrm *pStart, *pEnd;
1468 ::lcl_GetStartEndCell( rCursor, pStart, pEnd );
1470 //TabCols besorgen, den ueber diese stellen wir die Tabelle neu ein.
1471 SwFrm* pBoxFrm = pStart;
1472 while( pBoxFrm && !pBoxFrm->IsCellFrm() )
1473 pBoxFrm = pBoxFrm->GetUpper();
1475 if ( !pBoxFrm )
1476 return; // robust
1478 SwTabCols aTabCols;
1479 GetTabCols( aTabCols, 0, (SwCellFrm*)pBoxFrm );
1481 if ( ! aTabCols.Count() )
1482 return;
1484 const BYTE nTmp = (BYTE)Max( USHORT(255), USHORT(aTabCols.Count() + 1) );
1485 SvUShorts aWish( nTmp, nTmp ),
1486 aMins( nTmp, nTmp );
1487 USHORT i;
1489 for ( i = 0; i <= aTabCols.Count(); ++i )
1491 aWish.Insert( USHORT(0), aWish.Count() );
1492 aMins.Insert( USHORT(0), aMins.Count() );
1494 ::lcl_CalcColValues( aWish, aTabCols, pStart, pEnd, TRUE );
1496 //Es ist Robuster wenn wir die Min-Werte fuer die ganze Tabelle berechnen.
1497 const SwTabFrm *pTab = pStart->ImplFindTabFrm();
1498 pStart = (SwLayoutFrm*)pTab->FirstCell();
1499 pEnd = (SwLayoutFrm*)pTab->FindLastCntnt()->GetUpper();
1500 while( !pEnd->IsCellFrm() )
1501 pEnd = pEnd->GetUpper();
1502 ::lcl_CalcColValues( aMins, aTabCols, pStart, pEnd, FALSE );
1504 if( bBalance )
1506 //Alle Spalten, die makiert sind haben jetzt einen Wunschwert
1507 //eingtragen. Wir addieren die aktuellen Werte, teilen das Ergebnis
1508 //durch die Anzahl und haben eine Wunschwert fuer den ausgleich.
1509 USHORT nWish = 0, nCnt = 0;
1510 for ( i = 0; i <= aTabCols.Count(); ++i )
1512 int nDiff = aWish[i];
1513 if ( nDiff )
1515 if ( i == 0 )
1516 nWish = static_cast<USHORT>( nWish + aTabCols[i] - aTabCols.GetLeft() );
1517 else if ( i == aTabCols.Count() )
1518 nWish = static_cast<USHORT>(nWish + aTabCols.GetRight() - aTabCols[i-1] );
1519 else
1520 nWish = static_cast<USHORT>(nWish + aTabCols[i] - aTabCols[i-1] );
1521 ++nCnt;
1524 nWish = nWish / nCnt;
1525 for ( i = 0; i < aWish.Count(); ++i )
1526 if ( aWish[i] )
1527 aWish[i] = nWish;
1530 const USHORT nOldRight = static_cast<USHORT>(aTabCols.GetRight());
1532 //Um die Impl. einfach zu gestalten, aber trotzdem in den meissten Faellen
1533 //den Platz richtig auszunutzen laufen wir zweimal.
1534 //Problem: Erste Spalte wird breiter, die anderen aber erst danach
1535 //schmaler. Die Wunschbreite der ersten Spalte wuerde abgelehnt, weil
1536 //mit ihr die max. Breite der Tabelle ueberschritten wuerde.
1537 for ( USHORT k= 0; k < 2; ++k )
1539 for ( i = 0; i <= aTabCols.Count(); ++i )
1541 int nDiff = aWish[i];
1542 if ( nDiff )
1544 int nMin = aMins[i];
1545 if ( nMin > nDiff )
1546 nDiff = nMin;
1548 if ( i == 0 )
1550 if( aTabCols.Count() )
1551 nDiff -= aTabCols[0] - aTabCols.GetLeft();
1552 else
1553 nDiff -= aTabCols.GetRight() - aTabCols.GetLeft();
1555 else if ( i == aTabCols.Count() )
1556 nDiff -= aTabCols.GetRight() - aTabCols[i-1];
1557 else
1558 nDiff -= aTabCols[i] - aTabCols[i-1];
1560 long nTabRight = aTabCols.GetRight() + nDiff;
1562 //Wenn die Tabelle zu breit wuerde begrenzen wir die Anpassung
1563 //auf das erlaubte Maximum.
1564 if ( !bBalance && nTabRight > aTabCols.GetRightMax() )
1566 const long nTmpD = nTabRight - aTabCols.GetRightMax();
1567 nDiff -= nTmpD;
1568 nTabRight -= nTmpD;
1570 for ( USHORT i2 = i; i2 < aTabCols.Count(); ++i2 )
1571 aTabCols[i2] += nDiff;
1572 aTabCols.SetRight( nTabRight );
1577 const USHORT nNewRight = static_cast<USHORT>(aTabCols.GetRight());
1579 SwFrmFmt *pFmt = pTblNd->GetTable().GetFrmFmt();
1580 const sal_Int16 nOriHori = pFmt->GetHoriOrient().GetHoriOrient();
1582 //So, die richtige Arbeit koennen wir jetzt der SwTable ueberlassen.
1583 SetTabCols( aTabCols, FALSE, 0, (SwCellFrm*)pBoxFrm );
1585 // i54248: lijian/fme
1586 // alignment might have been changed in SetTabCols, restore old value:
1587 const SwFmtHoriOrient &rHori = pFmt->GetHoriOrient();
1588 SwFmtHoriOrient aHori( rHori );
1589 if ( aHori.GetHoriOrient() != nOriHori )
1591 aHori.SetHoriOrient( nOriHori );
1592 pFmt->SetFmtAttr( aHori );
1595 //Bei Automatischer Breite wird auf Linksbuendig umgeschaltet.
1596 //Bei Randattributen wird der Rechte Rand angepasst.
1597 if( !bBalance && nNewRight < nOldRight )
1599 if( aHori.GetHoriOrient() == text::HoriOrientation::FULL )
1601 aHori.SetHoriOrient( text::HoriOrientation::LEFT );
1602 pFmt->SetFmtAttr( aHori );
1606 SetModified();