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