xref: /AOO41X/main/sw/source/core/fields/reffld.cxx (revision 8809db7a87f97847b57a57f4cd2b0104b2b83182)
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