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