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