xref: /trunk/main/sw/source/core/fields/reffld.cxx (revision efeef26f)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 
27 
28 #define _SVSTDARR_USHORTSSORT
29 #define _SVSTDARR_USHORTS
30 #include <svl/svstdarr.hxx>
31 #include <com/sun/star/text/ReferenceFieldPart.hpp>
32 #include <com/sun/star/text/ReferenceFieldSource.hpp>
33 #include <unotools/localedatawrapper.hxx>
34 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
35 #include <comphelper/processfactory.hxx>
36 #include <editeng/unolingu.hxx>
37 #include <doc.hxx>
38 #include <pam.hxx>
39 #include <cntfrm.hxx>
40 #include <pagefrm.hxx>
41 #include <docary.hxx>
42 #include <fmtfld.hxx>
43 #include <txtfld.hxx>
44 #include <txtftn.hxx>
45 #include <fmtrfmrk.hxx>
46 #include <txtrfmrk.hxx>
47 #include <fmtftn.hxx>
48 #include <ndtxt.hxx>
49 #include <chpfld.hxx>
50 #include <reffld.hxx>
51 #include <expfld.hxx>
52 #include <txtfrm.hxx>
53 #include <flyfrm.hxx>
54 #include <pagedesc.hxx>
55 #include <IMark.hxx>
56 #include <crossrefbookmark.hxx>
57 #include <ftnidx.hxx>
58 #include <viewsh.hxx>
59 #include <unofldmid.h>
60 #include <SwStyleNameMapper.hxx>
61 #include <shellres.hxx>
62 #include <poolfmt.hxx>
63 #include <poolfmt.hrc>
64 #include <comcore.hrc>
65 #include <numrule.hxx>
66 #include <SwNodeNum.hxx>
67 #include <switerator.hxx>
68 
69 using namespace ::com::sun::star;
70 using namespace ::com::sun::star::text;
71 using namespace ::com::sun::star::lang;
72 using ::rtl::OUString;
73 
74 extern void InsertSort( SvUShorts& rArr, sal_uInt16 nIdx, sal_uInt16* pInsPos = 0 );
75 
76 void lcl_GetLayTree( const SwFrm* pFrm, SvPtrarr& rArr )
77 {
78 	while( pFrm )
79 	{
80 		if( pFrm->IsBodyFrm() )		// soll uns nicht weiter interessieren
81 			pFrm = pFrm->GetUpper();
82 		else
83 		{
84 			void* p = (void*)pFrm;
85 			rArr.Insert( p, rArr.Count() );
86 
87 			// bei der Seite ist schluss
88 			if( pFrm->IsPageFrm() )
89 				break;
90 
91 			if( pFrm->IsFlyFrm() )
92                 pFrm = ((SwFlyFrm*)pFrm)->GetAnchorFrm();
93 			else
94 				pFrm = pFrm->GetUpper();
95 		}
96 	}
97 }
98 
99 
100 sal_Bool IsFrameBehind( const SwTxtNode& rMyNd, sal_uInt16 nMySttPos,
101 					const SwTxtNode& rBehindNd, sal_uInt16 nSttPos )
102 {
103 	const SwTxtFrm *pMyFrm = (SwTxtFrm*)rMyNd.getLayoutFrm( rMyNd.GetDoc()->GetCurrentLayout(), 0,0,sal_False),
104 				   *pFrm = (SwTxtFrm*)rBehindNd.getLayoutFrm( rBehindNd.GetDoc()->GetCurrentLayout(), 0,0,sal_False);
105 
106 	while( pFrm && !pFrm->IsInside( nSttPos ) )
107 		pFrm = (SwTxtFrm*)pFrm->GetFollow();
108 	while( pMyFrm && !pMyFrm->IsInside( nMySttPos ) )
109 		pMyFrm = (SwTxtFrm*)pMyFrm->GetFollow();
110 
111 	if( !pFrm || !pMyFrm || pFrm == pMyFrm )
112 		return sal_False;
113 
114 	SvPtrarr aRefArr( 10, 10 ), aArr( 10, 10 );
115 	::lcl_GetLayTree( pFrm, aRefArr );
116 	::lcl_GetLayTree( pMyFrm, aArr );
117 
118 	sal_uInt16 nRefCnt = aRefArr.Count() - 1, nCnt = aArr.Count() - 1;
119     sal_Bool bVert = sal_False;
120     sal_Bool bR2L = sal_False;
121 
122 	// solange bis ein Frame ungleich ist ?
123 	while( nRefCnt && nCnt && aRefArr[ nRefCnt ] == aArr[ nCnt ] )
124     {
125         const SwFrm* pTmpFrm = (const SwFrm*)aArr[ nCnt ];
126         bVert = pTmpFrm->IsVertical();
127         bR2L = pTmpFrm->IsRightToLeft();
128         --nCnt, --nRefCnt;
129     }
130 
131 	// sollte einer der Counter ueberlaeufen?
132 	if( aRefArr[ nRefCnt ] == aArr[ nCnt ] )
133 	{
134 		if( nCnt )
135 			--nCnt;
136 		else
137 			--nRefCnt;
138 	}
139 
140 	const SwFrm* pRefFrm = (const SwFrm*)aRefArr[ nRefCnt ];
141 	const SwFrm* pFldFrm = (const SwFrm*)aArr[ nCnt ];
142 
143 	// unterschiedliche Frames, dann ueberpruefe deren Y-/X-Position
144 	sal_Bool bRefIsLower = sal_False;
145 	if( ( FRM_COLUMN | FRM_CELL ) & pFldFrm->GetType() ||
146 		( FRM_COLUMN | FRM_CELL ) & pRefFrm->GetType() )
147 	{
148 		if( pFldFrm->GetType() == pRefFrm->GetType() )
149 		{
150 			// hier ist die X-Pos wichtiger!
151             if( bVert )
152             {
153                 if( bR2L )
154                     bRefIsLower = pRefFrm->Frm().Top() < pFldFrm->Frm().Top() ||
155                             ( pRefFrm->Frm().Top() == pFldFrm->Frm().Top() &&
156                               pRefFrm->Frm().Left() < pFldFrm->Frm().Left() );
157                 else
158                     bRefIsLower = pRefFrm->Frm().Top() < pFldFrm->Frm().Top() ||
159                             ( pRefFrm->Frm().Top() == pFldFrm->Frm().Top() &&
160                               pRefFrm->Frm().Left() > pFldFrm->Frm().Left() );
161             }
162             else if( bR2L )
163                 bRefIsLower = pRefFrm->Frm().Left() > pFldFrm->Frm().Left() ||
164                             ( pRefFrm->Frm().Left() == pFldFrm->Frm().Left() &&
165                               pRefFrm->Frm().Top() < pFldFrm->Frm().Top() );
166             else
167                 bRefIsLower = pRefFrm->Frm().Left() < pFldFrm->Frm().Left() ||
168                             ( pRefFrm->Frm().Left() == pFldFrm->Frm().Left() &&
169                               pRefFrm->Frm().Top() < pFldFrm->Frm().Top() );
170             pRefFrm = 0;
171 		}
172 		else if( ( FRM_COLUMN | FRM_CELL ) & pFldFrm->GetType() )
173 			pFldFrm = (const SwFrm*)aArr[ nCnt - 1 ];
174 		else
175 			pRefFrm = (const SwFrm*)aRefArr[ nRefCnt - 1 ];
176 	}
177 
178 	if( pRefFrm ) 				// als Flag missbrauchen
179     {
180         if( bVert )
181         {
182             if( bR2L )
183                 bRefIsLower = pRefFrm->Frm().Left() < pFldFrm->Frm().Left() ||
184                             ( pRefFrm->Frm().Left() == pFldFrm->Frm().Left() &&
185                                 pRefFrm->Frm().Top() < pFldFrm->Frm().Top() );
186             else
187                 bRefIsLower = pRefFrm->Frm().Left() > pFldFrm->Frm().Left() ||
188                             ( pRefFrm->Frm().Left() == pFldFrm->Frm().Left() &&
189                                 pRefFrm->Frm().Top() < pFldFrm->Frm().Top() );
190         }
191         else if( bR2L )
192             bRefIsLower = pRefFrm->Frm().Top() < pFldFrm->Frm().Top() ||
193                         ( pRefFrm->Frm().Top() == pFldFrm->Frm().Top() &&
194                             pRefFrm->Frm().Left() > pFldFrm->Frm().Left() );
195         else
196             bRefIsLower = pRefFrm->Frm().Top() < pFldFrm->Frm().Top() ||
197                         ( pRefFrm->Frm().Top() == pFldFrm->Frm().Top() &&
198                             pRefFrm->Frm().Left() < pFldFrm->Frm().Left() );
199     }
200     return bRefIsLower;
201 }
202 
203 /*--------------------------------------------------------------------
204 	Beschreibung: Referenzen holen
205  --------------------------------------------------------------------*/
206 
207 
208 SwGetRefField::SwGetRefField( SwGetRefFieldType* pFldType,
209 							  const String& rSetRef, sal_uInt16 nSubTyp,
210 							  sal_uInt16 nSeqenceNo, sal_uLong nFmt )
211     : SwField( pFldType, nFmt ),
212       sSetRefName( rSetRef ),
213       nSubType( nSubTyp ),
214       nSeqNo( nSeqenceNo )
215 {
216 }
217 
218 SwGetRefField::~SwGetRefField()
219 {
220 }
221 
222 String SwGetRefField::GetDescription() const
223 {
224     return SW_RES(STR_REFERENCE);
225 }
226 
227 sal_uInt16 SwGetRefField::GetSubType() const
228 {
229 	return nSubType;
230 }
231 
232 void SwGetRefField::SetSubType( sal_uInt16 n )
233 {
234 	nSubType = n;
235 }
236 
237 // --> OD 2007-11-09 #i81002#
238 bool SwGetRefField::IsRefToHeadingCrossRefBookmark() const
239 {
240     return GetSubType() == REF_BOOKMARK &&
241         ::sw::mark::CrossRefHeadingBookmark::IsLegalName(sSetRefName);
242 }
243 
244 bool SwGetRefField::IsRefToNumItemCrossRefBookmark() const
245 {
246     return GetSubType() == REF_BOOKMARK &&
247         ::sw::mark::CrossRefNumItemBookmark::IsLegalName(sSetRefName);
248 }
249 
250 const SwTxtNode* SwGetRefField::GetReferencedTxtNode() const
251 {
252     SwDoc* pDoc = dynamic_cast<SwGetRefFieldType*>(GetTyp())->GetDoc();
253     sal_uInt16 nDummy = USHRT_MAX;
254     return SwGetRefFieldType::FindAnchor( pDoc, sSetRefName, nSubType, nSeqNo, &nDummy );
255 }
256 // <--
257 // --> OD 2008-01-09 #i85090#
258 String SwGetRefField::GetExpandedTxtOfReferencedTxtNode() const
259 {
260     const SwTxtNode* pReferencedTxtNode( GetReferencedTxtNode() );
261     return pReferencedTxtNode
262            ? pReferencedTxtNode->GetExpandTxt( 0, STRING_LEN, true, true )
263            : aEmptyStr;
264 }
265 
266 String SwGetRefField::Expand() const
267 {
268 	return sTxt;
269 }
270 
271 
272 String SwGetRefField::GetFieldName() const
273 {
274 	String aStr(GetTyp()->GetName());
275 	aStr += ' ';
276 	aStr += sSetRefName;
277 	return aStr;
278 }
279 
280 // --> OD 2007-09-07 #i81002# - parameter <pFldTxtAttr> added
281 void SwGetRefField::UpdateField( const SwTxtFld* pFldTxtAttr )
282 {
283 	sTxt.Erase();
284 
285     SwDoc* pDoc = ((SwGetRefFieldType*)GetTyp())->GetDoc();
286     sal_uInt16 nStt = USHRT_MAX;
287     sal_uInt16 nEnd = USHRT_MAX;
288 	SwTxtNode* pTxtNd = SwGetRefFieldType::FindAnchor( pDoc, sSetRefName,
289 										nSubType, nSeqNo, &nStt, &nEnd );
290     if ( !pTxtNd )
291     {
292         sTxt = ViewShell::GetShellRes()->aGetRefFld_RefItemNotFound;
293 		return ;
294     }
295 
296 	switch( GetFormat() )
297 	{
298 	case REF_CONTENT:
299 	case REF_ONLYNUMBER:
300 	case REF_ONLYCAPTION:
301 	case REF_ONLYSEQNO:
302 		{
303 			switch( nSubType )
304 			{
305 			case REF_SEQUENCEFLD:
306 				nEnd = pTxtNd->GetTxt().Len();
307 				switch( GetFormat() )
308 				{
309 				case REF_ONLYNUMBER:
310 					if( nStt + 1 < nEnd )
311 						nEnd = nStt + 1;
312 					nStt = 0;
313 					break;
314 
315 				case REF_ONLYCAPTION:
316 					{
317                         const SwTxtAttr* const pTxtAttr =
318                             pTxtNd->GetTxtAttrForCharAt(nStt, RES_TXTATR_FIELD);
319 						if( pTxtAttr )
320 							nStt = SwGetExpField::GetReferenceTextPos(
321 												pTxtAttr->GetFld(), *pDoc );
322 						else if( nStt + 1 < nEnd )
323 							++nStt;
324 					}
325 					break;
326 
327 				case REF_ONLYSEQNO:
328 					if( nStt + 1 < nEnd )
329 						nEnd = nStt + 1;
330 					break;
331 
332 				default:
333 					nStt = 0;
334 					break;
335 				}
336 				break;
337 
338 			case REF_BOOKMARK:
339 				if( USHRT_MAX == nEnd )
340 				{
341 					// Text steht ueber verschiedene Nodes verteilt.
342 					// Gesamten Text oder nur bis zum Ende vom Node?
343 					nEnd = pTxtNd->GetTxt().Len();
344 				}
345 				break;
346 
347 			case REF_OUTLINE:
348 				break;
349 
350 			case REF_FOOTNOTE:
351 			case REF_ENDNOTE:
352 				{
353 					// die Nummer oder den NumString besorgen
354 					sal_uInt16 n, nFtnCnt = pDoc->GetFtnIdxs().Count();
355 					SwTxtFtn* pFtnIdx;
356 					for( n = 0; n < nFtnCnt; ++n )
357 						if( nSeqNo == (pFtnIdx = pDoc->GetFtnIdxs()[ n ])->GetSeqRefNo() )
358 						{
359 							sTxt = pFtnIdx->GetFtn().GetViewNumStr( *pDoc );
360 							break;
361 						}
362 					nStt = nEnd;		// kein Bereich, der String ist fertig
363 				}
364 				break;
365 			}
366 
367 			if( nStt != nEnd )		// ein Bereich?
368 			{
369                 sTxt = pTxtNd->GetExpandTxt( nStt, nEnd - nStt );
370 
371 				// alle Sonderzeichen entfernen (durch Blanks ersetzen):
372 				if( sTxt.Len() )
373                 {
374                     sTxt.EraseAllChars( 0xad );
375                     for( sal_Unicode* p = sTxt.GetBufferAccess(); *p; ++p )
376 					{
377 						if( *p < 0x20 )
378 							*p = 0x20;
379                         else if(*p == 0x2011)
380 							*p = '-';
381 					}
382                 }
383 			}
384 		}
385 		break;
386 
387 	case REF_PAGE:
388 	case REF_PAGE_PGDESC:
389 		{
390 			const SwTxtFrm* pFrm = (SwTxtFrm*)pTxtNd->getLayoutFrm( pDoc->GetCurrentLayout(), 0,0,sal_False),
391 						*pSave = pFrm;
392 			while( pFrm && !pFrm->IsInside( nStt ) )
393 				pFrm = (SwTxtFrm*)pFrm->GetFollow();
394 
395 			if( pFrm || 0 != ( pFrm = pSave ))
396 			{
397 				sal_uInt16 nPageNo = pFrm->GetVirtPageNum();
398 				const SwPageFrm *pPage;
399 				if( REF_PAGE_PGDESC == GetFormat() &&
400 					0 != ( pPage = pFrm->FindPageFrm() ) &&
401 					pPage->GetPageDesc() )
402 					sTxt = pPage->GetPageDesc()->GetNumType().GetNumStr( nPageNo );
403 				else
404 					sTxt = String::CreateFromInt32(nPageNo);
405 			}
406 		}
407 		break;
408 
409 	case REF_CHAPTER:
410 		{
411 			// ein bischen trickreich: suche irgend einen Frame
412 			const SwFrm* pFrm = pTxtNd->getLayoutFrm( pDoc->GetCurrentLayout() );
413 			if( pFrm )
414 			{
415 				SwChapterFieldType aFldTyp;
416 				SwChapterField aFld( &aFldTyp, 0 );
417 				aFld.SetLevel( MAXLEVEL - 1 );
418 				aFld.ChangeExpansion( pFrm, pTxtNd, sal_True );
419 				sTxt = aFld.GetNumber();
420 			}
421 		}
422 		break;
423 
424 	case REF_UPDOWN:
425 		{
426             // --> OD 2007-09-07 #i81002#
427             // simplified: use parameter <pFldTxtAttr>
428             if( !pFldTxtAttr || !pFldTxtAttr->GetpTxtNode() )
429 				break;
430 
431 			LocaleDataWrapper aLocaleData(
432 							::comphelper::getProcessServiceFactory(),
433 							SvxCreateLocale( GetLanguage() ) );
434 
435 			// erstmal ein "Kurz" - Test - falls beide im selben
436 			// Node stehen!
437             if( pFldTxtAttr->GetpTxtNode() == pTxtNd )
438 			{
439                 sTxt = nStt < *pFldTxtAttr->GetStart()
440 							? aLocaleData.getAboveWord()
441 							: aLocaleData.getBelowWord();
442 				break;
443 			}
444 
445             sTxt = ::IsFrameBehind( *pFldTxtAttr->GetpTxtNode(), *pFldTxtAttr->GetStart(),
446 									*pTxtNd, nStt )
447 						? aLocaleData.getAboveWord()
448 						: aLocaleData.getBelowWord();
449 		}
450 		break;
451     // --> OD 2007-08-24 #i81002#
452     case REF_NUMBER:
453     case REF_NUMBER_NO_CONTEXT:
454     case REF_NUMBER_FULL_CONTEXT:
455         {
456             if ( pFldTxtAttr && pFldTxtAttr->GetpTxtNode() )
457             {
458                 sTxt = MakeRefNumStr( pFldTxtAttr->GetTxtNode(), *pTxtNd, GetFormat() );
459             }
460         }
461         break;
462     // <--
463     default:
464         DBG_ERROR("<SwGetRefField::UpdateField(..)> - unknown format type");
465 	}
466 }
467 
468 // --> OD 2007-09-06 #i81002#
469 String SwGetRefField::MakeRefNumStr( const SwTxtNode& rTxtNodeOfField,
470                                      const SwTxtNode& rTxtNodeOfReferencedItem,
471                                      const sal_uInt32 nRefNumFormat ) const
472 {
473     if ( rTxtNodeOfReferencedItem.HasNumber() &&
474          rTxtNodeOfReferencedItem.IsCountedInList() )
475     {
476         ASSERT( rTxtNodeOfReferencedItem.GetNum(),
477                 "<SwGetRefField::MakeRefNumStr(..)> - referenced paragraph has number, but no <SwNodeNum> instance --> please inform OD!" );
478 
479         // Determine, up to which level the superior list labels have to be
480         // included - default is to include all superior list labels.
481         sal_uInt8 nRestrictInclToThisLevel( 0 );
482         // Determine for format REF_NUMBER the level, up to which the superior
483         // list labels have to be restricted, if the text node of the reference
484         // field and the text node of the referenced item are in the same
485         // document context.
486         if ( nRefNumFormat == REF_NUMBER &&
487              rTxtNodeOfField.FindFlyStartNode()
488                             == rTxtNodeOfReferencedItem.FindFlyStartNode() &&
489              rTxtNodeOfField.FindFootnoteStartNode()
490                             == rTxtNodeOfReferencedItem.FindFootnoteStartNode() &&
491              rTxtNodeOfField.FindHeaderStartNode()
492                             == rTxtNodeOfReferencedItem.FindHeaderStartNode() &&
493              rTxtNodeOfField.FindFooterStartNode()
494                             == rTxtNodeOfReferencedItem.FindFooterStartNode() )
495         {
496             const SwNodeNum* pNodeNumForTxtNodeOfField( 0 );
497             if ( rTxtNodeOfField.HasNumber() &&
498                  rTxtNodeOfField.GetNumRule() == rTxtNodeOfReferencedItem.GetNumRule() )
499             {
500                 pNodeNumForTxtNodeOfField = rTxtNodeOfField.GetNum();
501             }
502             else
503             {
504                 pNodeNumForTxtNodeOfField =
505                     rTxtNodeOfReferencedItem.GetNum()->GetPrecedingNodeNumOf( rTxtNodeOfField );
506             }
507             if ( pNodeNumForTxtNodeOfField )
508             {
509                 const SwNumberTree::tNumberVector rFieldNumVec = pNodeNumForTxtNodeOfField->GetNumberVector();
510                 const SwNumberTree::tNumberVector rRefItemNumVec = rTxtNodeOfReferencedItem.GetNum()->GetNumberVector();
511                 sal_uInt8 nLevel( 0 );
512                 while ( nLevel < rFieldNumVec.size() && nLevel < rRefItemNumVec.size() )
513                 {
514                     if ( rRefItemNumVec[nLevel] == rFieldNumVec[nLevel] )
515                     {
516                         nRestrictInclToThisLevel = nLevel + 1;
517                     }
518                     else
519                     {
520                         break;
521                     }
522                     ++nLevel;
523                 }
524             }
525         }
526 
527         // Determine, if superior list labels have to be included
528         const bool bInclSuperiorNumLabels(
529             ( nRestrictInclToThisLevel < rTxtNodeOfReferencedItem.GetActualListLevel() &&
530               ( nRefNumFormat == REF_NUMBER || nRefNumFormat == REF_NUMBER_FULL_CONTEXT ) ) );
531 
532         ASSERT( rTxtNodeOfReferencedItem.GetNumRule(),
533                 "<SwGetRefField::MakeRefNumStr(..)> - referenced numbered paragraph has no numbering rule set --> please inform OD!" );
534         return rTxtNodeOfReferencedItem.GetNumRule()->MakeRefNumString(
535                                             *(rTxtNodeOfReferencedItem.GetNum()),
536                                             bInclSuperiorNumLabels,
537                                             nRestrictInclToThisLevel );
538     }
539 
540     return String();
541 }
542 // <--
543 
544 SwField* SwGetRefField::Copy() const
545 {
546 	SwGetRefField* pFld = new SwGetRefField( (SwGetRefFieldType*)GetTyp(),
547 												sSetRefName, nSubType,
548 												nSeqNo, GetFormat() );
549 	pFld->sTxt = sTxt;
550 	return pFld;
551 }
552 
553 /*--------------------------------------------------------------------
554 	Beschreibung: ReferenzName holen
555  --------------------------------------------------------------------*/
556 
557 
558 const String& SwGetRefField::GetPar1() const
559 {
560 	return sSetRefName;
561 }
562 
563 
564 void SwGetRefField::SetPar1( const String& rName )
565 {
566 	sSetRefName = rName;
567 }
568 
569 
570 String SwGetRefField::GetPar2() const
571 {
572 	return Expand();
573 }
574 
575 sal_Bool SwGetRefField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
576 {
577     switch( nWhichId )
578 	{
579 	case FIELD_PROP_USHORT1:
580 		{
581 			sal_Int16 nPart = 0;
582 			switch(GetFormat())
583 			{
584 			case REF_PAGE		: nPart = ReferenceFieldPart::PAGE 				  ; break;
585 			case REF_CHAPTER	: nPart = ReferenceFieldPart::CHAPTER	 		  ; break;
586 			case REF_CONTENT	: nPart = ReferenceFieldPart::TEXT 				  ; break;
587 			case REF_UPDOWN		: nPart = ReferenceFieldPart::UP_DOWN 			  ; break;
588 			case REF_PAGE_PGDESC: nPart = ReferenceFieldPart::PAGE_DESC 		  ; break;
589 			case REF_ONLYNUMBER	: nPart = ReferenceFieldPart::CATEGORY_AND_NUMBER ; break;
590 			case REF_ONLYCAPTION: nPart = ReferenceFieldPart::ONLY_CAPTION 		  ; break;
591 			case REF_ONLYSEQNO	: nPart = ReferenceFieldPart::ONLY_SEQUENCE_NUMBER; break;
592             // --> OD 2007-09-06 #i81002#
593             case REF_NUMBER:              nPart = ReferenceFieldPart::NUMBER;              break;
594             case REF_NUMBER_NO_CONTEXT:   nPart = ReferenceFieldPart::NUMBER_NO_CONTEXT;   break;
595             case REF_NUMBER_FULL_CONTEXT: nPart = ReferenceFieldPart::NUMBER_FULL_CONTEXT; break;
596             // <--
597 			}
598 			rAny <<= nPart;
599 		}
600 		break;
601 	case FIELD_PROP_USHORT2:
602 		{
603 			sal_Int16 nSource = 0;
604 			switch(nSubType)
605 			{
606 			case  REF_SETREFATTR : nSource = ReferenceFieldSource::REFERENCE_MARK; break;
607 			case  REF_SEQUENCEFLD: nSource = ReferenceFieldSource::SEQUENCE_FIELD; break;
608 			case  REF_BOOKMARK   : nSource = ReferenceFieldSource::BOOKMARK; break;
609 			case  REF_OUTLINE    : DBG_ERROR("not implemented"); break;
610 			case  REF_FOOTNOTE   : nSource = ReferenceFieldSource::FOOTNOTE; break;
611 			case  REF_ENDNOTE    : nSource = ReferenceFieldSource::ENDNOTE; break;
612 			}
613 			rAny <<= nSource;
614 		}
615 		break;
616 	case FIELD_PROP_PAR1:
617     {
618         String  sTmp(GetPar1());
619         if(REF_SEQUENCEFLD == nSubType)
620         {
621             sal_uInt16 nPoolId = SwStyleNameMapper::GetPoolIdFromUIName( sTmp, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL );
622             switch( nPoolId )
623             {
624                 case RES_POOLCOLL_LABEL_ABB:
625                 case RES_POOLCOLL_LABEL_TABLE:
626                 case RES_POOLCOLL_LABEL_FRAME:
627                 case RES_POOLCOLL_LABEL_DRAWING:
628                     SwStyleNameMapper::FillProgName(nPoolId, sTmp) ;
629                 break;
630             }
631         }
632         rAny <<= rtl::OUString(sTmp);
633     }
634     break;
635 	case FIELD_PROP_PAR3:
636 		rAny <<= rtl::OUString(Expand());
637 		break;
638 	case FIELD_PROP_SHORT1:
639 		rAny <<= (sal_Int16)nSeqNo;
640 		break;
641 	default:
642 		DBG_ERROR("illegal property");
643 	}
644 	return sal_True;
645 }
646 
647 sal_Bool SwGetRefField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
648 {
649 	String sTmp;
650     switch( nWhichId )
651 	{
652 	case FIELD_PROP_USHORT1:
653 		{
654 			sal_Int16 nPart = 0;
655 			rAny >>= nPart;
656 			switch(nPart)
657 			{
658 			case ReferenceFieldPart::PAGE: 					nPart = REF_PAGE; break;
659 			case ReferenceFieldPart::CHAPTER:	 			nPart = REF_CHAPTER; break;
660 			case ReferenceFieldPart::TEXT: 					nPart = REF_CONTENT; break;
661 			case ReferenceFieldPart::UP_DOWN: 				nPart = REF_UPDOWN; break;
662 			case ReferenceFieldPart::PAGE_DESC: 			nPart = REF_PAGE_PGDESC; break;
663 			case ReferenceFieldPart::CATEGORY_AND_NUMBER: 	nPart = REF_ONLYNUMBER; break;
664 			case ReferenceFieldPart::ONLY_CAPTION: 			nPart = REF_ONLYCAPTION; break;
665 			case ReferenceFieldPart::ONLY_SEQUENCE_NUMBER : nPart = REF_ONLYSEQNO; break;
666             // --> OD 2007-09-06 #i81002#
667             case ReferenceFieldPart::NUMBER:              nPart = REF_NUMBER;              break;
668             case ReferenceFieldPart::NUMBER_NO_CONTEXT:   nPart = REF_NUMBER_NO_CONTEXT;   break;
669             case ReferenceFieldPart::NUMBER_FULL_CONTEXT: nPart = REF_NUMBER_FULL_CONTEXT; break;
670             // <--
671 			default: return sal_False;
672 			}
673 			SetFormat(nPart);
674 		}
675 		break;
676 	case FIELD_PROP_USHORT2:
677 		{
678 			sal_Int16 nSource = 0;
679 			rAny >>= nSource;
680 			switch(nSource)
681 			{
682 			case ReferenceFieldSource::REFERENCE_MARK : nSubType = REF_SETREFATTR ; break;
683             case ReferenceFieldSource::SEQUENCE_FIELD :
684             {
685                 if(REF_SEQUENCEFLD == nSubType)
686                     break;
687                 nSubType = REF_SEQUENCEFLD;
688                 ConvertProgrammaticToUIName();
689             }
690             break;
691 			case ReferenceFieldSource::BOOKMARK		  : nSubType = REF_BOOKMARK   ; break;
692 			case ReferenceFieldSource::FOOTNOTE		  : nSubType = REF_FOOTNOTE   ; break;
693 			case ReferenceFieldSource::ENDNOTE		  : nSubType = REF_ENDNOTE    ; break;
694 			}
695 		}
696 		break;
697 	case FIELD_PROP_PAR1:
698     {
699         OUString sTmpStr;
700         rAny >>= sTmpStr;
701         SetPar1(sTmpStr);
702         ConvertProgrammaticToUIName();
703     }
704     break;
705 	case FIELD_PROP_PAR3:
706 		SetExpand( ::GetString( rAny, sTmp ));
707 		break;
708 	case FIELD_PROP_SHORT1:
709 		{
710 			sal_Int16 nSetSeq = 0;
711 			rAny >>= nSetSeq;
712 			if(nSetSeq >= 0)
713 				nSeqNo = nSetSeq;
714 		}
715 		break;
716 	default:
717 		DBG_ERROR("illegal property");
718 	}
719 	return sal_True;
720 }
721 
722 void SwGetRefField::ConvertProgrammaticToUIName()
723 {
724     if(GetTyp() && REF_SEQUENCEFLD == nSubType)
725     {
726         SwDoc* pDoc = ((SwGetRefFieldType*)GetTyp())->GetDoc();
727         const String& rPar1 = GetPar1();
728         //don't convert when the name points to an existing field type
729         if(!pDoc->GetFldType(RES_SETEXPFLD, rPar1, false))
730         {
731             sal_uInt16 nPoolId = SwStyleNameMapper::GetPoolIdFromProgName( rPar1, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL );
732             sal_uInt16 nResId = USHRT_MAX;
733             switch( nPoolId )
734             {
735                 case RES_POOLCOLL_LABEL_ABB:
736                     nResId = STR_POOLCOLL_LABEL_ABB;
737                 break;
738                 case RES_POOLCOLL_LABEL_TABLE:
739                     nResId = STR_POOLCOLL_LABEL_TABLE;
740                 break;
741                 case RES_POOLCOLL_LABEL_FRAME:
742                     nResId = STR_POOLCOLL_LABEL_FRAME;
743                 break;
744                 case RES_POOLCOLL_LABEL_DRAWING:
745                     nResId = STR_POOLCOLL_LABEL_DRAWING;
746                 break;
747             }
748             if( nResId != USHRT_MAX )
749                 SetPar1(SW_RESSTR( nResId ));
750         }
751     }
752 }
753 
754 SwGetRefFieldType::SwGetRefFieldType( SwDoc* pDc )
755 	: SwFieldType( RES_GETREFFLD ), pDoc( pDc )
756 {}
757 
758 
759 SwFieldType* SwGetRefFieldType::Copy() const
760 {
761 	return new SwGetRefFieldType( pDoc );
762 }
763 
764 
765 void SwGetRefFieldType::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew )
766 {
767 	// Update auf alle GetReferenz-Felder
768 	if( !pNew && !pOld )
769 	{
770 		SwIterator<SwFmtFld,SwFieldType> aIter( *this );
771 		for( SwFmtFld* pFld = aIter.First(); pFld; pFld = aIter.Next() )
772 		{
773 			// nur die GetRef-Felder Updaten
774 			//JP 3.4.2001: Task 71231 - we need the correct language
775 			SwGetRefField* pGRef = (SwGetRefField*)pFld->GetFld();
776 			const SwTxtFld* pTFld;
777 			if( !pGRef->GetLanguage() &&
778 				0 != ( pTFld = pFld->GetTxtFld()) &&
779                 pTFld->GetpTxtNode() )
780             {
781 				pGRef->SetLanguage( pTFld->GetpTxtNode()->GetLang(
782 												*pTFld->GetStart() ) );
783             }
784 
785             // --> OD 2007-09-06 #i81002#
786             pGRef->UpdateField( pFld->GetTxtFld() );
787             // <--
788 		}
789 	}
790 	// weiter an die Text-Felder, diese "Expandieren" den Text
791 	NotifyClients( pOld, pNew );
792 }
793 
794 SwTxtNode* SwGetRefFieldType::FindAnchor( SwDoc* pDoc, const String& rRefMark,
795 										sal_uInt16 nSubType, sal_uInt16 nSeqNo,
796 										sal_uInt16* pStt, sal_uInt16* pEnd )
797 {
798 	ASSERT( pStt, "warum wird keine StartPos abgefragt?" );
799 
800 	SwTxtNode* pTxtNd = 0;
801 	switch( nSubType )
802 	{
803 	case REF_SETREFATTR:
804 		{
805 			const SwFmtRefMark *pRef = pDoc->GetRefMark( rRefMark );
806 			if( pRef && pRef->GetTxtRefMark() )
807 			{
808 				pTxtNd = (SwTxtNode*)&pRef->GetTxtRefMark()->GetTxtNode();
809 				*pStt = *pRef->GetTxtRefMark()->GetStart();
810 				if( pEnd )
811 					*pEnd = *pRef->GetTxtRefMark()->GetAnyEnd();
812 			}
813 		}
814 		break;
815 
816 	case REF_SEQUENCEFLD:
817 		{
818 			SwFieldType* pFldType = pDoc->GetFldType( RES_SETEXPFLD, rRefMark, false );
819 			if( pFldType && pFldType->GetDepends() &&
820 				nsSwGetSetExpType::GSE_SEQ & ((SwSetExpFieldType*)pFldType)->GetType() )
821 			{
822 				SwIterator<SwFmtFld,SwFieldType> aIter( *pFldType );
823 				for( SwFmtFld* pFld = aIter.First(); pFld; pFld = aIter.Next() )
824 				{
825 					if( pFld->GetTxtFld() && nSeqNo ==
826 						((SwSetExpField*)pFld->GetFld())->GetSeqNumber() )
827 					{
828 						SwTxtFld* pTxtFld = pFld->GetTxtFld();
829 						pTxtNd = (SwTxtNode*)pTxtFld->GetpTxtNode();
830 						*pStt = *pTxtFld->GetStart();
831 						if( pEnd )
832 							*pEnd = (*pStt) + 1;
833 						break;
834 					}
835 				}
836 			}
837 		}
838 		break;
839 
840     case REF_BOOKMARK:
841         {
842             IDocumentMarkAccess::const_iterator_t ppMark = pDoc->getIDocumentMarkAccess()->findMark(rRefMark);
843             if(ppMark != pDoc->getIDocumentMarkAccess()->getMarksEnd())
844             {
845                 const ::sw::mark::IMark* pBkmk = ppMark->get();
846                 const SwPosition* pPos = &pBkmk->GetMarkStart();
847 
848                 pTxtNd = pPos->nNode.GetNode().GetTxtNode();
849                 *pStt = pPos->nContent.GetIndex();
850                 if(pEnd)
851                 {
852                     if(!pBkmk->IsExpanded())
853                     {
854                         *pEnd = *pStt;
855                         // --> OD 2007-10-18 #i81002#
856                         if(dynamic_cast< ::sw::mark::CrossRefBookmark const *>(pBkmk))
857                         {
858                             ASSERT( pTxtNd,
859                                     "<SwGetRefFieldType::FindAnchor(..)> - node marked by cross-reference bookmark isn't a text node --> crash" );
860                             *pEnd = pTxtNd->Len();
861                         }
862                         // <--
863                     }
864                     else if(pBkmk->GetOtherMarkPos().nNode == pBkmk->GetMarkPos().nNode)
865                         *pEnd = pBkmk->GetMarkEnd().nContent.GetIndex();
866                     else
867                         *pEnd = USHRT_MAX;
868                 }
869             }
870         }
871         break;
872 
873 	case REF_OUTLINE:
874 		break;
875 
876 	case REF_FOOTNOTE:
877 	case REF_ENDNOTE:
878 		{
879 			sal_uInt16 n, nFtnCnt = pDoc->GetFtnIdxs().Count();
880 			SwTxtFtn* pFtnIdx;
881 			for( n = 0; n < nFtnCnt; ++n )
882 				if( nSeqNo == (pFtnIdx = pDoc->GetFtnIdxs()[ n ])->GetSeqRefNo() )
883 				{
884 					SwNodeIndex* pIdx = pFtnIdx->GetStartNode();
885 					if( pIdx )
886 					{
887 						SwNodeIndex aIdx( *pIdx, 1 );
888 						if( 0 == ( pTxtNd = aIdx.GetNode().GetTxtNode()))
889 							pTxtNd = (SwTxtNode*)pDoc->GetNodes().GoNext( &aIdx );
890 					}
891 					*pStt = 0;
892 					if( pEnd )
893 						*pEnd = 0;
894 					break;
895 				}
896 		}
897 		break;
898 	}
899 
900 	return pTxtNd;
901 }
902 
903 
904 struct _RefIdsMap
905 {
906 	String aName;
907 	SvUShortsSort aIds, aDstIds, aIdsMap;
908 	SvUShorts aMap;
909 	sal_Bool bInit;
910 
911 	_RefIdsMap( const String& rName )
912 		: aName( rName ), aIds( 16, 16 ), aIdsMap( 16, 16 ), aMap( 16, 16 ),
913 		bInit( sal_False )
914 	{}
915 
916 	void Check( SwDoc& rDoc, SwDoc& rDestDoc, SwGetRefField& rFld,
917 					sal_Bool bField = sal_True );
918 
919 	sal_Bool IsInit() const { return bInit; }
920 };
921 
922 SV_DECL_PTRARR_DEL( _RefIdsMaps, _RefIdsMap*, 5, 5 )
923 SV_IMPL_PTRARR( _RefIdsMaps, _RefIdsMap* )
924 
925 void _RefIdsMap::Check( SwDoc& rDoc, SwDoc& rDestDoc, SwGetRefField& rFld,
926 						sal_Bool bField )
927 {
928 
929 	if( !bInit )
930 	{
931 		if( bField )
932 		{
933 			const SwTxtNode* pNd;
934 			SwFieldType* pType;
935 			if( 0 != ( pType = rDestDoc.GetFldType( RES_SETEXPFLD, aName, false ) ))
936 			{
937 				SwIterator<SwFmtFld,SwFieldType> aIter( *pType );
938 				for( SwFmtFld* pF = aIter.First(); pF; pF = aIter.Next() )
939 					if( pF->GetTxtFld() &&
940 						0 != ( pNd = pF->GetTxtFld()->GetpTxtNode() ) &&
941 						pNd->GetNodes().IsDocNodes() )
942 						aIds.Insert( ((SwSetExpField*)pF->GetFld())->GetSeqNumber() );
943 			}
944 			if( 0 != ( pType = rDoc.GetFldType( RES_SETEXPFLD, aName, false ) ))
945 			{
946 				SwIterator<SwFmtFld,SwFieldType> aIter( *pType );
947 				for( SwFmtFld* pF = aIter.First(); pF; pF = aIter.Next() )
948 					if( pF->GetTxtFld() &&
949 						0 != ( pNd = pF->GetTxtFld()->GetpTxtNode() ) &&
950 						pNd->GetNodes().IsDocNodes() )
951 						aDstIds.Insert( ((SwSetExpField*)pF->GetFld())->GetSeqNumber() );
952 			}
953 		}
954 		else
955 		{
956 			sal_uInt16 n;
957 
958 			for( n = rDestDoc.GetFtnIdxs().Count(); n; )
959 				aIds.Insert( rDestDoc.GetFtnIdxs()[ --n ]->GetSeqRefNo() );
960 			for( n = rDoc.GetFtnIdxs().Count(); n; )
961 				aDstIds.Insert( rDoc.GetFtnIdxs()[ --n ]->GetSeqRefNo() );
962 		}
963 		bInit = sal_True;
964 	}
965 
966 	// dann teste mal, ob die Nummer schon vergeben ist
967 	// oder ob eine neue bestimmt werden muss.
968 	sal_uInt16 nPos, nSeqNo = rFld.GetSeqNo();
969 	if( aIds.Seek_Entry( nSeqNo ) && aDstIds.Seek_Entry( nSeqNo ))
970 	{
971 		// ist schon vergeben, also muss eine neue
972 		// erzeugt werden.
973 		if( aIdsMap.Seek_Entry( nSeqNo, &nPos ))
974 			rFld.SetSeqNo( aMap[ nPos ] );
975 		else
976 		{
977 			sal_uInt16 n;
978 
979 			for( n = 0; n < aIds.Count(); ++n )
980 				if( n != aIds[ n ] )
981 					break;
982 
983 			// die neue SeqNo eintragen, damit die "belegt" ist
984 			aIds.Insert( n );
985 			aIdsMap.Insert( nSeqNo, nPos );
986 			aMap.Insert( n, nPos );
987 			rFld.SetSeqNo( n );
988 
989 			// und noch die Felder oder Fuss-/EndNote auf die neue
990 			// Id umsetzen
991 			if( bField )
992 			{
993 				SwFieldType* pType = rDoc.GetFldType( RES_SETEXPFLD, aName, false );
994 				if( pType )
995 				{
996 				    SwIterator<SwFmtFld,SwFieldType> aIter( *pType );
997 				    for( SwFmtFld* pF = aIter.First(); pF; pF = aIter.Next() )
998 						if( pF->GetTxtFld() && nSeqNo ==
999 							((SwSetExpField*)pF->GetFld())->GetSeqNumber() )
1000 							((SwSetExpField*)pF->GetFld())->SetSeqNumber( n );
1001 				}
1002 			}
1003 			else
1004 			{
1005 				SwTxtFtn* pFtnIdx;
1006 				for( sal_uInt16 i = 0, nCnt = rDoc.GetFtnIdxs().Count(); i < nCnt; ++i )
1007 					if( nSeqNo == (pFtnIdx = rDoc.GetFtnIdxs()[ i ])->GetSeqRefNo() )
1008 					{
1009 						pFtnIdx->SetSeqNo( n );
1010 						break;
1011 					}
1012 			}
1013 		}
1014 	}
1015 	else
1016 	{
1017 		aIds.Insert( nSeqNo );
1018 		aIdsMap.Insert( nSeqNo, nPos );
1019 		aMap.Insert( nSeqNo, nPos );
1020 	}
1021 }
1022 
1023 
1024 void SwGetRefFieldType::MergeWithOtherDoc( SwDoc& rDestDoc )
1025 {
1026 	if( &rDestDoc != pDoc &&
1027 		rDestDoc.GetSysFldType( RES_GETREFFLD )->GetDepends() )
1028 	{
1029 		// dann gibt es im DestDoc RefFelder, also muessen im SourceDoc
1030 		// alle RefFelder auf einduetige Ids in beiden Docs umgestellt
1031 		// werden.
1032 		_RefIdsMap aFntMap( aEmptyStr );
1033 		_RefIdsMaps aFldMap;
1034 
1035 		SwIterator<SwFmtFld,SwFieldType> aIter( *this );
1036 		for( SwFmtFld* pFld = aIter.First(); pFld; pFld = aIter.Next() )
1037 		{
1038 			SwGetRefField& rRefFld = *(SwGetRefField*)pFld->GetFld();
1039 			switch( rRefFld.GetSubType() )
1040 			{
1041 			case REF_SEQUENCEFLD:
1042 				{
1043 					_RefIdsMap* pMap = 0;
1044 					for( sal_uInt16 n = aFldMap.Count(); n; )
1045 						if( aFldMap[ --n ]->aName == rRefFld.GetSetRefName() )
1046 						{
1047 							pMap = aFldMap[ n ];
1048 							break;
1049 						}
1050 					if( !pMap )
1051 					{
1052 						pMap = new _RefIdsMap( rRefFld.GetSetRefName() );
1053 						aFldMap.C40_INSERT( _RefIdsMap, pMap, aFldMap.Count() );
1054 					}
1055 
1056 					pMap->Check( *pDoc, rDestDoc, rRefFld, sal_True );
1057 				}
1058 				break;
1059 
1060 			case REF_FOOTNOTE:
1061 			case REF_ENDNOTE:
1062 				aFntMap.Check( *pDoc, rDestDoc, rRefFld, sal_False );
1063 				break;
1064 			}
1065 		}
1066 	}
1067 }
1068 
1069