xref: /trunk/main/sw/source/filter/rtf/rtffly.cxx (revision 870262e3)
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