update dev300-m58
[ooovba.git] / sw / source / core / txtnode / thints.cxx
blob7802c1d576217ff9e3229901f3096fba26cdc919
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: thints.cxx,v $
10 * $Revision: 1.65.62.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
35 #include <hintids.hxx>
36 #include <sot/factory.hxx>
37 #include <svx/xmlcnitm.hxx>
38 #include <svtools/whiter.hxx>
39 #include <svtools/itemiter.hxx>
40 #include <svtools/stylepool.hxx>
41 #include <svx/fontitem.hxx>
42 #include <svx/langitem.hxx>
43 #include <svx/emphitem.hxx>
44 #include <svx/charscaleitem.hxx>
45 #include <svx/charrotateitem.hxx>
46 // --> OD 2008-01-16 #newlistlevelattrs#
47 #include <svx/lrspitem.hxx>
48 // <--
49 #include <txtinet.hxx>
50 #include <txtflcnt.hxx>
51 #include <fmtfld.hxx>
52 #include <fmtanchr.hxx>
53 #include <fmtinfmt.hxx>
54 #include <txtatr.hxx>
55 #include <fchrfmt.hxx>
56 #include <fmtautofmt.hxx>
57 #include <fmtflcnt.hxx>
58 #include <fmtftn.hxx>
59 #include <txttxmrk.hxx>
60 #include <txtrfmrk.hxx>
61 #include <txtftn.hxx>
62 #include <txtfld.hxx>
63 #include <charatr.hxx>
64 #include <charfmt.hxx>
65 #include <frmfmt.hxx>
66 #include <ftnidx.hxx>
67 #include <fmtruby.hxx>
68 #include <breakit.hxx>
69 #include <doc.hxx>
70 #include <errhdl.hxx>
71 #include <fldbas.hxx>
72 #include <pam.hxx>
73 #include <ndtxt.hxx>
74 #include <txtfrm.hxx>
75 #include <rolbck.hxx> // fuer SwRegHistory
76 #include <ddefld.hxx>
77 #include <docufld.hxx>
78 #include <expfld.hxx>
79 #include <usrfld.hxx>
80 #include <poolfmt.hxx>
81 #include <swfont.hxx>
82 #include <istyleaccess.hxx>
83 // OD 26.06.2003 #108784#
84 #include <dcontact.hxx>
85 #include <docsh.hxx>
86 #include <svtools/smplhint.hxx>
87 #include <algorithm>
88 #include <map>
90 #ifndef PRODUCT
91 #define CHECK Check();
92 #else
93 #define CHECK
94 #endif
96 using namespace ::com::sun::star::i18n;
99 SwpHints::SwpHints()
100 : m_pHistory(0)
101 , m_bFontChange(true)
102 , m_bInSplitNode(false)
103 , m_bCalcHiddenParaField(false)
104 , m_bHasHiddenParaField(false)
105 , m_bFootnote(false)
106 , m_bDDEFields(false)
111 // This function takes care for the following text attribute:
112 // RES_TXTATR_CHARFMT, RES_TXTATR_INETFMT, RES_TXTATR_AUTOFMT, and
113 // RES_TXTATR_CJK_RUBY. These attributes have to be handled in a
114 // special way (Portion building).
115 // 1. New attribute is RES_TXTATR_AUTOFMT or RES_TXTATR_CHARFMT:
116 // The new attribute will be split by any existing RES_TXTATR_AUTOFMT,
117 // RES_TXTATR_CHARFMT or RES_TXTATR_INETFMT. The new attribute itself will
118 // split any existing RES_TXTATR_AUTOFMT or RES_TXTATR_CHARFMT.
119 // 2. New attribute is RES_TXTATR_INETFMT:
120 // The new attribute will split any existing RES_TXTATR_AUTOFMT or RES_TXTATR_CHARFMT.
121 // The new attribute will suppress any existing RES_TXTATR_INETFMT.
122 // 3. New attribute is RES_TXTATR_CJK_RUBY:
123 // The new attribute will suppress any existing RES_TXTATR_CJK_RUBY.
125 void SwpHints::BuildPortions( SwTxtNode& rNode, SwTxtAttr& rNewHint, USHORT nMode )
127 ASSERT( RES_TXTATR_CHARFMT == rNewHint.Which() ||
128 RES_TXTATR_INETFMT == rNewHint.Which() ||
129 RES_TXTATR_AUTOFMT == rNewHint.Which() ||
130 RES_TXTATR_CJK_RUBY == rNewHint.Which(),
131 "Expecting CHARFMT or AUTOFMT or INETFMT or RUBY" )
133 const USHORT nWhich = rNewHint.Which();
135 const xub_StrLen nThisStart = *rNewHint.GetStart();
136 const xub_StrLen nThisEnd = *rNewHint.GetEnd();
137 const bool bNoLengthAttribute = nThisStart == nThisEnd;
139 std::vector<SwTxtAttr*> aInsDelHints;
140 std::vector<SwTxtAttr*>::iterator aIter;
143 // 1. Some attributes are not allowed to overlap.
144 // They should displace attributes of the same kind.
145 // This is a special case for RES_TXTATR_INETFMT and
146 // RES_TXTATR_CJK_RUBY.
148 if ( RES_TXTATR_INETFMT == nWhich || RES_TXTATR_CJK_RUBY == nWhich )
150 for ( USHORT i = 0; i < Count(); ++i )
152 SwTxtAttr* pOther = GetTextHint(i);
154 if ( nWhich == pOther->Which() )
156 xub_StrLen nOtherStart = *pOther->GetStart();
157 const xub_StrLen nOtherEnd = *pOther->GetEnd();
159 // Check if start of new attribute overlaps with pOther.
160 // Split pOther if necessary:
161 if ( nOtherStart < nThisStart && nThisStart < nOtherEnd )
163 SwTxtAttr* pNewAttr = rNode.MakeTxtAttr( pOther->GetAttr(), nOtherStart, nThisStart );
164 aInsDelHints.push_back( pNewAttr );
166 NoteInHistory( pOther );
167 *pOther->GetStart() = nThisStart;
168 NoteInHistory( pOther, true );
169 nOtherStart = nThisStart;
172 // Check if end of new attribute overlaps with pOther:
173 // Split pOther if necessary:
174 if ( nOtherStart < nThisEnd && nThisEnd < nOtherEnd )
176 SwTxtAttr* pNewAttr = rNode.MakeTxtAttr( pOther->GetAttr(),
177 nOtherStart, nThisEnd );
178 aInsDelHints.push_back( pNewAttr );
180 NoteInHistory( pOther );
181 *pOther->GetStart() = nThisEnd;
182 NoteInHistory( pOther, true );
187 // Insert the newly created attributes:
188 const sal_uInt16 nCharFmtID = static_cast<sal_uInt16>( RES_TXTATR_INETFMT == nWhich ?
189 RES_POOLCHR_INET_NORMAL :
190 RES_POOLCHR_RUBYTEXT );
191 SwCharFmt* pFmt = rNode.GetDoc()->GetCharFmtFromPool( nCharFmtID );
193 for ( aIter = aInsDelHints.begin(); aIter != aInsDelHints.end(); ++aIter )
195 if ( RES_TXTATR_INETFMT == nWhich )
197 SwTxtINetFmt* pInetAttr = static_cast<SwTxtINetFmt*>(*aIter);
198 pInetAttr->ChgTxtNode( &rNode );
199 pFmt->Add( pInetAttr );
203 else
205 SwTxtRuby* pRubyAttr = static_cast<SwTxtRuby*>(*aIter);
206 pRubyAttr->ChgTxtNode( &rNode );
207 pFmt->Add( pRubyAttr );
211 SwpHintsArray::Insert( *aIter );
212 NoteInHistory( *aIter, true );
215 aInsDelHints.clear();
217 // Now delete all attributes of the same type as the new one
218 // which are fully covered by the new attribute:
219 for ( USHORT i = 0; i < Count(); ++i )
221 SwTxtAttr* pOther = GetTextHint(i);
222 if ( nWhich == pOther->Which() )
224 const xub_StrLen nOtherStart = *pOther->GetStart();
225 const xub_StrLen nOtherEnd = *pOther->GetEnd();
227 if ( nOtherStart >= nThisStart && nOtherEnd <= nThisEnd )
228 aInsDelHints.push_back( pOther );
231 for ( aIter = aInsDelHints.begin(); aIter != aInsDelHints.end(); ++aIter )
233 Delete( *aIter );
234 rNode.DestroyAttr( *aIter );
237 SwpHintsArray::Insert( &rNewHint );
238 NoteInHistory( &rNewHint, true );
240 return;
243 ASSERT( RES_TXTATR_CHARFMT == rNewHint.Which() ||
244 RES_TXTATR_AUTOFMT == rNewHint.Which(),
245 "Expecting CHARFMT or AUTOFMT" )
248 // 2. Find the hints which cover the start and end position
249 // of the new hint. These hints have to be split into two portions:
251 if ( !bNoLengthAttribute ) // nothing to do for no length attributes
253 for ( USHORT i = 0; i < Count(); ++i )
255 SwTxtAttr* pOther = GetTextHint(i);
257 if ( RES_TXTATR_CHARFMT != pOther->Which() &&
258 RES_TXTATR_AUTOFMT != pOther->Which() )
259 continue;
261 xub_StrLen nOtherStart = *pOther->GetStart();
262 const xub_StrLen nOtherEnd = *pOther->GetEnd();
264 // Check if start of new attribute overlaps with pOther:
265 // Split pOther if necessary:
266 if ( nOtherStart < nThisStart && nThisStart < nOtherEnd )
268 SwTxtAttr* pNewAttr = rNode.MakeTxtAttr( pOther->GetAttr(), nOtherStart, nThisStart );
269 if ( RES_TXTATR_CHARFMT == pOther->Which() )
270 static_cast<SwTxtCharFmt*>(pNewAttr)->SetSortNumber( static_cast<SwTxtCharFmt*>(pOther)->GetSortNumber() );
271 aInsDelHints.push_back( pNewAttr );
273 NoteInHistory( pOther );
274 *pOther->GetStart() = nThisStart;
275 NoteInHistory( pOther, true );
277 nOtherStart = nThisStart;
280 // Check if end of new attribute overlaps with pOther:
281 // Split pOther if necessary:
282 if ( nOtherStart < nThisEnd && nThisEnd < nOtherEnd )
284 SwTxtAttr* pNewAttr = rNode.MakeTxtAttr( pOther->GetAttr(), nOtherStart, nThisEnd );
285 if ( RES_TXTATR_CHARFMT == pOther->Which() )
286 static_cast<SwTxtCharFmt*>(pNewAttr)->SetSortNumber( static_cast<SwTxtCharFmt*>(pOther)->GetSortNumber() );
287 aInsDelHints.push_back( pNewAttr );
289 NoteInHistory( pOther );
290 *pOther->GetStart() = nThisEnd;
291 NoteInHistory( pOther, true );
295 // Insert the newly created attributes:
296 for ( aIter = aInsDelHints.begin(); aIter != aInsDelHints.end(); ++aIter )
298 SwpHintsArray::Insert( *aIter );
299 NoteInHistory( *aIter, true );
303 #ifndef PRODUCT
304 if( !rNode.GetDoc()->IsInReading() )
305 CHECK;
306 #endif
309 // 4. Split rNewHint into 1 ... n new hints:
311 std::set<xub_StrLen> aBounds;
312 aBounds.insert( nThisStart );
313 aBounds.insert( nThisEnd );
315 if ( !bNoLengthAttribute ) // nothing to do for no length attributes
317 for ( USHORT i = 0; i < Count(); ++i )
319 const SwTxtAttr* pOther = GetTextHint(i);
321 if ( RES_TXTATR_CHARFMT != pOther->Which() &&
322 RES_TXTATR_AUTOFMT != pOther->Which() )
323 continue;
325 const xub_StrLen nOtherStart = *pOther->GetStart();
326 const xub_StrLen nOtherEnd = *pOther->GetEnd();
328 aBounds.insert( nOtherStart );
329 aBounds.insert( nOtherEnd );
333 std::set<xub_StrLen>::iterator aStartIter = aBounds.lower_bound( nThisStart );
334 std::set<xub_StrLen>::iterator aEndIter = aBounds.upper_bound( nThisEnd );
335 xub_StrLen nPorStart = *aStartIter;
336 ++aStartIter;
337 bool bDestroyHint = true;
340 // Insert the 1...n new parts of the new attribute:
342 while ( aStartIter != aEndIter || bNoLengthAttribute )
344 ASSERT( bNoLengthAttribute || nPorStart < *aStartIter, "AUTOSTYLES: BuildPortion trouble" )
346 const xub_StrLen nPorEnd = bNoLengthAttribute ? nPorStart : *aStartIter;
347 aInsDelHints.clear();
349 // Get all hints that are in [nPorStart, nPorEnd[:
350 for ( USHORT i = 0; i < Count(); ++i )
352 SwTxtAttr *pOther = GetTextHint(i);
354 if ( RES_TXTATR_CHARFMT != pOther->Which() &&
355 RES_TXTATR_AUTOFMT != pOther->Which() )
356 continue;
358 const xub_StrLen nOtherStart = *pOther->GetStart();
360 if ( nOtherStart > nPorStart )
361 break;
363 if ( pOther->GetEnd() && *pOther->GetEnd() == nPorEnd && nOtherStart == nPorStart )
365 ASSERT( *pOther->GetEnd() == nPorEnd, "AUTOSTYLES: BuildPortion trouble" )
366 aInsDelHints.push_back( pOther );
370 SwTxtAttr* pNewAttr = 0;
371 if ( RES_TXTATR_CHARFMT == nWhich )
373 // pNewHint can be inserted after calculating the sort value.
374 // This should ensure, that pNewHint comes behind the already present
375 // character style
376 USHORT nCharStyleCount = 0;
377 aIter = aInsDelHints.begin();
378 while ( aIter != aInsDelHints.end() )
380 if ( RES_TXTATR_CHARFMT == (*aIter)->Which() )
382 // --> FME 2007-02-16 #i74589#
383 const SwFmtCharFmt& rOtherCharFmt = (*aIter)->GetCharFmt();
384 const SwFmtCharFmt& rThisCharFmt = rNewHint.GetCharFmt();
385 const bool bSameCharFmt = rOtherCharFmt.GetCharFmt() == rThisCharFmt.GetCharFmt();
386 // <--
388 // --> OD 2009-03-24 #i90311#
389 // Do not remove existing character format hint during XML import
390 if ( !rNode.GetDoc()->IsInXMLImport() &&
391 ( !( nsSetAttrMode::SETATTR_DONTREPLACE & nMode ) ||
392 bNoLengthAttribute ||
393 bSameCharFmt ) )
394 // <--
396 // Remove old hint
397 Delete( *aIter );
398 rNode.DestroyAttr( *aIter );
400 else
401 ++nCharStyleCount;
403 else
405 // remove all attributes from auto styles, which are explicitely set in
406 // the new character format:
407 ASSERT( RES_TXTATR_AUTOFMT == (*aIter)->Which(), "AUTOSTYLES - Misc trouble" )
408 SwTxtAttr* pOther = *aIter;
409 boost::shared_ptr<SfxItemSet> pOldStyle = static_cast<const SwFmtAutoFmt&>(pOther->GetAttr()).GetStyleHandle();
411 // For each attribute in the automatic style check if it
412 // is also set the the new character style:
413 SfxItemSet aNewSet( *pOldStyle->GetPool(), RES_CHRATR_BEGIN, RES_CHRATR_END );
414 SfxItemIter aItemIter( *pOldStyle );
415 const SfxPoolItem* pItem = aItemIter.GetCurItem();
416 while( TRUE )
418 if ( !CharFmt::IsItemIncluded( pItem->Which(), &rNewHint ) )
420 aNewSet.Put( *pItem );
423 if( aItemIter.IsAtEnd() )
424 break;
426 pItem = aItemIter.NextItem();
429 // Remove old hint
430 Delete( pOther );
431 rNode.DestroyAttr( pOther );
433 // Create new AutoStyle
434 if ( aNewSet.Count() )
436 pNewAttr = rNode.MakeTxtAttr( aNewSet,
437 nPorStart, nPorEnd );
438 SwpHintsArray::Insert( pNewAttr );
439 NoteInHistory( pNewAttr, true );
442 ++aIter;
445 // If there is no current hint and start and end of rNewHint
446 // is ok, we do not need to create a new txtattr.
447 if ( nPorStart == nThisStart &&
448 nPorEnd == nThisEnd &&
449 !nCharStyleCount )
451 pNewAttr = &rNewHint;
452 bDestroyHint = false;
454 else
456 pNewAttr = rNode.MakeTxtAttr( rNewHint.GetAttr(), nPorStart, nPorEnd );
457 static_cast<SwTxtCharFmt*>(pNewAttr)->SetSortNumber( nCharStyleCount );
460 else
462 // Find the current autostyle. Mix attributes if necessary.
463 SwTxtAttr* pCurrentAutoStyle = 0;
464 SwTxtAttr* pCurrentCharFmt = 0;
465 aIter = aInsDelHints.begin();
466 while ( aIter != aInsDelHints.end() )
468 if ( RES_TXTATR_AUTOFMT == (*aIter)->Which() )
469 pCurrentAutoStyle = *aIter;
470 else if ( RES_TXTATR_CHARFMT == (*aIter)->Which() )
471 pCurrentCharFmt = *aIter;
472 ++aIter;
475 boost::shared_ptr<SfxItemSet> pNewStyle = static_cast<const SwFmtAutoFmt&>(rNewHint.GetAttr()).GetStyleHandle();
476 if ( pCurrentAutoStyle )
478 boost::shared_ptr<SfxItemSet> pCurrentStyle = static_cast<const SwFmtAutoFmt&>(pCurrentAutoStyle->GetAttr()).GetStyleHandle();
480 // Merge attributes
481 SfxItemSet aNewSet( *pCurrentStyle );
482 aNewSet.Put( *pNewStyle );
484 // --> FME 2007-4-11 #i75750# Remove attributes already set at whole paragraph
485 // --> FME 2007-09-24 #i81764# This should not be applied for no length attributes!!! <--
486 if ( !bNoLengthAttribute && rNode.HasSwAttrSet() && aNewSet.Count() )
488 SfxItemIter aIter2( aNewSet );
489 const SfxPoolItem* pItem = aIter2.GetCurItem();
490 const SfxItemSet& rWholeParaAttrSet = rNode.GetSwAttrSet();
494 const SfxPoolItem* pTmpItem = 0;
495 if ( SFX_ITEM_SET == rWholeParaAttrSet.GetItemState( pItem->Which(), FALSE, &pTmpItem ) &&
496 pTmpItem == pItem )
498 // Do not clear item if the attribute is set in a character format:
499 if ( !pCurrentCharFmt || 0 == CharFmt::GetItem( *pCurrentCharFmt, pItem->Which() ) )
500 aNewSet.ClearItem( pItem->Which() );
503 while (!aIter2.IsAtEnd() && 0 != (pItem = aIter2.NextItem()));
505 // <--
507 // Remove old hint
508 Delete( pCurrentAutoStyle );
509 rNode.DestroyAttr( pCurrentAutoStyle );
511 // Create new AutoStyle
512 if ( aNewSet.Count() )
513 pNewAttr = rNode.MakeTxtAttr( aNewSet, nPorStart, nPorEnd );
515 else
517 // Remove any attributes which are already set at the whole paragraph:
518 bool bOptimizeAllowed = true;
520 SfxItemSet* pNewSet = 0;
521 // --> FME 2007-4-11 #i75750# Remove attributes already set at whole paragraph
522 // --> FME 2007-09-24 #i81764# This should not be applied for no length attributes!!! <--
523 if ( !bNoLengthAttribute && rNode.HasSwAttrSet() && pNewStyle->Count() )
525 SfxItemIter aIter2( *pNewStyle );
526 const SfxPoolItem* pItem = aIter2.GetCurItem();
527 const SfxItemSet& rWholeParaAttrSet = rNode.GetSwAttrSet();
531 const SfxPoolItem* pTmpItem = 0;
532 if ( SFX_ITEM_SET == rWholeParaAttrSet.GetItemState( pItem->Which(), FALSE, &pTmpItem ) &&
533 pTmpItem == pItem )
535 // Do not clear item if the attribute is set in a character format:
536 if ( !pCurrentCharFmt || 0 == CharFmt::GetItem( *pCurrentCharFmt, pItem->Which() ) )
538 if ( !pNewSet )
539 pNewSet = pNewStyle->Clone( TRUE );
540 pNewSet->ClearItem( pItem->Which() );
544 while (!aIter2.IsAtEnd() && 0 != (pItem = aIter2.NextItem()));
546 if ( pNewSet )
548 bOptimizeAllowed = false;
549 if ( pNewSet->Count() )
550 pNewStyle = rNode.getIDocumentStyleAccess().getAutomaticStyle( *pNewSet, IStyleAccess::AUTO_STYLE_CHAR );
551 else
552 pNewStyle.reset();
554 delete pNewSet;
557 // <--
559 // Create new AutoStyle
560 // If there is no current hint and start and end of rNewHint
561 // is ok, we do not need to create a new txtattr.
562 if ( bOptimizeAllowed &&
563 nPorStart == nThisStart &&
564 nPorEnd == nThisEnd )
566 pNewAttr = &rNewHint;
567 bDestroyHint = false;
569 else if ( pNewStyle.get() )
571 pNewAttr = rNode.MakeTxtAttr( *pNewStyle, nPorStart, nPorEnd );
576 if ( pNewAttr )
578 SwpHintsArray::Insert( pNewAttr );
579 // if ( bDestroyHint )
580 NoteInHistory( pNewAttr, true );
583 if ( !bNoLengthAttribute )
585 nPorStart = *aStartIter;
586 ++aStartIter;
588 else
589 break;
592 if ( bDestroyHint )
593 rNode.DestroyAttr( &rNewHint );
596 /*************************************************************************
597 * SwTxtNode::MakeTxtAttr()
598 *************************************************************************/
600 // create new text attribute
601 SwTxtAttr* SwTxtNode::MakeTxtAttr( const SfxPoolItem& rAttr,
602 xub_StrLen nStt, xub_StrLen nEnd, bool bRedlineAttr )
604 SwDoc* pDoc = GetDoc();
606 if ( !bRedlineAttr && isCHRATR(rAttr.Which()) )
608 // Somebody wants to build a SwTxtAttr for a character attribute (and
609 // this attribute is not meant for redlining). Sorry, this is not allowed
610 // any longer. You'll get a brand new autostyle attribute:
611 SfxItemSet aItemSet( pDoc->GetAttrPool(), RES_CHRATR_BEGIN, RES_CHRATR_END );
612 aItemSet.Put( rAttr );
613 return MakeTxtAttr( aItemSet, nStt, nEnd );
615 else if ( RES_TXTATR_AUTOFMT == rAttr.Which() &&
616 static_cast<const SwFmtAutoFmt&>(rAttr).GetStyleHandle()->GetPool() != &pDoc->GetAttrPool() )
618 // If the attribut is an autostyle which referes to a pool that is different from
619 // pDoc's pool, we have to correct this:
620 const StylePool::SfxItemSet_Pointer_t pAutoStyle = static_cast<const SwFmtAutoFmt&>(rAttr).GetStyleHandle();
621 const SfxItemSet* pNewSet = pAutoStyle->SfxItemSet::Clone( TRUE, &pDoc->GetAttrPool() );
622 SwTxtAttr* pNew = MakeTxtAttr( *pNewSet, nStt, nEnd );
623 delete pNewSet;
624 return pNew;
627 // Put new attribute into pool unless we are asked to build a redline attribute
628 const SfxPoolItem& rNew = !bRedlineAttr ? GetDoc()->GetAttrPool().Put( rAttr ) : rAttr;
630 SwTxtAttr* pNew = 0;
631 switch( rNew.Which() )
633 case RES_TXTATR_CHARFMT:
635 SwFmtCharFmt &rFmtCharFmt = (SwFmtCharFmt&) rNew;
636 if( !rFmtCharFmt.GetCharFmt() )
637 rFmtCharFmt.SetCharFmt( GetDoc()->GetDfltCharFmt() );
639 pNew = new SwTxtCharFmt( rFmtCharFmt, nStt, nEnd );
641 break;
642 case RES_TXTATR_INETFMT:
643 pNew = new SwTxtINetFmt( (SwFmtINetFmt&)rNew, nStt, nEnd );
644 break;
645 case RES_TXTATR_FIELD:
646 pNew = new SwTxtFld( (SwFmtFld&)rNew, nStt );
647 break;
648 case RES_TXTATR_FLYCNT:
650 // erst hier wird das Frame-Format kopiert (mit Inhalt) !!
651 pNew = new SwTxtFlyCnt( (SwFmtFlyCnt&)rNew, nStt );
652 // Kopie von einem Text-Attribut
653 if( ((SwFmtFlyCnt&)rAttr).GetTxtFlyCnt() )
654 // dann muss das Format Kopiert werden
655 ((SwTxtFlyCnt*)pNew)->CopyFlyFmt( GetDoc() );
657 break;
658 case RES_TXTATR_FTN:
659 pNew = new SwTxtFtn( (SwFmtFtn&)rNew, nStt );
660 // ggfs. SeqNo kopieren
661 if( ((SwFmtFtn&)rAttr).GetTxtFtn() )
662 ((SwTxtFtn*)pNew)->SetSeqNo( ((SwFmtFtn&)rAttr).GetTxtFtn()->GetSeqRefNo() );
663 break;
664 case RES_TXTATR_HARDBLANK:
665 pNew = new SwTxtHardBlank( (SwFmtHardBlank&)rNew, nStt );
666 break;
667 case RES_CHRATR_TWO_LINES:
668 pNew = new SwTxt2Lines( (SvxTwoLinesItem&)rNew, nStt, nEnd );
669 break;
670 case RES_TXTATR_REFMARK:
671 pNew = nStt == nEnd
672 ? new SwTxtRefMark( (SwFmtRefMark&)rNew, nStt )
673 : new SwTxtRefMark( (SwFmtRefMark&)rNew, nStt, &nEnd );
674 break;
675 case RES_TXTATR_TOXMARK:
676 pNew = new SwTxtTOXMark( (SwTOXMark&)rNew, nStt, &nEnd );
677 break;
678 case RES_UNKNOWNATR_CONTAINER:
679 case RES_TXTATR_UNKNOWN_CONTAINER:
680 pNew = new SwTxtXMLAttrContainer( (SvXMLAttrContainerItem&)rNew,
681 nStt, nEnd );
682 break;
683 case RES_TXTATR_CJK_RUBY:
684 pNew = new SwTxtRuby( (SwFmtRuby&)rNew, nStt, nEnd );
685 break;
686 default:
687 pNew = new SwTxtAttrEnd( rNew, nStt, nEnd );
688 break;
691 return pNew;
694 SwTxtAttr* SwTxtNode::MakeTxtAttr( const SfxItemSet& rSet, xub_StrLen nStt, xub_StrLen nEnd )
696 IStyleAccess& rStyleAccess = getIDocumentStyleAccess();
697 const StylePool::SfxItemSet_Pointer_t pAutoStyle = rStyleAccess.getAutomaticStyle( rSet, IStyleAccess::AUTO_STYLE_CHAR );
698 SwFmtAutoFmt aNewAutoFmt;
699 aNewAutoFmt.SetStyleHandle( pAutoStyle );
700 SwTxtAttr* pNew = MakeTxtAttr( aNewAutoFmt, nStt, nEnd );
701 return pNew;
705 // loesche das Text-Attribut (muss beim Pool abgemeldet werden!)
706 void SwTxtNode::DestroyAttr( SwTxtAttr* pAttr )
708 if( pAttr )
710 // einige Sachen muessen vorm Loeschen der "Format-Attribute" erfolgen
711 SwDoc* pDoc = GetDoc();
712 USHORT nDelMsg = 0;
713 switch( pAttr->Which() )
715 case RES_TXTATR_FLYCNT:
717 // siehe auch die Anmerkung "Loeschen von Formaten
718 // zeichengebundener Frames" in fesh.cxx, SwFEShell::DelFmt()
719 SwFrmFmt* pFmt = pAttr->GetFlyCnt().GetFrmFmt();
720 if( pFmt ) // vom Undo auf 0 gesetzt ??
721 pDoc->DelLayoutFmt( (SwFlyFrmFmt*)pFmt );
723 break;
725 case RES_CHRATR_HIDDEN:
726 SetCalcHiddenCharFlags();
727 break;
729 case RES_TXTATR_FTN:
730 ((SwTxtFtn*)pAttr)->SetStartNode( 0 );
731 nDelMsg = RES_FOOTNOTE_DELETED;
732 break;
734 case RES_TXTATR_FIELD:
735 if( !pDoc->IsInDtor() )
737 // Wenn wir ein HiddenParaField sind, dann muessen wir
738 // ggf. fuer eine Neuberechnung des Visible-Flags sorgen.
739 const SwField* pFld = pAttr->GetFld().GetFld();
741 //JP 06-08-95: DDE-Felder bilden eine Ausnahme
742 ASSERT( RES_DDEFLD == pFld->GetTyp()->Which() ||
743 this == ((SwTxtFld*)pAttr)->GetpTxtNode(),
744 "Wo steht denn dieses Feld?" )
746 // bestimmte Felder mussen am Doc das Calculations-Flag updaten
747 switch( pFld->GetTyp()->Which() )
749 case RES_HIDDENPARAFLD:
750 SetCalcHiddenParaField();
751 // kein break !
752 case RES_DBSETNUMBERFLD:
753 case RES_GETEXPFLD:
754 case RES_DBFLD:
755 case RES_SETEXPFLD:
756 case RES_HIDDENTXTFLD:
757 case RES_DBNUMSETFLD:
758 case RES_DBNEXTSETFLD:
759 if( !pDoc->IsNewFldLst() && GetNodes().IsDocNodes() )
760 pDoc->InsDelFldInFldLst( FALSE, *(SwTxtFld*)pAttr );
761 break;
762 case RES_DDEFLD:
763 if( GetNodes().IsDocNodes() &&
764 ((SwTxtFld*)pAttr)->GetpTxtNode() )
765 ((SwDDEFieldType*)pFld->GetTyp())->DecRefCnt();
766 break;
767 case RES_POSTITFLD:
769 const_cast<SwFmtFld&>(pAttr->GetFld()).Broadcast( SwFmtFldHint( &((SwTxtFld*)pAttr)->GetFld(), SWFMTFLD_REMOVED ) );
770 break;
774 nDelMsg = RES_FIELD_DELETED;
775 break;
777 case RES_TXTATR_TOXMARK:
778 nDelMsg = RES_TOXMARK_DELETED;
779 break;
781 case RES_TXTATR_REFMARK:
782 nDelMsg = RES_REFMARK_DELETED;
783 break;
786 if( nDelMsg && !pDoc->IsInDtor() && GetNodes().IsDocNodes() )
788 SwPtrMsgPoolItem aMsgHint( nDelMsg, (void*)&pAttr->GetAttr() );
789 pDoc->GetUnoCallBack()->Modify( &aMsgHint, &aMsgHint );
792 pAttr->RemoveFromPool( pDoc->GetAttrPool() );
793 delete pAttr;
797 /*************************************************************************
798 * SwTxtNode::Insert()
799 *************************************************************************/
801 // lege ein neues TextAttribut an und fuege es ins SwpHints-Array ein
802 SwTxtAttr* SwTxtNode::InsertItem( const SfxPoolItem& rAttr,
803 xub_StrLen nStt, xub_StrLen nEnd, USHORT nMode )
805 // character attributes will be inserted as automatic styles:
806 ASSERT( !isCHRATR(rAttr.Which()), "AUTOSTYLES - "
807 "SwTxtNode::InsertItem should not be called with character attributes");
809 SwTxtAttr* pNew = MakeTxtAttr( rAttr, nStt, nEnd );
811 if ( pNew )
812 Insert( pNew, nMode );
814 return pNew;
817 // uebernehme den Pointer auf das Text-Attribut
818 BOOL SwTxtNode::Insert( SwTxtAttr *pAttr, USHORT nMode )
820 BOOL bHiddenPara = FALSE;
822 ASSERT( pAttr && *pAttr->GetStart() <= Len(), "StartIdx hinter Len!" );
824 if( !pAttr->GetEnd() )
826 USHORT nInsMode = nMode;
827 switch( pAttr->Which() )
829 case RES_TXTATR_FLYCNT:
831 SwTxtFlyCnt *pFly = (SwTxtFlyCnt *)pAttr;
832 SwFrmFmt* pFmt = pAttr->GetFlyCnt().GetFrmFmt();
833 if( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode) )
835 // Wir muessen zuerst einfuegen, da in SetAnchor()
836 // dem FlyFrm GetStart() uebermittelt wird.
837 //JP 11.05.98: falls das Anker-Attribut schon richtig
838 // gesetzt ist, dann korrigiere dieses nach dem Einfuegen
839 // des Zeichens. Sonst muesste das immer ausserhalb
840 // erfolgen (Fehleranfaellig !)
841 const SwFmtAnchor* pAnchor = 0;
842 pFmt->GetItemState( RES_ANCHOR, FALSE,
843 (const SfxPoolItem**)&pAnchor );
845 SwIndex aIdx( this, *pAttr->GetStart() );
846 Insert( GetCharOfTxtAttr(*pAttr), aIdx );
847 nInsMode |= nsSetAttrMode::SETATTR_NOTXTATRCHR;
849 if( pAnchor && FLY_IN_CNTNT == pAnchor->GetAnchorId() &&
850 pAnchor->GetCntntAnchor() &&
851 pAnchor->GetCntntAnchor()->nNode == *this &&
852 pAnchor->GetCntntAnchor()->nContent == aIdx )
853 ((SwIndex&)pAnchor->GetCntntAnchor()->nContent)--;
855 pFly->SetAnchor( this );
857 // Format-Pointer kann sich im SetAnchor geaendert haben!
858 // (Kopieren in andere Docs!)
859 pFmt = pAttr->GetFlyCnt().GetFrmFmt();
860 SwDoc *pDoc = pFmt->GetDoc();
862 // OD 26.06.2003 #108784# - allow drawing objects in header/footer.
863 // But don't allow control objects in header/footer
864 if( RES_DRAWFRMFMT == pFmt->Which() &&
865 pDoc->IsInHeaderFooter( pFmt->GetAnchor().GetCntntAnchor()->nNode ) )
867 SwDrawContact* pDrawContact =
868 static_cast<SwDrawContact*>(pFmt->FindContactObj());
869 if ( pDrawContact &&
870 pDrawContact->GetMaster() &&
871 ::CheckControlLayer( pDrawContact->GetMaster() ) )
873 // das soll nicht meoglich sein; hier verhindern
874 // Der Dtor des TxtHints loescht nicht das Zeichen.
875 // Wenn ein CH_TXTATR_.. vorliegt, dann muss man
876 // dieses explizit loeschen
877 if( nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode )
879 // loesche das Zeichen aus dem String !
880 ASSERT( ( CH_TXTATR_BREAKWORD ==
881 m_Text.GetChar(*pAttr->GetStart() ) ||
882 CH_TXTATR_INWORD ==
883 m_Text.GetChar(*pAttr->GetStart())),
884 "where is my attribute character?" );
885 m_Text.Erase( *pAttr->GetStart(), 1 );
886 // Indizies Updaten
887 SwIndex aTmpIdx( this, *pAttr->GetStart() );
888 Update( aTmpIdx, 1, TRUE );
890 // Format loeschen nicht ins Undo aufnehmen!!
891 BOOL bUndo = pDoc->DoesUndo();
892 pDoc->DoUndo( FALSE );
893 DestroyAttr( pAttr );
894 pDoc->DoUndo( bUndo );
895 return FALSE;
898 break;
901 case RES_TXTATR_FTN :
903 // Fussnoten, man kommt an alles irgendwie heran.
904 // CntntNode erzeugen und in die Inserts-Section stellen
905 SwDoc *pDoc = GetDoc();
906 SwNodes &rNodes = pDoc->GetNodes();
908 // FussNote in nicht Content-/Redline-Bereich einfuegen ??
909 if( StartOfSectionIndex() < rNodes.GetEndOfAutotext().GetIndex() )
911 // das soll nicht meoglich sein; hier verhindern
912 // Der Dtor des TxtHints loescht nicht das Zeichen.
913 // Wenn ein CH_TXTATR_.. vorliegt, dann muss man
914 // dieses explizit loeschen
915 if( nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode )
917 // loesche das Zeichen aus dem String !
918 ASSERT( ( CH_TXTATR_BREAKWORD ==
919 m_Text.GetChar(*pAttr->GetStart() ) ||
920 CH_TXTATR_INWORD ==
921 m_Text.GetChar(*pAttr->GetStart())),
922 "where is my attribute character?" );
923 m_Text.Erase( *pAttr->GetStart(), 1 );
924 // Indizies Updaten
925 SwIndex aTmpIdx( this, *pAttr->GetStart() );
926 Update( aTmpIdx, 1, TRUE );
928 DestroyAttr( pAttr );
929 return FALSE;
932 // wird eine neue Fussnote eingefuegt ??
933 BOOL bNewFtn = 0 == ((SwTxtFtn*)pAttr)->GetStartNode();
934 if( bNewFtn )
936 ((SwTxtFtn*)pAttr)->MakeNewTextSection( GetNodes() );
937 SwRegHistory* pHist = GetpSwpHints()
938 ? GetpSwpHints()->GetHistory() : 0;
939 if( pHist )
940 pHist->ChangeNodeIndex( GetIndex() );
942 else if ( !GetpSwpHints() || !GetpSwpHints()->IsInSplitNode() )
944 // loesche alle Frames der Section, auf die der StartNode zeigt
945 ULONG nSttIdx =
946 ((SwTxtFtn*)pAttr)->GetStartNode()->GetIndex();
947 ULONG nEndIdx = rNodes[ nSttIdx++ ]->EndOfSectionIndex();
948 SwCntntNode* pCNd;
949 for( ; nSttIdx < nEndIdx; ++nSttIdx )
950 if( 0 != ( pCNd = rNodes[ nSttIdx ]->GetCntntNode() ))
951 pCNd->DelFrms();
954 if( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode) )
956 // Wir muessen zuerst einfuegen, da sonst gleiche Indizes
957 // entstehen koennen und das Attribut im _SortArr_ am
958 // Dokument nicht eingetrage wird.
959 SwIndex aNdIdx( this, *pAttr->GetStart() );
960 Insert( GetCharOfTxtAttr(*pAttr), aNdIdx );
961 nInsMode |= nsSetAttrMode::SETATTR_NOTXTATRCHR;
964 // Wir tragen uns am FtnIdx-Array des Docs ein ...
965 SwTxtFtn* pTxtFtn = 0;
966 if( !bNewFtn )
968 // eine alte Ftn wird umgehaengt (z.B. SplitNode)
969 for( USHORT n = 0; n < pDoc->GetFtnIdxs().Count(); ++n )
970 if( pAttr == pDoc->GetFtnIdxs()[n] )
972 // neuen Index zuweisen, dafuer aus dem SortArray
973 // loeschen und neu eintragen
974 pTxtFtn = pDoc->GetFtnIdxs()[n];
975 pDoc->GetFtnIdxs().Remove( n );
976 break;
978 // wenn ueber Undo der StartNode gesetzt wurde, kann
979 // der Index noch gar nicht in der Verwaltung stehen !!
981 if( !pTxtFtn )
982 pTxtFtn = (SwTxtFtn*)pAttr;
984 // fuers Update der Nummern und zum Sortieren
985 // muss der Node gesetzt sein.
986 ((SwTxtFtn*)pAttr)->ChgTxtNode( this );
988 // FussNote im Redline-Bereich NICHT ins FtnArray einfuegen!
989 if( StartOfSectionIndex() > rNodes.GetEndOfRedlines().GetIndex() )
991 #ifndef PRODUCT
992 const BOOL bSuccess =
993 #endif
994 pDoc->GetFtnIdxs().Insert( pTxtFtn );
995 #ifndef PRODUCT
996 ASSERT( bSuccess, "FtnIdx nicht eingetragen." );
997 #endif
999 SwNodeIndex aTmpIndex( *this );
1000 pDoc->GetFtnIdxs().UpdateFtn( aTmpIndex);
1001 ((SwTxtFtn*)pAttr)->SetSeqRefNo();
1003 break;
1005 case RES_TXTATR_FIELD:
1007 // fuer HiddenParaFields Benachrichtigungsmechanismus
1008 // anwerfen
1009 if( RES_HIDDENPARAFLD ==
1010 pAttr->GetFld().GetFld()->GetTyp()->Which() )
1011 bHiddenPara = TRUE;
1013 break;
1016 // Fuer SwTxtHints ohne Endindex werden CH_TXTATR_..
1017 // eingefuegt, aStart muss danach um einen zurueckgesetzt werden.
1018 // Wenn wir im SwTxtNode::Copy stehen, so wurde das Zeichen bereits
1019 // mitkopiert. In solchem Fall ist SETATTR_NOTXTATRCHR angegeben worden.
1020 if( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode) )
1022 SwIndex aIdx( this, *pAttr->GetStart() );
1023 Insert( GetCharOfTxtAttr(*pAttr), aIdx );
1026 else {
1027 ASSERT( *pAttr->GetEnd() <= Len(), "EndIdx hinter Len!" );
1030 GetOrCreateSwpHints();
1032 // 4263: AttrInsert durch TextInsert => kein Adjust
1033 m_pSwpHints->Insert( pAttr, *this, nMode );
1035 // 47375: In pSwpHints->Insert wird u.a. Merge gerufen und das Hints-Array
1036 // von ueberfluessigen Hints befreit, dies kann u.U. sogar der frisch
1037 // eingefuegte Hint pAttr sein, der dann zerstoert wird!!
1038 if ( USHRT_MAX == m_pSwpHints->GetPos( pAttr ) )
1040 return FALSE;
1043 if( bHiddenPara )
1044 SetCalcHiddenParaField();
1046 return TRUE;
1050 /*************************************************************************
1051 * SwTxtNode::Delete()
1052 *************************************************************************/
1054 void SwTxtNode::Delete( SwTxtAttr *pAttr, BOOL bThisOnly )
1056 if ( !HasHints() )
1057 return;
1059 if( bThisOnly )
1061 xub_StrLen* pEndIdx = pAttr->GetEnd();
1062 if( !pEndIdx )
1064 // hat es kein Ende kann es nur das sein, was hier steht!
1065 // Unbedingt Copy-konstruieren!
1066 const SwIndex aIdx( this, *pAttr->GetStart() );
1067 Erase( aIdx, 1 );
1069 else
1071 // den MsgHint jetzt fuettern, weil gleich sind
1072 // Start und End weg.
1073 SwUpdateAttr aHint( *pAttr->GetStart(), *pEndIdx, pAttr->Which() );
1074 m_pSwpHints->Delete( pAttr );
1075 pAttr->RemoveFromPool( GetDoc()->GetAttrPool() );
1076 delete pAttr;
1077 SwModify::Modify( 0, &aHint ); // die Frames benachrichtigen
1079 TryDeleteSwpHints();
1082 return;
1084 Delete( pAttr->Which(), *pAttr->GetStart(), *pAttr->GetAnyEnd() );
1087 /*************************************************************************
1088 * SwTxtNode::Delete()
1089 *************************************************************************/
1091 void SwTxtNode::Delete( USHORT nTxtWhich, xub_StrLen nStt, xub_StrLen nEnd )
1093 if ( !HasHints() )
1094 return;
1096 const xub_StrLen *pEndIdx;
1097 const xub_StrLen *pSttIdx;
1098 SwTxtAttr* pTxtHt;
1100 for ( USHORT nPos = 0; m_pSwpHints && nPos < m_pSwpHints->Count(); nPos++ )
1102 pTxtHt = m_pSwpHints->GetTextHint( nPos );
1103 const USHORT nWhich = pTxtHt->Which();
1104 if( nWhich == nTxtWhich &&
1105 *( pSttIdx = pTxtHt->GetStart()) == nStt )
1107 if ( nWhich == RES_CHRATR_HIDDEN )
1108 SetCalcHiddenCharFlags();
1109 else if ( nWhich == RES_TXTATR_CHARFMT )
1111 // Check if character format contains hidden attribute:
1112 const SwCharFmt* pFmt = pTxtHt->GetCharFmt().GetCharFmt();
1113 const SfxPoolItem* pItem;
1114 if ( SFX_ITEM_SET == pFmt->GetItemState( RES_CHRATR_HIDDEN, TRUE, &pItem ) )
1115 SetCalcHiddenCharFlags();
1117 // --> FME 2007-03-16 #i75430# Recalc hidden flags if necessary
1118 else if ( nWhich == RES_TXTATR_AUTOFMT )
1120 // Check if auto style contains hidden attribute:
1121 const SfxPoolItem* pHiddenItem = CharFmt::GetItem( *pTxtHt, RES_CHRATR_HIDDEN );
1122 if ( pHiddenItem )
1123 SetCalcHiddenCharFlags();
1125 // <--
1127 pEndIdx = pTxtHt->GetEnd();
1129 // Text-Attribute sind voellig dynamisch, so dass diese nur
1130 // mit ihrer Start-Position verglichen werden.
1131 if( !pEndIdx )
1133 // Unbedingt Copy-konstruieren!
1134 const SwIndex aIdx( this, *pSttIdx );
1135 Erase( aIdx, 1 );
1136 break;
1138 else if( *pEndIdx == nEnd )
1140 // den MsgHint jetzt fuettern, weil gleich sind
1141 // Start und End weg.
1142 // Das CalcVisibleFlag bei HiddenParaFields entfaellt,
1143 // da dies das Feld im Dtor selbst erledigt.
1144 SwUpdateAttr aHint( *pSttIdx, *pEndIdx, nTxtWhich );
1145 m_pSwpHints->DeleteAtPos( nPos ); // gefunden, loeschen,
1146 pTxtHt->RemoveFromPool( GetDoc()->GetAttrPool() );
1147 delete pTxtHt;
1148 SwModify::Modify( 0, &aHint ); // die Frames benachrichtigen
1149 break;
1153 TryDeleteSwpHints();
1156 /*************************************************************************
1157 * SwTxtNode::DelSoftHyph()
1158 *************************************************************************/
1160 void SwTxtNode::DelSoftHyph( const xub_StrLen nStt, const xub_StrLen nEnd )
1162 xub_StrLen nFndPos = nStt, nEndPos = nEnd;
1163 while( STRING_NOTFOUND !=
1164 ( nFndPos = m_Text.Search( CHAR_SOFTHYPHEN, nFndPos )) &&
1165 nFndPos < nEndPos )
1167 const SwIndex aIdx( this, nFndPos );
1168 Erase( aIdx, 1 );
1169 --nEndPos;
1173 // setze diese Attribute am TextNode. Wird der gesamte Bereich umspannt,
1174 // dann setze sie nur im AutoAttrSet (SwCntntNode:: SetAttr)
1175 BOOL SwTxtNode::SetAttr( const SfxItemSet& rSet, xub_StrLen nStt,
1176 xub_StrLen nEnd, USHORT nMode )
1178 if( !rSet.Count() )
1179 return FALSE;
1181 // teil die Sets auf (fuer Selektion in Nodes)
1182 const SfxItemSet* pSet = &rSet;
1183 SfxItemSet aTxtSet( *rSet.GetPool(), RES_TXTATR_BEGIN, RES_TXTATR_END-1 );
1185 // gesamter Bereich
1186 if ( !nStt && (nEnd == m_Text.Len()) &&
1187 !(nMode & nsSetAttrMode::SETATTR_NOFORMATATTR ) )
1189 // sind am Node schon Zeichenvorlagen gesetzt, muss man diese Attribute
1190 // (rSet) immer als TextAttribute setzen, damit sie angezeigt werden.
1191 int bHasCharFmts = FALSE;
1192 if ( HasHints() )
1194 for ( USHORT n = 0; n < m_pSwpHints->Count(); ++n )
1196 if ( (*m_pSwpHints)[ n ]->IsCharFmtAttr() )
1198 bHasCharFmts = TRUE;
1199 break;
1204 if( !bHasCharFmts )
1206 aTxtSet.Put( rSet );
1207 // If there are any character attributes in rSet,
1208 // we want to set them at the paragraph:
1209 if( aTxtSet.Count() != rSet.Count() )
1211 BOOL bRet = SetAttr( rSet );
1212 if( !aTxtSet.Count() )
1213 return bRet;
1216 // check for auto style:
1217 const SfxPoolItem* pItem;
1218 const bool bAutoStyle = SFX_ITEM_SET == aTxtSet.GetItemState( RES_TXTATR_AUTOFMT, FALSE, &pItem );
1219 if ( bAutoStyle )
1221 boost::shared_ptr<SfxItemSet> pAutoStyleSet = static_cast<const SwFmtAutoFmt*>(pItem)->GetStyleHandle();
1222 BOOL bRet = SetAttr( *pAutoStyleSet );
1223 if( 1 == aTxtSet.Count() )
1224 return bRet;
1227 // Continue with the text attributes:
1228 pSet = &aTxtSet;
1232 GetOrCreateSwpHints();
1234 SfxItemSet aCharSet( *rSet.GetPool(), aCharAutoFmtSetRange );
1236 USHORT nWhich, nCount = 0;
1237 SwTxtAttr* pNew;
1238 SfxItemIter aIter( *pSet );
1239 const SfxPoolItem* pItem = aIter.GetCurItem();
1243 if ( pItem && (reinterpret_cast<SfxPoolItem*>(-1) != pItem))
1245 nWhich = pItem->Which();
1246 if ( isCHRATR(nWhich) || isTXTATR(nWhich) || isUNKNOWNATR(nWhich) )
1248 if ((RES_TXTATR_CHARFMT == nWhich) &&
1249 (GetDoc()->GetDfltCharFmt() ==
1250 static_cast<const SwFmtCharFmt*>(pItem)->GetCharFmt()))
1252 SwIndex aIndex( this, nStt );
1253 RstAttr( aIndex, nEnd - nStt, RES_TXTATR_CHARFMT, 0 );
1254 DontExpandFmt( aIndex );
1256 else
1258 if (isCHRATR(nWhich) ||
1259 (RES_TXTATR_UNKNOWN_CONTAINER == nWhich))
1261 aCharSet.Put( *pItem );
1263 else
1265 pNew = MakeTxtAttr( *pItem, nStt, nEnd );
1266 if ( pNew )
1268 if ( nEnd != nStt && !pNew->GetEnd() )
1270 ASSERT(false,
1271 "Attribut without end, but area marked");
1272 DestroyAttr( pNew ); // do not insert
1274 else if ( Insert( pNew, nMode ) )
1276 ++nCount;
1283 if ( aIter.IsAtEnd() )
1284 break;
1285 pItem = aIter.NextItem();
1286 } while( true );
1288 if ( aCharSet.Count() )
1290 SwTxtAttr* pTmpNew = MakeTxtAttr( aCharSet, nStt, nEnd );
1291 if ( Insert( pTmpNew, nMode ) )
1292 ++nCount;
1295 TryDeleteSwpHints();
1297 return nCount ? TRUE : FALSE;
1300 void lcl_MergeAttr( SfxItemSet& rSet, const SfxPoolItem& rAttr )
1302 if ( RES_TXTATR_AUTOFMT == rAttr.Which() )
1304 const SfxItemSet* pCFSet = CharFmt::GetItemSet( rAttr );
1305 if ( !pCFSet )
1306 return;
1307 SfxWhichIter aIter( *pCFSet );
1308 USHORT nWhich = aIter.FirstWhich();
1309 while( nWhich )
1311 if( ( nWhich < RES_CHRATR_END ||
1312 RES_TXTATR_UNKNOWN_CONTAINER == nWhich ) &&
1313 ( SFX_ITEM_SET == pCFSet->GetItemState( nWhich, TRUE ) ) )
1314 rSet.Put( pCFSet->Get( nWhich ) );
1315 nWhich = aIter.NextWhich();
1318 else
1319 rSet.Put( rAttr );
1322 void lcl_MergeAttr_ExpandChrFmt( SfxItemSet& rSet, const SfxPoolItem& rAttr )
1324 if( RES_TXTATR_CHARFMT == rAttr.Which() ||
1325 RES_TXTATR_INETFMT == rAttr.Which() ||
1326 RES_TXTATR_AUTOFMT == rAttr.Which() )
1328 const SfxItemSet* pCFSet = CharFmt::GetItemSet( rAttr );
1330 if ( pCFSet )
1332 SfxWhichIter aIter( *pCFSet );
1333 USHORT nWhich = aIter.FirstWhich();
1334 while( nWhich )
1336 if( ( nWhich < RES_CHRATR_END ||
1337 ( RES_TXTATR_AUTOFMT == rAttr.Which() && RES_TXTATR_UNKNOWN_CONTAINER == nWhich ) ) &&
1338 ( SFX_ITEM_SET == pCFSet->GetItemState( nWhich, TRUE ) ) )
1339 rSet.Put( pCFSet->Get( nWhich ) );
1340 nWhich = aIter.NextWhich();
1345 // aufnehmen als MergeWert (falls noch nicht gesetzt neu setzen!)
1347 /* wenn mehrere Attribute ueberlappen gewinnt der letze !!
1349 1234567890123456789
1350 |------------| Font1
1351 |------| Font2
1353 |--| Abfragebereich: -> Gueltig ist Font2
1355 rSet.Put( rAttr );
1358 struct SwPoolItemEndPair
1360 public:
1361 const SfxPoolItem* mpItem;
1362 xub_StrLen mnEndPos;
1364 SwPoolItemEndPair() : mpItem( 0 ), mnEndPos( 0 ) {};
1367 // --> OD 2008-01-16 #newlistlevelattrs#
1368 void lcl_MergeListLevelIndentAsLRSpaceItem( const SwTxtNode& rTxtNode,
1369 SfxItemSet& rSet )
1371 if ( rTxtNode.AreListLevelIndentsApplicable() )
1373 const SwNumRule* pRule = rTxtNode.GetNumRule();
1374 if ( pRule && rTxtNode.GetActualListLevel() >= 0 )
1376 const SwNumFmt& rFmt = pRule->Get(static_cast<USHORT>(rTxtNode.GetActualListLevel()));
1377 if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
1379 SvxLRSpaceItem aLR( RES_LR_SPACE );
1380 aLR.SetTxtLeft( rFmt.GetIndentAt() );
1381 aLR.SetTxtFirstLineOfst( static_cast<short>(rFmt.GetFirstLineIndent()) );
1382 rSet.Put( aLR );
1388 // erfrage die Attribute vom TextNode ueber den Bereich
1389 // --> OD 2008-01-16 #newlistlevelattrs#
1390 BOOL SwTxtNode::GetAttr( SfxItemSet& rSet, xub_StrLen nStt, xub_StrLen nEnd,
1391 BOOL bOnlyTxtAttr, BOOL bGetFromChrFmt,
1392 const bool bMergeIndentValuesOfNumRule ) const
1394 if( HasHints() )
1396 /* stelle erstmal fest, welche Text-Attribut in dem Bereich gueltig
1397 * sind. Dabei gibt es folgende Faelle:
1398 * UnEindeutig wenn: (wenn != Format-Attribut)
1399 * - das Attribut liegt vollstaendig im Bereich
1400 * - das Attributende liegt im Bereich
1401 * - der Attributanfang liegt im Bereich:
1402 * Eindeutig (im Set mergen):
1403 * - das Attrib umfasst den Bereich
1404 * nichts tun:
1405 * das Attribut liegt ausserhalb des Bereiches
1408 void (*fnMergeAttr)( SfxItemSet&, const SfxPoolItem& )
1409 = bGetFromChrFmt ? &lcl_MergeAttr_ExpandChrFmt
1410 : &lcl_MergeAttr;
1412 // dann besorge mal die Auto-(Fmt)Attribute
1413 SfxItemSet aFmtSet( *rSet.GetPool(), rSet.GetRanges() );
1414 if( !bOnlyTxtAttr )
1416 SwCntntNode::GetAttr( aFmtSet );
1417 // --> OD 2008-01-16 #newlistlevelattrs#
1418 if ( bMergeIndentValuesOfNumRule )
1420 lcl_MergeListLevelIndentAsLRSpaceItem( *this, aFmtSet );
1422 // <--
1425 const USHORT nSize = m_pSwpHints->Count();
1426 USHORT n;
1427 xub_StrLen nAttrStart;
1428 const xub_StrLen* pAttrEnd;
1430 if( nStt == nEnd ) // kein Bereich:
1432 for( n = 0; n < nSize; ++n ) //
1434 const SwTxtAttr* pHt = (*m_pSwpHints)[n];
1435 nAttrStart = *pHt->GetStart();
1436 if( nAttrStart > nEnd ) // ueber den Bereich hinaus
1437 break;
1439 if( 0 == ( pAttrEnd = pHt->GetEnd() )) // nie Attribute ohne Ende
1440 continue;
1442 if( ( nAttrStart < nStt &&
1443 ( pHt->DontExpand() ? nStt < *pAttrEnd
1444 : nStt <= *pAttrEnd )) ||
1445 ( nStt == nAttrStart &&
1446 ( nAttrStart == *pAttrEnd || !nStt )))
1447 (*fnMergeAttr)( rSet, pHt->GetAttr() );
1450 else // es ist ein Bereich definiert
1452 // --> FME 2007-03-13 #i75299#
1453 std::vector< SwPoolItemEndPair >* pAttrArr = 0;
1454 // <--
1456 const USHORT coArrSz = static_cast<USHORT>(RES_TXTATR_WITHEND_END) -
1457 static_cast<USHORT>(RES_CHRATR_BEGIN) +
1458 static_cast<USHORT>(RES_UNKNOWNATR_END) -
1459 static_cast<USHORT>(RES_UNKNOWNATR_BEGIN);
1461 for( n = 0; n < nSize; ++n )
1463 const SwTxtAttr* pHt = (*m_pSwpHints)[n];
1464 nAttrStart = *pHt->GetStart();
1465 if( nAttrStart > nEnd ) // ueber den Bereich hinaus
1466 break;
1468 if( 0 == ( pAttrEnd = pHt->GetEnd() )) // nie Attribute ohne Ende
1469 continue;
1471 BOOL bChkInvalid = FALSE;
1472 if( nAttrStart <= nStt ) // vor oder genau Start
1474 if( *pAttrEnd <= nStt ) // liegt davor
1475 continue;
1477 if( nEnd <= *pAttrEnd ) // hinter oder genau Ende
1478 (*fnMergeAttr)( aFmtSet, pHt->GetAttr() );
1479 else
1480 // else if( pHt->GetAttr() != aFmtSet.Get( pHt->Which() ) )
1481 // uneindeutig
1482 bChkInvalid = TRUE;
1484 else if( nAttrStart < nEnd // reicht in den Bereich
1485 )// && pHt->GetAttr() != aFmtSet.Get( pHt->Which() ) )
1486 bChkInvalid = TRUE;
1488 if( bChkInvalid )
1490 // uneindeutig ?
1491 SfxItemIter* pItemIter = 0;
1492 const SfxPoolItem* pItem = 0;
1494 if ( RES_TXTATR_AUTOFMT == pHt->Which() )
1496 const SfxItemSet* pAutoSet = CharFmt::GetItemSet( pHt->GetAttr() );
1497 if ( pAutoSet )
1499 pItemIter = new SfxItemIter( *pAutoSet );
1500 pItem = pItemIter->GetCurItem();
1503 else
1504 pItem = &pHt->GetAttr();
1506 const USHORT nHintEnd = *pAttrEnd;
1508 while ( pItem )
1510 const USHORT nHintWhich = pItem->Which();
1512 if( !pAttrArr )
1513 pAttrArr = new std::vector< SwPoolItemEndPair >( coArrSz );
1515 std::vector< SwPoolItemEndPair >::iterator pPrev = pAttrArr->begin();
1516 if (isCHRATR(nHintWhich) ||
1517 isTXTATR_WITHEND(nHintWhich))
1519 pPrev += nHintWhich - RES_CHRATR_BEGIN;
1521 else if (isUNKNOWNATR(nHintWhich))
1523 pPrev += nHintWhich - RES_UNKNOWNATR_BEGIN + (
1524 static_cast< USHORT >(RES_TXTATR_WITHEND_END) -
1525 static_cast< USHORT >(RES_CHRATR_BEGIN) );
1527 else
1529 pPrev = pAttrArr->end();
1532 #if OSL_DEBUG_LEVEL > 1
1533 SwPoolItemEndPair aTmp = *pPrev;
1534 #endif
1536 if( pPrev != pAttrArr->end() )
1538 if( !pPrev->mpItem )
1540 if ( bOnlyTxtAttr || *pItem != aFmtSet.Get( nHintWhich ) )
1542 if( nAttrStart > nStt )
1544 rSet.InvalidateItem( nHintWhich );
1545 pPrev->mpItem = (SfxPoolItem*)-1;
1547 else
1549 pPrev->mpItem = pItem;
1550 pPrev->mnEndPos = nHintEnd;
1554 else if( (SfxPoolItem*)-1 != pPrev->mpItem )
1556 if( pPrev->mnEndPos == nAttrStart &&
1557 *pPrev->mpItem == *pItem )
1559 pPrev->mpItem = pItem;
1560 pPrev->mnEndPos = nHintEnd;
1562 else
1564 rSet.InvalidateItem( nHintWhich );
1565 pPrev->mpItem = (SfxPoolItem*)-1;
1570 pItem = ( pItemIter && !pItemIter->IsAtEnd() ) ? pItemIter->NextItem() : 0;
1571 } // end while
1573 delete pItemIter;
1577 if( pAttrArr )
1579 for( n = 0; n < coArrSz; ++n )
1581 const SwPoolItemEndPair& rItemPair = (*pAttrArr)[ n ];
1582 if( (0 != rItemPair.mpItem) && ((SfxPoolItem*)-1 != rItemPair.mpItem) )
1584 USHORT nWh;
1585 if( n < static_cast<USHORT>( static_cast<USHORT>(RES_TXTATR_WITHEND_END) -
1586 static_cast<USHORT>(RES_CHRATR_BEGIN) ) )
1587 nWh = static_cast<USHORT>(n + RES_CHRATR_BEGIN);
1588 else
1589 nWh = n - static_cast<USHORT>( static_cast<USHORT>(RES_TXTATR_WITHEND_END) -
1590 static_cast<USHORT>(RES_CHRATR_BEGIN) +
1591 static_cast<USHORT>(RES_UNKNOWNATR_BEGIN) );
1593 if( nEnd <= rItemPair.mnEndPos ) // hinter oder genau Ende
1595 if( *rItemPair.mpItem != aFmtSet.Get( nWh ) )
1596 (*fnMergeAttr)( rSet, *rItemPair.mpItem );
1598 else
1599 // uneindeutig
1600 rSet.InvalidateItem( nWh );
1604 delete pAttrArr;
1607 if( aFmtSet.Count() )
1609 // aus dem Format-Set alle entfernen, die im TextSet auch gesetzt sind
1610 aFmtSet.Differentiate( rSet );
1611 // jetzt alle zusammen "mergen"
1612 rSet.Put( aFmtSet );
1615 else if( !bOnlyTxtAttr )
1617 // dann besorge mal die Auto-(Fmt)Attribute
1618 SwCntntNode::GetAttr( rSet );
1619 // --> OD 2008-01-16 #newlistlevelattrs#
1620 if ( bMergeIndentValuesOfNumRule )
1622 lcl_MergeListLevelIndentAsLRSpaceItem( *this, rSet );
1624 // <--
1627 return rSet.Count() ? TRUE : FALSE;
1630 int lcl_IsNewAttrInSet( const SwpHints& rHints, const SfxPoolItem& rItem,
1631 const xub_StrLen nEnd )
1633 int bIns = TRUE;
1634 for( USHORT i = 0; i < rHints.Count(); ++i )
1636 const SwTxtAttr *pOther = rHints[ i ];
1637 if( *pOther->GetStart() )
1638 break;
1640 if( pOther->GetEnd() &&
1641 *pOther->GetEnd() == nEnd &&
1642 ( pOther->IsCharFmtAttr() || pOther->Which() == rItem.Which() ) )
1644 bIns = FALSE;
1645 break;
1648 return bIns;
1651 void SwTxtNode::FmtToTxtAttr( SwTxtNode* pNd )
1653 SfxItemSet aThisSet( GetDoc()->GetAttrPool(), aCharFmtSetRange );
1654 if( HasSwAttrSet() && GetpSwAttrSet()->Count() )
1655 aThisSet.Put( *GetpSwAttrSet() );
1657 GetOrCreateSwpHints();
1659 if( pNd == this )
1661 if( aThisSet.Count() )
1663 SfxItemIter aIter( aThisSet );
1664 const SfxPoolItem* pItem = aIter.GetCurItem();
1665 std::vector<USHORT> aClearWhichIds;
1667 while ( true )
1669 if (lcl_IsNewAttrInSet( *m_pSwpHints, *pItem, GetTxt().Len() ))
1671 m_pSwpHints->SwpHintsArray::Insert(
1672 MakeTxtAttr( *pItem, 0, GetTxt().Len() ) );
1673 aClearWhichIds.push_back( pItem->Which() );
1676 if( aIter.IsAtEnd() )
1677 break;
1678 pItem = aIter.NextItem();
1681 ClearItemsFromAttrSet( aClearWhichIds );
1684 else
1686 SfxItemSet aNdSet( pNd->GetDoc()->GetAttrPool(), aCharFmtSetRange );
1687 if( pNd->HasSwAttrSet() && pNd->GetpSwAttrSet()->Count() )
1688 aNdSet.Put( *pNd->GetpSwAttrSet() );
1690 pNd->GetOrCreateSwpHints();
1692 if( aThisSet.Count() )
1694 SfxItemIter aIter( aThisSet );
1695 const SfxPoolItem* pItem = aIter.GetCurItem(), *pNdItem;
1696 std::vector<USHORT> aClearWhichIds;
1698 while( TRUE )
1700 if( ( SFX_ITEM_SET != aNdSet.GetItemState( pItem->Which(), FALSE,
1701 &pNdItem ) || *pItem != *pNdItem ) &&
1702 lcl_IsNewAttrInSet( *m_pSwpHints, *pItem, GetTxt().Len() ) )
1704 m_pSwpHints->SwpHintsArray::Insert(
1705 MakeTxtAttr( *pItem, 0, GetTxt().Len() ) );
1706 aClearWhichIds.push_back( pItem->Which() );
1708 aNdSet.ClearItem( pItem->Which() );
1710 if( aIter.IsAtEnd() )
1711 break;
1712 pItem = aIter.NextItem();
1714 ClearItemsFromAttrSet( aClearWhichIds );
1717 if( aNdSet.Count() )
1719 SfxItemIter aIter( aNdSet );
1720 const SfxPoolItem* pItem = aIter.GetCurItem();
1721 std::vector<USHORT> aClearWhichIds;
1723 while ( true )
1725 if ( lcl_IsNewAttrInSet( *pNd->m_pSwpHints, *pItem,
1726 pNd->GetTxt().Len() ) )
1728 pNd->m_pSwpHints->SwpHintsArray::Insert(
1729 pNd->MakeTxtAttr( *pItem, 0, pNd->GetTxt().Len() ) );
1731 aClearWhichIds.push_back( pItem->Which() );
1733 if( aIter.IsAtEnd() )
1734 break;
1735 pItem = aIter.NextItem();
1738 pNd->ClearItemsFromAttrSet( aClearWhichIds );
1739 SwFmtChg aTmp1( pNd->GetFmtColl() );
1740 pNd->SwModify::Modify( &aTmp1, &aTmp1 );
1744 SetCalcHiddenCharFlags();
1746 pNd->TryDeleteSwpHints();
1749 /*************************************************************************
1750 * SwpHints::CalcFlags()
1751 *************************************************************************/
1753 void SwpHints::CalcFlags()
1755 m_bDDEFields = m_bFootnote = false;
1756 const USHORT nSize = Count();
1757 const SwTxtAttr* pAttr;
1758 for( USHORT nPos = 0; nPos < nSize; ++nPos )
1760 switch( ( pAttr = (*this)[ nPos ])->Which() )
1762 case RES_TXTATR_FTN:
1763 m_bFootnote = true;
1764 if ( m_bDDEFields )
1765 return;
1766 break;
1767 case RES_TXTATR_FIELD:
1769 const SwField* pFld = pAttr->GetFld().GetFld();
1770 if( RES_DDEFLD == pFld->GetTyp()->Which() )
1772 m_bDDEFields = true;
1773 if ( m_bFootnote )
1774 return;
1777 break;
1782 /*************************************************************************
1783 * SwpHints::CalcVisibleFlag()
1784 *************************************************************************/
1786 bool SwpHints::CalcHiddenParaField()
1788 m_bCalcHiddenParaField = false;
1789 bool bOldHasHiddenParaField = m_bHasHiddenParaField;
1790 bool bNewHasHiddenParaField = false;
1791 const USHORT nSize = Count();
1792 const SwTxtAttr *pTxtHt;
1794 for( USHORT nPos = 0; nPos < nSize; ++nPos )
1796 pTxtHt = (*this)[ nPos ];
1797 const USHORT nWhich = pTxtHt->Which();
1799 if( RES_TXTATR_FIELD == nWhich )
1801 const SwFmtFld& rFld = pTxtHt->GetFld();
1802 if( RES_HIDDENPARAFLD == rFld.GetFld()->GetTyp()->Which() )
1804 if( !((SwHiddenParaField*)rFld.GetFld())->IsHidden() )
1806 SetHiddenParaField(false);
1807 return bOldHasHiddenParaField != bNewHasHiddenParaField;
1809 else
1811 bNewHasHiddenParaField = true;
1816 SetHiddenParaField( bNewHasHiddenParaField );
1817 return bOldHasHiddenParaField != bNewHasHiddenParaField;
1821 /*************************************************************************
1822 * SwpHints::NoteInHistory()
1823 *************************************************************************/
1825 void SwpHints::NoteInHistory( SwTxtAttr *pAttr, const bool bNew )
1827 if ( m_pHistory ) { m_pHistory->AddHint( pAttr, bNew ); }
1830 /*************************************************************************
1831 * SwpHints::MergePortions( )
1832 *************************************************************************/
1834 bool SwpHints::MergePortions( SwTxtNode& rNode )
1836 if ( !Count() )
1837 return false;
1839 // sort before merging
1840 SwpHintsArray::Resort();
1842 bool bRet = false;
1843 typedef std::multimap< int, SwTxtAttr* > PortionMap;
1844 PortionMap aPortionMap;
1845 xub_StrLen nLastPorStart = STRING_LEN;
1846 USHORT i = 0;
1847 int nKey = 0;
1849 // get portions by start position:
1850 for ( i = 0; i < Count(); ++i )
1852 SwTxtAttr *pHt = GetTextHint( i );
1853 if ( RES_TXTATR_CHARFMT != pHt->Which() &&
1854 RES_TXTATR_AUTOFMT != pHt->Which() )
1855 //&&
1856 //RES_TXTATR_INETFMT != pHt->Which() )
1857 continue;
1859 const xub_StrLen nPorStart = *pHt->GetStart();
1860 if ( nPorStart != nLastPorStart && nLastPorStart != STRING_LEN )
1861 ++nKey;
1862 nLastPorStart = nPorStart;
1863 aPortionMap.insert( std::pair< const int, SwTxtAttr* >( nKey, pHt ) );
1866 // check if portion i can be merged with portion i+1:
1867 i = 0;
1868 int j = i + 1;
1869 while ( i <= nKey )
1871 std::pair< PortionMap::iterator, PortionMap::iterator > aRange1 = aPortionMap.equal_range( i );
1872 std::pair< PortionMap::iterator, PortionMap::iterator > aRange2 = aPortionMap.equal_range( j );
1873 PortionMap::iterator aIter1 = aRange1.first;
1874 PortionMap::iterator aIter2 = aRange2.first;
1876 bool bMerge = true;
1877 const USHORT nAttributesInPor1 = static_cast<USHORT>(std::distance( aRange1.first, aRange1.second ));
1878 const USHORT nAttributesInPor2 = static_cast<USHORT>(std::distance( aRange2.first, aRange2.second ));
1880 if ( nAttributesInPor1 == nAttributesInPor2 && nAttributesInPor1 != 0 )
1882 while ( aIter1 != aRange1.second )
1884 const SwTxtAttr* p1 = (*aIter1).second;
1885 const SwTxtAttr* p2 = (*aIter2).second;
1886 if ( *p1->GetEnd() < *p2->GetStart() || p1->Which() != p2->Which() || !(*p1 == *p2) )
1888 bMerge = false;
1889 break;
1891 ++aIter1;
1892 ++aIter2;
1895 else
1897 bMerge = false;
1900 if ( bMerge )
1902 // erase all elements with key i + 1
1903 xub_StrLen nNewPortionEnd = 0;
1904 for ( aIter2 = aRange2.first; aIter2 != aRange2.second; ++aIter2 )
1906 SwTxtAttr* p2 = (*aIter2).second;
1907 nNewPortionEnd = *p2->GetEnd();
1909 const USHORT nCountBeforeDelete = Count();
1910 Delete( p2 );
1912 // robust: check if deletion actually took place before destroying attribute:
1913 if ( Count() < nCountBeforeDelete )
1914 rNode.DestroyAttr( p2 );
1916 aPortionMap.erase( aRange2.first, aRange2.second );
1917 ++j;
1919 // change all attributes with key i
1920 aRange1 = aPortionMap.equal_range( i );
1921 for ( aIter1 = aRange1.first; aIter1 != aRange1.second; ++aIter1 )
1923 SwTxtAttr* p1 = (*aIter1).second;
1924 NoteInHistory( p1 );
1925 *p1->GetEnd() = nNewPortionEnd;
1926 NoteInHistory( p1, true );
1927 bRet = true;
1930 else
1932 ++i;
1933 j = i + 1;
1937 if ( bRet )
1939 SwpHintsArray::Resort();
1942 return bRet;
1945 // check if there is already a character format and adjust the sort numbers
1946 void lcl_CheckSortNumber( const SwpHints& rHints, SwTxtCharFmt& rNewCharFmt )
1948 const xub_StrLen nHtStart = *rNewCharFmt.GetStart();
1949 const xub_StrLen nHtEnd = *rNewCharFmt.GetEnd();
1950 USHORT nSortNumber = 0;
1952 for ( USHORT i = 0; i < rHints.Count(); ++i )
1954 const SwTxtAttr* pOtherHt = rHints[i];
1956 const xub_StrLen nOtherStart = *pOtherHt->GetStart();
1958 if ( nOtherStart > nHtStart )
1959 break;
1961 if ( RES_TXTATR_CHARFMT == pOtherHt->Which() )
1963 const xub_StrLen nOtherEnd = *pOtherHt->GetEnd();
1965 if ( nOtherStart == nHtStart && nOtherEnd == nHtEnd )
1967 const USHORT nOtherSortNum = static_cast<const SwTxtCharFmt*>(pOtherHt)->GetSortNumber();
1968 nSortNumber = nOtherSortNum + 1;
1973 if ( nSortNumber > 0 )
1974 rNewCharFmt.SetSortNumber( nSortNumber );
1977 /*************************************************************************
1978 * SwpHints::Insert()
1979 *************************************************************************/
1982 * Insert: Der neue Hint wird immer eingefuegt. Wenn dabei ein
1983 * ueberlappender oder gleicher Hintbereich mit gleichem Attribut
1984 * und Wert gefunden, wird der neue Hint entsprechend veraendert
1985 * und der alte herausgenommen (und zerstoert:
1986 * SwpHints::Destroy()).
1989 void SwpHints::Insert( SwTxtAttr* pHint, SwTxtNode &rNode, USHORT nMode )
1991 // Irgendwann ist immer Schluss
1992 if( USHRT_MAX == Count() )
1993 return;
1995 // Felder bilden eine Ausnahme:
1996 // 1) Sie koennen nie ueberlappen
1997 // 2) Wenn zwei Felder genau aneinander liegen,
1998 // sollen sie nicht zu einem verschmolzen werden.
1999 // Wir koennen also auf die while-Schleife verzichten
2001 xub_StrLen *pHtEnd = pHint->GetEnd();
2002 USHORT nWhich = pHint->Which();
2004 switch( nWhich )
2006 case RES_TXTATR_CHARFMT:
2008 // Check if character format contains hidden attribute:
2009 const SwCharFmt* pFmt = pHint->GetCharFmt().GetCharFmt();
2010 const SfxPoolItem* pItem;
2011 if ( SFX_ITEM_SET == pFmt->GetItemState( RES_CHRATR_HIDDEN, TRUE, &pItem ) )
2012 rNode.SetCalcHiddenCharFlags();
2014 ((SwTxtCharFmt*)pHint)->ChgTxtNode( &rNode );
2015 break;
2017 // --> FME 2007-03-16 #i75430# Recalc hidden flags if necessary
2018 case RES_TXTATR_AUTOFMT:
2020 // Check if auto style contains hidden attribute:
2021 const SfxPoolItem* pHiddenItem = CharFmt::GetItem( *pHint, RES_CHRATR_HIDDEN );
2022 if ( pHiddenItem )
2023 rNode.SetCalcHiddenCharFlags();
2024 break;
2026 // <--
2027 case RES_TXTATR_INETFMT:
2029 ((SwTxtINetFmt*)pHint)->ChgTxtNode( &rNode );
2030 SwCharFmt* pFmt = rNode.GetDoc()->GetCharFmtFromPool( RES_POOLCHR_INET_NORMAL );
2031 pFmt->Add( (SwTxtINetFmt*)pHint );
2033 break;
2034 case RES_TXTATR_FIELD:
2036 BOOL bDelFirst = 0 != ((SwTxtFld*)pHint)->GetpTxtNode();
2037 ((SwTxtFld*)pHint)->ChgTxtNode( &rNode );
2038 SwDoc* pDoc = rNode.GetDoc();
2039 const SwField* pFld = ((SwTxtFld*)pHint)->GetFld().GetFld();
2041 if( !pDoc->IsNewFldLst() )
2043 // was fuer ein Feld ist es denn ??
2044 // bestimmte Felder mussen am Doc das Calculations-Flag updaten
2045 switch( pFld->GetTyp()->Which() )
2047 case RES_DBFLD:
2048 case RES_SETEXPFLD:
2049 case RES_HIDDENPARAFLD:
2050 case RES_HIDDENTXTFLD:
2051 case RES_DBNUMSETFLD:
2052 case RES_DBNEXTSETFLD:
2054 if( bDelFirst )
2055 pDoc->InsDelFldInFldLst( FALSE, *(SwTxtFld*)pHint );
2056 if( rNode.GetNodes().IsDocNodes() )
2057 pDoc->InsDelFldInFldLst( TRUE, *(SwTxtFld*)pHint );
2059 break;
2060 case RES_DDEFLD:
2061 if( rNode.GetNodes().IsDocNodes() )
2062 ((SwDDEFieldType*)pFld->GetTyp())->IncRefCnt();
2063 break;
2067 // gehts ins normale Nodes-Array?
2068 if( rNode.GetNodes().IsDocNodes() )
2070 BOOL bInsFldType = FALSE;
2071 switch( pFld->GetTyp()->Which() )
2073 case RES_SETEXPFLD:
2074 bInsFldType = ((SwSetExpFieldType*)pFld->GetTyp())->IsDeleted();
2075 if( nsSwGetSetExpType::GSE_SEQ & ((SwSetExpFieldType*)pFld->GetTyp())->GetType() )
2077 // bevor die ReferenzNummer gesetzt wird, sollte
2078 // das Feld am richtigen FeldTypen haengen!
2079 SwSetExpFieldType* pFldType = (SwSetExpFieldType*)
2080 pDoc->InsertFldType( *pFld->GetTyp() );
2081 if( pFldType != pFld->GetTyp() )
2083 SwFmtFld* pFmtFld = (SwFmtFld*)&((SwTxtFld*)pHint)
2084 ->GetFld();
2085 pFldType->Add( pFmtFld ); // ummelden
2086 pFmtFld->GetFld()->ChgTyp( pFldType );
2088 pFldType->SetSeqRefNo( *(SwSetExpField*)pFld );
2090 break;
2091 case RES_USERFLD:
2092 bInsFldType = ((SwUserFieldType*)pFld->GetTyp())->IsDeleted();
2093 break;
2095 case RES_DDEFLD:
2096 if( pDoc->IsNewFldLst() )
2097 ((SwDDEFieldType*)pFld->GetTyp())->IncRefCnt();
2098 bInsFldType = ((SwDDEFieldType*)pFld->GetTyp())->IsDeleted();
2099 break;
2101 case RES_POSTITFLD:
2102 if ( pDoc->GetDocShell() )
2103 pDoc->GetDocShell()->Broadcast( SwFmtFldHint( &((SwTxtFld*)pHint)->GetFld(), SWFMTFLD_INSERTED ) );
2104 break;
2106 if( bInsFldType )
2107 pDoc->InsDeletedFldType( *pFld->GetTyp() );
2110 break;
2111 case RES_TXTATR_FTN :
2112 ((SwTxtFtn*)pHint)->ChgTxtNode( &rNode );
2113 break;
2114 case RES_TXTATR_REFMARK:
2115 ((SwTxtRefMark*)pHint)->ChgTxtNode( &rNode );
2116 if( rNode.GetNodes().IsDocNodes() )
2118 // search for a reference with the same name
2119 SwTxtAttr* pTmpHt;
2120 xub_StrLen *pTmpHtEnd, *pTmpHintEnd;
2121 for( USHORT n = 0, nEnd = Count(); n < nEnd; ++n )
2123 if (RES_TXTATR_REFMARK == (pTmpHt = GetTextHint(n))->Which() &&
2124 pHint->GetAttr() == pTmpHt->GetAttr() &&
2125 0 != ( pTmpHtEnd = pTmpHt->GetEnd() ) &&
2126 0 != ( pTmpHintEnd = pHint->GetEnd() ) )
2128 SwComparePosition eCmp = ::ComparePosition(
2129 *pTmpHt->GetStart(), *pTmpHtEnd,
2130 *pHint->GetStart(), *pTmpHintEnd );
2131 BOOL bDelOld = TRUE, bChgStart = FALSE, bChgEnd = FALSE;
2132 switch( eCmp )
2134 case POS_BEFORE:
2135 case POS_BEHIND: bDelOld = FALSE; break;
2137 case POS_OUTSIDE: bChgStart = bChgEnd = TRUE; break;
2139 case POS_COLLIDE_END:
2140 case POS_OVERLAP_BEFORE: bChgStart = TRUE; break;
2141 case POS_COLLIDE_START:
2142 case POS_OVERLAP_BEHIND: bChgEnd = TRUE; break;
2143 default: break;
2146 if( bChgStart )
2147 *pHint->GetStart() = *pTmpHt->GetStart();
2148 if( bChgEnd )
2149 *pTmpHintEnd = *pTmpHtEnd;
2151 if( bDelOld )
2153 NoteInHistory( pTmpHt );
2154 rNode.DestroyAttr( Cut( n-- ) );
2155 --nEnd;
2160 break;
2161 case RES_TXTATR_TOXMARK:
2162 ((SwTxtTOXMark*)pHint)->ChgTxtNode( &rNode );
2163 break;
2165 case RES_TXTATR_CJK_RUBY:
2167 ((SwTxtRuby*)pHint)->ChgTxtNode( &rNode );
2168 SwCharFmt* pFmt = rNode.GetDoc()->GetCharFmtFromPool(
2169 RES_POOLCHR_RUBYTEXT );
2170 pFmt->Add( (SwTxtRuby*)pHint );
2172 break;
2174 case RES_CHRATR_HIDDEN:
2175 rNode.SetCalcHiddenCharFlags();
2176 break;
2179 if( nsSetAttrMode::SETATTR_DONTEXPAND & nMode )
2180 pHint->SetDontExpand( TRUE );
2182 // SwTxtAttrs ohne Ende werden sonderbehandelt:
2183 // Sie werden natuerlich in das Array insertet, aber sie werden nicht
2184 // in die pPrev/Next/On/Off-Verkettung aufgenommen.
2185 // Der Formatierer erkennt diese TxtHints an dem CH_TXTATR_.. im Text !
2186 xub_StrLen nHtStart = *pHint->GetStart();
2187 if( !pHtEnd )
2189 SwpHintsArray::Insert( pHint );
2190 CalcFlags();
2191 #ifndef PRODUCT
2192 if( !rNode.GetDoc()->IsInReading() )
2193 CHECK;
2194 #endif
2195 // ... und die Abhaengigen benachrichtigen
2196 if ( rNode.GetDepends() )
2198 SwUpdateAttr aHint( nHtStart, nHtStart, nWhich );
2199 rNode.Modify( 0, &aHint );
2201 return;
2204 // ----------------------------------------------------------------
2205 // Ab hier gibt es nur noch pHint mit einem EndIdx !!!
2207 if( *pHtEnd < nHtStart )
2209 ASSERT( *pHtEnd >= nHtStart,
2210 "+SwpHints::Insert: invalid hint, end < start" );
2212 // Wir drehen den Quatsch einfach um:
2213 *pHint->GetStart() = *pHtEnd;
2214 *pHtEnd = nHtStart;
2215 nHtStart = *pHint->GetStart();
2218 // I need this value later on for notification but the pointer may become invalid
2219 const xub_StrLen nHintEnd = *pHtEnd;
2220 const bool bNoHintAdjustMode = (nsSetAttrMode::SETATTR_NOHINTADJUST & nMode);
2222 // Currently REFMARK and TOXMARK have OverlapAllowed set to true.
2223 // These attributes may be inserted directly.
2224 // Also attributes without length may be inserted directly.
2225 // SETATTR_NOHINTADJUST is set e.g., during undo.
2226 // Portion building in not necessary during XML import.
2227 if ( !bNoHintAdjustMode &&
2228 !pHint->IsOverlapAllowedAttr() &&
2229 !rNode.GetDoc()->IsInXMLImport() &&
2230 ( RES_TXTATR_AUTOFMT == nWhich ||
2231 RES_TXTATR_INETFMT == nWhich ||
2232 RES_TXTATR_CHARFMT == nWhich ||
2233 RES_TXTATR_CJK_RUBY == nWhich ) )
2235 ASSERT( nWhich != RES_TXTATR_AUTOFMT ||
2236 static_cast<const SwFmtAutoFmt&>(pHint->GetAttr()).GetStyleHandle()->GetPool() ==
2237 &rNode.GetDoc()->GetAttrPool(),
2238 "AUTOSTYLES - Pool mismatch" )
2240 BuildPortions( rNode, *pHint, nMode );
2242 if ( nHtStart < nHintEnd ) // skip merging for 0-length attributes
2243 MergePortions( rNode );
2245 else
2247 // There may be more than one character style at the current position.
2248 // Take care of the sort number.
2249 // Special case ruby portion: During import, the ruby attribute is set
2250 // multiple times
2251 // Special case hyperlink: During import, the ruby attribute is set
2252 // multiple times
2253 // FME 2007-11-08 #i82989# in NOHINTADJUST mode, we want to insert
2254 // character attributes directly
2255 if ( ( RES_TXTATR_CHARFMT == nWhich && !bNoHintAdjustMode ) ||
2256 RES_TXTATR_CJK_RUBY == nWhich ||
2257 RES_TXTATR_INETFMT == nWhich )
2258 BuildPortions( rNode, *pHint, nMode );
2259 else
2261 // --> FME 2007-11-08 #i82989# Check sort numbers in NoHintAdjustMode
2262 if ( RES_TXTATR_CHARFMT == nWhich )
2263 lcl_CheckSortNumber( *this, *static_cast<SwTxtCharFmt*>(pHint) );
2264 // <--
2266 SwpHintsArray::Insert( pHint );
2267 NoteInHistory( pHint, true );
2271 // ... und die Abhaengigen benachrichtigen
2272 if ( rNode.GetDepends() )
2274 SwUpdateAttr aHint( nHtStart, nHtStart == nHintEnd ? nHintEnd + 1 : nHintEnd, nWhich );
2275 rNode.Modify( 0, &aHint );
2278 #ifndef PRODUCT
2279 if( !bNoHintAdjustMode && !rNode.GetDoc()->IsInReading() )
2280 CHECK;
2281 #endif
2283 return;
2286 /*************************************************************************
2287 * SwpHints::DeleteAtPos()
2288 *************************************************************************/
2290 void SwpHints::DeleteAtPos( const USHORT nPos )
2292 SwTxtAttr *pHint = GetTextHint(nPos);
2293 // ChainDelete( pHint );
2294 NoteInHistory( pHint );
2295 SwpHintsArray::DeleteAtPos( nPos );
2297 if( RES_TXTATR_FIELD == pHint->Which() )
2299 SwFieldType* pFldTyp = ((SwTxtFld*)pHint)->GetFld().GetFld()->GetTyp();
2300 if( RES_DDEFLD == pFldTyp->Which() )
2302 const SwTxtNode* pNd = ((SwTxtFld*)pHint)->GetpTxtNode();
2303 if( pNd && pNd->GetNodes().IsDocNodes() )
2304 ((SwDDEFieldType*)pFldTyp)->DecRefCnt();
2305 ((SwTxtFld*)pHint)->ChgTxtNode( 0 );
2307 else if( RES_POSTITFLD == pFldTyp->Which() )
2309 const_cast<SwFmtFld&>(((SwTxtFld*)pHint)->GetFld()).Broadcast( SwFmtFldHint( &((SwTxtFld*)pHint)->GetFld(), SWFMTFLD_REMOVED ) );
2311 else if ( m_bHasHiddenParaField &&
2312 RES_HIDDENPARAFLD == pFldTyp->Which() )
2314 m_bCalcHiddenParaField = true;
2318 CalcFlags();
2319 CHECK;
2322 // Ist der Hint schon bekannt, dann suche die Position und loesche ihn.
2323 // Ist er nicht im Array, so gibt es ein ASSERT !!
2325 void SwpHints::Delete( SwTxtAttr* pTxtHt )
2327 // Attr 2.0: SwpHintsArr::Delete( pTxtHt );
2328 const USHORT nPos = GetStartOf( pTxtHt );
2329 ASSERT( USHRT_MAX != nPos, "Attribut nicht im Attribut-Array!" );
2330 if( USHRT_MAX != nPos )
2331 DeleteAtPos( nPos );
2334 void SwTxtNode::ClearSwpHintsArr( bool bDelFields )
2336 if ( HasHints() )
2338 USHORT nPos = 0;
2339 while ( nPos < m_pSwpHints->Count() )
2341 SwTxtAttr* pDel = m_pSwpHints->GetTextHint( nPos );
2342 bool bDel = false;
2344 switch( pDel->Which() )
2346 case RES_TXTATR_FLYCNT:
2347 case RES_TXTATR_FTN:
2348 break;
2350 case RES_TXTATR_FIELD:
2351 case RES_TXTATR_HARDBLANK:
2352 if( bDelFields )
2353 bDel = true;
2354 break;
2355 default:
2356 bDel = true; break;
2359 if( bDel )
2361 m_pSwpHints->SwpHintsArray::DeleteAtPos( nPos );
2362 DestroyAttr( pDel );
2364 else
2365 ++nPos;
2370 USHORT SwTxtNode::GetLang( const xub_StrLen nBegin, const xub_StrLen nLen,
2371 USHORT nScript ) const
2373 USHORT nRet = LANGUAGE_DONTKNOW;
2375 if ( ! nScript )
2377 nScript = pBreakIt->GetRealScriptOfText( m_Text, nBegin );
2380 // --> FME 2008-09-29 #i91465# hennerdrewes: Consider nScript if pSwpHints == 0
2381 const USHORT nWhichId = GetWhichOfScript( RES_CHRATR_LANGUAGE, nScript );
2382 // <--
2384 if ( HasHints() )
2386 const xub_StrLen nEnd = nBegin + nLen;
2387 for ( USHORT i = 0, nSize = m_pSwpHints->Count(); i < nSize; ++i )
2389 // ist der Attribut-Anfang schon groesser als der Idx ?
2390 const SwTxtAttr *pHt = m_pSwpHints->operator[](i);
2391 const xub_StrLen nAttrStart = *pHt->GetStart();
2392 if( nEnd < nAttrStart )
2393 break;
2395 const USHORT nWhich = pHt->Which();
2397 if( nWhichId == nWhich ||
2398 ( ( pHt->IsCharFmtAttr() || RES_TXTATR_AUTOFMT == nWhich ) && CharFmt::IsItemIncluded( nWhichId, pHt ) ) )
2400 const xub_StrLen *pEndIdx = pHt->GetEnd();
2401 // Ueberlappt das Attribut den Bereich?
2403 if( pEndIdx &&
2404 nLen ? ( nAttrStart < nEnd && nBegin < *pEndIdx )
2405 : (( nAttrStart < nBegin &&
2406 ( pHt->DontExpand() ? nBegin < *pEndIdx
2407 : nBegin <= *pEndIdx )) ||
2408 ( nBegin == nAttrStart &&
2409 ( nAttrStart == *pEndIdx || !nBegin ))) )
2411 const SfxPoolItem* pItem = CharFmt::GetItem( *pHt, nWhichId );
2412 USHORT nLng = ((SvxLanguageItem*)pItem)->GetLanguage();
2414 // Umfasst das Attribut den Bereich komplett?
2415 if( nAttrStart <= nBegin && nEnd <= *pEndIdx )
2416 nRet = nLng;
2417 else if( LANGUAGE_DONTKNOW == nRet )
2418 nRet = nLng; // partielle Ueberlappung, der 1. gewinnt
2423 if( LANGUAGE_DONTKNOW == nRet )
2425 nRet = ((SvxLanguageItem&)GetSwAttrSet().Get( nWhichId )).GetLanguage();
2426 if( LANGUAGE_DONTKNOW == nRet )
2427 nRet = static_cast<USHORT>(GetAppLanguage());
2429 return nRet;
2433 sal_Unicode GetCharOfTxtAttr( const SwTxtAttr& rAttr )
2435 sal_Unicode cRet = CH_TXTATR_BREAKWORD;
2436 switch ( rAttr.Which() )
2438 case RES_TXTATR_REFMARK:
2439 case RES_TXTATR_TOXMARK:
2441 // case RES_TXTATR_FIELD: ??????
2442 // case RES_TXTATR_FLYCNT, // 29
2444 case RES_TXTATR_FTN:
2445 cRet = CH_TXTATR_INWORD;
2446 break;
2448 // depends on the character ??
2449 // case RES_TXTATR_HARDBLANK:
2450 // cRet = CH_TXTATR_INWORD;
2451 // break;
2453 return cRet;