xref: /trunk/main/sw/source/core/fields/reffld.cxx (revision dec99bbd)
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 
lcl_GetLayTree(const SwFrm * pFrm,SvPtrarr & rArr)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 
IsFrameBehind(const SwTxtNode & rMyNd,sal_uInt16 nMySttPos,const SwTxtNode & rBehindNd,sal_uInt16 nSttPos)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 
SwGetRefField(SwGetRefFieldType * pFldType,const String & rSetRef,sal_uInt16 nSubTyp,sal_uInt16 nSeqenceNo,sal_uLong nFmt)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 
~SwGetRefField()218 SwGetRefField::~SwGetRefField()
219 {
220 }
221 
GetDescription() const222 String SwGetRefField::GetDescription() const
223 {
224     return SW_RES(STR_REFERENCE);
225 }
226 
GetSubType() const227 sal_uInt16 SwGetRefField::GetSubType() const
228 {
229 	return nSubType;
230 }
231 
SetSubType(sal_uInt16 n)232 void SwGetRefField::SetSubType( sal_uInt16 n )
233 {
234 	nSubType = n;
235 }
236 
237 // --> OD 2007-11-09 #i81002#
IsRefToHeadingCrossRefBookmark() const238 bool SwGetRefField::IsRefToHeadingCrossRefBookmark() const
239 {
240     return GetSubType() == REF_BOOKMARK &&
241         ::sw::mark::CrossRefHeadingBookmark::IsLegalName(sSetRefName);
242 }
243 
IsRefToNumItemCrossRefBookmark() const244 bool SwGetRefField::IsRefToNumItemCrossRefBookmark() const
245 {
246     return GetSubType() == REF_BOOKMARK &&
247         ::sw::mark::CrossRefNumItemBookmark::IsLegalName(sSetRefName);
248 }
249 
GetReferencedTxtNode() const250 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#
GetExpandedTxtOfReferencedTxtNode() const258 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 
Expand() const266 String SwGetRefField::Expand() const
267 {
268 	return sTxt;
269 }
270 
271 
GetFieldName() const272 String SwGetRefField::GetFieldName() const
273 {
274 	String aStr(GetTyp()->GetName());
275 	aStr += ' ';
276 	aStr += sSetRefName;
277 	return aStr;
278 }
279 
UpdateField(const SwTxtFld * pFldTxtAttr)280 void SwGetRefField::UpdateField( const SwTxtFld* pFldTxtAttr )
281 {
282     sTxt.Erase();
283 
284     SwDoc* pDoc = ((SwGetRefFieldType*)GetTyp())->GetDoc();
285     sal_uInt16 nStt = USHRT_MAX;
286     sal_uInt16 nEnd = USHRT_MAX;
287     SwTxtNode* pTxtNd = SwGetRefFieldType::FindAnchor( pDoc, sSetRefName, nSubType, nSeqNo, &nStt, &nEnd );
288     if ( !pTxtNd )
289     {
290         sTxt = ViewShell::GetShellRes()->aGetRefFld_RefItemNotFound;
291         return ;
292     }
293 
294 	switch( GetFormat() )
295 	{
296 	case REF_CONTENT:
297 	case REF_ONLYNUMBER:
298 	case REF_ONLYCAPTION:
299 	case REF_ONLYSEQNO:
300 		{
301 			switch( nSubType )
302 			{
303 			case REF_SEQUENCEFLD:
304 				nEnd = pTxtNd->GetTxt().Len();
305 				switch( GetFormat() )
306 				{
307 				case REF_ONLYNUMBER:
308 					if( nStt + 1 < nEnd )
309 						nEnd = nStt + 1;
310 					nStt = 0;
311 					break;
312 
313                 case REF_ONLYCAPTION:
314                     {
315                         const SwTxtAttr* const pTxtAttr = pTxtNd->GetTxtAttrForCharAt(nStt, RES_TXTATR_FIELD);
316                         if( pTxtAttr != NULL )
317                             nStt = SwGetExpField::GetReferenceTextPos( pTxtAttr->GetFmtFld(), *pDoc );
318                         else if( nStt + 1 < nEnd )
319                             ++nStt;
320                     }
321                     break;
322 
323 				case REF_ONLYSEQNO:
324 					if( nStt + 1 < nEnd )
325 						nEnd = nStt + 1;
326 					break;
327 
328 				default:
329 					nStt = 0;
330 					break;
331 				}
332 				break;
333 
334 			case REF_BOOKMARK:
335 				if( USHRT_MAX == nEnd )
336 				{
337 					// Text steht ueber verschiedene Nodes verteilt.
338 					// Gesamten Text oder nur bis zum Ende vom Node?
339 					nEnd = pTxtNd->GetTxt().Len();
340 				}
341 				break;
342 
343 			case REF_OUTLINE:
344 				break;
345 
346 			case REF_FOOTNOTE:
347 			case REF_ENDNOTE:
348 				{
349 					// die Nummer oder den NumString besorgen
350 					sal_uInt16 n, nFtnCnt = pDoc->GetFtnIdxs().Count();
351 					SwTxtFtn* pFtnIdx;
352 					for( n = 0; n < nFtnCnt; ++n )
353 						if( nSeqNo == (pFtnIdx = pDoc->GetFtnIdxs()[ n ])->GetSeqRefNo() )
354 						{
355 							sTxt = pFtnIdx->GetFtn().GetViewNumStr( *pDoc );
356 							break;
357 						}
358 					nStt = nEnd;		// kein Bereich, der String ist fertig
359 				}
360 				break;
361 			}
362 
363 			if( nStt != nEnd )		// ein Bereich?
364 			{
365                 sTxt = pTxtNd->GetExpandTxt( nStt, nEnd - nStt );
366 
367 				// alle Sonderzeichen entfernen (durch Blanks ersetzen):
368 				if( sTxt.Len() )
369                 {
370                     sTxt.EraseAllChars( 0xad );
371                     for( sal_Unicode* p = sTxt.GetBufferAccess(); *p; ++p )
372 					{
373 						if( *p < 0x20 )
374 							*p = 0x20;
375                         else if(*p == 0x2011)
376 							*p = '-';
377 					}
378                 }
379 			}
380 		}
381 		break;
382 
383 	case REF_PAGE:
384 	case REF_PAGE_PGDESC:
385 		{
386 			const SwTxtFrm* pFrm = (SwTxtFrm*)pTxtNd->getLayoutFrm( pDoc->GetCurrentLayout(), 0,0,sal_False),
387 						*pSave = pFrm;
388 			while( pFrm && !pFrm->IsInside( nStt ) )
389 				pFrm = (SwTxtFrm*)pFrm->GetFollow();
390 
391 			if( pFrm || 0 != ( pFrm = pSave ))
392 			{
393 				sal_uInt16 nPageNo = pFrm->GetVirtPageNum();
394 				const SwPageFrm *pPage;
395 				if( REF_PAGE_PGDESC == GetFormat() &&
396 					0 != ( pPage = pFrm->FindPageFrm() ) &&
397 					pPage->GetPageDesc() )
398 					sTxt = pPage->GetPageDesc()->GetNumType().GetNumStr( nPageNo );
399 				else
400 					sTxt = String::CreateFromInt32(nPageNo);
401 			}
402 		}
403 		break;
404 
405 	case REF_CHAPTER:
406 		{
407 			// ein bischen trickreich: suche irgend einen Frame
408 			const SwFrm* pFrm = pTxtNd->getLayoutFrm( pDoc->GetCurrentLayout() );
409 			if( pFrm )
410 			{
411 				SwChapterFieldType aFldTyp;
412 				SwChapterField aFld( &aFldTyp, 0 );
413 				aFld.SetLevel( MAXLEVEL - 1 );
414 				aFld.ChangeExpansion( pFrm, pTxtNd, sal_True );
415 				sTxt = aFld.GetNumber();
416 			}
417 		}
418 		break;
419 
420     case REF_UPDOWN:
421         {
422             // simplified: use parameter <pFldTxtAttr>
423             if( !pFldTxtAttr || !pFldTxtAttr->GetpTxtNode() )
424                 break;
425 
426             LocaleDataWrapper aLocaleData( ::comphelper::getProcessServiceFactory(), SvxCreateLocale( GetLanguage() ) );
427 
428             // erstmal ein "Kurz" - Test - falls beide im selben
429             // Node stehen!
430             if( pFldTxtAttr->GetpTxtNode() == pTxtNd )
431             {
432                 sTxt = nStt < *pFldTxtAttr->GetStart()
433                     ? aLocaleData.getAboveWord()
434                     : aLocaleData.getBelowWord();
435                 break;
436             }
437 
438             sTxt =
439                 ::IsFrameBehind( *pFldTxtAttr->GetpTxtNode(), *pFldTxtAttr->GetStart(), *pTxtNd, nStt )
440                 ? aLocaleData.getAboveWord()
441                 : aLocaleData.getBelowWord();
442         }
443         break;
444 
445     case REF_NUMBER:
446     case REF_NUMBER_NO_CONTEXT:
447     case REF_NUMBER_FULL_CONTEXT:
448         {
449             if ( pFldTxtAttr && pFldTxtAttr->GetpTxtNode() )
450             {
451                 sTxt = MakeRefNumStr( pFldTxtAttr->GetTxtNode(), *pTxtNd, GetFormat() );
452             }
453         }
454         break;
455 
456     default:
457         DBG_ERROR("<SwGetRefField::UpdateField(..)> - unknown format type");
458 	}
459 }
460 
461 // --> OD 2007-09-06 #i81002#
MakeRefNumStr(const SwTxtNode & rTxtNodeOfField,const SwTxtNode & rTxtNodeOfReferencedItem,const sal_uInt32 nRefNumFormat) const462 String SwGetRefField::MakeRefNumStr( const SwTxtNode& rTxtNodeOfField,
463                                      const SwTxtNode& rTxtNodeOfReferencedItem,
464                                      const sal_uInt32 nRefNumFormat ) const
465 {
466     if ( rTxtNodeOfReferencedItem.HasNumber() &&
467          rTxtNodeOfReferencedItem.IsCountedInList() )
468     {
469         ASSERT( rTxtNodeOfReferencedItem.GetNum(),
470                 "<SwGetRefField::MakeRefNumStr(..)> - referenced paragraph has number, but no <SwNodeNum> instance --> please inform OD!" );
471 
472         // Determine, up to which level the superior list labels have to be
473         // included - default is to include all superior list labels.
474         sal_uInt8 nRestrictInclToThisLevel( 0 );
475         // Determine for format REF_NUMBER the level, up to which the superior
476         // list labels have to be restricted, if the text node of the reference
477         // field and the text node of the referenced item are in the same
478         // document context.
479         if ( nRefNumFormat == REF_NUMBER &&
480              rTxtNodeOfField.FindFlyStartNode()
481                             == rTxtNodeOfReferencedItem.FindFlyStartNode() &&
482              rTxtNodeOfField.FindFootnoteStartNode()
483                             == rTxtNodeOfReferencedItem.FindFootnoteStartNode() &&
484              rTxtNodeOfField.FindHeaderStartNode()
485                             == rTxtNodeOfReferencedItem.FindHeaderStartNode() &&
486              rTxtNodeOfField.FindFooterStartNode()
487                             == rTxtNodeOfReferencedItem.FindFooterStartNode() )
488         {
489             const SwNodeNum* pNodeNumForTxtNodeOfField( 0 );
490             if ( rTxtNodeOfField.HasNumber() &&
491                  rTxtNodeOfField.GetNumRule() == rTxtNodeOfReferencedItem.GetNumRule() )
492             {
493                 pNodeNumForTxtNodeOfField = rTxtNodeOfField.GetNum();
494             }
495             else
496             {
497                 pNodeNumForTxtNodeOfField =
498                     rTxtNodeOfReferencedItem.GetNum()->GetPrecedingNodeNumOf( rTxtNodeOfField );
499             }
500             if ( pNodeNumForTxtNodeOfField )
501             {
502                 const SwNumberTree::tNumberVector rFieldNumVec = pNodeNumForTxtNodeOfField->GetNumberVector();
503                 const SwNumberTree::tNumberVector rRefItemNumVec = rTxtNodeOfReferencedItem.GetNum()->GetNumberVector();
504                 sal_uInt8 nLevel( 0 );
505                 while ( nLevel < rFieldNumVec.size() && nLevel < rRefItemNumVec.size() )
506                 {
507                     if ( rRefItemNumVec[nLevel] == rFieldNumVec[nLevel] )
508                     {
509                         nRestrictInclToThisLevel = nLevel + 1;
510                     }
511                     else
512                     {
513                         break;
514                     }
515                     ++nLevel;
516                 }
517             }
518         }
519 
520         // Determine, if superior list labels have to be included
521         const bool bInclSuperiorNumLabels(
522             ( nRestrictInclToThisLevel < rTxtNodeOfReferencedItem.GetActualListLevel() &&
523               ( nRefNumFormat == REF_NUMBER || nRefNumFormat == REF_NUMBER_FULL_CONTEXT ) ) );
524 
525         ASSERT( rTxtNodeOfReferencedItem.GetNumRule(),
526                 "<SwGetRefField::MakeRefNumStr(..)> - referenced numbered paragraph has no numbering rule set --> please inform OD!" );
527         return rTxtNodeOfReferencedItem.GetNumRule()->MakeRefNumString(
528                                             *(rTxtNodeOfReferencedItem.GetNum()),
529                                             bInclSuperiorNumLabels,
530                                             nRestrictInclToThisLevel );
531     }
532 
533     return String();
534 }
535 // <--
536 
Copy() const537 SwField* SwGetRefField::Copy() const
538 {
539 	SwGetRefField* pFld = new SwGetRefField( (SwGetRefFieldType*)GetTyp(),
540 												sSetRefName, nSubType,
541 												nSeqNo, GetFormat() );
542 	pFld->sTxt = sTxt;
543 	return pFld;
544 }
545 
546 /*--------------------------------------------------------------------
547 	Beschreibung: ReferenzName holen
548  --------------------------------------------------------------------*/
549 
550 
GetPar1() const551 const String& SwGetRefField::GetPar1() const
552 {
553 	return sSetRefName;
554 }
555 
556 
SetPar1(const String & rName)557 void SwGetRefField::SetPar1( const String& rName )
558 {
559 	sSetRefName = rName;
560 }
561 
562 
GetPar2() const563 String SwGetRefField::GetPar2() const
564 {
565 	return Expand();
566 }
567 
QueryValue(uno::Any & rAny,sal_uInt16 nWhichId) const568 sal_Bool SwGetRefField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
569 {
570     switch( nWhichId )
571 	{
572 	case FIELD_PROP_USHORT1:
573 		{
574 			sal_Int16 nPart = 0;
575 			switch(GetFormat())
576 			{
577 			case REF_PAGE		: nPart = ReferenceFieldPart::PAGE 				  ; break;
578 			case REF_CHAPTER	: nPart = ReferenceFieldPart::CHAPTER	 		  ; break;
579 			case REF_CONTENT	: nPart = ReferenceFieldPart::TEXT 				  ; break;
580 			case REF_UPDOWN		: nPart = ReferenceFieldPart::UP_DOWN 			  ; break;
581 			case REF_PAGE_PGDESC: nPart = ReferenceFieldPart::PAGE_DESC 		  ; break;
582 			case REF_ONLYNUMBER	: nPart = ReferenceFieldPart::CATEGORY_AND_NUMBER ; break;
583 			case REF_ONLYCAPTION: nPart = ReferenceFieldPart::ONLY_CAPTION 		  ; break;
584 			case REF_ONLYSEQNO	: nPart = ReferenceFieldPart::ONLY_SEQUENCE_NUMBER; break;
585             // --> OD 2007-09-06 #i81002#
586             case REF_NUMBER:              nPart = ReferenceFieldPart::NUMBER;              break;
587             case REF_NUMBER_NO_CONTEXT:   nPart = ReferenceFieldPart::NUMBER_NO_CONTEXT;   break;
588             case REF_NUMBER_FULL_CONTEXT: nPart = ReferenceFieldPart::NUMBER_FULL_CONTEXT; break;
589             // <--
590 			}
591 			rAny <<= nPart;
592 		}
593 		break;
594 	case FIELD_PROP_USHORT2:
595 		{
596 			sal_Int16 nSource = 0;
597 			switch(nSubType)
598 			{
599 			case  REF_SETREFATTR : nSource = ReferenceFieldSource::REFERENCE_MARK; break;
600 			case  REF_SEQUENCEFLD: nSource = ReferenceFieldSource::SEQUENCE_FIELD; break;
601 			case  REF_BOOKMARK   : nSource = ReferenceFieldSource::BOOKMARK; break;
602 			case  REF_OUTLINE    : DBG_ERROR("not implemented"); break;
603 			case  REF_FOOTNOTE   : nSource = ReferenceFieldSource::FOOTNOTE; break;
604 			case  REF_ENDNOTE    : nSource = ReferenceFieldSource::ENDNOTE; break;
605 			}
606 			rAny <<= nSource;
607 		}
608 		break;
609 	case FIELD_PROP_PAR1:
610     {
611         String  sTmp(GetPar1());
612         if(REF_SEQUENCEFLD == nSubType)
613         {
614             sal_uInt16 nPoolId = SwStyleNameMapper::GetPoolIdFromUIName( sTmp, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL );
615             switch( nPoolId )
616             {
617                 case RES_POOLCOLL_LABEL_ABB:
618                 case RES_POOLCOLL_LABEL_TABLE:
619                 case RES_POOLCOLL_LABEL_FRAME:
620                 case RES_POOLCOLL_LABEL_DRAWING:
621                     SwStyleNameMapper::FillProgName(nPoolId, sTmp) ;
622                 break;
623             }
624         }
625         rAny <<= rtl::OUString(sTmp);
626     }
627     break;
628 	case FIELD_PROP_PAR3:
629 		rAny <<= rtl::OUString(Expand());
630 		break;
631 	case FIELD_PROP_SHORT1:
632 		rAny <<= (sal_Int16)nSeqNo;
633 		break;
634 	default:
635 		DBG_ERROR("illegal property");
636 	}
637 	return sal_True;
638 }
639 
PutValue(const uno::Any & rAny,sal_uInt16 nWhichId)640 sal_Bool SwGetRefField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
641 {
642 	String sTmp;
643     switch( nWhichId )
644 	{
645 	case FIELD_PROP_USHORT1:
646 		{
647 			sal_Int16 nPart = 0;
648 			rAny >>= nPart;
649 			switch(nPart)
650 			{
651 			case ReferenceFieldPart::PAGE: 					nPart = REF_PAGE; break;
652 			case ReferenceFieldPart::CHAPTER:	 			nPart = REF_CHAPTER; break;
653 			case ReferenceFieldPart::TEXT: 					nPart = REF_CONTENT; break;
654 			case ReferenceFieldPart::UP_DOWN: 				nPart = REF_UPDOWN; break;
655 			case ReferenceFieldPart::PAGE_DESC: 			nPart = REF_PAGE_PGDESC; break;
656 			case ReferenceFieldPart::CATEGORY_AND_NUMBER: 	nPart = REF_ONLYNUMBER; break;
657 			case ReferenceFieldPart::ONLY_CAPTION: 			nPart = REF_ONLYCAPTION; break;
658 			case ReferenceFieldPart::ONLY_SEQUENCE_NUMBER : nPart = REF_ONLYSEQNO; break;
659             // --> OD 2007-09-06 #i81002#
660             case ReferenceFieldPart::NUMBER:              nPart = REF_NUMBER;              break;
661             case ReferenceFieldPart::NUMBER_NO_CONTEXT:   nPart = REF_NUMBER_NO_CONTEXT;   break;
662             case ReferenceFieldPart::NUMBER_FULL_CONTEXT: nPart = REF_NUMBER_FULL_CONTEXT; break;
663             // <--
664 			default: return sal_False;
665 			}
666 			SetFormat(nPart);
667 		}
668 		break;
669 	case FIELD_PROP_USHORT2:
670 		{
671 			sal_Int16 nSource = 0;
672 			rAny >>= nSource;
673 			switch(nSource)
674 			{
675 			case ReferenceFieldSource::REFERENCE_MARK : nSubType = REF_SETREFATTR ; break;
676             case ReferenceFieldSource::SEQUENCE_FIELD :
677             {
678                 if(REF_SEQUENCEFLD == nSubType)
679                     break;
680                 nSubType = REF_SEQUENCEFLD;
681                 ConvertProgrammaticToUIName();
682             }
683             break;
684 			case ReferenceFieldSource::BOOKMARK		  : nSubType = REF_BOOKMARK   ; break;
685 			case ReferenceFieldSource::FOOTNOTE		  : nSubType = REF_FOOTNOTE   ; break;
686 			case ReferenceFieldSource::ENDNOTE		  : nSubType = REF_ENDNOTE    ; break;
687 			}
688 		}
689 		break;
690 	case FIELD_PROP_PAR1:
691     {
692         OUString sTmpStr;
693         rAny >>= sTmpStr;
694         SetPar1(sTmpStr);
695         ConvertProgrammaticToUIName();
696     }
697     break;
698 	case FIELD_PROP_PAR3:
699 		SetExpand( ::GetString( rAny, sTmp ));
700 		break;
701 	case FIELD_PROP_SHORT1:
702 		{
703 			sal_Int16 nSetSeq = 0;
704 			rAny >>= nSetSeq;
705 			if(nSetSeq >= 0)
706 				nSeqNo = nSetSeq;
707 		}
708 		break;
709 	default:
710 		DBG_ERROR("illegal property");
711 	}
712 	return sal_True;
713 }
714 
ConvertProgrammaticToUIName()715 void SwGetRefField::ConvertProgrammaticToUIName()
716 {
717     if(GetTyp() && REF_SEQUENCEFLD == nSubType)
718     {
719         SwDoc* pDoc = ((SwGetRefFieldType*)GetTyp())->GetDoc();
720         const String& rPar1 = GetPar1();
721         //don't convert when the name points to an existing field type
722         if(!pDoc->GetFldType(RES_SETEXPFLD, rPar1, false))
723         {
724             sal_uInt16 nPoolId = SwStyleNameMapper::GetPoolIdFromProgName( rPar1, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL );
725             sal_uInt16 nResId = USHRT_MAX;
726             switch( nPoolId )
727             {
728                 case RES_POOLCOLL_LABEL_ABB:
729                     nResId = STR_POOLCOLL_LABEL_ABB;
730                 break;
731                 case RES_POOLCOLL_LABEL_TABLE:
732                     nResId = STR_POOLCOLL_LABEL_TABLE;
733                 break;
734                 case RES_POOLCOLL_LABEL_FRAME:
735                     nResId = STR_POOLCOLL_LABEL_FRAME;
736                 break;
737                 case RES_POOLCOLL_LABEL_DRAWING:
738                     nResId = STR_POOLCOLL_LABEL_DRAWING;
739                 break;
740             }
741             if( nResId != USHRT_MAX )
742                 SetPar1(SW_RESSTR( nResId ));
743         }
744     }
745 }
746 
SwGetRefFieldType(SwDoc * pDc)747 SwGetRefFieldType::SwGetRefFieldType( SwDoc* pDc )
748 	: SwFieldType( RES_GETREFFLD ), pDoc( pDc )
749 {}
750 
751 
Copy() const752 SwFieldType* SwGetRefFieldType::Copy() const
753 {
754 	return new SwGetRefFieldType( pDoc );
755 }
756 
757 
Modify(const SfxPoolItem * pOld,const SfxPoolItem * pNew)758 void SwGetRefFieldType::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew )
759 {
760     // Update auf alle GetReferenz-Felder
761     if( !pNew && !pOld )
762     {
763         SwIterator<SwFmtFld,SwFieldType> aIter( *this );
764         for( SwFmtFld* pFmtFld = aIter.First(); pFmtFld; pFmtFld = aIter.Next() )
765         {
766             // nur die GetRef-Felder Updaten
767             //JP 3.4.2001: Task 71231 - we need the correct language
768             SwGetRefField* pGRef = (SwGetRefField*)pFmtFld->GetField();
769             const SwTxtFld* pTFld;
770             if( !pGRef->GetLanguage() &&
771                 0 != ( pTFld = pFmtFld->GetTxtFld()) &&
772                 pTFld->GetpTxtNode() )
773             {
774                 pGRef->SetLanguage( pTFld->GetpTxtNode()->GetLang(
775                                                 *pTFld->GetStart() ) );
776             }
777 
778             pGRef->UpdateField( pFmtFld->GetTxtFld() );
779         }
780     }
781     // weiter an die Text-Felder, diese "Expandieren" den Text
782     NotifyClients( pOld, pNew );
783 }
784 
FindAnchor(SwDoc * pDoc,const String & rRefMark,sal_uInt16 nSubType,sal_uInt16 nSeqNo,sal_uInt16 * pStt,sal_uInt16 * pEnd)785 SwTxtNode* SwGetRefFieldType::FindAnchor( SwDoc* pDoc, const String& rRefMark,
786 										sal_uInt16 nSubType, sal_uInt16 nSeqNo,
787 										sal_uInt16* pStt, sal_uInt16* pEnd )
788 {
789 	ASSERT( pStt, "warum wird keine StartPos abgefragt?" );
790 
791 	SwTxtNode* pTxtNd = 0;
792 	switch( nSubType )
793 	{
794 	case REF_SETREFATTR:
795 		{
796 			const SwFmtRefMark *pRef = pDoc->GetRefMark( rRefMark );
797 			if( pRef && pRef->GetTxtRefMark() )
798 			{
799 				pTxtNd = (SwTxtNode*)&pRef->GetTxtRefMark()->GetTxtNode();
800 				*pStt = *pRef->GetTxtRefMark()->GetStart();
801 				if( pEnd )
802 					*pEnd = *pRef->GetTxtRefMark()->GetAnyEnd();
803 			}
804 		}
805 		break;
806 
807 	case REF_SEQUENCEFLD:
808 		{
809 			SwFieldType* pFldType = pDoc->GetFldType( RES_SETEXPFLD, rRefMark, false );
810 			if( pFldType && pFldType->GetDepends() &&
811 				nsSwGetSetExpType::GSE_SEQ & ((SwSetExpFieldType*)pFldType)->GetType() )
812 			{
813 				SwIterator<SwFmtFld,SwFieldType> aIter( *pFldType );
814 				for( SwFmtFld* pFmtFld = aIter.First(); pFmtFld; pFmtFld = aIter.Next() )
815 				{
816 					if( pFmtFld->GetTxtFld() && nSeqNo ==
817 						((SwSetExpField*)pFmtFld->GetField())->GetSeqNumber() )
818 					{
819 						SwTxtFld* pTxtFld = pFmtFld->GetTxtFld();
820 						pTxtNd = (SwTxtNode*)pTxtFld->GetpTxtNode();
821 						*pStt = *pTxtFld->GetStart();
822 						if( pEnd )
823 							*pEnd = (*pStt) + 1;
824 						break;
825 					}
826 				}
827 			}
828 		}
829 		break;
830 
831     case REF_BOOKMARK:
832         {
833             IDocumentMarkAccess::const_iterator_t ppMark = pDoc->getIDocumentMarkAccess()->findMark(rRefMark);
834             if(ppMark != pDoc->getIDocumentMarkAccess()->getAllMarksEnd())
835             {
836                 const ::sw::mark::IMark* pBkmk = ppMark->get();
837                 const SwPosition* pPos = &pBkmk->GetMarkStart();
838 
839                 pTxtNd = pPos->nNode.GetNode().GetTxtNode();
840                 *pStt = pPos->nContent.GetIndex();
841                 if(pEnd)
842                 {
843                     if(!pBkmk->IsExpanded())
844                     {
845                         *pEnd = *pStt;
846                         // --> OD 2007-10-18 #i81002#
847                         if(dynamic_cast< ::sw::mark::CrossRefBookmark const *>(pBkmk))
848                         {
849                             ASSERT( pTxtNd,
850                                     "<SwGetRefFieldType::FindAnchor(..)> - node marked by cross-reference bookmark isn't a text node --> crash" );
851                             *pEnd = pTxtNd->Len();
852                         }
853                         // <--
854                     }
855                     else if(pBkmk->GetOtherMarkPos().nNode == pBkmk->GetMarkPos().nNode)
856                         *pEnd = pBkmk->GetMarkEnd().nContent.GetIndex();
857                     else
858                         *pEnd = USHRT_MAX;
859                 }
860             }
861         }
862         break;
863 
864 	case REF_OUTLINE:
865 		break;
866 
867 	case REF_FOOTNOTE:
868 	case REF_ENDNOTE:
869 		{
870 			sal_uInt16 n, nFtnCnt = pDoc->GetFtnIdxs().Count();
871 			SwTxtFtn* pFtnIdx;
872 			for( n = 0; n < nFtnCnt; ++n )
873 				if( nSeqNo == (pFtnIdx = pDoc->GetFtnIdxs()[ n ])->GetSeqRefNo() )
874 				{
875 					SwNodeIndex* pIdx = pFtnIdx->GetStartNode();
876 					if( pIdx )
877 					{
878 						SwNodeIndex aIdx( *pIdx, 1 );
879 						if( 0 == ( pTxtNd = aIdx.GetNode().GetTxtNode()))
880 							pTxtNd = (SwTxtNode*)pDoc->GetNodes().GoNext( &aIdx );
881 					}
882 					*pStt = 0;
883 					if( pEnd )
884 						*pEnd = 0;
885 					break;
886 				}
887 		}
888 		break;
889 	}
890 
891 	return pTxtNd;
892 }
893 
894 
895 struct _RefIdsMap
896 {
897 	String aName;
898 	SvUShortsSort aIds, aDstIds, aIdsMap;
899 	SvUShorts aMap;
900 	sal_Bool bInit;
901 
_RefIdsMap_RefIdsMap902 	_RefIdsMap( const String& rName )
903 		: aName( rName ), aIds( 16, 16 ), aIdsMap( 16, 16 ), aMap( 16, 16 ),
904 		bInit( sal_False )
905 	{}
906 
907 	void Check( SwDoc& rDoc, SwDoc& rDestDoc, SwGetRefField& rFld,
908 					sal_Bool bField = sal_True );
909 
IsInit_RefIdsMap910 	sal_Bool IsInit() const { return bInit; }
911 };
912 
913 SV_DECL_PTRARR_DEL( _RefIdsMaps, _RefIdsMap*, 5, 5 )
SV_IMPL_PTRARR(_RefIdsMaps,_RefIdsMap *)914 SV_IMPL_PTRARR( _RefIdsMaps, _RefIdsMap* )
915 
916 void _RefIdsMap::Check( SwDoc& rDoc, SwDoc& rDestDoc, SwGetRefField& rFld,
917 						sal_Bool bField )
918 {
919 
920 	if( !bInit )
921 	{
922 		if( bField )
923 		{
924 			const SwTxtNode* pNd;
925 			SwFieldType* pType;
926 			if( 0 != ( pType = rDestDoc.GetFldType( RES_SETEXPFLD, aName, false ) ))
927 			{
928 				SwIterator<SwFmtFld,SwFieldType> aIter( *pType );
929 				for( SwFmtFld* pF = aIter.First(); pF; pF = aIter.Next() )
930 					if( pF->GetTxtFld() &&
931 						0 != ( pNd = pF->GetTxtFld()->GetpTxtNode() ) &&
932 						pNd->GetNodes().IsDocNodes() )
933 						aIds.Insert( ((SwSetExpField*)pF->GetField())->GetSeqNumber() );
934 			}
935 			if( 0 != ( pType = rDoc.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 						aDstIds.Insert( ((SwSetExpField*)pF->GetField())->GetSeqNumber() );
943 			}
944 		}
945 		else
946 		{
947 			sal_uInt16 n;
948 
949 			for( n = rDestDoc.GetFtnIdxs().Count(); n; )
950 				aIds.Insert( rDestDoc.GetFtnIdxs()[ --n ]->GetSeqRefNo() );
951 			for( n = rDoc.GetFtnIdxs().Count(); n; )
952 				aDstIds.Insert( rDoc.GetFtnIdxs()[ --n ]->GetSeqRefNo() );
953 		}
954 		bInit = sal_True;
955 	}
956 
957 	// dann teste mal, ob die Nummer schon vergeben ist
958 	// oder ob eine neue bestimmt werden muss.
959 	sal_uInt16 nPos, nSeqNo = rFld.GetSeqNo();
960 	if( aIds.Seek_Entry( nSeqNo ) && aDstIds.Seek_Entry( nSeqNo ))
961 	{
962 		// ist schon vergeben, also muss eine neue
963 		// erzeugt werden.
964 		if( aIdsMap.Seek_Entry( nSeqNo, &nPos ))
965 			rFld.SetSeqNo( aMap[ nPos ] );
966 		else
967 		{
968 			sal_uInt16 n;
969 
970 			for( n = 0; n < aIds.Count(); ++n )
971 				if( n != aIds[ n ] )
972 					break;
973 
974 			// die neue SeqNo eintragen, damit die "belegt" ist
975 			aIds.Insert( n );
976 			aIdsMap.Insert( nSeqNo, nPos );
977 			aMap.Insert( n, nPos );
978 			rFld.SetSeqNo( n );
979 
980 			// und noch die Felder oder Fuss-/EndNote auf die neue
981 			// Id umsetzen
982 			if( bField )
983 			{
984 				SwFieldType* pType = rDoc.GetFldType( RES_SETEXPFLD, aName, false );
985 				if( pType )
986 				{
987 				    SwIterator<SwFmtFld,SwFieldType> aIter( *pType );
988 				    for( SwFmtFld* pF = aIter.First(); pF; pF = aIter.Next() )
989 						if( pF->GetTxtFld() && nSeqNo ==
990 							((SwSetExpField*)pF->GetField())->GetSeqNumber() )
991 							((SwSetExpField*)pF->GetField())->SetSeqNumber( n );
992 				}
993 			}
994 			else
995 			{
996 				SwTxtFtn* pFtnIdx;
997 				for( sal_uInt16 i = 0, nCnt = rDoc.GetFtnIdxs().Count(); i < nCnt; ++i )
998 					if( nSeqNo == (pFtnIdx = rDoc.GetFtnIdxs()[ i ])->GetSeqRefNo() )
999 					{
1000 						pFtnIdx->SetSeqNo( n );
1001 						break;
1002 					}
1003 			}
1004 		}
1005 	}
1006 	else
1007 	{
1008 		aIds.Insert( nSeqNo );
1009 		aIdsMap.Insert( nSeqNo, nPos );
1010 		aMap.Insert( nSeqNo, nPos );
1011 	}
1012 }
1013 
1014 
MergeWithOtherDoc(SwDoc & rDestDoc)1015 void SwGetRefFieldType::MergeWithOtherDoc( SwDoc& rDestDoc )
1016 {
1017 	if( &rDestDoc != pDoc &&
1018 		rDestDoc.GetSysFldType( RES_GETREFFLD )->GetDepends() )
1019 	{
1020 		// dann gibt es im DestDoc RefFelder, also muessen im SourceDoc
1021 		// alle RefFelder auf einduetige Ids in beiden Docs umgestellt
1022 		// werden.
1023 		_RefIdsMap aFntMap( aEmptyStr );
1024 		_RefIdsMaps aFldMap;
1025 
1026 		SwIterator<SwFmtFld,SwFieldType> aIter( *this );
1027 		for( SwFmtFld* pFld = aIter.First(); pFld; pFld = aIter.Next() )
1028 		{
1029 			SwGetRefField& rRefFld = *(SwGetRefField*)pFld->GetField();
1030 			switch( rRefFld.GetSubType() )
1031 			{
1032 			case REF_SEQUENCEFLD:
1033 				{
1034 					_RefIdsMap* pMap = 0;
1035 					for( sal_uInt16 n = aFldMap.Count(); n; )
1036 						if( aFldMap[ --n ]->aName == rRefFld.GetSetRefName() )
1037 						{
1038 							pMap = aFldMap[ n ];
1039 							break;
1040 						}
1041 					if( !pMap )
1042 					{
1043 						pMap = new _RefIdsMap( rRefFld.GetSetRefName() );
1044 						aFldMap.C40_INSERT( _RefIdsMap, pMap, aFldMap.Count() );
1045 					}
1046 
1047 					pMap->Check( *pDoc, rDestDoc, rRefFld, sal_True );
1048 				}
1049 				break;
1050 
1051 			case REF_FOOTNOTE:
1052 			case REF_ENDNOTE:
1053 				aFntMap.Check( *pDoc, rDestDoc, rRefFld, sal_False );
1054 				break;
1055 			}
1056 		}
1057 	}
1058 }
1059 
1060