xref: /AOO41X/main/sw/source/filter/rtf/rtftbl.cxx (revision b264d727df3f2f855962c46c6c4fbcd5e27e6a7e)
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 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */
27 
28 #ifdef WTC
29 #define private public
30 #endif
31 #include <hintids.hxx>
32 #include <editeng/lrspitem.hxx>
33 #include <editeng/boxitem.hxx>
34 #include <editeng/frmdiritem.hxx>
35 #include <svtools/rtftoken.h>
36 #include <fmtfsize.hxx>
37 #include <fmtpdsc.hxx>
38 #include <ndtxt.hxx>
39 #include <doc.hxx>
40 #include <pam.hxx>
41 #include <swparrtf.hxx>
42 #include <swtable.hxx>
43 #include <tblsel.hxx>
44 #include <swtblfmt.hxx>
45 #include <wrtswtbl.hxx>
46 #include <tblenum.hxx>
47 #include <frmatr.hxx>
48 #include <fmtrowsplt.hxx>
49 
50 using namespace ::com::sun::star;
51 
52 typedef SwTableBoxFmt* SwTableBoxFmtPtr;
53 SV_DECL_PTRARR( SwBoxFrmFmts, SwTableBoxFmtPtr, 25, 50 )
54 
55 class SwShareBoxFmts;
56 extern void _DeleteBox( SwTable& rTbl, SwTableBox* pBox, SwUndo* = 0,
57                     sal_Bool = sal_True, const sal_Bool = sal_True, SwShareBoxFmts* = 0 );
58 
59 struct Row
60 {
61     bool mbUseLeftRowPad, mbUseRightRowPad, mbUseTopRowPad, mbUseBottomRowPad;
62     long mnLeftRowPad, mnRightRowPad, mnTopRowPad, mnBottomRowPad;
63     sal_uInt16 mnBrdDist;
RowRow64     Row() :
65         mbUseLeftRowPad(false), mbUseRightRowPad(false),
66         mbUseTopRowPad(false), mbUseBottomRowPad(false),
67         mnLeftRowPad(0), mnRightRowPad(0), mnTopRowPad(0), mnBottomRowPad(0),
68         mnBrdDist(MIN_BORDER_DIST)
69     {}
70 };
71 
SetRowBorder(SfxItemSet & rSet,const Row & rRow)72 static void SetRowBorder(SfxItemSet& rSet, const Row &rRow)
73 {
74 #if 1
75     SvxBoxItem aBox((const SvxBoxItem&)rSet.Get(RES_BOX, false));
76     aBox.SetDistance( static_cast< sal_uInt16 >(rRow.mbUseLeftRowPad ? rRow.mnLeftRowPad : rRow.mnBrdDist),
77             BOX_LINE_LEFT);
78 
79     aBox.SetDistance( static_cast< sal_uInt16 >(rRow.mbUseRightRowPad ? rRow.mnRightRowPad : rRow.mnBrdDist),
80             BOX_LINE_RIGHT);
81 
82     aBox.SetDistance( static_cast< sal_uInt16 >(rRow.mbUseTopRowPad ? rRow.mnTopRowPad : 0),
83             BOX_LINE_TOP);
84 
85     aBox.SetDistance( static_cast< sal_uInt16 >(rRow.mbUseBottomRowPad ? rRow.mnBottomRowPad : 0),
86             BOX_LINE_BOTTOM);
87 
88     rSet.Put(aBox);
89 #else
90     const SfxPoolItem* pItem;
91     if (SFX_ITEM_SET == rSet.GetItemState(RES_BOX, sal_False, &pItem))
92     {
93         SvxBoxItem aBox( *(SvxBoxItem*)pItem );
94         aBox.SetDistance(rRow.mbUseLeftRowPad ? rRow.mnLeftRowPad : rRow.mnBrdDist,
95                 BOX_LINE_LEFT);
96 
97         aBox.SetDistance(rRow.mbUseRightRowPad ? rRow.mnRightRowPad : rRow.mnBrdDist,
98                 BOX_LINE_RIGHT);
99 
100         aBox.SetDistance(rRow.mbUseTopRowPad ? rRow.mnTopRowPad : 0,
101                 BOX_LINE_TOP);
102 
103         aBox.SetDistance(rRow.mbUseBottomRowPad ? rRow.mnBottomRowPad : 0,
104                 BOX_LINE_BOTTOM);
105 
106         rSet.Put(aBox);
107     }
108 #endif
109 }
110 
PrependedInlineNode(const SwPosition & rPos,const SwNode & rNode)111 void rtfSections::PrependedInlineNode(const SwPosition &rPos,
112     const SwNode &rNode)
113 {
114     ASSERT(!mrReader.IsNewDoc() || !maSegments.empty(),
115         "should not be possible, must be at least one segment in a new document");
116     if ((!maSegments.empty()) && (maSegments.back().maStart == rPos.nNode))
117         maSegments.back().maStart = SwNodeIndex(rNode);
118 }
119 
IsBorderToken(int nToken)120 bool SwRTFParser::IsBorderToken(int nToken)
121 {
122     /*
123         i30222 i28983
124         Our ability to sense border tokens is broken rtftoken.h is
125         organised in a way that ignores some border tokens. ReadBorderAttr
126         still doesn't support the more exotic borders but at least this
127         won't cause the parser to prematuerely exit the table
128     */
129     bool bResult = false;
130 
131     bResult =   (nToken >= RTF_BRDRDASHD && nToken <= RTF_BRDRTHTNMG) ||
132                 (nToken >=  RTF_BRDRTNTHSG && nToken <= RTF_BRDRWAVY);
133 
134     return bResult;
135 }
136 
ReadTable(int nToken)137 void SwRTFParser::ReadTable( int nToken )
138 {
139     nInsTblRow = USHRT_MAX;
140 
141     if (CantUseTables())
142     {
143         // alle Tabellen-Tokens ueberlesen
144         nToken = GetNextToken();        // RTF_TROWD ueberlesen
145         do {
146             if( RTF_TABLEDEF != (nToken & ~(0xff | RTF_SWGDEFS)) &&
147                 RTF_UNKNOWNCONTROL != nToken )
148             {
149                 SkipToken( -1 );
150                 break;
151             }
152             nToken = GetNextToken();
153         } while( IsParserWorking() );
154         return ;
155     }
156 
157     // verhinder Tabelle in Tabelle/Footnote
158     SwTwips nTblSz = 0;
159     int bReadNewCell = sal_False, bChkExistTbl = sal_False;
160 
161 
162     enum Limits {eMAXCELLS=64000};
163 
164     SvBools aMergeBackup(aMergeBoxes);
165 
166     // kein TROWD aber ein TabellenToken -> zwischen TROWD und Tab.Token
167     // waren andere Zeichen (siehe Bug 27445.rtf)
168     if( RTF_TROWD == nToken || !pTableNode )
169     {
170         if( RTF_TROWD == nToken )
171             nToken = GetNextToken();        // RTF_TROWD ueberlesen
172 
173         // Flag for delete merged boxes
174         aMergeBoxes.clear();
175         aMergeBoxes.push_back( (sal_Bool)sal_False );
176         m_nCurrentBox = 0;
177 
178         // wenn schon in einer Tabellen, dann splitte oder benutze
179         // die bisherigen Boxen weiter
180         bChkExistTbl = 0 != pPam->GetPoint()->nNode.GetNode().FindTableNode();
181     }
182     else
183     {
184         bReadNewCell = sal_True;
185         SwTableLines& rLns = pTableNode->GetTable().GetTabLines();
186         SwTableLine* pLine = rLns[ rLns.Count()-1 ];
187         // very robust to avoid crashes like bug 127425 + crash reports 118743
188         if( pLine )
189         {
190             sal_uInt16 nTmpBox = m_nCurrentBox;
191             if( nTmpBox > pLine->GetTabBoxes().Count() )
192                 nTmpBox = pLine->GetTabBoxes().Count();
193 
194             for (sal_uInt16 n = nTmpBox; n; )
195             {
196                 const SwTableBox *pTmp = pLine->GetTabBoxes()[ --n ];
197                 if( pTmp )
198                 {
199                     const SwFrmFmt* pTmpFmt = pTmp->GetFrmFmt();
200                     if( pTmpFmt )
201                         nTblSz += pTmpFmt->GetFrmSize().GetWidth();
202                 }
203             }
204         }
205     }
206 
207 
208     sal_Int16 eAdjust = text::HoriOrientation::LEFT;      // default fuer Tabellen
209     SwTwips nLSpace = 0;
210     Row aRow;
211 
212     bool bUseLeftCellPad = false, bUseRightCellPad = false,
213         bUseTopCellPad = false, bUseBottomCellPad = false;
214     long nLeftCellPad = 0, nRightCellPad = 0, nTopCellPad = 0,
215         nBottomCellPad = 0;
216 
217     sal_Int16 eVerOrient = text::VertOrientation::NONE;
218     long nLineHeight = 0;
219     if (aMergeBoxes.empty()) // can this actually happen?
220     {
221         OSL_ASSERT(false);
222         aMergeBoxes.push_back(sal_False);
223     }
224     size_t nBoxCnt = aMergeBoxes.size()-1;
225     SwBoxFrmFmts aBoxFmts;
226     SwTableBoxFmt* pBoxFmt = pDoc->MakeTableBoxFmt();
227     SvxFrameDirection eDir = FRMDIR_HORI_LEFT_TOP;
228     bool bCantSplit = false;
229 
230     int bWeiter = sal_True;
231     do {
232         switch( nToken )
233         {
234         case RTF_TRPADDFL:
235             aRow.mbUseLeftRowPad = (nTokenValue == 3) ? true : false;
236             break;
237         case RTF_TRPADDFT:
238             aRow.mbUseTopRowPad = (nTokenValue == 3) ? true : false;
239             break;
240         case RTF_TRPADDFR:
241             aRow.mbUseRightRowPad = (nTokenValue == 3) ? true : false;
242             break;
243         case RTF_TRPADDFB:
244             aRow.mbUseBottomRowPad = (nTokenValue == 3) ? true : false;
245             break;
246         case RTF_TRPADDL:
247             aRow.mnLeftRowPad = nTokenValue;
248             break;
249         case RTF_TRPADDT:
250             aRow.mnTopRowPad = nTokenValue;
251             break;
252         case RTF_TRPADDR:
253             aRow.mnRightRowPad = nTokenValue;
254             break;
255         case RTF_TRPADDB:
256             aRow.mnBottomRowPad = nTokenValue;
257             break;
258 
259         case RTF_CLPADFL:
260             bUseLeftCellPad = (nTokenValue == 3) ? true : false;
261             break;
262         case RTF_CLPADFT:
263             bUseTopCellPad = (nTokenValue == 3) ? true : false;
264             break;
265         case RTF_CLPADFR:
266             bUseRightCellPad = (nTokenValue == 3) ? true : false;
267             break;
268         case RTF_CLPADFB:
269             bUseBottomCellPad = (nTokenValue == 3) ? true : false;
270             break;
271         case RTF_CLPADL:
272             nLeftCellPad = nTokenValue;
273             break;
274         case RTF_CLPADT:
275             nTopCellPad = nTokenValue;
276             break;
277         case RTF_CLPADR:
278             nRightCellPad = nTokenValue;
279             break;
280         case RTF_CLPADB:
281             nBottomCellPad = nTokenValue;
282             break;
283 
284         case RTF_TRRH:
285             nLineHeight = nTokenValue;
286             break;
287 
288         case RTF_CLMRG:
289             // would crash later on reading \cellx (#i112657#):
290             // the first cell cannot be merged with earlier ones.
291             if (nBoxCnt != 0)
292             {
293                 aMergeBoxes.back() = sal_True;
294             }
295             break;
296 
297         case RTF_CELLX:
298             if (!bTrowdRead && (aMergeBoxes.size() < (SAL_MAX_UINT16 - 1)))
299             {
300                 SwTableBoxFmt* pFmt = pBoxFmt;
301                 SwTwips nSize = nTokenValue - nTblSz;
302                 if( aMergeBoxes.back() )
303                 {
304                     // neue Zellen lesen und noch keine Formate vorhanden,
305                     // dann benutze das der vorhergebende
306                     if( bReadNewCell && !aBoxFmts.Count() )
307                     {
308                         SwTableLines& rLns = pTableNode->GetTable().GetTabLines();
309                         SwTableLine* pLine = rLns[ rLns.Count()-1 ];
310                         if (m_nCurrentBox != 0)
311                         {
312                             --m_nCurrentBox;
313                         }
314                         if (m_nCurrentBox < pLine->GetTabBoxes().Count())
315                         {
316                             pFmt = static_cast<SwTableBoxFmt*>(
317                               pLine->GetTabBoxes()[m_nCurrentBox]->GetFrmFmt());
318                         }
319                     }
320                     else
321                         pFmt = aBoxFmts[ aBoxFmts.Count()-1 ];
322 
323                     // --> OD 2007-01-25 #i73790# - method renamed
324                     pBoxFmt->ResetAllFmtAttr();
325                     // <--
326                     nSize += pFmt->GetFrmSize().GetWidth();
327                 }
328                 else
329                 {
330                   //
331                   if (nSize<=2*aRow.mnBrdDist) {
332                     aRow.mnRightRowPad=0;
333                     aRow.mbUseRightRowPad=sal_True;
334                   }
335                     SetRowBorder((SfxItemSet&)pBoxFmt->GetAttrSet(), aRow);
336                     aBoxFmts.Insert( pBoxFmt, aBoxFmts.Count() );
337                     pBoxFmt = pDoc->MakeTableBoxFmt();
338                 }
339 
340                 if( !nSize )
341                     nSize = COL_DFLT_WIDTH;
342                 pFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nSize, 0 ));
343                 nTblSz = nTokenValue;
344                 aMergeBoxes.push_back( (sal_Bool)sal_False );
345                 ++nBoxCnt;
346 
347                 SvxBoxItem aBox(pFmt->GetBox());
348 
349                 if (bUseRightCellPad)
350                     aBox.SetDistance( static_cast< sal_uInt16 >(nRightCellPad), BOX_LINE_RIGHT);
351                 if (bUseBottomCellPad)
352                     aBox.SetDistance( static_cast< sal_uInt16 >(nBottomCellPad), BOX_LINE_BOTTOM);
353 
354                 //Yes, these are the wrong way around, there appears to
355                 //be a bug in word where these are swapped.
356                 if (bUseLeftCellPad)
357                     aBox.SetDistance( static_cast< sal_uInt16 >(nLeftCellPad), BOX_LINE_TOP);
358                 if (bUseTopCellPad)
359                     aBox.SetDistance( static_cast< sal_uInt16 >(nTopCellPad), BOX_LINE_LEFT);
360 
361 
362                 /*#106415# The Cell Borders are now balanced on import to
363                 improve the layout of tables.
364                 */
365 /*
366                 if ( aBoxFmts.Count()>1)
367                 {
368 
369                     SwTableBoxFmt* prevpFmt = aBoxFmts[ aBoxFmts.Count()-2 ];
370                     SvxBoxItem prevaBox(prevpFmt->GetBox());
371                     sal_uInt16 prevWidthRight=0;
372                     sal_uInt16 currWidthLeft=0;
373                     bool bDoubleLine=false;
374                     const SvxBorderLine*   brdrline ;
375                     const Color* pPrevRightColor;
376                     if(prevaBox.GetRight())
377                     {
378                         brdrline=prevaBox.GetRight();
379                         prevWidthRight = brdrline->GetOutWidth();
380                         pPrevRightColor = &brdrline->GetColor();
381                         if(brdrline->GetInWidth())
382                             bDoubleLine=true;
383                     }
384                     if(aBox.GetLeft())
385                     {
386                         brdrline=aBox.GetLeft();
387                         currWidthLeft = brdrline->GetOutWidth();
388                         if(brdrline->GetInWidth())
389                             bDoubleLine=true;
390                     }
391 
392                     if((currWidthLeft >0 || prevWidthRight >0) &&
393                         !bDoubleLine)
394                     {
395                         sal_uInt16 newBorderWidth=(currWidthLeft+prevWidthRight)/2 ;
396                         if(newBorderWidth /2 ==DEF_LINE_WIDTH_0 )
397                         {
398                             newBorderWidth =DEF_LINE_WIDTH_0;
399                         }
400                         else if(newBorderWidth /2 >=(DEF_LINE_WIDTH_4-DEF_LINE_WIDTH_3))
401                         {
402                             newBorderWidth =DEF_LINE_WIDTH_4;
403                         }
404                         else if(newBorderWidth /2 >=(DEF_LINE_WIDTH_3-DEF_LINE_WIDTH_2))
405                         {
406                             newBorderWidth =DEF_LINE_WIDTH_3;
407                         }
408                         else if(newBorderWidth /2>=(DEF_LINE_WIDTH_2-DEF_LINE_WIDTH_1))
409                         {
410                             newBorderWidth =DEF_LINE_WIDTH_2;
411                         }
412                         else if(newBorderWidth /2>=(DEF_LINE_WIDTH_1 - DEF_LINE_WIDTH_0)  )
413                         {
414                             newBorderWidth =DEF_LINE_WIDTH_1;
415                         }
416                         else
417                         {
418                             newBorderWidth =DEF_LINE_WIDTH_0;
419                         }
420                         const SvxBorderLine  newbrdrline(pPrevRightColor, newBorderWidth,0,0);
421                         aBox.SetLine(&newbrdrline,BOX_LINE_LEFT);
422                         prevaBox.SetLine(&newbrdrline,BOX_LINE_RIGHT);
423                         prevpFmt->SetAttr(prevaBox);
424                     }
425 
426                 }
427 */
428 
429                 pFmt->SetFmtAttr(aBox);
430 
431                 bUseLeftCellPad = false;
432                 bUseRightCellPad = false;
433                 bUseTopCellPad = false;
434                 bUseBottomCellPad = false;
435             }
436             break;
437 
438         case RTF_TRGAPH:
439                 //$flr bug #117887#: RTF: wrong internal table cell margin imported (A13)
440                 aRow.mnBrdDist = (nTokenValue>0?(sal_uInt16)nTokenValue:0); // filter out negative values of \trgaph
441             break;
442 
443         case RTF_TRQL:          eAdjust = text::HoriOrientation::LEFT;    break;
444         case RTF_TRQR:          eAdjust = text::HoriOrientation::RIGHT;   break;
445         case RTF_TRQC:          eAdjust = text::HoriOrientation::CENTER;  break;
446 
447                                 // mit text::VertOrientation::TOP kommt der Dialog nicht klar!
448                                 // Bug #65126#
449         case RTF_CLVERTALT:     eVerOrient = text::VertOrientation::NONE;     break;
450 
451         case RTF_CLVERTALC:     eVerOrient = text::VertOrientation::CENTER;   break;
452         case RTF_CLVERTALB:     eVerOrient = text::VertOrientation::BOTTOM;   break;
453 
454         case RTF_TRLEFT:
455             if( text::HoriOrientation::LEFT == eAdjust )
456                 eAdjust = text::HoriOrientation::LEFT_AND_WIDTH;
457             nLSpace = nTokenValue;
458             nTblSz = nTokenValue;
459             break;
460 
461         case RTF_TRHDR:
462             nRowsToRepeat++;
463             break;
464 
465         case RTF_CLTXLRTB:
466         case RTF_CLTXTBRL:
467         case RTF_INTBL:     // das wissen wir !
468         case RTF_CLMGF:
469         case RTF_CLVMGF:
470         case RTF_CLVMRG:
471             break;
472         case RTF_LTRROW:
473             eDir = FRMDIR_HORI_LEFT_TOP;
474             break;
475         case RTF_RTLROW:
476             eDir = FRMDIR_HORI_RIGHT_TOP;
477             break;
478         case RTF_TRBRDRB:
479         case RTF_TRBRDRH:
480         case RTF_TRBRDRL:
481         case RTF_TRBRDRR:
482         case RTF_TRBRDRT:
483         case RTF_TRBRDRV:
484                 break;
485         case RTF_TRKEEP:
486                 bCantSplit = true;
487                 break;
488 
489         default:
490             if( ( nToken & ~(0xff | RTF_TABLEDEF)) == RTF_SHADINGDEF )
491             {
492                 if( aMergeBoxes.back() )
493                     break;
494                 ReadBackgroundAttr( nToken,
495                         (SfxItemSet&)pBoxFmt->GetAttrSet(), sal_True );
496             }
497             else if( ( nToken & ~(0xff | RTF_TABLEDEF) ) == RTF_BRDRDEF ||
498                       IsBorderToken(nToken))
499             {
500                 if( aMergeBoxes.back() )
501                     break;
502 
503                 SfxItemSet& rSet = (SfxItemSet&)pBoxFmt->GetAttrSet();
504                 if(!IsBorderToken( nToken ))
505                     ReadBorderAttr( nToken, rSet, sal_True );
506                 else
507                     NextToken( nToken );
508             }
509             else if( RTF_TABLEDEF != (nToken & ~(0xff | RTF_SWGDEFS)) )
510             {
511                 if( RTF_UNKNOWNCONTROL == nToken )
512                     NextToken( nToken );
513                 else
514                     bWeiter = sal_False;
515             }
516             break;
517         }
518 
519         if( text::VertOrientation::NONE != eVerOrient )
520         {
521             if( !aMergeBoxes.back() )
522                 pBoxFmt->SetFmtAttr( SwFmtVertOrient( 0, eVerOrient ));
523             eVerOrient = text::VertOrientation::NONE;
524         }
525         if( bWeiter )
526             nToken = GetNextToken();
527     } while( bWeiter && IsParserWorking() );
528 
529     // das letzte temp. BoxFmt loeschen
530     delete pBoxFmt;
531 
532     // It has been recognized as not single box
533     if ((m_nCurrentBox == nBoxCnt) || ( bReadNewCell && !pTableNode ))
534     {
535         aMergeBoxes = aMergeBackup;
536         SkipToken( -1 );            // go back to the last valid
537         return;
538     }
539 
540     nTblSz -= nLSpace;
541 
542     int bNewTbl = sal_True;
543     SwTableLine* pNewLine;
544     bTrowdRead=true;
545 
546     // lege eine neue Tabelle an oder erweiter die aktuelle um eine neue Line
547     // oder Box !
548     SwNode* pNd;
549 
550     if( bChkExistTbl )
551     {
552         // es ist eine Tabelle vorhanden, teste mal ob die weiter benutzt
553         // werden kann oder ob sie abgesplittet und neu gefuellt werden
554         // muss.
555         pTableNode = pPam->GetNode()->FindTableNode();
556 
557         // Cursor kann nur in der letzten Line stehen
558 
559         // das Attribut darf nicht ueber das Modify an der
560         // Tabelle gesetzt werden, denn sonst werden alle
561         // Boxen wieder auf 0 zurueck gesetzt !!!!!
562         SwFrmFmt* pFmt = pTableNode->GetTable().GetFrmFmt();
563         const SwFmtFrmSize& rTblSz = pFmt->GetFrmSize();
564         const SwFmtHoriOrient& rHoriz = pFmt->GetHoriOrient();
565 
566         const SwTableLines* pLns = &pTableNode->GetTable().GetTabLines();
567 
568         if( 1 == pLns->Count() )
569         {
570             if( eAdjust != rHoriz.GetHoriOrient() )
571             {
572                 ((SfxItemSet&)pFmt->GetAttrSet()).Put( SwFmtHoriOrient( 0,
573                                                             eAdjust ) );
574             }
575             if( rTblSz.GetWidth() != nTblSz )
576             {
577                 SwFmtFrmSize aSz( rTblSz );
578                 aSz.SetWidth( nTblSz );
579                 ((SfxItemSet&)pFmt->GetAttrSet()).Put( aSz );
580             }
581 
582             if( text::HoriOrientation::LEFT_AND_WIDTH == eAdjust &&
583                 nLSpace != pFmt->GetLRSpace().GetLeft() )
584             {
585                 SvxLRSpaceItem aL( RES_LR_SPACE ); aL.SetLeft( nLSpace );
586                 ((SfxItemSet&)pFmt->GetAttrSet()).Put( aL );
587             }
588         }
589         else if
590             (
591               1 < pLns->Count() &&
592               (
593                 rTblSz.GetWidth() != nTblSz ||
594                 rHoriz.GetHoriOrient() != eAdjust ||
595                 (
596                   text::HoriOrientation::LEFT_AND_WIDTH == eAdjust &&
597                   nLSpace != pFmt->GetLRSpace().GetLeft()
598                 ) ||
599                 pTableNode->GetTable().GetTabSortBoxes().Count() >= eMAXCELLS
600               )
601             )
602         {
603             // Tabelle ab der PaM-Position splitten
604             // die vorherige Line!
605             pNewLine = (*pLns)[ pLns->Count() - 2 ];
606             SwTableBox* pBox = pNewLine->GetTabBoxes()[ 0 ];
607             while( ( pLns = &pBox->GetTabLines() )->Count() )
608                 pBox = (*pLns)[ 0 ]->GetTabBoxes()[ 0 ];
609 
610             SwNodeIndex aTmpIdx( *pBox->GetSttNd() );
611             pDoc->GetNodes().SplitTable( aTmpIdx, HEADLINE_NONE, sal_False );
612             pTableNode = pPam->GetNode()->FindTableNode();
613             pFmt = pTableNode->GetTable().GetFrmFmt();
614 
615             SwFmtFrmSize aSz( rTblSz );
616             aSz.SetWidth( nTblSz );
617             ((SfxItemSet&)pFmt->GetAttrSet()).Put( aSz );
618             ((SfxItemSet&)pFmt->GetAttrSet()).Put( SwFmtHoriOrient( 0,
619                                                             eAdjust ) );
620             if( text::HoriOrientation::LEFT_AND_WIDTH == eAdjust && nLSpace )
621             {
622                 SvxLRSpaceItem aL( RES_LR_SPACE ); aL.SetLeft( nLSpace );
623                 ((SfxItemSet&)pFmt->GetAttrSet()).Put( aL );
624             }
625         }
626 
627         pLns = &pTableNode->GetTable().GetTabLines();
628         pNewLine = (*pLns)[ pLns->Count() - 1 ];
629 
630         // jetzt die Boxen abgleichen
631         sal_uInt16 nBoxes = Min( pNewLine->GetTabBoxes().Count(), aBoxFmts.Count() );
632         sal_uInt16 n;
633 
634         for( n = 0; n < nBoxes; ++n )
635         {
636             SwTableBox* pBox = pNewLine->GetTabBoxes()[ n ];
637             *pBox->GetFrmFmt() = *aBoxFmts[ n ];
638             delete aBoxFmts[ n ];
639         }
640         aBoxFmts.Remove( 0, n );
641 
642         if( aBoxFmts.Count() )      // es muessen noch neue zugefuegt werden
643         {
644             m_nCurrentBox = n;
645         }
646         else                        // es mussen noch Boxen geloescht werden
647         {
648             // remove ContentIndex of other Bound
649             pPam->SetMark(); pPam->DeleteMark();
650             while( n < pNewLine->GetTabBoxes().Count() )
651                 _DeleteBox( pTableNode->GetTable(),
652                             pNewLine->GetTabBoxes()[ n ], 0, sal_False, sal_False );
653         }
654 
655         pOldTblNd = pTableNode;
656         bNewTbl = sal_False;
657     }
658     else
659     {
660         if( !bReadNewCell && ( pNd = pDoc->GetNodes()[
661             pPam->GetPoint()->nNode.GetIndex()-1 ])->IsEndNode() )
662         {
663             pTableNode = pNd->StartOfSectionNode()->GetTableNode();
664             if( pTableNode )
665             {
666                 // dann test mal ob wirklich nur eine neue Line eingefuegt
667                 // werden soll!
668                 SwTable &rTable = pTableNode->GetTable();
669                 SwFrmFmt* pFmt = rTable.GetFrmFmt();
670                 const SwFmtFrmSize& rTblSz = pFmt->GetFrmSize();
671                 const SwFmtHoriOrient& rHoriz = pFmt->GetHoriOrient();
672                 if (
673                     rTblSz.GetWidth() != nTblSz ||
674                     rHoriz.GetHoriOrient() != eAdjust ||
675                     rTable.GetTabSortBoxes().Count() >= eMAXCELLS
676                     )
677                 {
678                     pTableNode = 0;
679                 }
680             }
681         }
682 
683         if( pTableNode && !bForceNewTable)
684         {
685 
686             // das Attribut darf nicht ueber das Modify an der
687             // Tabelle gesetzt werden, denn sonst werden alle
688             // Boxen wieder auf 0 zurueck gesetzt !!!!!
689             SwFrmFmt* pFmt = pTableNode->GetTable().GetFrmFmt();
690             const SwFmtFrmSize& rTblSz = pFmt->GetFrmSize();
691             if( rTblSz.GetWidth() < nTblSz )
692             {
693                 SwFmtFrmSize aSz( rTblSz );
694                 aSz.SetWidth( nTblSz );
695                 ((SfxItemSet&)pFmt->GetAttrSet()).Put( aSz );
696             }
697 
698             SwTableLines& rLns = pTableNode->GetTable().GetTabLines();
699 
700             if( bReadNewCell )
701                 pNewLine = rLns[ rLns.Count()-1 ];
702             else
703             {
704                 pNewLine = new SwTableLine(
705                         (SwTableLineFmt*)rLns[ rLns.Count()-1 ]->GetFrmFmt(),
706                         aBoxFmts.Count(), 0 );
707                 pNewLine->ClaimFrmFmt();
708                 pNewLine->GetFrmFmt()->ResetFmtAttr( RES_FRM_SIZE );
709                 rLns.C40_INSERT( SwTableLine, pNewLine, rLns.Count() );
710             }
711             bNewTbl = sal_False;
712         }
713         else
714         {
715             bForceNewTable = false;
716             const SwTable *pTable =
717                 pDoc->InsertTable(
718                     SwInsertTableOptions( tabopts::HEADLINE_NO_BORDER, 0 ),
719                     *pPam->GetPoint(), 1, 1, eAdjust, 0, 0, sal_False, sal_False );
720             bContainsTablePara=true; //#117881#
721             pTableNode = pTable ? pTable->GetTableNode() : 0;
722 
723             if (pTableNode)
724             {
725                 maSegments.PrependedInlineNode(*pPam->GetPoint(),
726                     *pTableNode);
727             }
728             else
729             {
730                 SkipToken( -1 );            // zum Letzen gueltigen zurueck
731                 return;
732             }
733 
734             SwTableLines& rLns = pTableNode->GetTable().GetTabLines();
735             pNewLine = rLns[ rLns.Count()-1 ];
736 
737             SwFrmFmt* pFmt = pTableNode->GetTable().GetFrmFmt();
738             SwFmtFrmSize aSz( pFmt->GetFrmSize() );
739             aSz.SetWidth( nTblSz );
740             ((SfxItemSet&)pFmt->GetAttrSet()).Put( aSz );
741             ((SfxItemSet&)pFmt->GetAttrSet()).Put(SvxFrameDirectionItem(eDir, RES_FRAMEDIR));
742 
743             if( text::HoriOrientation::LEFT_AND_WIDTH == eAdjust && nLSpace )
744             {
745                 SvxLRSpaceItem aL( RES_LR_SPACE ); aL.SetLeft( nLSpace );
746                 ((SfxItemSet&)pFmt->GetAttrSet()).Put( aL );
747             }
748 
749             m_nCurrentBox = 0;
750             pOldTblNd = pTableNode;
751         }
752     }
753 
754     if( nLineHeight )
755     {
756         SwFrmSize eSize;
757         if( 0 > nLineHeight )
758             eSize = ATT_FIX_SIZE, nLineHeight = -nLineHeight;
759         else
760             eSize = ATT_MIN_SIZE;
761         pNewLine->ClaimFrmFmt()->SetFmtAttr(SwFmtFrmSize(eSize, 0, nLineHeight));
762     }
763 
764     pNewLine->ClaimFrmFmt()->SetFmtAttr(SwFmtRowSplit(!bCantSplit));
765 
766     if( aBoxFmts.Count() )
767     {
768         // setze das default Style
769         SwTxtFmtColl* pColl = aTxtCollTbl.Get( 0 );
770         if( !pColl )
771             pColl = pDoc->GetTxtCollFromPool( RES_POOLCOLL_STANDARD, false );
772 
773         sal_uInt16 nStt = 0;
774         if( bNewTbl )
775         {
776             SwTableBox* pBox = pNewLine->GetTabBoxes()[0];
777             pBoxFmt = (SwTableBoxFmt*)pBox->GetFrmFmt();
778             pBox->ForgetFrmFmt();
779             delete pBoxFmt;
780             pBox->RegisterToFormat( *aBoxFmts[0] );
781             SwTxtNode* pTNd = pDoc->GetNodes()[ pBox->GetSttIdx()+1 ]
782                                             ->GetTxtNode();
783             ASSERT( pTNd, "wo ist der Textnode dieser Box?" );
784             pTNd->ChgFmtColl( pColl );
785             ++nStt;
786             nRowsToRepeat=0;
787         }
788 
789         for( ; nStt < aBoxFmts.Count(); ++nStt )
790         {
791             pDoc->GetNodes().InsBoxen( pTableNode, pNewLine,
792                     aBoxFmts[ nStt ],
793                     // Formate fuer den TextNode der Box
794                     pColl, 0,
795                     m_nCurrentBox + nStt, 1 );
796         }
797     }
798 
799     if( bChkExistTbl )
800     {
801         m_nCurrentBox = 0;
802     }
803 
804     maInsertedTables.InsertTable(*pTableNode, *pPam);
805 
806     SwNodeIndex aOldIdx(pPam->GetPoint()->nNode);
807     SwNodeIdx aOldPos(aOldIdx);
808     SwPaM aRg(*pPam);
809 
810     bool bFailure = true;
811     if (pNewLine)
812     {
813         SwTableBoxes &rBoxes = pNewLine->GetTabBoxes();
814         if (SwTableBox* pBox = ((m_nCurrentBox < rBoxes.Count())
815                 ? rBoxes[m_nCurrentBox] : 0))
816         {
817             if (const SwStartNode *pStart = pBox->GetSttNd())
818             {
819                 if (const SwEndNode *pEnd = pStart->EndOfSectionNode())
820                 {
821                     pPam->GetPoint()->nNode = *pEnd;
822                     pPam->Move( fnMoveBackward, fnGoCntnt );
823                     bFailure = false;
824                 }
825             }
826         }
827     }
828 
829     ASSERT(!bFailure, "RTF Table failure");
830     if (bFailure)
831     {
832         SkipToken( -1 );            // zum Letzen gueltigen zurueck
833         return;
834     }
835 
836     //It might be that there was content at this point which is not already in
837     //a table, but which is being followed by properties to place it into the
838     //table. e.g. #109199#. If this is the case then move the para/char
839     //properties inside the table, and move any content of that paragraph into
840     //the table
841     bool bInTable = aRg.GetPoint()->nNode.GetNode().FindTableNode();
842     if (!bInTable)
843     {
844         SwNodeIndex aNewIdx(pPam->GetPoint()->nNode);
845         SwNodeIdx aNewPos(aNewIdx);
846 
847         if (aRg.GetPoint()->nContent.GetIndex())
848         {
849             //If there is content in this node then move it entirely inside the
850             //table
851             aRg.SetMark();
852             aRg.GetMark()->nContent.Assign(aRg.GetCntntNode(), 0);
853             pDoc->MoveRange(aRg, *pPam->GetPoint(),
854                     IDocumentContentOperations::DOC_MOVEDEFAULT);
855         }
856 
857         //Update the attribute stack entries to reflect that the properties
858         //which were intended to be inside the tablerow are now left outside
859         //the table after the row was placed before the current insertion point
860         SvxRTFItemStack& rAttrStk = GetAttrStack();
861         for (size_t n = 0; n < rAttrStk.size(); ++n)
862         {
863             SvxRTFItemStackType* pStk = rAttrStk[n];
864             pStk->MoveFullNode(aOldPos, aNewPos);
865         }
866     }
867     SkipToken( -1 );            // zum Letzen gueltigen zurueck
868 }
869 
870 // in die naechste Box dieser Line (opt.: falls es nicht die letzte ist)
GotoNextBox()871 void SwRTFParser::GotoNextBox()
872 {
873     nInsTblRow = USHRT_MAX;
874 
875     ASSERT( pTableNode, "Kein Tabellennode, dann auch keine Box" );
876 
877     if (!pTableNode)
878         return;
879 
880     SwTableLines& rLns = pTableNode->GetTable().GetTabLines();
881     SwTableLine* pLine = rLns[ rLns.Count()-1 ];
882     SwTableBoxes& rBoxes = pLine->GetTabBoxes();
883     SwTableBox* pBox = rBoxes[ rBoxes.Count()-1 ];
884 
885     if (++m_nCurrentBox >= aMergeBoxes.size())
886     {
887         OSL_ENSURE(aMergeBoxes.size() < SAL_MAX_UINT16, "too many boxes?");
888         m_nCurrentBox = static_cast<sal_uInt16>(aMergeBoxes.size()-1);
889     }
890 
891     if (!aMergeBoxes[ m_nCurrentBox ])
892     {
893         int bMove = sal_True;
894         if( pBox->GetSttIdx() > pPam->GetPoint()->nNode.GetIndex() )
895         {
896             sal_uInt16 nRealBox = 0;
897             for (sal_uInt16 nTmp = 0; nTmp < m_nCurrentBox; ++nTmp)
898                 if( !aMergeBoxes[ nTmp ] )
899                     ++nRealBox;
900 
901             if( nRealBox < rBoxes.Count() )
902             {
903                 pPam->GetPoint()->nNode = *rBoxes[ nRealBox ]->GetSttNd()->EndOfSectionNode();
904                 pPam->Move( fnMoveBackward, fnGoCntnt );
905                 bMove = sal_False;
906             }
907         }
908 
909         if (bMove &&
910                ((static_cast<size_t>(m_nCurrentBox) + 1) == aMergeBoxes.size()))
911             // dann hinter die Tabelle
912             pPam->Move( fnMoveForward, fnGoNode );
913     }
914     else if (pPam->GetPoint()->nNode.GetNode().IsCntntNode())
915         // dann in die vorherige ans Ende
916         pPam->Move( fnMoveBackward, fnGoCntnt );
917 }
918 
919 
NewTblLine()920 void SwRTFParser::NewTblLine()
921 {
922     nInsTblRow = USHRT_MAX;
923 
924     // erweiter die aktuelle um eine neue Line
925     sal_Bool bMakeCopy = sal_False;
926     SwNode* pNd = pDoc->GetNodes()[ pPam->GetPoint()->nNode.GetIndex()-1 ];
927     if( !pNd->IsEndNode() ||
928         !(pNd = pNd->StartOfSectionNode())->IsTableNode() )
929     {
930         if( !pOldTblNd )
931             return ;
932 
933         bMakeCopy = sal_True;
934         pNd = pOldTblNd;
935     }
936     pTableNode = (SwTableNode*)pNd;
937 
938     SwTableLines* pLns = &pTableNode->GetTable().GetTabLines();
939     SwTableLine* pLine = (*pLns)[ pLns->Count()-1 ];
940     SwTableBoxes& rBoxes = pLine->GetTabBoxes();
941     SwTableBox* pBox = rBoxes[ rBoxes.Count()-1 ];
942 
943     if(nRowsToRepeat>0)
944         pTableNode->GetTable().SetRowsToRepeat( nRowsToRepeat );
945 
946     if( !bMakeCopy &&
947         64000 < pTableNode->GetTable().GetTabSortBoxes().Count() )
948     {
949         bMakeCopy = sal_True;       // spaetestens jetzt eine neue anfangen!
950     }
951 
952     if( bMakeCopy )
953     {
954         // und die Selektion kopieren
955         SwSelBoxes aBoxes;
956         pTableNode->GetTable().SelLineFromBox( pBox, aBoxes );
957         pTableNode->GetTable().MakeCopy( pDoc, *pPam->GetPoint(),
958                                         aBoxes, sal_False );
959         sal_uLong nNd = pPam->GetPoint()->nNode.GetIndex()-1;
960         pTableNode = pDoc->GetNodes()[ nNd ]->FindTableNode();
961         pOldTblNd = pTableNode;
962 
963         nRowsToRepeat=0;
964         pTableNode->GetTable().SetRowsToRepeat(nRowsToRepeat);
965         pLns = &pTableNode->GetTable().GetTabLines();
966     }
967     else
968 //      pDoc->InsertRow( aBoxes );
969         pTableNode->GetTable().AppendRow( pDoc );
970 
971     pBox = (*pLns)[ pLns->Count()-1 ]->GetTabBoxes()[0];
972 
973     sal_uLong nOldPos = pPam->GetPoint()->nNode.GetIndex();
974     pPam->GetPoint()->nNode = *pBox->GetSttNd();
975     pPam->Move( fnMoveForward );
976     m_nCurrentBox = 0;
977 
978     // alle Nodes in den Boxen auf die "default" Vorlage setzten
979     {
980         SwTxtFmtColl* pColl = aTxtCollTbl.Get( 0 );
981         if( !pColl )
982             pColl = pDoc->GetTxtCollFromPool( RES_POOLCOLL_STANDARD, false );
983         pPam->SetMark();
984 
985         pLine = (*pLns)[ pLns->Count()-1 ];
986         pBox = pLine->GetTabBoxes()[ pLine->GetTabBoxes().Count() -1 ];
987         pPam->GetPoint()->nNode = *pBox->GetSttNd()->EndOfSectionNode();
988         pPam->Move( fnMoveBackward );
989         pDoc->SetTxtFmtColl( *pPam, pColl );
990         // Bug 73940 - remove ALL attributes (NumRules/Break/etc.)
991         {
992             SwNodeIndex aIdx( pPam->GetMark()->nNode );
993             SwNodeIndex& rEndIdx = pPam->GetPoint()->nNode;
994             while( aIdx <= rEndIdx )
995             {
996                 SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode();
997                 if( pCNd && pCNd->HasSwAttrSet() )
998                     pCNd->ResetAllAttr();
999                 aIdx++;
1000             }
1001         }
1002         pPam->Exchange();
1003         pPam->DeleteMark();
1004     }
1005 
1006     // all attributes which will be displayed in new Box
1007     SvxRTFItemStack& rAttrStk = GetAttrStack();
1008     const SvxRTFItemStackType* pStk;
1009     for( size_t n = 0; n < rAttrStk.size(); ++n )
1010         if( ( pStk = rAttrStk[ n ])->GetSttNodeIdx() == sal_uLong(nOldPos) &&
1011             !pStk->GetSttCnt() )
1012             ((SvxRTFItemStackType*)pStk)->SetStartPos( SwxPosition( pPam ) );
1013 }
1014 
CheckInsNewTblLine()1015 void SwRTFParser::CheckInsNewTblLine()
1016 {
1017     if( USHRT_MAX != nInsTblRow )
1018     {
1019         if( nInsTblRow > GetOpenBrakets() || IsPardTokenRead() )
1020             nInsTblRow = USHRT_MAX;
1021         else if( !pTableNode )      // Tabelle nicht mehr vorhanden ?
1022             NewTblLine();           // evt. Line copieren
1023     }
1024 }
1025 
1026 /* vi:set tabstop=4 shiftwidth=4 expandtab: */
1027