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