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 #include <hintids.hxx>
28 #include <tools/list.hxx>
29 #include <tools/cachestr.hxx>
30 #include <svtools/rtftoken.h>
31 #include <svl/itemiter.hxx>
32 #include <editeng/prntitem.hxx>
33 #include <editeng/opaqitem.hxx>
34 #include <editeng/protitem.hxx>
35 #include <editeng/ulspitem.hxx>
36 #include <editeng/lrspitem.hxx>
37 #include <editeng/boxitem.hxx>
38 #include <editeng/frmdiritem.hxx>
39 #include <fmtfsize.hxx>
40 #include <fmtanchr.hxx>
41 #include <fmtpdsc.hxx>
42 #include <fmtsrnd.hxx>
43 #include <fmtclds.hxx>
44 #include <fmtcntnt.hxx>
45 #include <frmatr.hxx>
46 #include <doc.hxx>
47 #include <pam.hxx>
48 #include <ndtxt.hxx>
49 #include <shellio.hxx>
50 #include <swparrtf.hxx>
51 #include <grfatr.hxx>
52 #include <paratr.hxx>
53 #include <rtf.hxx>
54 #include <ndgrf.hxx>
55 #include <pagedesc.hxx>
56 #include <swtable.hxx>
57 #include <txtflcnt.hxx>
58 #include <fmtflcnt.hxx>
59 #include <fltini.hxx>
60 #include <unoframe.hxx>
61 #include <deque>
62 #include <map>
63 #include <utility>
64 // --> OD 2004-06-30 #i27767#
65 #include <fmtwrapinfluenceonobjpos.hxx>
66 // <--
67 #include <editeng/brshitem.hxx>
68 #include <fmtfollowtextflow.hxx>
69 // --> OD, FLR 2006-02-16 #131205#
70 #include "dcontact.hxx"
71 // <--
72
73
74 using namespace ::com::sun::star;
75
76 #define ANCHOR(p) ((SwFmtAnchor*)p)
77
78 // steht in shellio.hxx
79 extern SwCntntNode* GoNextNds( SwNodeIndex * pIdx, sal_Bool bChk );
80
SV_IMPL_PTRARR(SwFlySaveArr,SwFlySave *) const81 SV_IMPL_PTRARR( SwFlySaveArr, SwFlySave* )
82
83 inline const SwFmtFrmSize GetFrmSize(const SfxItemSet& rSet, sal_Bool bInP=sal_True)
84 {
85 return (const SwFmtFrmSize&)rSet.Get(RES_FRM_SIZE,bInP);
86 }
87
SwFlySave(const SwPaM & rPam,SfxItemSet & rSet)88 SwFlySave::SwFlySave(const SwPaM& rPam, SfxItemSet& rSet)
89 : aFlySet(rSet), nSttNd(rPam.GetPoint()->nNode), nEndNd(nSttNd), nEndCnt(0),
90 nPageWidth(ATT_MIN_SIZE), nDropLines(0), nDropAnchor(0)
91 {
92 }
93
IsEqualFly(const SwPaM & rPos,SfxItemSet & rSet)94 int SwFlySave::IsEqualFly( const SwPaM& rPos, SfxItemSet& rSet )
95 {
96 if( rSet.Count() != aFlySet.Count() || nDropAnchor )
97 return sal_False;
98
99 // nur TextNodes zusammenfassen
100 if( nSttNd == nEndNd && nEndNd.GetNode().IsNoTxtNode() )
101 return sal_False;
102
103 // teste auf gleiche / naechste Position
104 if( rPos.GetPoint()->nNode.GetIndex() == nEndNd.GetIndex() )
105 {
106 if( 1 < (rPos.GetPoint()->nContent.GetIndex() - nEndCnt) )
107 return sal_False;
108 }
109 else if( rPos.GetPoint()->nContent.GetIndex() )
110 return sal_False;
111 else
112 {
113 SwNodeIndex aIdx( nEndNd );
114 SwCntntNode *const pCNd = aIdx.GetNode().GetCntntNode();
115 if( !GoNextNds( &aIdx, sal_True ) ||
116 aIdx.GetIndex() != rPos.GetPoint()->nNode.GetIndex() ||
117 ( pCNd && pCNd->Len() != nEndCnt ))
118 {
119 return sal_False;
120 }
121 }
122
123 if( rSet.Count() )
124 {
125 SfxItemIter aIter( rSet );
126 const SfxPoolItem *pItem, *pCurr = aIter.GetCurItem();
127 while( sal_True )
128 {
129 if( SFX_ITEM_SET != aFlySet.GetItemState( pCurr->Which(),
130 sal_False, &pItem ) ||
131 // Ankerattribute gesondert behandeln
132 ( RES_ANCHOR == pCurr->Which()
133 ? (ANCHOR(pCurr)->GetAnchorId() != ANCHOR(pItem)->GetAnchorId() ||
134 ANCHOR(pCurr)->GetPageNum() != ANCHOR(pItem)->GetPageNum())
135 : *pItem != *pCurr ))
136 return sal_False;
137
138 if( aIter.IsAtEnd() )
139 break;
140 pCurr = aIter.NextItem();
141 }
142 }
143 return sal_True;
144 }
145
SetFlySize(const SwTableNode & rTblNd)146 void SwFlySave::SetFlySize( const SwTableNode& rTblNd )
147 {
148 // sollte der Fly kleiner als diese Tabelle sein, dann
149 // korrigiere diesen (nur bei abs. Angaben!)
150 SwTwips nWidth = rTblNd.GetTable().GetFrmFmt()->GetFrmSize().GetWidth();
151 const SwFmtFrmSize& rSz = GetFrmSize( aFlySet );
152 if( nWidth > rSz.GetWidth() )
153 aFlySet.Put( SwFmtFrmSize( rSz.GetHeightSizeType(), nWidth, rSz.GetHeight() ));
154 }
155
lcl_HasBreakAttrs(const SwCntntNode & rNd)156 sal_Bool lcl_HasBreakAttrs( const SwCntntNode& rNd )
157 {
158 sal_Bool bRet = sal_False;
159 const SfxItemSet& rSet = rNd.GetSwAttrSet();
160 const SfxPoolItem* pItem;
161 if( SFX_ITEM_SET == rSet.GetItemState( RES_BREAK, sal_True, &pItem ) &&
162 SVX_BREAK_NONE != ((SvxFmtBreakItem*)pItem)->GetBreak() )
163 bRet = sal_True;
164 else if( SFX_ITEM_SET == rSet.GetItemState( RES_PAGEDESC, sal_True, &pItem )&&
165 0 != ((SwFmtPageDesc*)pItem)->GetPageDesc() )
166 bRet = sal_True;
167 return bRet;
168 }
169
170
lcl_CpyBreakAttrs(SwCntntNode * pSrcNd,SwCntntNode * pDstNd,SwNodeIndex * pNewIdx)171 void lcl_CpyBreakAttrs( SwCntntNode* pSrcNd, SwCntntNode* pDstNd,
172 SwNodeIndex* pNewIdx )
173 {
174 const SfxItemSet* pSet;
175 if( pSrcNd && pDstNd && 0 != ( pSet = pSrcNd->GetpSwAttrSet() ) )
176 {
177 const SfxPoolItem *pDescItem, *pBreakItem;
178
179 if( SFX_ITEM_SET != pSet->GetItemState( RES_BREAK,
180 sal_False, &pBreakItem ) )
181 pBreakItem = 0;
182
183 if( SFX_ITEM_SET != pSet->GetItemState( RES_PAGEDESC,
184 sal_False, &pDescItem ) )
185 pDescItem = 0;
186
187 if( pDescItem || pBreakItem )
188 {
189 if( lcl_HasBreakAttrs( *pDstNd ))
190 {
191 SwPosition aPos( *pDstNd, SwIndex( pDstNd ));
192 aPos.nNode--;
193 pDstNd->GetDoc()->AppendTxtNode( aPos );
194 if( pNewIdx )
195 *pNewIdx = aPos.nNode;
196
197 SwCntntNode* pOldNd = pDstNd;
198 pDstNd = aPos.nNode.GetNode().GetCntntNode();
199 pDstNd->ChgFmtColl( pOldNd->GetFmtColl() );
200 if( pDstNd->HasSwAttrSet() )
201 {
202 SfxItemSet aSet( *pDstNd->GetpSwAttrSet() );
203 aSet.ClearItem( RES_BREAK );
204 aSet.ClearItem( RES_PAGEDESC );
205 pDstNd->SetAttr( aSet );
206 }
207 }
208 if( pBreakItem )
209 {
210 pDstNd->SetAttr( *pBreakItem );
211 pSrcNd->ResetAttr( RES_BREAK );
212 }
213 if( pDescItem )
214 {
215 pDstNd->SetAttr( *pDescItem );
216 pSrcNd->ResetAttr( RES_PAGEDESC );
217 }
218 }
219 }
220 }
221
SetFlysInDoc()222 void SwRTFParser::SetFlysInDoc()
223 {
224 // !! von Oben abarbeiten, CntntPos ist kein Index !
225 SwNodes & rNds = pDoc->GetNodes();
226 typedef std::pair<SwFlyFrmFmt*, SwFmtAnchor> frameEntry;
227 typedef std::deque<frameEntry> rtfframesAtIndex;
228 typedef std::map<const SwNode*, rtfframesAtIndex> rtfFmtMap;
229 rtfFmtMap aPrevFmts;
230
231 SwFrmFmt* pParent = pDoc->GetFrmFmtFromPool( RES_POOLFRM_FRAME );
232 for( sal_uInt16 n = 0; n < aFlyArr.Count(); ++n )
233 {
234 SwFlySave* pFlySave = aFlyArr[ n ];
235
236 ASSERT( !pFlySave->nSttNd.GetNode().FindFlyStartNode(),
237 "Content vom Fly steht in einem Fly" );
238 ASSERT( pFlySave->nSttNd.GetIndex() <= pFlySave->nEndNd.GetIndex(),
239 "Fly hat falschen Bereich" );
240
241
242
243 //JP 21.09.98: wenn ein DropCap ist, dann Text im Node belassen, am
244 // Absatz das Absatz Attribut setzen. Ggfs noch die
245 // FontSize zuruecksetzen, damit das DropCap nicht zu
246 // gro? wird.
247 if( pFlySave->nDropAnchor )
248 {
249 SwTxtNode* pSttNd = pFlySave->nSttNd.GetNode().GetTxtNode();
250 SwTxtNode* pEndNd = pFlySave->nEndNd.GetNode().GetTxtNode();
251 if( pSttNd && pEndNd &&
252 pSttNd->GetIndex() + 1 == pEndNd->GetIndex()
253 && pSttNd->GetTxt().Len()>0 /* #i38227# leave drop caps with no content as fly frames */ )
254 {
255 sal_uLong nPos = pSttNd->GetIndex();
256 SwDoc * pDoc1 = pSttNd->GetDoc();
257
258 sal_Bool bJoined;
259 {
260 SwPaM aTmp( *pSttNd, pSttNd->GetTxt().Len(), *pEndNd, 0 );
261 bJoined = pDoc1->DeleteAndJoin( aTmp );
262 }
263
264 SwTxtNode * pNd = (pDoc1->GetNodes()[nPos])->GetTxtNode();
265
266 if( bJoined && pNd != NULL)
267 {
268 SwFmtDrop aDropCap;
269 aDropCap.GetLines() = (sal_uInt8)pFlySave->nDropLines;
270 aDropCap.GetChars() = 1;
271
272 SwIndex aIdx( pEndNd );
273 pNd->RstTxtAttr( aIdx, 1, RES_CHRATR_FONTSIZE );
274 pNd->SetAttr( aDropCap );
275 }
276 delete pFlySave;
277 continue;
278 }
279 }
280
281 // liegt Ende und Start vom Naechsten im gleichen Node, dann muss
282 // gesplittet werden
283 if (((static_cast<size_t>(n) + 1) < aFlyArr.Count()) &&
284 pFlySave->nEndCnt &&
285 pFlySave->nEndNd == aFlyArr[ n + 1 ]->nSttNd )
286 {
287 SwCntntNode *const pCNd = pFlySave->nEndNd.GetNode().GetCntntNode();
288 if( pCNd )
289 {
290 SwPosition aPos( pFlySave->nEndNd,
291 SwIndex( pCNd, pFlySave->nEndCnt ));
292 pDoc->SplitNode( aPos, false );
293 pFlySave->nEndNd--;
294 }
295 else
296 pFlySave->nEndCnt = 0;
297 }
298
299 // verschiebe den Inhalt von diesem Anchor in den Auto-TextBereich
300 // und erzeuge dadurch den richtigen SwG-Rahmen
301 SwNodeRange aRg(pFlySave->nSttNd, 0, pFlySave->nEndNd, 0);
302 //Make a new section, unless there is no content at all
303 const bool bMakeEmptySection = aRg.aStart < aRg.aEnd || ((aRg.aStart == aRg.aEnd) && pFlySave->nEndCnt);
304
305 {
306 // Nur TextNodes koennen in Tabellen stehen !!
307 const SwNode* pNd = &pFlySave->nSttNd.GetNode();
308 if( pNd->IsNoTxtNode() )
309 {
310 // die Size muss noch korrigiert werden!
311 nAktPageDesc = 0; // Standart PageDesc
312 if( SFX_ITEM_SET != pFlySave->aFlySet.GetItemState(
313 RES_FRM_SIZE, sal_False ) )
314 _SetPictureSize( *(SwNoTxtNode*)pNd, aRg.aStart,
315 pFlySave->aFlySet );
316 if( 0 != ( pNd = pNd->FindTableNode() ) )
317 pFlySave->SetFlySize( *(SwTableNode*)pNd );
318 }
319 else
320 {
321 // Take care for table nodes
322 pNd = pNd->GetNodes()[ pNd->GetIndex() - 2 ]->GetTableNode();
323 if( pNd ) // if the table starts imediately before aRg -> expand aRg
324 aRg.aStart = *pNd;
325
326 if( bMakeEmptySection )
327 {
328 pNd = &aRg.aEnd.GetNode();
329 sal_uLong nSectEnd = pNd->EndOfSectionIndex()+1;
330
331 if (!pNd->IsTableNode() && 0 !=(pNd = pNd->FindTableNode())
332 && (pNd->GetIndex() >= aRg.aStart.GetNode().GetIndex()) )
333 {
334 const SwNode* pTblBxNd;
335
336 // Ende der Tabelle ist hinter dieser Box ??
337 if( pNd->EndOfSectionIndex() == nSectEnd )
338 aRg.aEnd = nSectEnd+1;
339 // is the end in the first box of the table, then
340 // move before the table (Bug 67663)
341 // but the range must not become emtpy, i.e. aStart==aEnd
342 // because otherwise we will get a crash (126506) later on
343 else if( 0 != ( pTblBxNd = aRg.aEnd.GetNode().
344 FindTableBoxStartNode()) &&
345 pTblBxNd->GetIndex() - 1 == pNd->GetIndex() &&
346 &aRg.aStart.GetNode() != pNd )
347 aRg.aEnd = *pNd;
348 else
349 {
350 // Tabelle ist noch groesser, also splitte sie hier.
351 rNds.SplitTable( aRg.aEnd, sal_True );
352 aRg.aEnd = pNd->EndOfSectionIndex() + 1;
353 }
354 }
355 }
356 }
357 }
358
359 // vorm verschieben muss sich der Index auf die alte Position
360 // gemerkt werden, der Index wird mit verschoben !!!
361
362 SwNodeIndex aTmpIdx( rNds.GetEndOfAutotext() );
363 SwStartNode* pSttNd = bMakeEmptySection
364 ? rNds.MakeEmptySection( aTmpIdx, SwFlyStartNode )
365 : rNds.MakeTextSection( aTmpIdx, SwFlyStartNode,
366 (SwTxtFmtColl*)pDoc->GetDfltTxtFmtColl() );
367
368 // das ist die Verankerungs-Position (fuers Layout!)
369 pFlySave->nSttNd = aRg.aStart.GetIndex()-1;
370 if( bMakeEmptySection )
371 {
372 // check: the move does not clear the surrounded section. If all
373 // nodes moved away, then create a new TxtNode
374 {
375 // i76403: an empty selection is not a good idea
376 if( aRg.aStart == aRg.aEnd && aRg.aStart.GetNode().GetTxtNode() )
377 aRg.aEnd++;
378 SwNodeIndex aPrev( aRg.aStart, -1 );
379 if( aPrev.GetNode().IsStartNode() &&
380 aPrev.GetNode().EndOfSectionNode() == &aRg.aEnd.GetNode())
381 {
382 // create new txtnode, because the section does never be empty
383 pDoc->GetNodes().MakeTxtNode( aRg.aEnd,
384 (SwTxtFmtColl*)pDoc->GetDfltTxtFmtColl() );
385 aRg.aEnd--;
386 }
387 }
388 aTmpIdx = *pSttNd->EndOfSectionNode();
389 pDoc->MoveNodeRange( aRg, aTmpIdx,
390 IDocumentContentOperations::DOC_MOVEDEFAULT );
391 }
392
393 // patch from cmc for #i52542#
394 if (pSttNd->GetIndex() + 1 == pSttNd->EndOfSectionIndex())
395 {
396 ASSERT(!this, "nothing in this frame, not legal");
397 delete pFlySave;
398 continue;
399 }
400
401 pFlySave->aFlySet.Put( SwFmtCntnt( pSttNd ));
402
403 CalculateFlySize( pFlySave->aFlySet, pFlySave->nSttNd,
404 pFlySave->nPageWidth );
405
406 // THIS >>>>>
407 // if the section only contains one Node and this has a
408 // border or backgorund, then put it to the frame
409 // Not in our own RTF-Format!
410 // <<<<< DOES NOT MAKE SENSE TO ME (flr)
411 // #102781#. Added support for transparent frames.
412 if( pSttNd->GetIndex() + 1 != pSttNd->EndOfSectionIndex() &&
413 !bSwPageDesc )
414 {
415 SwCntntNode* pSrcNd = pDoc->GetNodes()[ pSttNd->GetIndex() + 1 ]->GetCntntNode();
416 SfxItemSet aTmpSet( pDoc->GetAttrPool(),
417 RES_BACKGROUND, RES_BOX );
418 const SvxBrushItem* pBackgroundBrush = (const SvxBrushItem*)pFlySave->aFlySet.GetItem(RES_BACKGROUND, sal_False);
419 if( pSrcNd && pSrcNd->HasSwAttrSet() )
420 aTmpSet.Put( *pSrcNd->GetpSwAttrSet() );
421 if (pBackgroundBrush)
422 {
423 aTmpSet.Put(*pBackgroundBrush, RES_BACKGROUND);
424 }
425 else
426 {
427 pBackgroundBrush = (const SvxBrushItem*)aTmpSet.GetItem(RES_BACKGROUND, sal_False);
428 if (pBackgroundBrush)
429 {
430 Color& rBackgroundColor = const_cast<SvxBrushItem*>(pBackgroundBrush)->GetColor();
431 rBackgroundColor.SetTransparency(0xFE);
432 }
433 else
434 {
435 Color aColor = Color(0xff, 0xff, 0xff);
436 aColor.SetTransparency( 0xFE);
437 SvxBrushItem aBrush(aColor, RES_BACKGROUND);
438 aTmpSet.Put(aBrush, RES_BACKGROUND);
439 }
440 }
441 // #117914# Topic 6.
442 pFlySave->aFlySet.Put( aTmpSet );
443 if( pSrcNd && pSrcNd->HasSwAttrSet() )
444 {
445 pSrcNd->ResetAttr( RES_BACKGROUND, RES_BOX );
446 }
447 }
448
449 SwFlyFrmFmt* pFmt = pDoc->MakeFlyFrmFmt( aEmptyStr, pParent );
450 pFmt->SetFmtAttr( pFlySave->aFlySet );
451 const SwFmtAnchor& rAnchor = pFmt->GetAnchor();
452 if (FLY_AS_CHAR != rAnchor.GetAnchorId())
453 {
454 // korrigiere noch den Absatz, ist immer der vorhergehende !
455 // JP 20.09.95: wenn es diesen gibt! (DocAnfang!)
456
457 //JP 02.08.99: that is wrong. The anchor is ever the NEXT!
458 //JP 05.08.99: there are an Bug in the ExportFilter which will
459 // be fixed in the Version 517 - by SWG-Export
460 // the fly will be after the paragraph - but in RTF
461 // the flys will be before the paragraph.
462 if( !bSwPageDesc || 5430 < GetVersionNo() )
463 pFlySave->nSttNd++;
464
465 // if( !pFlySave->nSttNd.GetNode().IsCntntNode() )
466 {
467 // Seitenumbrueche in den Bodybereich verschieben!
468 SwCntntNode* pSrcNd = aRg.aStart.GetNode().GetCntntNode();
469 SwCntntNode* pDstNd = pFlySave->nSttNd.GetNode().GetCntntNode();
470 if( !pDstNd )
471 pDstNd = pDoc->GetNodes().GoNext( &pFlySave->nSttNd );
472
473 ::lcl_CpyBreakAttrs( pSrcNd, pDstNd, &pFlySave->nSttNd );
474 }
475
476 const SwNodeIndex aSttNd(*pSttNd);
477 SwNodeIndex aEndNd(*pSttNd->EndOfSectionNode());
478 aEndNd--;
479
480 SwPosition aPos( pFlySave->nSttNd );
481 SwFmtAnchor aAnchor(rAnchor);
482 aAnchor.SetAnchor(&aPos);
483
484 const SwNode *pCurrentAnchor = &(pFlySave->nSttNd.GetNode());
485 aPrevFmts[pCurrentAnchor].push_back(frameEntry(pFmt, aAnchor));
486
487 while (aEndNd > aSttNd)
488 {
489 typedef rtfframesAtIndex::iterator myIter;
490 rtfframesAtIndex &rDeque = aPrevFmts[&(aEndNd.GetNode())];
491 myIter aEnd = rDeque.end();
492 for (myIter aIter = rDeque.begin(); aIter != aEnd; ++aIter)
493 {
494 aIter->second.SetAnchor(&aPos);
495 // --> OD 2004-06-30 #i27767# - push on front to keep order
496 // of objects for the correct object positioning
497 //aPrevFmts[pCurrentAnchor].push_back(*aIter);
498 aPrevFmts[pCurrentAnchor].push_front(*aIter);
499 }
500 rDeque.clear();
501 aEndNd--;
502 }
503 }
504
505 // --> OD, FLR 2006-02-16 #131205#
506 // Create draw contact object, which also creates a <SdrObject> instance,
507 // in order to set the order number.
508 // The order number is assumed to be the order of the text flow.
509 SwFlyDrawContact* pContact =
510 new SwFlyDrawContact( pFmt,
511 pFmt->GetDoc()->GetOrCreateDrawModel() );
512 pContact->GetMaster()->SetOrdNum( n );
513 // <--
514
515 delete pFlySave;
516 }
517
518 typedef rtfFmtMap::reverse_iterator myriter;
519 myriter aEnd = aPrevFmts.rend();
520 for(myriter aIter = aPrevFmts.rbegin(); aIter != aEnd; ++aIter)
521 {
522 rtfframesAtIndex &rDeque = aIter->second;
523 typedef rtfframesAtIndex::iterator myIter;
524 myIter aQEnd = rDeque.end();
525 for (myIter aQIter = rDeque.begin(); aQIter != aQEnd; ++aQIter)
526 {
527 frameEntry &rEntry = *aQIter;
528 SwFlyFrmFmt *pFrm = rEntry.first;
529 SwFmtAnchor &rAnchor = rEntry.second;
530 pFrm->SetFmtAttr(rAnchor);
531 }
532 }
533
534 aFlyArr.Remove(0, aFlyArr.Count());
535 }
536
537 // clips the text box to the min or max position if it is outside our min or max boundry
GetSafePos(long nPos)538 long SwRTFParser::GetSafePos(long nPos)
539 {
540 if(nPos > SHRT_MAX)
541 nPos = SHRT_MAX;
542 else if(nPos < SHRT_MIN)
543 nPos = SHRT_MIN;
544
545 return nPos;
546 }
547
ReadFly(int nToken,SfxItemSet * pSet)548 void SwRTFParser::ReadFly( int nToken, SfxItemSet* pSet )
549 {
550 // ein Set fuer die FrmFmt-Attribute
551 SfxItemSet aSet( pDoc->GetAttrPool(), RES_FRMATR_BEGIN, RES_FRMATR_END-1 );
552 if( !IsNewDoc() )
553 Reader::ResetFrmFmtAttrs( aSet );
554
555 // der Fly beginnt immer in einem neuen Absatz
556 if( pPam->GetPoint()->nContent.GetIndex() )
557 InsertPara();
558
559 // RTF-Defaults setzen:
560 // --> OD 2004-06-24 #i27767#
561 SwFmtAnchor aAnchor( FLY_AT_PARA );
562
563 SwFmtHoriOrient aHori( 0, text::HoriOrientation::LEFT, text::RelOrientation::FRAME );
564 SwFmtVertOrient aVert( 0, text::VertOrientation::TOP, text::RelOrientation::FRAME );
565 // <--
566 SvxFrameDirectionItem aFrmDir( FRMDIR_HORI_LEFT_TOP, RES_FRAMEDIR );
567
568 sal_uInt16 nCols = USHRT_MAX, nColSpace = USHRT_MAX, nAktCol = 0;
569 SvUShorts aColumns;
570
571 sal_Bool bChkDropCap = 0 == pSet;
572 sal_uInt16 nDropCapLines = 0, nDropCapAnchor = 0;
573 int nNumOpenBrakets = GetOpenBrakets();
574
575 if( !pSet )
576 {
577 pSet = &aSet;
578 }
579 else
580 {
581 // die Werte aus dem uebergebenen!
582 aAnchor = (SwFmtAnchor&)pSet->Get( RES_ANCHOR );
583 aHori = (SwFmtHoriOrient&)pSet->Get( RES_HORI_ORIENT );
584 aVert = (SwFmtVertOrient&)pSet->Get( RES_VERT_ORIENT );
585 }
586
587 // dann sammel mal alle Attribute zusammen
588 int bWeiter = sal_True;
589 int nAppliedProps=0;
590 do {
591 sal_uInt16 nVal = sal_uInt16(nTokenValue);
592 /*
593 #i5263#
594 Assume that a property genuinely contributes towards creating a frame,
595 and if turns out to be a non contributing one reduce the count.
596 */
597 ++nAppliedProps;
598 switch( nToken )
599 {
600 case RTF_ABSW:
601 {
602 SwFmtFrmSize aSz( ATT_MIN_SIZE, nTokenValue, 0 );
603 const SfxPoolItem* pItem;
604 if( SFX_ITEM_SET == pSet->GetItemState( RES_FRM_SIZE, sal_True,
605 &pItem ))
606 {
607 aSz.SetHeightSizeType( ((SwFmtFrmSize*)pItem)->GetHeightSizeType() );
608 aSz.SetHeight( ((SwFmtFrmSize*)pItem)->GetHeight() );
609 }
610 if( MINFLY > nTokenValue ) nTokenValue = MINFLY;
611 aSet.Put( aSz );
612 }
613 break;
614 case RTF_ABSH:
615 {
616 SwFmtFrmSize aSz( ATT_MIN_SIZE, 0, MINFLY );
617 const SfxPoolItem* pItem;
618 if( SFX_ITEM_SET == pSet->GetItemState( RES_FRM_SIZE, sal_True,
619 &pItem ))
620 {
621 aSz.SetWidth( ((SwFmtFrmSize*)pItem)->GetWidth() );
622 }
623
624 if( 0 > nTokenValue )
625 {
626 nTokenValue = -nTokenValue;
627 aSz.SetHeightSizeType( ATT_FIX_SIZE );
628 }
629 if( MINFLY > nTokenValue ) nTokenValue = MINFLY;
630 aSz.SetHeight( nTokenValue );
631 aSet.Put( aSz );
632 }
633 break;
634
635 case RTF_NOWRAP:
636 {
637 pSet->Put( SwFmtSurround( SURROUND_NONE ));
638 }
639 break;
640 case RTF_DXFRTEXT:
641 {
642 SvxULSpaceItem aUL( RES_UL_SPACE );
643 SvxLRSpaceItem aLR( RES_LR_SPACE );
644 aUL.SetUpper( nVal ); aUL.SetLower( nVal );
645 aLR.SetLeft( nVal ); aLR.SetRight( nVal );
646 pSet->Put( aUL );
647 pSet->Put( aLR );
648 }
649 break;
650
651 case RTF_DFRMTXTX:
652 {
653 SvxLRSpaceItem aLR( RES_LR_SPACE );
654 aLR.SetLeft( nVal ); aLR.SetRight( nVal );
655 pSet->Put( aLR );
656 }
657 break;
658 case RTF_DFRMTXTY:
659 {
660 SvxULSpaceItem aUL( RES_UL_SPACE );
661 aUL.SetUpper( nVal ); aUL.SetLower( nVal );
662 pSet->Put( aUL );
663 }
664 break;
665
666 case RTF_POSNEGX:
667 case RTF_POSX: aHori.SetHoriOrient( text::HoriOrientation::NONE );
668 aHori.SetPos( GetSafePos((long)nTokenValue) );
669 break;
670 case RTF_POSXC: aHori.SetHoriOrient( text::HoriOrientation::CENTER ); break;
671 case RTF_POSXI: aHori.SetHoriOrient( text::HoriOrientation::LEFT );
672 aHori.SetPosToggle( sal_True );
673 break;
674 case RTF_POSXO: aHori.SetHoriOrient( text::HoriOrientation::RIGHT );
675 aHori.SetPosToggle( sal_True );
676 break;
677 case RTF_POSXL: aHori.SetHoriOrient( text::HoriOrientation::LEFT ); break;
678 case RTF_POSXR: aHori.SetHoriOrient( text::HoriOrientation::RIGHT ); break;
679
680 case RTF_POSNEGY:
681 case RTF_POSY: aVert.SetVertOrient( text::VertOrientation::NONE );
682 aVert.SetPos( GetSafePos((long)nTokenValue) );
683 break;
684 case RTF_POSYT: aVert.SetVertOrient( text::VertOrientation::TOP ); break;
685 case RTF_POSYB: aVert.SetVertOrient( text::VertOrientation::BOTTOM ); break;
686 case RTF_POSYC: aVert.SetVertOrient( text::VertOrientation::CENTER ); break;
687
688 case RTF_PHMRG: aHori.SetRelationOrient( text::RelOrientation::PAGE_PRINT_AREA ); break;
689 case RTF_PVMRG: aVert.SetRelationOrient( text::RelOrientation::PAGE_PRINT_AREA ); break;
690 case RTF_PHPG: aHori.SetRelationOrient( text::RelOrientation::PAGE_FRAME ); break;
691 case RTF_PVPG: aVert.SetRelationOrient( text::RelOrientation::PAGE_FRAME );break;
692 case RTF_PHCOL: aHori.SetRelationOrient( text::RelOrientation::FRAME ); break;
693 case RTF_PVPARA: aVert.SetRelationOrient( text::RelOrientation::FRAME ); break;
694
695 case RTF_POSYIL:
696 break;
697 case RTF_ABSLOCK:
698 /*
699 #i5263#
700 Not sufficient to make a frame at least word won't do it with just
701 an abslock
702 */
703 --nAppliedProps;
704 break;
705 case RTF_FRMTXLRTB:
706 aFrmDir.SetValue( FRMDIR_HORI_LEFT_TOP );
707 break;
708 case RTF_FRMTXTBRL:
709 aFrmDir.SetValue( FRMDIR_HORI_RIGHT_TOP );
710 break;
711 case RTF_FRMTXLRTBV:
712 aFrmDir.SetValue( FRMDIR_VERT_TOP_LEFT );
713 break;
714 case RTF_FRMTXTBRLV:
715 aFrmDir.SetValue( FRMDIR_VERT_TOP_RIGHT );
716 break;
717
718 case RTF_DROPCAPLI: // Dropcaps !!
719 if( bChkDropCap )
720 {
721 nDropCapLines = sal_uInt16( nTokenValue );
722 if( !nDropCapAnchor )
723 nDropCapAnchor = 1;
724 }
725 break;
726 case RTF_DROPCAPT:
727 if( bChkDropCap )
728 {
729 nDropCapAnchor = sal_uInt16( nTokenValue );
730 if( !nDropCapLines )
731 nDropCapLines = 3;
732 }
733 break;
734
735
736 // fuer die "alten" Writer - haben die Spaltigkeit falsch heraus-
737 // geschrieben
738 case RTF_COLS: nCols = sal_uInt16( nTokenValue ); break;
739 case RTF_COLSX: nColSpace = sal_uInt16( nTokenValue ); break;
740 case RTF_COLNO:
741 nAktCol = sal_uInt16( nTokenValue );
742 if( RTF_COLW == GetNextToken() )
743 {
744 sal_uInt16 nWidth = sal_uInt16( nTokenValue ), nSpace = 0;
745 if( RTF_COLSR == GetNextToken() )
746 nSpace = sal_uInt16( nTokenValue );
747 else
748 SkipToken( -1 ); // wieder zurueck
749
750 if( --nAktCol == ( aColumns.Count() / 2 ) )
751 {
752 aColumns.Insert( nWidth + nSpace, aColumns.Count() );
753 aColumns.Insert( nSpace, aColumns.Count() );
754 }
755 }
756 break;
757
758 case '{':
759 {
760 short nSkip = 0;
761 if( RTF_IGNOREFLAG != ( nToken = GetNextToken() ))
762 {
763 if( RTF_SHADINGDEF == (nToken & ~0xff) )
764 {
765 ReadBackgroundAttr( nToken, aSet );
766 GetNextToken(); // Klammer ueberlesen
767 }
768 else
769 nSkip = -1;
770 }
771 else if( RTF_APOCTL ==
772 ((nToken = GetNextToken() ) & ~(0xff | RTF_SWGDEFS)) )
773 {
774 bReadSwFly = true; // alles kommt in den akt. Fly
775 SvxLRSpaceItem aLR( RES_LR_SPACE );
776 SvxULSpaceItem aUL( RES_UL_SPACE );
777 nCols = USHRT_MAX; // neu aufsetzen
778 nColSpace = USHRT_MAX;
779 do {
780 nVal = sal_uInt16(nTokenValue);
781 switch( nToken )
782 {
783 // Swg-Frame-Tokens
784 case RTF_FLYPRINT:
785 {
786 pSet->Put( SvxPrintItem( RES_PRINT, sal_False ));
787 }
788 break;
789 case RTF_FLYOPAQUE:
790 {
791 pSet->Put( SvxOpaqueItem( RES_OPAQUE, sal_False ));
792 }
793 break;
794
795 case RTF_FLYPRTCTD:
796 {
797 RTFProtect aP( (sal_uInt8)nTokenValue );
798 SvxProtectItem aProtectItem( RES_PROTECT );
799 aProtectItem.SetCntntProtect( aP.GetCntnt() );
800 aProtectItem.SetSizeProtect( aP.GetSize() );
801 aProtectItem.SetPosProtect( aP.GetPos() );
802 pSet->Put( aProtectItem );
803 }
804 break;
805
806 case RTF_FLYMAINCNT:
807 {
808 RTFSurround aMC( (sal_uInt8)nTokenValue );
809 SwFmtSurround aSurr( (SwSurround)aMC.GetOrder());
810 if( aMC.GetGoldCut() )
811 aSurr.SetSurround( SURROUND_IDEAL );
812 pSet->Put( aSurr );
813 }
814 break;
815 case RTF_FLYVERT:
816 {
817 RTFVertOrient aVO( nVal );
818 aVert.SetVertOrient( aVO.GetOrient() );
819 aVert.SetRelationOrient( aVO.GetRelation() );
820 }
821 break;
822 case RTF_FLYHORZ:
823 {
824 RTFHoriOrient aHO( nVal );
825 aHori.SetHoriOrient( aHO.GetOrient() );
826 aHori.SetRelationOrient( aHO.GetRelation() );
827 }
828 break;
829 case RTF_FLYOUTLEFT: aLR.SetLeft( nVal ); break;
830 case RTF_FLYOUTRIGHT: aLR.SetRight( nVal ); break;
831 case RTF_FLYOUTUPPER: aUL.SetUpper( nVal ); break;
832 case RTF_FLYOUTLOWER: aUL.SetLower( nVal ); break;
833 case RTF_FLYANCHOR:
834 switch( GetNextToken() )
835 {
836 case RTF_FLY_PAGE:
837 aAnchor.SetType( FLY_AT_PAGE );
838 aAnchor.SetPageNum( sal_uInt16(nTokenValue));
839 aAnchor.SetAnchor( 0 );
840 break;
841
842 case RTF_FLY_CNTNT:
843 {
844 SwNodeIndex aIdx( pPam->GetPoint()->nNode );
845 pDoc->GetNodes().GoPrevious( &aIdx );
846 SwPosition aPos( aIdx );
847 aAnchor.SetType( FLY_AT_PARA );
848 aAnchor.SetAnchor( &aPos );
849 }
850 break;
851
852 // JP 26.09.94: die Bindung an die Spalte gibt es nicht mehr !!
853 // case RTF_FLY_COLUMN:
854 }
855 break;
856 case RTF_COLS: nCols = sal_uInt16( nTokenValue ); break;
857 case RTF_COLSX: nColSpace = sal_uInt16( nTokenValue ); break;
858 case RTF_COLNO:
859 nAktCol = sal_uInt16( nTokenValue );
860 if( RTF_COLW == GetNextToken() )
861 {
862 sal_uInt16 nWidth = sal_uInt16( nTokenValue ), nSpace = 0;
863 if( RTF_COLSR == GetNextToken() )
864 nSpace = sal_uInt16( nTokenValue );
865 else
866 SkipToken( -1 ); // wieder zurueck
867
868 if( --nAktCol == ( aColumns.Count() / 2 ) )
869 {
870 aColumns.Insert( nWidth + nSpace, aColumns.Count() );
871 aColumns.Insert( nSpace, aColumns.Count() );
872 }
873 }
874 break;
875
876 case '{':
877 if( RTF_BRDBOX == ( nToken = GetNextToken() ) )
878 ReadBorderAttr( nToken, aSet );
879 else if( RTF_SHADINGDEF == (nToken & ~0xff ) )
880 ReadBackgroundAttr( nToken, aSet );
881 else if( RTF_IGNOREFLAG == nToken )
882 {
883 int bSkipGrp = sal_True;
884 switch( nToken = GetNextToken() )
885 {
886 case RTF_SHADOW:
887 case RTF_BRDBOX:
888 ReadAttr( SkipToken( -2 ), &aSet );
889 bSkipGrp = sal_False;
890 break;
891
892 case RTF_BRDRT:
893 case RTF_BRDRB:
894 case RTF_BRDRR:
895 case RTF_BRDRL:
896 bSkipGrp = sal_False;
897 ReadBorderAttr( SkipToken( -2 ), aSet );
898 break;
899 }
900
901 // keine weitere Klammer mehr ueberlesen!!!
902 if( !bSkipGrp )
903 break;
904
905 SkipGroup();
906 }
907 else
908 SkipGroup();
909 GetNextToken(); // Klammer ueberlesen
910 break;
911 }
912 } while( IsParserWorking() &&
913 '}' != ( nToken = GetNextToken() ));
914
915 if( aUL.GetUpper() || aUL.GetLower() )
916 pSet->Put( aUL );
917 if( aLR.GetLeft() || aLR.GetRight() )
918 pSet->Put( aLR );
919 }
920 else if( RTF_BRDBOX == nToken )
921 ReadBorderAttr( nToken, aSet );
922 else if( RTF_SHADOW == nToken )
923 ReadAttr( SkipToken( -2 ), &aSet );
924 else if( RTF_SHADINGDEF == (nToken & ~0xff ) )
925 ReadBackgroundAttr( nToken, aSet );
926 else if( RTF_UNKNOWNCONTROL == nToken )
927 SkipGroup();
928 else
929 nSkip = -2;
930
931 if( nSkip )
932 {
933 nToken = SkipToken( nSkip );
934 bWeiter = sal_False;
935 }
936 }
937 break;
938
939 default:
940 --nAppliedProps; //Not sufficient to make a frame
941 bWeiter = sal_False;
942 }
943
944 if( bWeiter )
945 nToken = GetNextToken();
946 } while( bWeiter && IsParserWorking() );
947
948 pSet->Put( aAnchor );
949 pSet->Put( aHori );
950 pSet->Put( aVert );
951
952 // --> OD 2004-06-30 #i27767# - set wrapping style influence
953 // --> OD 2004-10-18 #i35017# - constant name has changed
954 pSet->Put( SwFmtWrapInfluenceOnObjPos(
955 text::WrapInfluenceOnPosition::ONCE_SUCCESSIVE ));
956 // <--
957
958 SwFmtFollowTextFlow aFollowTextFlow( sal_False );
959 pSet->Put( aFollowTextFlow );
960
961 if( !( aFrmDir == pSet->Get( RES_FRAMEDIR )) )
962 pSet->Put( aFrmDir );
963
964 if( nCols && USHRT_MAX != nCols )
965 {
966 SwFmtCol aCol;
967 if( USHRT_MAX == nColSpace )
968 nColSpace = 720;
969
970 sal_uLong nWidth = USHRT_MAX;
971 aCol.Init( nCols, nColSpace, sal_uInt16( nWidth ) );
972 if( nCols == ( aColumns.Count() / 2 ) )
973 {
974 for( sal_uInt16 n = 0, i = 0; n < aColumns.Count(); n += 2, ++i )
975 {
976 SwColumn* pCol = aCol.GetColumns()[ i ];
977 sal_uLong nTmp = aColumns[ n ];
978 nTmp *= USHRT_MAX;
979 nTmp /= nWidth;
980 pCol->SetWishWidth( sal_uInt16(nTmp) );
981 /*
982 JP 07.07.95: der Dialog kennt nur eine Breite fuer alle Spalten
983 darum hier nicht weiter beachten
984 nTmp = aColumns[ n+1 ];
985 if( nTmp )
986 pCol->SetRight( sal_uInt16(nTmp) );
987 else
988 pCol->SetRight( 0 );
989 pCol->SetLeft( 0 );
990 */
991 }
992 }
993 pSet->Put( aCol );
994 }
995
996 if( pSet != &aSet ) // wurde der Set uebergeben, dann wars das
997 return ;
998
999 // ein neues FlyFormat anlegen oder das alte benutzen ?
1000 // (teste ob es die selben Attribute besitzt!)
1001 SwFlySave* pFlySave = 0;
1002 sal_uInt16 nFlyArrCnt = aFlyArr.Count();
1003 /*
1004 #i5263#
1005 There were not enough frame properties found to actually justify creating
1006 an absolutely positioned frame.
1007 */
1008 if (nAppliedProps)
1009 {
1010 if( !nFlyArrCnt ||
1011 !( pFlySave = aFlyArr[ nFlyArrCnt-1 ])->IsEqualFly( *pPam, aSet ))
1012 {
1013 pFlySave = new SwFlySave( *pPam, aSet );
1014 Size aPgSize;
1015 GetPageSize( aPgSize );
1016 pFlySave->nPageWidth = aPgSize.Width();
1017
1018 if( nDropCapAnchor )
1019 {
1020 pFlySave->nDropAnchor = nDropCapAnchor;
1021 pFlySave->nDropLines = nDropCapLines;
1022 }
1023 if (nFlyArrCnt >0){
1024 SwFlySave* pFlySavePrev = aFlyArr[nFlyArrCnt-1];
1025 if (pFlySave->nSttNd.GetIndex() < pFlySavePrev->nEndNd.GetIndex())
1026 {
1027 pFlySavePrev->nEndNd=pFlySave->nSttNd;
1028 }
1029 }
1030 aFlyArr.Insert( pFlySave, nFlyArrCnt++ );
1031 // --> OD 2008-12-22 #i83368# - reset
1032 mbReadCellWhileReadSwFly = false;
1033 // <--
1034 }
1035 }
1036
1037 SetPardTokenRead( sal_False );
1038 const SwTableNode* pTblNd = pPam->GetNode()->FindTableNode();
1039
1040 while( !IsPardTokenRead() && IsParserWorking() )
1041 {
1042 if( RTF_PARD == nToken || nNumOpenBrakets > GetOpenBrakets() )
1043 break;
1044
1045 NextToken( nToken );
1046
1047 if( !IsPardTokenRead() )
1048 {
1049 // #102781#. Added support for transparent frames.
1050 if (nToken == RTF_CBPAT && nFlyArrCnt > 0)
1051 {
1052 sal_uInt16 _index=sal_uInt16(nTokenValue);
1053 const Color& rColor = GetColor(_index);
1054 SvxBrushItem aBrush(rColor, RES_BACKGROUND);
1055 SwFlySave* pFS = aFlyArr[nFlyArrCnt-1];
1056 pFS->aFlySet.Put(aBrush, RES_BACKGROUND);
1057 }
1058
1059 nToken = GetNextToken();
1060
1061 // BUG 22036: kommt zwischen Fly-Attributen ein unbekanntes,
1062 // dann erzeuge nie 2 FlyFrames, sondern fasse
1063 // beide zusammen !!!
1064 while( RTF_APOCTL == ( nToken & ~(0xff | RTF_SWGDEFS) ))
1065 {
1066 if( RTF_FLY_INPARA == nToken )
1067 break;
1068
1069 if( RTF_IGNOREFLAG == SkipToken( -1 ) )
1070 {
1071 if( '{' == SkipToken( -1 ) )
1072 nToken = '{';
1073 else
1074 SkipToken( 2 );
1075 }
1076 else
1077 SkipToken( 1 );
1078
1079 ReadFly( nToken, pFlySave ? &pFlySave->aFlySet : 0);
1080 nToken = GetNextToken();
1081 }
1082 }
1083 }
1084
1085 /*
1086 #i5263#
1087 There were enough frame properties found to actually justify creating
1088 an absolutely positioned frame.
1089 */
1090 if (!nAppliedProps)
1091 {
1092 bReadSwFly = false;
1093 SkipToken( -1 );
1094 return;
1095 }
1096
1097 if( pTblNd && !pPam->GetPoint()->nContent.GetIndex() &&
1098 pTblNd->EndOfSectionIndex() + 1 ==
1099 pPam->GetPoint()->nNode.GetIndex() )
1100 {
1101 // nicht mehr in der Tabelle, sondern dahinter ?
1102 // Dann aber wieder zurueck in die Tabelle
1103 pPam->Move( fnMoveBackward );
1104 }
1105 else
1106 pTblNd = 0;
1107
1108 // wurde garnichts eingefuegt?
1109 if( !pTblNd &&
1110 pPam->GetPoint()->nNode == pFlySave->nSttNd &&
1111 !pPam->GetPoint()->nContent.GetIndex() )
1112 {
1113 // // dann erzeuge mindestens einen leeren TextNode
1114 // pDoc->AppendTxtNode(*pPam);
1115 // dann zerstoere den FlySave wieder.
1116 aFlyArr.DeleteAndDestroy( --nFlyArrCnt );
1117
1118 }
1119 else
1120 {
1121 sal_Bool bMovePaM = 0 != pTblNd;
1122
1123 pFlySave->nEndNd = pPam->GetPoint()->nNode;
1124 pFlySave->nEndCnt = pPam->GetPoint()->nContent.GetIndex();
1125
1126 if( bMovePaM )
1127 pPam->Move( fnMoveForward );
1128
1129 pTblNd = pFlySave->nSttNd.GetNode().FindTableNode();
1130 if( pTblNd && !pFlySave->nEndCnt &&
1131 pTblNd == pFlySave->nEndNd.GetNode().FindTableNode() )
1132 {
1133 // dann teste mal, ob das \pard nicht zu spaet kam und
1134 // eigentlich in die vorherige Zelle gehoert
1135 const SwStartNode* pSttBoxNd = pFlySave->nSttNd.GetNode().
1136 FindTableBoxStartNode(),
1137 * pEndBoxNd = pFlySave->nEndNd.GetNode().
1138 FindTableBoxStartNode();
1139 if( pSttBoxNd && pEndBoxNd &&
1140 bMovePaM ? ( pSttBoxNd == pEndBoxNd )
1141 : ( pSttBoxNd->EndOfSectionIndex() + 1 ==
1142 pEndBoxNd->GetIndex() &&
1143 pEndBoxNd->GetIndex() + 1 ==
1144 pFlySave->nEndNd.GetIndex() ))
1145 {
1146 // dann gehoert das Ende in die vorherige Box!
1147 SwPosition aPos( *pPam->GetPoint() );
1148 pPam->GetPoint()->nNode = *pSttBoxNd->EndOfSectionNode();
1149 pPam->Move( fnMoveBackward, fnGoNode );
1150
1151 DelLastNode();
1152
1153 pPam->GetPoint()->nNode = *pSttBoxNd->EndOfSectionNode();
1154 pPam->Move( fnMoveBackward, fnGoNode );
1155
1156 pFlySave->nEndNd = pPam->GetPoint()->nNode;
1157 pFlySave->nEndCnt = pPam->GetPoint()->nContent.GetIndex();
1158
1159 *pPam->GetPoint() = aPos;
1160 }
1161 }
1162 else if( !bReadSwFly && !pFlySave->nEndCnt &&
1163 pFlySave->nSttNd.GetIndex() + 1 == pFlySave->nEndNd.GetIndex() &&
1164 pFlySave->nSttNd.GetNode().IsTxtNode() )
1165 {
1166
1167 SwTxtNode* pTxtNd = pFlySave->nSttNd.GetNode().GetTxtNode();
1168 SwTxtFlyCnt* pFlyCnt = 0;
1169 if( 1 == pTxtNd->GetTxt().Len() &&
1170 0 != (pFlyCnt = static_cast<SwTxtFlyCnt*>(
1171 pTxtNd->GetTxtAttrForCharAt(0, RES_TXTATR_FLYCNT))) &&
1172 pFlyCnt->GetFlyCnt().GetFrmFmt() )
1173 {
1174 // then move the content into the surrounded fly
1175 SwFrmFmt* pFlyFmt = pFlyCnt->GetFlyCnt().GetFrmFmt();
1176 const SwNodeIndex* pFlySNd = pFlyFmt->GetCntnt().GetCntntIdx();
1177 SwNodeRange aRg( *pFlySNd, 1,
1178 *pFlySNd->GetNode().EndOfSectionNode(), 0 );
1179
1180 // merge the itemsets
1181 SwFmtFrmSize aSz1( (SwFmtFrmSize&)pFlyFmt->GetAttrSet().
1182 Get( RES_FRM_SIZE ));
1183 SwFmtFrmSize aSz2( (SwFmtFrmSize&)pFlySave->aFlySet.
1184 Get( RES_FRM_SIZE ));
1185 // if
1186 if( !aRg.aStart.GetNode().IsNoTxtNode() ||
1187 !aSz1.GetHeight() || !aSz1.GetWidth() ||
1188 !aSz2.GetHeight() || !aSz2.GetWidth() ||
1189 ( aSz1.GetHeight() == aSz2.GetHeight() &&
1190 aSz1.GetWidth() == aSz2.GetWidth() ) )
1191 {
1192 SfxItemSet aDiffs( pFlyFmt->GetAttrSet() );
1193 aDiffs.ClearItem( RES_ANCHOR );
1194 aDiffs.ClearItem( RES_FRM_SIZE );
1195 aDiffs.ClearItem( RES_CNTNT );
1196 aDiffs.Differentiate( pFlySave->aFlySet );
1197 pFlySave->aFlySet.Put( aDiffs );
1198
1199 sal_Bool bSet = sal_False;
1200 if( aSz1.GetHeight() && !aSz2.GetHeight() )
1201 {
1202 bSet = sal_True;
1203 aSz2.SetHeight( aSz1.GetHeight() );
1204 }
1205 if( aSz1.GetWidth() && !aSz2.GetWidth() )
1206 {
1207 bSet = sal_True;
1208 aSz2.SetWidth( aSz1.GetWidth() );
1209 }
1210 if( bSet )
1211 pFlySave->aFlySet.Put( aSz2 );
1212
1213 // move any PageBreak/Desc Attr to the next Para
1214 {
1215 SwCntntNode* pSrcNd = pFlySave->nSttNd.GetNode().GetCntntNode();
1216 SwCntntNode* pDstNd = pFlySave->nEndNd.GetNode().GetCntntNode();
1217
1218 ::lcl_CpyBreakAttrs( pSrcNd, pDstNd, &pFlySave->nEndNd );
1219 }
1220
1221 // create new txtnode, because the section does never be empty
1222 pDoc->GetNodes().MakeTxtNode( aRg.aStart,
1223 (SwTxtFmtColl*)pDoc->GetDfltTxtFmtColl() );
1224
1225 SwNodeIndex aTmp( pFlySave->nSttNd, +1 );
1226 pDoc->MoveNodeRange( aRg, aTmp,
1227 IDocumentContentOperations::DOC_MOVEDEFAULT );
1228
1229 // now delete the redundant txtnode
1230 pDoc->GetNodes().Delete( pFlySave->nSttNd, 1 );
1231 }
1232 }
1233 }
1234 }
1235
1236 bReadSwFly = false;
1237 SkipToken( -1 );
1238 }
1239
1240
InsPicture(const String & rGrfNm,const Graphic * pGrf,const SvxRTFPictureType * pPicType)1241 void SwRTFParser::InsPicture( const String& rGrfNm, const Graphic* pGrf,
1242 const SvxRTFPictureType* pPicType )
1243 {
1244 // kennzeichen fuer Swg-Dokumente:
1245 // (dann ist das FlyFmt fuer die Grafik!)
1246 SwGrfNode * pGrfNd;
1247 // --> OD 2008-12-22 #i83368#
1248 // Assure that graphic node is enclosed by fly frame node.
1249 // if( bReadSwFly )
1250 if ( bReadSwFly && !mbReadCellWhileReadSwFly )
1251 // <--
1252 {
1253 OSL_ENSURE(aFlyArr.Count(),
1254 "SwRTFParser::InsPicture: fly array empty.");
1255 if (aFlyArr.Count())
1256 {
1257 // erzeuge nur einen normalen GrafikNode und ersetze diesen gegen
1258 // den vorhandenen Textnode
1259 SwNodeIndex& rIdx = pPam->GetPoint()->nNode;
1260 pGrfNd = pDoc->GetNodes().MakeGrfNode( rIdx,
1261 rGrfNm, aEmptyStr, // Name der Graphic !!
1262 pGrf,
1263 (SwGrfFmtColl*)pDoc->GetDfltGrfFmtColl() );
1264
1265 if( pGrfAttrSet )
1266 pGrfNd->SetAttr( *pGrfAttrSet );
1267
1268 SwFlySave* pFlySave = aFlyArr[ aFlyArr.Count()-1 ];
1269 pFlySave->nSttNd = rIdx.GetIndex() - 1;
1270
1271 if( 1 < aFlyArr.Count() )
1272 {
1273 pFlySave = aFlyArr[ aFlyArr.Count() - 2 ];
1274 if( pFlySave->nEndNd == rIdx )
1275 pFlySave->nEndNd = rIdx.GetIndex() - 1;
1276 }
1277 }
1278 }
1279 else
1280 {
1281 // wenn normale RTF-Grafik, dann steht diese im Textfluss !
1282 SwAttrSet aFlySet( pDoc->GetAttrPool(), RES_OPAQUE, /*RES_OPAQUE,
1283 RES_VERT_ORIENT,*/ RES_ANCHOR );
1284 const SwPosition* pPos = pPam->GetPoint();
1285
1286 SwFmtAnchor aAnchor( FLY_AS_CHAR );
1287 aAnchor.SetAnchor( pPos );
1288 aFlySet.Put( aAnchor );
1289 aFlySet.Put( SwFmtVertOrient( 0, text::VertOrientation::TOP ));
1290
1291 if (pDoc->IsInHeaderFooter(pPos->nNode))
1292 {
1293 SvxOpaqueItem aOpaqueItem(RES_OPAQUE, sal_False);
1294 SwFmtSurround aSurroundItem(SURROUND_THROUGHT);
1295 aFlySet.Put(aOpaqueItem);
1296 aFlySet.Put(aSurroundItem);
1297 }
1298
1299 SwFlyFrmFmt* pFlyFmt = pDoc->Insert( *pPam,
1300 rGrfNm, aEmptyStr, // Name der Graphic !!
1301 pGrf,
1302 &aFlySet, // Attribute fuer den FlyFrm
1303 pGrfAttrSet, NULL ); // Attribute fuer die Grafik
1304
1305 pGrfNd = pDoc->GetNodes()[ pFlyFmt->GetCntnt().GetCntntIdx()->
1306 GetIndex()+1 ]->GetGrfNode();
1307
1308 _SetPictureSize( *pGrfNd, pPos->nNode,
1309 (SfxItemSet&)pFlyFmt->GetAttrSet(),
1310 pPicType );
1311 if( pPicType )
1312 {
1313 PictPropertyNameValuePairs::const_iterator aIt = pPicType->aPropertyPairs.begin();
1314 PictPropertyNameValuePairs::const_iterator aEnd = pPicType->aPropertyPairs.end();
1315 while( aIt != aEnd)
1316 {
1317 if( aIt->first.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM( "wzDescription") ))
1318 {
1319 SwXFrame::GetOrCreateSdrObject( pFlyFmt );
1320 pDoc->SetFlyFrmDescription( *(pFlyFmt), aIt->second );
1321 }
1322 else if( aIt->first.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM( "wzName") ))
1323 {
1324 SwXFrame::GetOrCreateSdrObject( pFlyFmt );
1325 pDoc->SetFlyFrmTitle( *(pFlyFmt), aIt->second );
1326 }
1327 ++aIt;
1328 }
1329 }
1330
1331 }
1332
1333 if( pGrfAttrSet )
1334 DELETEZ( pGrfAttrSet );
1335 }
1336
_SetPictureSize(const SwNoTxtNode & rNd,const SwNodeIndex & rAnchor,SfxItemSet & rSet,const SvxRTFPictureType * pPicType)1337 void SwRTFParser::_SetPictureSize( const SwNoTxtNode& rNd,
1338 const SwNodeIndex& rAnchor,
1339 SfxItemSet& rSet,
1340 const SvxRTFPictureType* pPicType )
1341 {
1342 Size aSize( ((SwNoTxtNode&)rNd).GetTwipSize() );
1343 if( pPicType )
1344 {
1345 if( rNd.IsGrfNode() )
1346 {
1347 if( SvxRTFPictureType::WIN_METAFILE != pPicType->eStyle &&
1348 pPicType->nGoalWidth && pPicType->nGoalHeight )
1349 {
1350 aSize.Width() = pPicType->nGoalWidth;
1351 aSize.Height() =pPicType->nGoalHeight;
1352 }
1353 else if( SvxRTFPictureType::MAC_QUICKDRAW == pPicType->eStyle )
1354 {
1355 // IMMER auf 72 DPI bezogen, also 1pt == 20 Twip !!
1356 aSize.Width() = pPicType->nWidth * 20;
1357 aSize.Height() = pPicType->nHeight * 20;
1358 }
1359 else
1360 {
1361 // von 100TH_MM nach TWIP umrechenen!
1362 // #117879# when \picwgoal resp \pichgoal are present, then use them.
1363 // The values of \picwgoal and \picwgoal are already given in twips.
1364 aSize.Width() = (pPicType->nGoalWidth?pPicType->nGoalWidth:(pPicType->nWidth*144)/254);
1365 aSize.Height() = (pPicType->nGoalHeight?pPicType->nGoalHeight:(pPicType->nHeight*144)/254);
1366 }
1367 ((SwGrfNode&)rNd).SetTwipSize( aSize );
1368 }
1369
1370 if( 100 != pPicType->nScalX )
1371 aSize.Width() = (((long)pPicType->nScalX) * ( aSize.Width() -
1372 ( pPicType->nCropL + pPicType->nCropR ))) / 100L;
1373
1374 if( 100 != pPicType->nScalY )
1375 aSize.Height() = (((long)pPicType->nScalY) * ( aSize.Height() -
1376 ( pPicType->nCropT + pPicType->nCropB ))) / 100L;
1377 }
1378
1379 //steht der Fly etwa in einer Tabelle ?
1380 const SwNode* pAnchorNd = & rAnchor.GetNode();
1381 const SwTableNode* pTblNd = pAnchorNd->FindTableNode();
1382 if( pTblNd )
1383 {
1384 // Box feststellen:
1385 const SwTableBox* pBox = pTblNd->GetTable().GetTblBox(
1386 pAnchorNd->StartOfSectionIndex() );
1387 if( pBox )
1388 {
1389 long nBoxWidth = pBox->GetFrmFmt()->GetFrmSize().GetWidth();
1390 if( aSize.Width() > nBoxWidth )
1391 aSize.Width() = nBoxWidth;
1392 }
1393 }
1394
1395 //JP 8.11.2001: bug 94450 - if no size exist, then the size is set by
1396 // the swapin of the graphic.
1397 SwGrfNode* pGrfNd;
1398 if( !aSize.Width() && !aSize.Height() &&
1399 0 != (pGrfNd = (SwGrfNode*)rNd.GetGrfNode() ) && pGrfNd->IsGrfLink() )
1400 pGrfNd->SetChgTwipSize( sal_True );
1401
1402 // min. Werte einhalten !!
1403 if( aSize.Width() < MINFLY )
1404 aSize.Width() = MINFLY;
1405 if( aSize.Height() < MINFLY)
1406 aSize.Height() = MINFLY;
1407
1408 if( pPicType )
1409 {
1410 sal_Bool bChg = sal_False;
1411 SwCropGrf aCrop;
1412
1413 /*
1414 JP 28.07.99: Bug 67800 - no crop by MAC_QUICKDRAW. At time i dont know why
1415 it has been coded. But this has used for any
1416 RTF-File, but i dont found them.
1417 if( SvxRTFPictureType::MAC_QUICKDRAW == pPicType->eStyle )
1418 {
1419 // evt. ein wenig Croppen ??
1420 // IMMER auf 72 DPI bezogen, also 1pt == 20 Twip !!
1421 long nTmp = pPicType->nWidth * 20;
1422 if( nTmp != aSize.Width() )
1423 {
1424 // in der Breite (also rechts) croppen
1425 aCrop.Right() = nTmp - aSize.Width();
1426 aSize.Width() = nTmp;
1427 bChg = sal_True;
1428 }
1429
1430 nTmp = pPicType->nHeight * 20;
1431 if( nTmp != aSize.Height() )
1432 {
1433 // in der Hoehe (also unten) croppen
1434 aCrop.Bottom() = nTmp - aSize.Height();
1435 aSize.Height() = nTmp;
1436 bChg = sal_True;
1437 }
1438 }
1439 */
1440 if( pPicType->nCropT )
1441 {
1442 aCrop.SetTop( pPicType->nCropT );
1443 bChg = sal_True;
1444 }
1445 if( pPicType->nCropB )
1446 {
1447 aCrop.SetBottom( pPicType->nCropB );
1448 bChg = sal_True;
1449 }
1450 if( pPicType->nCropL )
1451 {
1452 aCrop.SetLeft( pPicType->nCropL );
1453 bChg = sal_True;
1454 }
1455 if( pPicType->nCropR )
1456 {
1457 aCrop.SetRight( pPicType->nCropR );
1458 bChg = sal_True;
1459 }
1460
1461 if( bChg )
1462 {
1463 // dann mal an die CropWerte an die GrafikSize anpassen.
1464 ((SwNoTxtNode&)rNd).SetAttr( aCrop );
1465 }
1466 }
1467 rSet.Put( SwFmtFrmSize( ATT_FIX_SIZE, aSize.Width(), aSize.Height() ));
1468 }
1469
GetPageSize(Size & rSize)1470 void SwRTFParser::GetPageSize( Size& rSize )
1471 {
1472 ASSERT(!maSegments.empty(), "not possible");
1473 if (maSegments.empty())
1474 {
1475 rSize.Width() = 12240 - 1800 - 1800;
1476 rSize.Height() = 15840 - 1440 - 1440;
1477 return;
1478 }
1479
1480 const rtfSection &rSect = maSegments.back();
1481
1482 rSize.Width() = rSect.maPageInfo.mnPgwsxn - rSect.maPageInfo.mnMarglsxn - rSect.maPageInfo.mnMargrsxn;
1483 rSize.Height() = rSect.maPageInfo.mnPghsxn - rSect.maPageInfo.mnMargtsxn - rSect.maPageInfo.mnMargbsxn;
1484
1485 long nCols = rSect.NoCols();
1486 if (1 < nCols)
1487 {
1488 rSize.Width() /= nCols;
1489 rSize.Height() /= nCols;
1490 }
1491 }
1492
ReadBitmapData()1493 void SwRTFParser::ReadBitmapData()
1494 {
1495 Graphic aGrf;
1496 SvxRTFPictureType aPicType;
1497 if( ReadBmpData( aGrf, aPicType ) )
1498 InsPicture( aEmptyStr, &aGrf, &aPicType );
1499 }
1500
1501 #ifdef READ_OLE_OBJECT
ReadOLEData()1502 void SwRTFParser::ReadOLEData()
1503 {
1504 SvCacheStream aTmpFile( 0xA000 );
1505 Graphic aGrf;
1506 SvxRTFPictureType aPicType, aOleType;
1507
1508 int nToken, bValidOle = sal_True, bWeiter = sal_True;
1509 int nOpenBrakets = 1; // die erste wurde schon vorher erkannt !!
1510
1511 String* pStr = 0;
1512 String sObjClass, sObjName, sObjData;
1513
1514 while( nOpenBrakets && IsParserWorking() && bWeiter && bValidOle )
1515 {
1516 nToken = GetNextToken();
1517 sal_uInt16 nVal = sal_uInt16( nTokenValue );
1518 switch( nToken )
1519 {
1520 case '}': --nOpenBrakets; pStr = 0; break;
1521 case '{':
1522 {
1523 if( RTF_IGNOREFLAG != GetNextToken() )
1524 nToken = SkipToken( -1 );
1525 else if( RTF_UNKNOWNCONTROL != GetNextToken() )
1526 nToken = SkipToken( -2 );
1527 else
1528 {
1529 // gleich herausfiltern
1530 ReadUnknownData();
1531 nToken = GetNextToken();
1532 if( '}' != nToken )
1533 eState = SVPAR_ERROR;
1534 break;
1535 }
1536 ++nOpenBrakets;
1537 }
1538 break;
1539
1540 case RTF_OBJECT:
1541 case RTF_OBJEMB: // default ist embedded
1542 case RTF_LINKSELF: // ??
1543 case RTF_OBJLOCK: // ??
1544 case RTF_OBJUPDATE: // ??
1545 case RTF_OBJTIME: // ??
1546 case RTF_OBJSETSIZE:
1547 case RTF_OBJALIGN:
1548 case RTF_OBJTRANSY:
1549 case RTF_OBJATTPH:
1550 break;
1551
1552 case RTF_OBJLINK: // ?? welche Daten sind das ??
1553 case RTF_OBJAUTLINK: // ?? -""- ??
1554 case RTF_OBJSUB:
1555 case RTF_OBJPUB:
1556 case RTF_OBJICEMB:
1557 case RTF_OBJOCX:
1558 case RTF_OBJHTML:
1559 case RTF_OBJALIAS:
1560 case RTF_OBJSECT:
1561 bValidOle = sal_False; // diese Typen koennen wir nicht
1562 break;
1563
1564 case RTF_OBJCLASS:
1565 // Daten lesen
1566 pStr = &sObjClass;
1567 break;
1568
1569 case RTF_OBJNAME:
1570 // Daten lesen
1571 pStr = &sObjName;
1572 break;
1573
1574 case RTF_OBJDATA:
1575 pStr = &sObjData;
1576 break;
1577
1578 case RTF_RESULT:
1579 {
1580 // hier weitermachen, wenn das OLE-Object ungueltig ist
1581 bWeiter = sal_False;
1582 }
1583 break;
1584 case RTF_RSLTBMP: // diese sollten wir ignorieren
1585 case RTF_RSLTMERGE:
1586 case RTF_RSLTPICT:
1587 case RTF_RSLTRTF:
1588 case RTF_RSLTTXT:
1589 break;
1590
1591 case RTF_OBJW: aOleType.nWidth = nVal; break;
1592 case RTF_OBJH: aOleType.nHeight = nVal; break;
1593 case RTF_OBJCROPT: aOleType.nCropT = (short)nTokenValue; break;
1594 case RTF_OBJCROPB: aOleType.nCropB = (short)nTokenValue; break;
1595 case RTF_OBJCROPL: aOleType.nCropL = (short)nTokenValue; break;
1596 case RTF_OBJCROPR: aOleType.nCropR = (short)nTokenValue; break;
1597 case RTF_OBJSCALEX: aOleType.nScalX = nVal; break;
1598 case RTF_OBJSCALEY: aOleType.nScalY = nVal; break;
1599
1600 case RTF_TEXTTOKEN:
1601 if( 1 < nOpenBrakets && pStr )
1602 {
1603 if( pStr == &sObjData )
1604 {
1605 xub_StrLen nHexLen = HexToBin( aToken );
1606 if( STRING_NOTFOUND != nHexLen )
1607 bValidOle = sal_False;
1608 else
1609 {
1610 aTmpFile.Write( (sal_Char*)aToken.GetBuffer(), nHexLen );
1611 bValidOle = 0 == aTmpFile.GetError();
1612 }
1613 }
1614 else
1615 *pStr += aToken;
1616 }
1617 break;
1618 }
1619 }
1620
1621 if( bValidOle )
1622 {
1623 bValidOle = sal_False; // erstmal
1624 }
1625
1626 if( !bWeiter ) // dann stehen wir noch im Result
1627 {
1628 // ist das Ole-Object Ok?
1629 // -> dann solange SkipGroup rufen, bis zur letzten
1630 // schliessenden Klammer
1631 // ansonsten alle Token verarbeiten, bis zur letzten
1632 // schliessenden Klammer
1633
1634 bWeiter = sal_True;
1635 while( nOpenBrakets && IsParserWorking() && bWeiter )
1636 {
1637 switch( nToken = GetNextToken() )
1638 {
1639 case '}': --nOpenBrakets; break;
1640 case '{': ++nOpenBrakets; break;
1641 }
1642 if( nOpenBrakets && !bValidOle )
1643 NextToken( nToken );
1644 }
1645 }
1646
1647 if( !bValidOle && '}' != nToken )
1648 SkipGroup();
1649
1650 SkipToken( -1 ); // die schliesende Klammer wird "oben" ausgewertet
1651 }
1652 #endif
1653
1654 /* vi:set tabstop=4 shiftwidth=4 expandtab: */
1655