xref: /trunk/main/sw/source/core/tox/tox.cxx (revision cdf0e10c)
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 #include <tools/resid.hxx>
32 #include <hintids.hxx>
33 #include <swtypes.hxx>
34 #include <errhdl.hxx>
35 #include <txtatr.hxx>
36 #include <ndtxt.hxx>
37 #include <txttxmrk.hxx>
38 #include <tox.hxx>
39 #include <poolfmt.hrc>
40 #include <doc.hxx>
41 #include <docary.hxx>
42 #include <paratr.hxx>
43 #include <editeng/tstpitem.hxx>
44 #include <SwStyleNameMapper.hxx>
45 #include <hints.hxx> // SwPtrMsgPoolItem
46 #include <algorithm>
47 #include <functional>
48 #include <switerator.hxx>
49 
50 using namespace std;
51 
52 const sal_Char* SwForm::aFormEntry      = "<E>";
53 const sal_Char* SwForm::aFormTab        = "<T>";
54 const sal_Char* SwForm::aFormPageNums   = "<#>";
55 const sal_Char* SwForm::aFormLinkStt    = "<LS>";
56 const sal_Char* SwForm::aFormLinkEnd    = "<LE>";
57 const sal_Char* SwForm::aFormEntryNum   = "<E#>";
58 const sal_Char* SwForm::aFormEntryTxt   = "<ET>";
59 const sal_Char* SwForm::aFormChapterMark= "<C>";
60 const sal_Char* SwForm::aFormText       = "<X>";
61 const sal_Char* SwForm::aFormAuth       = "<A>";
62 sal_uInt8 SwForm::nFormTabLen            = 3;
63 sal_uInt8 SwForm::nFormEntryLen          = 3;
64 sal_uInt8 SwForm::nFormPageNumsLen       = 3;
65 sal_uInt8 SwForm::nFormLinkSttLen        = 4;
66 sal_uInt8 SwForm::nFormLinkEndLen        = 4;
67 sal_uInt8 SwForm::nFormEntryNumLen       = 4;
68 sal_uInt8 SwForm::nFormEntryTxtLen       = 4;
69 sal_uInt8 SwForm::nFormChapterMarkLen    = 3;
70 sal_uInt8 SwForm::nFormTextLen           = 3;
71 sal_uInt8 SwForm::nFormAuthLen           = 5;
72 
73 SV_IMPL_PTRARR(SwTOXMarks, SwTOXMark*)
74 
75 TYPEINIT2( SwTOXMark, SfxPoolItem, SwClient );    // fuers rtti
76 
77 struct PatternIni
78 {
79     sal_uInt16 n1;
80     sal_uInt16 n2;
81     sal_uInt16 n3;
82     sal_uInt16 n4;
83     sal_uInt16 n5;
84 };
85 const PatternIni aPatternIni[] =
86 {
87     {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX},    //Header - no pattern
88     {AUTH_FIELD_AUTHOR, AUTH_FIELD_TITLE, AUTH_FIELD_YEAR, USHRT_MAX, USHRT_MAX},   //AUTH_TYPE_ARTICLE,
89     {AUTH_FIELD_AUTHOR, AUTH_FIELD_TITLE, AUTH_FIELD_YEAR, USHRT_MAX, USHRT_MAX},     //AUTH_TYPE_BOOK,
90     {AUTH_FIELD_AUTHOR, AUTH_FIELD_TITLE, AUTH_FIELD_YEAR, USHRT_MAX, USHRT_MAX},     //AUTH_TYPE_BOOKLET,
91     {AUTH_FIELD_AUTHOR, AUTH_FIELD_TITLE, AUTH_FIELD_YEAR, USHRT_MAX, USHRT_MAX},     //AUTH_TYPE_CONFERENCE,
92     {AUTH_FIELD_AUTHOR, AUTH_FIELD_TITLE, AUTH_FIELD_YEAR, USHRT_MAX, USHRT_MAX},     //AUTH_TYPE_INBOOK,
93     {AUTH_FIELD_AUTHOR, AUTH_FIELD_TITLE, AUTH_FIELD_YEAR, USHRT_MAX, USHRT_MAX},     //AUTH_TYPE_INCOLLECTION,
94     {AUTH_FIELD_AUTHOR, AUTH_FIELD_TITLE, AUTH_FIELD_YEAR, USHRT_MAX, USHRT_MAX},     //AUTH_TYPE_INPROCEEDINGS,
95     {AUTH_FIELD_AUTHOR, AUTH_FIELD_TITLE, AUTH_FIELD_YEAR, USHRT_MAX, USHRT_MAX},     //AUTH_TYPE_JOURNAL,
96     {AUTH_FIELD_AUTHOR, AUTH_FIELD_TITLE, AUTH_FIELD_YEAR, USHRT_MAX, USHRT_MAX},     //AUTH_TYPE_MANUAL,
97     {AUTH_FIELD_AUTHOR, AUTH_FIELD_TITLE, AUTH_FIELD_YEAR, USHRT_MAX, USHRT_MAX},     //AUTH_TYPE_MASTERSTHESIS,
98     {AUTH_FIELD_AUTHOR, AUTH_FIELD_TITLE, AUTH_FIELD_YEAR, USHRT_MAX, USHRT_MAX},     //AUTH_TYPE_MISC,
99     {AUTH_FIELD_AUTHOR, AUTH_FIELD_TITLE, AUTH_FIELD_YEAR, USHRT_MAX, USHRT_MAX},     //AUTH_TYPE_PHDTHESIS,
100     {AUTH_FIELD_AUTHOR, AUTH_FIELD_TITLE, AUTH_FIELD_YEAR, USHRT_MAX, USHRT_MAX},     //AUTH_TYPE_PROCEEDINGS,
101     {AUTH_FIELD_AUTHOR, AUTH_FIELD_TITLE, AUTH_FIELD_YEAR, USHRT_MAX, USHRT_MAX},     //AUTH_TYPE_TECHREPORT,
102     {AUTH_FIELD_AUTHOR, AUTH_FIELD_TITLE, AUTH_FIELD_YEAR, USHRT_MAX, USHRT_MAX},     //AUTH_TYPE_UNPUBLISHED,
103     {AUTH_FIELD_AUTHOR, AUTH_FIELD_TITLE, AUTH_FIELD_YEAR, USHRT_MAX, USHRT_MAX},     //AUTH_TYPE_EMAIL,
104     {AUTH_FIELD_AUTHOR, AUTH_FIELD_TITLE, AUTH_FIELD_YEAR, AUTH_FIELD_URL, USHRT_MAX},//AUTH_TYPE_WWW,
105     {AUTH_FIELD_AUTHOR, AUTH_FIELD_TITLE, AUTH_FIELD_YEAR, USHRT_MAX, USHRT_MAX},     //AUTH_TYPE_CUSTOM1,
106     {AUTH_FIELD_AUTHOR, AUTH_FIELD_TITLE, AUTH_FIELD_YEAR, USHRT_MAX, USHRT_MAX},     //AUTH_TYPE_CUSTOM2,
107     {AUTH_FIELD_AUTHOR, AUTH_FIELD_TITLE, AUTH_FIELD_YEAR, USHRT_MAX, USHRT_MAX},     //AUTH_TYPE_CUSTOM3,
108     {AUTH_FIELD_AUTHOR, AUTH_FIELD_TITLE, AUTH_FIELD_YEAR, USHRT_MAX, USHRT_MAX},     //AUTH_TYPE_CUSTOM4,
109     {AUTH_FIELD_AUTHOR, AUTH_FIELD_TITLE, AUTH_FIELD_YEAR, USHRT_MAX, USHRT_MAX},     //AUTH_TYPE_CUSTOM5,
110     {AUTH_FIELD_AUTHOR, AUTH_FIELD_TITLE, AUTH_FIELD_YEAR, USHRT_MAX, USHRT_MAX},     //AUTH_FIELD_YEAR,
111     {AUTH_FIELD_AUTHOR, AUTH_FIELD_TITLE, AUTH_FIELD_YEAR, USHRT_MAX, USHRT_MAX},     //AUTH_FIELD_URL,
112     {AUTH_FIELD_AUTHOR, AUTH_FIELD_TITLE, AUTH_FIELD_YEAR, USHRT_MAX, USHRT_MAX},     //AUTH_FIELD_CUSTOM1,
113     {AUTH_FIELD_AUTHOR, AUTH_FIELD_TITLE, AUTH_FIELD_YEAR, USHRT_MAX, USHRT_MAX},     //AUTH_FIELD_CUSTOM2,
114     {AUTH_FIELD_AUTHOR, AUTH_FIELD_TITLE, AUTH_FIELD_YEAR, USHRT_MAX, USHRT_MAX},     //AUTH_FIELD_CUSTOM3,
115     {AUTH_FIELD_AUTHOR, AUTH_FIELD_TITLE, AUTH_FIELD_YEAR, USHRT_MAX, USHRT_MAX},     //AUTH_FIELD_CUSTOM4,
116     {AUTH_FIELD_AUTHOR, AUTH_FIELD_TITLE, AUTH_FIELD_YEAR, USHRT_MAX, USHRT_MAX},     //AUTH_FIELD_CUSTOM5,
117     {USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX, USHRT_MAX}
118 };
119 
120 SwFormTokens lcl_GetAuthPattern(sal_uInt16 nTypeId)
121 {
122     SwFormTokens aRet;
123 
124     PatternIni aIni = aPatternIni[nTypeId];
125     sal_uInt16 nVals[5];
126     nVals[0] = aIni.n1;
127     nVals[1] = aIni.n2;
128     nVals[2] = aIni.n3;
129     nVals[3] = aIni.n4;
130     nVals[4] = aIni.n5;
131 
132     SwFormToken aStartToken( TOKEN_AUTHORITY );
133     aStartToken.nAuthorityField = AUTH_FIELD_IDENTIFIER;
134     aRet.push_back( aStartToken );
135     SwFormToken aSeparatorToken( TOKEN_TEXT );
136     aSeparatorToken.sText = String::CreateFromAscii( ": " );
137     aRet.push_back( aSeparatorToken );
138     SwFormToken aTextToken( TOKEN_TEXT );
139     aTextToken.sText = String::CreateFromAscii( ", " );
140 
141     for(sal_uInt16 i = 0; i < 5 ; i++)
142     {
143         if(nVals[i] == USHRT_MAX)
144             break;
145         if( i > 0 )
146             aRet.push_back( aTextToken );
147 
148          // -> #i21237#
149         SwFormToken aToken(TOKEN_AUTHORITY);
150 
151         aToken.nAuthorityField = nVals[i];
152         aRet.push_back(aToken);
153         // <- #i21237#
154     }
155 
156     return aRet;
157 }
158 /*--------------------------------------------------------------------
159      Beschreibung:  Verzeichnis-Markierungen D/Ctor
160  --------------------------------------------------------------------*/
161 
162 
163 /// pool default constructor
164 SwTOXMark::SwTOXMark()
165     : SfxPoolItem( RES_TXTATR_TOXMARK )
166     , SwModify( 0 )
167     ,
168     pTxtAttr( 0 ),
169     bAutoGenerated(sal_False),
170     bMainEntry(sal_False)
171 {
172 }
173 
174 
175 SwTOXMark::SwTOXMark( const SwTOXType* pTyp )
176     : SfxPoolItem( RES_TXTATR_TOXMARK )
177     , SwModify( const_cast<SwTOXType*>(pTyp) )
178     ,
179     pTxtAttr( 0 ), nLevel( 0 ),
180     bAutoGenerated(sal_False),
181     bMainEntry(sal_False)
182 {
183 }
184 
185 
186 SwTOXMark::SwTOXMark( const SwTOXMark& rCopy )
187     : SfxPoolItem( RES_TXTATR_TOXMARK )
188     , SwModify(rCopy.GetRegisteredInNonConst())
189     ,
190     aPrimaryKey( rCopy.aPrimaryKey ), aSecondaryKey( rCopy.aSecondaryKey ),
191     aTextReading( rCopy.aTextReading ),
192     aPrimaryKeyReading( rCopy.aPrimaryKeyReading ),
193     aSecondaryKeyReading( rCopy.aSecondaryKeyReading ),
194     pTxtAttr( 0 ), nLevel( rCopy.nLevel ),
195     bAutoGenerated( rCopy.bAutoGenerated),
196     bMainEntry(rCopy.bMainEntry)
197 {
198     // AlternativString kopieren
199     aAltText = rCopy.aAltText;
200 }
201 
202 
203 SwTOXMark::~SwTOXMark()
204 {
205 }
206 
207 
208 void SwTOXMark::RegisterToTOXType( SwTOXType& rMark )
209 {
210     rMark.Add(this);
211 }
212 
213 int SwTOXMark::operator==( const SfxPoolItem& rAttr ) const
214 {
215     ASSERT( SfxPoolItem::operator==( rAttr ), "keine gleichen Attribute" );
216     return GetRegisteredIn() == ((SwTOXMark&)rAttr).GetRegisteredIn();
217 }
218 
219 
220 SfxPoolItem* SwTOXMark::Clone( SfxItemPool* ) const
221 {
222     return new SwTOXMark( *this );
223 }
224 
225 void SwTOXMark::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew)
226 {
227     NotifyClients(pOld, pNew);
228     if (pOld && (RES_REMOVE_UNO_OBJECT == pOld->Which()))
229     {   // invalidate cached uno object
230         SetXTOXMark(::com::sun::star::uno::Reference<
231                         ::com::sun::star::text::XDocumentIndexMark>(0));
232     }
233 }
234 
235 void SwTOXMark::InvalidateTOXMark()
236 {
237     SwPtrMsgPoolItem aMsgHint( RES_REMOVE_UNO_OBJECT,
238         &static_cast<SwModify&>(*this) ); // cast to base class!
239     NotifyClients(&aMsgHint, &aMsgHint);
240 }
241 
242 String SwTOXMark::GetText() const
243 {
244     String aStr;
245     if( aAltText.Len() )
246         aStr = aAltText;
247     else if( pTxtAttr && pTxtAttr->GetpTxtNd() )
248     {
249         xub_StrLen* pEndIdx = pTxtAttr->GetEnd();
250         ASSERT( pEndIdx, "TOXMark ohne Mark!!");
251         if( pEndIdx )
252         {
253             const xub_StrLen nStt = *pTxtAttr->GetStart();
254             aStr = pTxtAttr->GetpTxtNd()->GetExpandTxt( nStt, *pEndIdx-nStt );
255         }
256     }
257     return aStr;
258 }
259 
260 void SwTOXMark::InsertTOXMarks( SwTOXMarks& aMarks, const SwTOXType& rType )
261 {
262     SwIterator<SwTOXMark,SwTOXType> aIter(rType);
263     SwTOXMark* pMark = aIter.First();
264 	while( pMark )
265 	{
266 		if(pMark->GetTxtTOXMark())
267 			aMarks.C40_INSERT(SwTOXMark, pMark, aMarks.Count());
268         pMark = aIter.Next();
269 	}
270 }
271 
272 /*--------------------------------------------------------------------
273      Beschreibung: Typen von Verzeichnissen verwalten
274  --------------------------------------------------------------------*/
275 
276 SwTOXType::SwTOXType( TOXTypes eTyp, const String& rName )
277     : SwModify(0),
278     aName(rName),
279     eType(eTyp)
280 {
281 }
282 
283 
284 SwTOXType::SwTOXType(const SwTOXType& rCopy)
285     : SwModify( (SwModify*)rCopy.GetRegisteredIn() ),
286     aName(rCopy.aName),
287     eType(rCopy.eType)
288 {
289 }
290 
291 /*--------------------------------------------------------------------
292     Beschreibung: Formen bearbeiten
293   --------------------------------------------------------------------*/
294 
295 SwForm::SwForm( TOXTypes eTyp ) // #i21237#
296     : eType( eTyp ), nFormMaxLevel( SwForm::GetFormMaxLevel( eTyp )),
297 //  nFirstTabPos( lNumIndent ),
298     bCommaSeparated(sal_False)
299 {
300     //bHasFirstTabPos =
301     bGenerateTabPos = sal_False;
302     bIsRelTabPos = sal_True;
303 
304     // Inhaltsverzeichnis hat entsprechend Anzahl Headlines + Ueberschrift
305     // Benutzer hat 10 Ebenen + Ueberschrift
306     // Stichwort hat 3 Ebenen + Ueberschrift + Trenner
307     // indexes of tables, objects illustrations and authorities consist of a heading and one level
308 
309     sal_uInt16 nPoolId;
310     switch( eType )
311     {
312     case TOX_INDEX:         nPoolId = STR_POOLCOLL_TOX_IDXH;    break;
313     case TOX_USER:          nPoolId = STR_POOLCOLL_TOX_USERH;   break;
314     case TOX_CONTENT:       nPoolId = STR_POOLCOLL_TOX_CNTNTH;  break;
315     case TOX_ILLUSTRATIONS: nPoolId = STR_POOLCOLL_TOX_ILLUSH;  break;
316     case TOX_OBJECTS      : nPoolId = STR_POOLCOLL_TOX_OBJECTH; break;
317     case TOX_TABLES       : nPoolId = STR_POOLCOLL_TOX_TABLESH; break;
318     case TOX_AUTHORITIES  : nPoolId = STR_POOLCOLL_TOX_AUTHORITIESH;    break;
319     default:
320         ASSERT( !this, "ungueltiger TOXTyp");
321         return ;
322     }
323 
324     SwFormTokens aTokens;
325     if (TOX_CONTENT == eType)
326     {
327         aTokens.push_back(SwFormToken(TOKEN_ENTRY_NO));
328         aTokens.push_back(SwFormToken(TOKEN_ENTRY_TEXT));
329     }
330     else
331         aTokens.push_back(SwFormToken(TOKEN_ENTRY));
332 
333     if (TOX_AUTHORITIES != eType)
334     {
335         SwFormToken aToken(TOKEN_TAB_STOP);
336         aToken.nTabStopPosition = 0;
337 
338         // --> FME 2004-12-10 #i36870# right aligned tab for all
339         aToken.cTabFillChar = '.';
340         aToken.eTabAlign = SVX_TAB_ADJUST_END;
341         // <--
342 
343         aTokens.push_back(aToken);
344         aTokens.push_back(SwFormToken(TOKEN_PAGE_NUMS));
345     }
346 
347     SetTemplate( 0, SW_RESSTR( nPoolId++ ));
348 
349     if(TOX_INDEX == eType)
350     {
351         for( sal_uInt16 i = 1; i < 5; ++i  )
352         {
353             if(1 == i)
354             {
355                 SwFormTokens aTmpTokens;
356                 SwFormToken aTmpToken(TOKEN_ENTRY);
357                 aTmpTokens.push_back(aTmpToken);
358 
359                 SetPattern( i, aTmpTokens );
360                 SetTemplate( i, SW_RESSTR( STR_POOLCOLL_TOX_IDXBREAK    ));
361             }
362             else
363             {
364                 SetPattern( i, aTokens );
365                 SetTemplate( i, SW_RESSTR( STR_POOLCOLL_TOX_IDX1 + i - 2 ));
366             }
367         }
368     }
369     else
370         for( sal_uInt16 i = 1; i < GetFormMax(); ++i, ++nPoolId )    // Nr 0 ist der Titel
371         {
372             if(TOX_AUTHORITIES == eType)
373                 SetPattern(i, lcl_GetAuthPattern(i));
374             else
375                 SetPattern( i, aTokens );
376 
377             if( TOX_CONTENT == eType && 6 == i )
378                 nPoolId = STR_POOLCOLL_TOX_CNTNT6;
379             else if( TOX_USER == eType && 6 == i )
380                 nPoolId = STR_POOLCOLL_TOX_USER6;
381             else if( TOX_AUTHORITIES == eType )
382                 nPoolId = STR_POOLCOLL_TOX_AUTHORITIES1;
383             SetTemplate( i, SW_RESSTR( nPoolId ) );
384         }
385 }
386 
387 
388 SwForm::SwForm(const SwForm& rForm)
389     : eType( rForm.eType )
390 {
391     *this = rForm;
392 }
393 
394 
395 SwForm& SwForm::operator=(const SwForm& rForm)
396 {
397     eType = rForm.eType;
398     nFormMaxLevel = rForm.nFormMaxLevel;
399 //  nFirstTabPos = rForm.nFirstTabPos;
400 //  bHasFirstTabPos = rForm.bHasFirstTabPos;
401     bGenerateTabPos = rForm.bGenerateTabPos;
402     bIsRelTabPos = rForm.bIsRelTabPos;
403     bCommaSeparated = rForm.bCommaSeparated;
404     for(sal_uInt16 i=0; i < nFormMaxLevel; ++i)
405     {
406         aPattern[i] = rForm.aPattern[i];
407         aTemplate[i] = rForm.aTemplate[i];
408     }
409     return *this;
410 }
411 
412 sal_uInt16 SwForm::GetFormMaxLevel( TOXTypes eTOXType )
413 {
414     sal_uInt16 nRet = 0;
415     switch( eTOXType )
416     {
417         case TOX_INDEX:         nRet = 5;                   break;
418         case TOX_USER:          nRet = MAXLEVEL+1;          break;
419         case TOX_CONTENT:       nRet = MAXLEVEL+1;          break;
420         case TOX_ILLUSTRATIONS:
421         case TOX_OBJECTS      :
422         case TOX_TABLES       : nRet = 2; break;
423         case TOX_AUTHORITIES  : nRet = AUTH_TYPE_END + 1;       break;
424     }
425     return nRet;
426 }
427 
428 // #i21237#
429 bool operator == (const SwFormToken & rToken, FormTokenType eType)
430 {
431     return rToken.eTokenType == eType;
432 }
433 
434 //-----------------------------------------------------------------------------
435 void SwForm::AdjustTabStops(SwDoc& rDoc, sal_Bool bInsertNewTapStops) // #i21237#
436 {
437     for(sal_uInt16 nLevel = 1; nLevel < GetFormMax(); nLevel++)
438     {
439         const String& sTemplateName = GetTemplate(nLevel);
440 
441         SwTxtFmtColl* pColl = rDoc.FindTxtFmtCollByName( sTemplateName );
442         if( !pColl )
443         {
444             sal_uInt16 nId = SwStyleNameMapper::GetPoolIdFromUIName
445                 ( sTemplateName, nsSwGetPoolIdFromName::GET_POOLID_TXTCOLL ); // #i21237#
446             if( USHRT_MAX != nId )
447                 pColl = rDoc.GetTxtCollFromPool( nId );
448         }
449 
450         const SvxTabStopItem* pTabStops = 0;
451         sal_uInt16 nTabCount = 0;
452         if( pColl &&
453             0 != ( pTabStops = &pColl->GetTabStops(sal_False) ) &&
454             0 != ( nTabCount = pTabStops->Count() ) )
455         {
456             // #i21237#
457             SwFormTokens aCurrentPattern = GetPattern(nLevel);
458             SwFormTokens::iterator aIt = aCurrentPattern.begin();
459 
460             sal_Bool bChanged = sal_False;
461 
462             for(sal_uInt16 nTab = 0; nTab < nTabCount; ++nTab)
463             {
464                 const SvxTabStop& rTab = (*pTabStops)[nTab];
465 
466                 // --> FME 2004-12-16 #i29178#
467                 // For Word import, we do not want to replace exising tokens,
468                 // we insert new tabstop tokens without a tabstop character:
469                 if ( bInsertNewTapStops )
470                 {
471                     if ( SVX_TAB_ADJUST_DEFAULT != rTab.GetAdjustment() )
472                     {
473                         bChanged = sal_True;
474                         SwFormToken aToken(TOKEN_TAB_STOP);
475                         aToken.bWithTab = sal_False;
476                         aToken.nTabStopPosition = rTab.GetTabPos();
477                         aToken.eTabAlign = rTab.GetAdjustment();
478                         aToken.cTabFillChar = rTab.GetFill();
479                         aCurrentPattern.push_back(aToken);
480                     }
481                 }
482                 // <--
483                 else
484                 {
485                     aIt = find_if(aIt, aCurrentPattern.end(),
486                                   SwFormTokenEqualToFormTokenType
487                                   (TOKEN_TAB_STOP));
488                     if ( aIt != aCurrentPattern.end() )
489                     {
490                         bChanged = sal_True;
491                         aIt->nTabStopPosition = rTab.GetTabPos();
492                         aIt->eTabAlign = nTab == nTabCount - 1 &&
493                                          SVX_TAB_ADJUST_RIGHT == rTab.GetAdjustment() ?
494                                          SVX_TAB_ADJUST_END :
495                                          rTab.GetAdjustment();
496                         aIt->cTabFillChar = rTab.GetFill();
497                         ++aIt;
498                     }
499                     else
500                         break; // no more tokens to replace
501                 }
502             }
503             // <--
504 
505             if(bChanged)
506                 SetPattern(nLevel, aCurrentPattern); // #i21237#
507         }
508     }
509 }
510 /*--------------------------------------------------------------------
511      Beschreibung: Ctor TOXBase
512  --------------------------------------------------------------------*/
513 
514 
515 SwTOXBase::SwTOXBase(const SwTOXType* pTyp, const SwForm& rForm,
516                      sal_uInt16 nCreaType, const String& rTitle )
517     : SwClient((SwModify*)pTyp),
518     aForm(rForm),
519     aTitle(rTitle),
520     eLanguage((LanguageType)::GetAppLanguage()),
521     nCreateType(nCreaType),
522     nOLEOptions(0),
523     eCaptionDisplay(CAPTION_COMPLETE),
524     bProtected( sal_True ),
525     bFromChapter(sal_False),
526     bFromObjectNames(sal_False),
527     bLevelFromChapter(sal_False)
528 {
529     aData.nOptions = 0;
530 }
531 
532 
533 SwTOXBase::SwTOXBase( const SwTOXBase& rSource, SwDoc* pDoc )
534     : SwClient( rSource.GetRegisteredInNonConst() )
535 {
536     CopyTOXBase( pDoc, rSource );
537 }
538 
539 void SwTOXBase::RegisterToTOXType( SwTOXType& rType )
540 {
541     rType.Add( this );
542 }
543 
544 SwTOXBase& SwTOXBase::CopyTOXBase( SwDoc* pDoc, const SwTOXBase& rSource )
545 {
546     SwTOXType* pType = (SwTOXType*)rSource.GetTOXType();
547     if( pDoc && USHRT_MAX == pDoc->GetTOXTypes().GetPos( pType ))
548     {
549         // type not in pDoc, so create it now
550         const SwTOXTypes& rTypes = pDoc->GetTOXTypes();
551         sal_Bool bFound = sal_False;
552         for( sal_uInt16 n = rTypes.Count(); n; )
553         {
554             const SwTOXType* pCmp = rTypes[ --n ];
555             if( pCmp->GetType() == pType->GetType() &&
556                 pCmp->GetTypeName() == pType->GetTypeName() )
557             {
558                 pType = (SwTOXType*)pCmp;
559                 bFound = sal_True;
560                 break;
561             }
562         }
563 
564         if( !bFound )
565             pType = (SwTOXType*)pDoc->InsertTOXType( *pType );
566     }
567     pType->Add( this );
568 
569     nCreateType = rSource.nCreateType;
570     aTitle      = rSource.aTitle;
571     aForm       = rSource.aForm;
572     bProtected  = rSource.bProtected;
573     bFromChapter = rSource.bFromChapter;
574     bFromObjectNames = rSource.bFromObjectNames;
575     sMainEntryCharStyle = rSource.sMainEntryCharStyle;
576     sSequenceName = rSource.sSequenceName;
577     eCaptionDisplay = rSource.eCaptionDisplay;
578     nOLEOptions = rSource.nOLEOptions;
579     eLanguage = rSource.eLanguage;
580     sSortAlgorithm = rSource.sSortAlgorithm;
581 
582     for( sal_uInt16 i = 0; i < MAXLEVEL; ++i )
583         aStyleNames[i] = rSource.aStyleNames[i];
584 
585     // its the same data type!
586     aData.nOptions =  rSource.aData.nOptions;
587 
588     if( !pDoc || pDoc->IsCopyIsMove() )
589         aName = rSource.GetTOXName();
590     else
591         aName = pDoc->GetUniqueTOXBaseName( *pType, &rSource.GetTOXName() );
592 
593     return *this;
594 }
595 
596 /*--------------------------------------------------------------------
597      Beschreibung: Verzeichnisspezifische Funktionen
598  --------------------------------------------------------------------*/
599 
600 SwTOXBase::~SwTOXBase()
601 {
602 //    if( GetTOXType()->GetType() == TOX_USER  )
603 //        delete aData.pTemplateName;
604 }
605 
606 void SwTOXBase::SetTitle(const String& rTitle)
607 	{	aTitle = rTitle; }
608 
609 
610 SwTOXBase & SwTOXBase::operator = (const SwTOXBase & rSource)
611 {
612     ByteString aTmpStr(aTitle, RTL_TEXTENCODING_ASCII_US);
613     ByteString aTmpStr1(rSource.aTitle, RTL_TEXTENCODING_ASCII_US);
614 
615     aForm = rSource.aForm;
616     aName = rSource.aName;
617     aTitle = rSource.aTitle;
618     sMainEntryCharStyle = rSource.sMainEntryCharStyle;
619     for(sal_uInt16 nLevel = 0; nLevel < MAXLEVEL; nLevel++)
620         aStyleNames[nLevel] = rSource.aStyleNames[nLevel];
621     sSequenceName = rSource.sSequenceName;
622     eLanguage = rSource.eLanguage;
623     sSortAlgorithm = rSource.sSortAlgorithm;
624     aData = rSource.aData;
625     nCreateType = rSource.nCreateType;
626     nOLEOptions = rSource.nOLEOptions;
627     eCaptionDisplay = rSource.eCaptionDisplay;
628     bProtected = rSource.bProtected;
629     bFromChapter = rSource.bFromChapter;
630     bFromObjectNames = rSource.bFromObjectNames;
631     bLevelFromChapter = rSource.bLevelFromChapter;
632 
633     if (rSource.GetAttrSet())
634         SetAttrSet(*rSource.GetAttrSet());
635 
636     return *this;
637 }
638 
639 /* -----------------16.07.99 16:02-------------------
640 
641 SwTOXBase & SwTOXBase::operator = (const SwTOXBase & rSource)
642 {
643     aForm = rSource.aForm;
644     aName = rSource.aName;
645     aTitle = rSource.aTitle;
646     sMainEntryCharStyle = rSource.sMainEntryCharStyle;
647     sSequenceName = rSource.sSequenceName;
648     eLanguage = rSource.eLanguage;
649     sSortAlgorithm = rSource.sSortAlgorithm;
650     aData = rSource.aData;
651     nCreateType = rSource.nCreateType;
652     nOLEOptions = rSource.nOLEOptions;
653     eCaptionDisplay = rSource.eCaptionDisplay;
654     bProtected = rSource.bProtected;
655     bFromChapter = rSource.bFromChapter;
656     bFromObjectNames = rSource.bFromObjectNames;
657     bLevelFromChapter = rSource.bLevelFromChapter;
658 
659     if (rSource.GetAttrSet())
660         SetAttrSet(*rSource.GetAttrSet());
661 
662     return *this;
663 }
664 
665  --------------------------------------------------*/
666 
667 String SwFormToken::GetString() const
668 {
669     String sRet;
670 
671     sal_Bool bAppend = sal_True;
672     switch( eTokenType )
673     {
674         case TOKEN_ENTRY_NO:
675             sRet.AssignAscii( SwForm::aFormEntryNum );
676         break;
677         case TOKEN_ENTRY_TEXT:
678             sRet.AssignAscii( SwForm::aFormEntryTxt );
679         break;
680         case TOKEN_ENTRY:
681             sRet.AssignAscii( SwForm::aFormEntry );
682         break;
683         case TOKEN_TAB_STOP:
684             sRet.AssignAscii( SwForm::aFormTab );
685         break;
686         case TOKEN_TEXT:
687             sRet.AssignAscii( SwForm::aFormText );
688         break;
689         case TOKEN_PAGE_NUMS:
690             sRet.AssignAscii( SwForm::aFormPageNums );
691         break;
692         case TOKEN_CHAPTER_INFO:
693             sRet.AssignAscii( SwForm::aFormChapterMark );
694         break;
695         case TOKEN_LINK_START:
696             sRet.AssignAscii( SwForm::aFormLinkStt );
697         break;
698         case TOKEN_LINK_END:
699             sRet.AssignAscii( SwForm::aFormLinkEnd );
700         break;
701         case TOKEN_AUTHORITY:
702         {
703             sRet.AssignAscii( SwForm::aFormAuth );
704             String sTmp( String::CreateFromInt32( nAuthorityField ));
705             if( sTmp.Len() < 2 )
706                 sTmp.Insert('0', 0);
707             sRet.Insert( sTmp, 2 );
708         }
709         break;
710         case TOKEN_END:
711         break;
712     }
713     sRet.Erase( sRet.Len() - 1 );
714     sRet += ' ';
715     sRet += sCharStyleName;
716     sRet += ',';
717     sRet += String::CreateFromInt32( nPoolId );
718     sRet += ',';
719 
720     // TabStopPosition and TabAlign or ChapterInfoFormat
721     if(TOKEN_TAB_STOP == eTokenType)
722     {
723         sRet += String::CreateFromInt32( nTabStopPosition );
724         sRet += ',';
725         sRet += String::CreateFromInt32( static_cast< sal_Int32 >(eTabAlign) );
726         sRet += ',';
727         sRet += cTabFillChar;
728         sRet += ',';
729         sRet += String::CreateFromInt32( bWithTab );
730     }
731     else if(TOKEN_CHAPTER_INFO == eTokenType)
732     {
733         sRet += String::CreateFromInt32( nChapterFormat );
734 //add maximum permetted level
735         sRet += ',';
736         sRet += String::CreateFromInt32( nOutlineLevel );
737     }
738     else if(TOKEN_TEXT == eTokenType)
739     {
740         //append Text if Len() > 0 only!
741         if( sText.Len() )
742         {
743             sRet += TOX_STYLE_DELIMITER;
744             String sTmp( sText );
745             sTmp.EraseAllChars( TOX_STYLE_DELIMITER );
746             sRet += sTmp;
747             sRet += TOX_STYLE_DELIMITER;
748         }
749         else
750             bAppend = sal_False;
751     }
752     else if(TOKEN_ENTRY_NO == eTokenType)
753     {
754         sRet += String::CreateFromInt32( nChapterFormat );
755 //add maximum permitted level
756         sRet += ',';
757         sRet += String::CreateFromInt32( nOutlineLevel );
758     }
759 
760     if(bAppend)
761     {
762         sRet += '>';
763     }
764     else
765     {
766         // don't append empty text tokens
767         sRet.Erase();
768     }
769 
770     return sRet;
771 }
772 
773 // -> #i21237#
774 SwFormTokensHelper::SwFormTokensHelper(const String & rPattern)
775 {
776     xub_StrLen nCurPatternPos = 0;
777     xub_StrLen nCurPatternLen = 0;
778 
779     while (nCurPatternPos < rPattern.Len())
780     {
781         nCurPatternPos = nCurPatternPos + nCurPatternLen;
782 
783         SwFormToken aToken = BuildToken(rPattern, nCurPatternPos);
784         aTokens.push_back(aToken);
785     }
786 }
787 
788 SwFormToken SwFormTokensHelper::BuildToken( const String & sPattern,
789                                            xub_StrLen & nCurPatternPos ) const
790 {
791     String sToken( SearchNextToken(sPattern, nCurPatternPos) );
792     nCurPatternPos = nCurPatternPos + sToken.Len();
793     xub_StrLen nTokenLen;
794     FormTokenType eTokenType = GetTokenType(sToken, &nTokenLen);
795 
796     // at this point sPattern contains the
797     // character style name, the PoolId, tab stop position, tab stop alignment, chapter info format
798     // the form is: CharStyleName, PoolId[, TabStopPosition|ChapterInfoFormat[, TabStopAlignment[, TabFillChar]]]
799     // in text tokens the form differs from the others: CharStyleName, PoolId[,\0xffinserted text\0xff]
800     SwFormToken eRet( eTokenType );
801     String sAuthFieldEnum = sToken.Copy( 2, 2 );
802     sToken = sToken.Copy( nTokenLen, sToken.Len() - nTokenLen - 1);
803 
804     eRet.sCharStyleName = sToken.GetToken( 0, ',');
805     String sTmp( sToken.GetToken( 1, ',' ));
806     if( sTmp.Len() )
807         eRet.nPoolId = static_cast<sal_uInt16>(sTmp.ToInt32());
808 
809     switch( eTokenType )
810     {
811 //i53420
812     case TOKEN_ENTRY_NO:
813         if( (sTmp = sToken.GetToken( 2, ',' ) ).Len() )
814             eRet.nChapterFormat = static_cast<sal_uInt16>(sTmp.ToInt32());
815         if( (sTmp = sToken.GetToken( 3, ',' ) ).Len() )
816             eRet.nOutlineLevel = static_cast<sal_uInt16>(sTmp.ToInt32()); //the maximum outline level to examine
817         break;
818 
819     case TOKEN_TEXT:
820         {
821             xub_StrLen nStartText = sToken.Search( TOX_STYLE_DELIMITER );
822             if( STRING_NOTFOUND != nStartText )
823             {
824                 xub_StrLen nEndText = sToken.Search( TOX_STYLE_DELIMITER,
825                                                 nStartText + 1);
826                 if( STRING_NOTFOUND != nEndText )
827                 {
828                     eRet.sText = sToken.Copy( nStartText + 1,
829                                                 nEndText - nStartText - 1);
830                 }
831             }
832         }
833         break;
834 
835     case TOKEN_TAB_STOP:
836         if( (sTmp = sToken.GetToken( 2, ',' ) ).Len() )
837             eRet.nTabStopPosition = sTmp.ToInt32();
838 
839         if( (sTmp = sToken.GetToken( 3, ',' ) ).Len() )
840             eRet.eTabAlign = static_cast<SvxTabAdjust>(sTmp.ToInt32());
841 
842         if( (sTmp = sToken.GetToken( 4, ',' ) ).Len() )
843             eRet.cTabFillChar = sTmp.GetChar(0);
844 
845         if( (sTmp = sToken.GetToken( 5, ',' ) ).Len() )
846             eRet.bWithTab = 0 != sTmp.ToInt32();
847         break;
848 
849     case TOKEN_CHAPTER_INFO:
850         if( (sTmp = sToken.GetToken( 2, ',' ) ).Len() )
851             eRet.nChapterFormat = static_cast<sal_uInt16>(sTmp.ToInt32()); //SwChapterFormat;
852  //i53420
853         if( (sTmp = sToken.GetToken( 3, ',' ) ).Len() )
854             eRet.nOutlineLevel = static_cast<sal_uInt16>(sTmp.ToInt32()); //the maximum outline level to examine
855 
856         break;
857 
858     case TOKEN_AUTHORITY:
859         eRet.nAuthorityField = static_cast<sal_uInt16>(sAuthFieldEnum.ToInt32());
860         break;
861     default: break;
862     }
863     return eRet;
864 }
865 
866 String SwFormTokensHelper::SearchNextToken( const String & sPattern,
867                                             xub_StrLen nStt ) const
868 {
869     //it's not so easy - it doesn't work if the text part contains a '>'
870     //sal_uInt16 nTokenEnd = sPattern.Search('>');
871 
872     String aResult;
873 
874     xub_StrLen nEnd = sPattern.Search( '>', nStt );
875     if( STRING_NOTFOUND == nEnd )
876     {
877         nEnd = sPattern.Len();
878     }
879     else
880     {
881         xub_StrLen nTextSeparatorFirst = sPattern.Search( TOX_STYLE_DELIMITER, nStt );
882         if( STRING_NOTFOUND != nTextSeparatorFirst )
883         {
884             xub_StrLen nTextSeparatorSecond = sPattern.Search( TOX_STYLE_DELIMITER,
885                                                                nTextSeparatorFirst + 1 );
886             if( STRING_NOTFOUND != nTextSeparatorSecond &&
887                 nEnd > nTextSeparatorFirst )
888                 nEnd = sPattern.Search( '>', nTextSeparatorSecond );
889         }
890 
891         ++nEnd;
892 
893         aResult = sPattern.Copy( nStt, nEnd - nStt );
894     }
895 
896     return aResult;
897 }
898 
899 FormTokenType SwFormTokensHelper::GetTokenType(const String & sToken,
900                                                xub_StrLen * pTokenLen) const
901 {
902     static struct
903     {
904         const sal_Char* pNm;
905         sal_uInt16 nLen;
906         sal_uInt16 nOffset;
907         FormTokenType eToken;
908     } __READONLY_DATA aTokenArr[] = {
909         { SwForm::aFormTab,       SwForm::nFormEntryLen,      1, TOKEN_TAB_STOP },
910         { SwForm::aFormPageNums,  SwForm::nFormPageNumsLen,   1, TOKEN_PAGE_NUMS },
911         { SwForm::aFormLinkStt,   SwForm::nFormLinkSttLen,    1, TOKEN_LINK_START },
912         { SwForm::aFormLinkEnd,   SwForm::nFormLinkEndLen,    1, TOKEN_LINK_END },
913         { SwForm::aFormEntryNum,  SwForm::nFormEntryNumLen,   1, TOKEN_ENTRY_NO },
914         { SwForm::aFormEntryTxt,  SwForm::nFormEntryTxtLen,   1, TOKEN_ENTRY_TEXT },
915         { SwForm::aFormChapterMark,SwForm::nFormChapterMarkLen,1,TOKEN_CHAPTER_INFO },
916         { SwForm::aFormText,      SwForm::nFormTextLen,       1, TOKEN_TEXT },
917         { SwForm::aFormEntry,     SwForm::nFormEntryLen,      1, TOKEN_ENTRY },
918         { SwForm::aFormAuth,      SwForm::nFormAuthLen,       3, TOKEN_AUTHORITY },
919         { 0,                      0,                          0, TOKEN_END }
920     };
921 
922     FormTokenType eTokenType = TOKEN_TEXT;
923     xub_StrLen nTokenLen = 0;
924     const sal_Char* pNm;
925     for( int i = 0; 0 != ( pNm = aTokenArr[ i ].pNm ); ++i )
926         if( COMPARE_EQUAL == sToken.CompareToAscii( pNm,
927                             aTokenArr[ i ].nLen - aTokenArr[ i ].nOffset ))
928         {
929             eTokenType = aTokenArr[ i ].eToken;
930             nTokenLen = aTokenArr[ i ].nLen;
931             break;
932         }
933 
934     ASSERT( pNm, "wrong token" );
935     if (pTokenLen)
936         *pTokenLen = nTokenLen;
937 
938     return eTokenType;
939 }
940 
941 // <- #i21237#
942 
943 void SwForm::SetPattern(sal_uInt16 nLevel, const SwFormTokens& rTokens)
944 {
945 	ASSERT(nLevel < GetFormMax(), "Index >= FORM_MAX");
946 	aPattern[nLevel] = rTokens;
947 }
948 
949 void SwForm::SetPattern(sal_uInt16 nLevel, const String & rStr)
950 {
951 	ASSERT(nLevel < GetFormMax(), "Index >= FORM_MAX");
952 
953     SwFormTokensHelper aHelper(rStr);
954 	aPattern[nLevel] = aHelper.GetTokens();
955 }
956 
957 const SwFormTokens& SwForm::GetPattern(sal_uInt16 nLevel) const
958 {
959 	ASSERT(nLevel < GetFormMax(), "Index >= FORM_MAX");
960 	return aPattern[nLevel];
961 }
962 
963