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