Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #include <hintids.hxx>
30 : : #include <sot/factory.hxx>
31 : : #include <editeng/xmlcnitm.hxx>
32 : : #include <svl/whiter.hxx>
33 : : #include <svl/itemiter.hxx>
34 : : #include <svl/stylepool.hxx>
35 : : #include <editeng/fontitem.hxx>
36 : : #include <editeng/langitem.hxx>
37 : : #include <editeng/emphitem.hxx>
38 : : #include <editeng/charscaleitem.hxx>
39 : : #include <editeng/charrotateitem.hxx>
40 : : #include <editeng/lrspitem.hxx>
41 : : #include <txtinet.hxx>
42 : : #include <txtflcnt.hxx>
43 : : #include <fmtfld.hxx>
44 : : #include <fmtanchr.hxx>
45 : : #include <fmtinfmt.hxx>
46 : : #include <txtatr.hxx>
47 : : #include <fchrfmt.hxx>
48 : : #include <fmtautofmt.hxx>
49 : : #include <fmtflcnt.hxx>
50 : : #include <fmtftn.hxx>
51 : : #include <txttxmrk.hxx>
52 : : #include <txtrfmrk.hxx>
53 : : #include <txtftn.hxx>
54 : : #include <txtfld.hxx>
55 : : #include <charatr.hxx>
56 : : #include <charfmt.hxx>
57 : : #include <frmfmt.hxx>
58 : : #include <ftnidx.hxx>
59 : : #include <fmtruby.hxx>
60 : : #include <fmtmeta.hxx>
61 : : #include <breakit.hxx>
62 : : #include <doc.hxx>
63 : : #include <IDocumentUndoRedo.hxx>
64 : : #include <fldbas.hxx>
65 : : #include <pam.hxx>
66 : : #include <ndtxt.hxx>
67 : : #include <txtfrm.hxx>
68 : : #include <rolbck.hxx> // fuer SwRegHistory
69 : : #include <ddefld.hxx>
70 : : #include <docufld.hxx>
71 : : #include <expfld.hxx>
72 : : #include <usrfld.hxx>
73 : : #include <poolfmt.hxx>
74 : : #include <swfont.hxx>
75 : : #include <istyleaccess.hxx>
76 : : // OD 26.06.2003 #108784#
77 : : #include <dcontact.hxx>
78 : : #include <docsh.hxx>
79 : : #include <svl/smplhint.hxx>
80 : : #include <algorithm>
81 : : #include <map>
82 : :
83 : : #ifdef DBG_UTIL
84 : : #define CHECK Check();
85 : : #else
86 : : #define CHECK
87 : : #endif
88 : :
89 : : using namespace ::com::sun::star::i18n;
90 : :
91 : :
92 : 6621 : SwpHints::SwpHints()
93 : : : m_pHistory(0)
94 : : , m_bFontChange(true)
95 : : , m_bInSplitNode(false)
96 : : , m_bCalcHiddenParaField(false)
97 : : , m_bHasHiddenParaField(false)
98 : : , m_bFootnote(false)
99 : 6621 : , m_bDDEFields(false)
100 : : {
101 : 6621 : }
102 : :
103 : : struct TxtAttrDeleter
104 : : {
105 : : SwAttrPool & m_rPool;
106 : 4 : TxtAttrDeleter( SwDoc & rDoc ) : m_rPool( rDoc.GetAttrPool() ) { }
107 : 4 : void operator() (SwTxtAttr * const pAttr)
108 : : {
109 [ - + # # ]: 4 : if (RES_TXTATR_META == pAttr->Which() ||
[ + - ]
110 : 0 : RES_TXTATR_METAFIELD == pAttr->Which())
111 : : {
112 : 4 : static_cast<SwTxtMeta *>(pAttr)->ChgTxtNode(0); // prevents ASSERT
113 : : }
114 : 4 : SwTxtAttr::Destroy( pAttr, m_rPool );
115 : 4 : }
116 : : };
117 : :
118 : : struct TxtAttrContains
119 : : {
120 : : xub_StrLen m_nPos;
121 : 60 : TxtAttrContains( const xub_StrLen nPos ) : m_nPos( nPos ) { }
122 : 78 : bool operator() (SwTxtAttrEnd * const pAttr)
123 : : {
124 [ + + ][ + + ]: 78 : return (*pAttr->GetStart() < m_nPos) && (m_nPos < *pAttr->GetEnd());
125 : : }
126 : : };
127 : :
128 : : // a: |-----|
129 : : // b:
130 : : // |---| => valid: b before a
131 : : // |-----| => valid: start == end; b before a
132 : : // |---------| => invalid: overlap (1)
133 : : // |-----------| => valid: same end; b around a
134 : : // |-----------------| => valid: b around a
135 : : // |---| => valid; same start; b within a
136 : : // |-----| => valid; same start and end; b around or within a?
137 : : // |-----------| => valid: same start: b around a
138 : : // |-| => valid: b within a
139 : : // |---| => valid: same end; b within a
140 : : // |---------| => invalid: overlap (2)
141 : : // |-----| => valid: end == start; b after a
142 : : // |---| => valid: b after a
143 : : // ===> 2 invalid overlap cases
144 : : static
145 : 2156 : bool isOverlap(const xub_StrLen nStart1, const xub_StrLen nEnd1,
146 : : const xub_StrLen nStart2, const xub_StrLen nEnd2)
147 : : {
148 : : return
149 : : ((nStart1 > nStart2) && (nStart1 < nEnd2) && (nEnd1 > nEnd2)) // (1)
150 [ + + ][ + + ]: 2156 : || ((nStart1 < nStart2) && (nStart2 < nEnd1) && (nEnd1 < nEnd2)); // (2)
[ + + ][ + + ]
[ + + ][ + + ]
151 : : }
152 : :
153 : : /// #i106930#: now asymmetric: empty hint1 is _not_ nested, but empty hint2 is
154 : : static
155 : 2070 : bool isNestedAny(const xub_StrLen nStart1, const xub_StrLen nEnd1,
156 : : const xub_StrLen nStart2, const xub_StrLen nEnd2)
157 : : {
158 : : return ((nStart1 == nStart2) || (nEnd1 == nEnd2))
159 : : // same start/end: nested except if hint1 empty and hint2 not empty
160 : : ? (nStart1 != nEnd1) || (nStart2 == nEnd2)
161 [ + + ][ + + ]: 2070 : : ((nStart1 < nStart2) ? (nEnd1 >= nEnd2) : (nEnd1 <= nEnd2));
[ + + ][ + + ]
[ + + ]
162 : : }
163 : :
164 : : static
165 : 641 : bool isSelfNestable(const sal_uInt16 nWhich)
166 : : {
167 [ + + ][ + + ]: 641 : if ((RES_TXTATR_INETFMT == nWhich) ||
168 : : (RES_TXTATR_CJK_RUBY == nWhich))
169 : 447 : return false;
170 : : OSL_ENSURE((RES_TXTATR_META == nWhich) ||
171 : : (RES_TXTATR_METAFIELD == nWhich), "???");
172 : 641 : return true;
173 : : }
174 : :
175 : : static
176 : 144 : bool isSplittable(const sal_uInt16 nWhich)
177 : : {
178 [ + + ][ + + ]: 144 : if ((RES_TXTATR_INETFMT == nWhich) ||
179 : : (RES_TXTATR_CJK_RUBY == nWhich))
180 : 82 : return true;
181 : : OSL_ENSURE((RES_TXTATR_META == nWhich) ||
182 : : (RES_TXTATR_METAFIELD == nWhich), "???");
183 : 144 : return false;
184 : : }
185 : :
186 : : enum Split_t { FAIL, SPLIT_NEW, SPLIT_OTHER };
187 : : /**
188 : : Calculate splitting policy for overlapping hints, based on what kind of
189 : : hint is inserted, and what kind of existing hint overlaps.
190 : : */
191 : : static Split_t
192 : 86 : splitPolicy(const sal_uInt16 nWhichNew, const sal_uInt16 nWhichOther)
193 : : {
194 [ + + ]: 86 : if (!isSplittable(nWhichOther))
195 : : {
196 [ + + ]: 58 : if (!isSplittable(nWhichNew))
197 : 4 : return FAIL;
198 : : else
199 : 54 : return SPLIT_NEW;
200 : : }
201 : : else
202 : : {
203 [ + + ][ + + ]: 28 : if ((RES_TXTATR_INETFMT == nWhichNew) &&
204 : : (RES_TXTATR_CJK_RUBY == nWhichOther))
205 : 6 : return SPLIT_NEW;
206 : : else
207 : 86 : return SPLIT_OTHER;
208 : : }
209 : : }
210 : :
211 : 115 : void SwTxtINetFmt::InitINetFmt(SwTxtNode & rNode)
212 : : {
213 : 115 : ChgTxtNode(&rNode);
214 : : SwCharFmt * const pFmt(
215 : 115 : rNode.GetDoc()->GetCharFmtFromPool(RES_POOLCHR_INET_NORMAL) );
216 : 115 : pFmt->Add( this );
217 : 115 : }
218 : :
219 : 386 : void SwTxtRuby::InitRuby(SwTxtNode & rNode)
220 : : {
221 : 386 : ChgTxtNode(&rNode);
222 : : SwCharFmt * const pFmt(
223 : 386 : rNode.GetDoc()->GetCharFmtFromPool(RES_POOLCHR_RUBYTEXT) );
224 : 386 : pFmt->Add( this );
225 : 386 : }
226 : :
227 : : /**
228 : : Create a new nesting text hint.
229 : : */
230 : : static SwTxtAttrNesting *
231 : 82 : MakeTxtAttrNesting(SwTxtNode & rNode, SwTxtAttrNesting & rNesting,
232 : : const xub_StrLen nStart, const xub_StrLen nEnd)
233 : : {
234 : : SwTxtAttr * const pNew( MakeTxtAttr(
235 : 82 : *rNode.GetDoc(), rNesting.GetAttr(), nStart, nEnd ) );
236 [ + + - ]: 82 : switch (pNew->Which())
237 : : {
238 : : case RES_TXTATR_INETFMT:
239 : : {
240 : 26 : static_cast<SwTxtINetFmt*>(pNew)->InitINetFmt(rNode);
241 : 26 : break;
242 : : }
243 : : case RES_TXTATR_CJK_RUBY:
244 : : {
245 : 56 : static_cast<SwTxtRuby*>(pNew)->InitRuby(rNode);
246 : 56 : break;
247 : : }
248 : : default:
249 : : OSL_FAIL("MakeTxtAttrNesting: what the hell is that?");
250 : 0 : break;
251 : : }
252 : 82 : return static_cast<SwTxtAttrNesting*>(pNew);
253 : : }
254 : :
255 : : typedef ::std::vector<SwTxtAttrNesting *> NestList_t;
256 : :
257 : : static void
258 : 60 : lcl_DoSplitNew(NestList_t & rSplits, SwTxtNode & rNode,
259 : : const xub_StrLen nNewStart,
260 : : const xub_StrLen nOtherStart, const xub_StrLen nOtherEnd, bool bOtherDummy)
261 : : {
262 : 60 : const bool bSplitAtStart(nNewStart < nOtherStart);
263 [ + + ]: 60 : const xub_StrLen nSplitPos( (bSplitAtStart) ? nOtherStart : nOtherEnd );
264 : : // first find the portion that is split (not necessarily the last one!)
265 : : NestList_t::iterator const iter(
266 : : ::std::find_if( rSplits.begin(), rSplits.end(),
267 [ + - ]: 60 : TxtAttrContains(nSplitPos) ) );
268 [ + - ][ + + ]: 60 : if (iter != rSplits.end()) // already split here?
269 : : {
270 : : const xub_StrLen nStartPos( // skip other's dummy character!
271 [ + + ][ + + ]: 56 : (bSplitAtStart && bOtherDummy) ? nSplitPos + 1 : nSplitPos );
272 : : SwTxtAttrNesting * const pNew( MakeTxtAttrNesting(
273 [ + - ][ + - ]: 56 : rNode, **iter, nStartPos, *(*iter)->GetEnd() ) );
274 [ + - ]: 56 : *(*iter)->GetEnd() = nSplitPos;
275 [ + - ][ + - ]: 56 : rSplits.insert(iter + 1, pNew);
276 : : }
277 : 60 : }
278 : :
279 : : /**
280 : : Insert nesting hint into the hints array. Also calls NoteInHistory.
281 : : @param rNewHint the hint to be inserted (must not overlap existing!)
282 : : */
283 : 725 : void SwpHints::InsertNesting(SwTxtAttrNesting & rNewHint)
284 : : {
285 : 725 : SwpHintsArray::Insert(& rNewHint);
286 : 725 : NoteInHistory( & rNewHint, true );
287 : 725 : }
288 : :
289 : : /**
290 : :
291 : : The following hints correspond to well-formed XML elements in ODF:
292 : : RES_TXTATR_INETFMT, RES_TXTATR_CJK_RUBY, RES_TXTATR_META, RES_TXTATR_METAFIELD
293 : :
294 : : The writer core must ensure that these do not overlap; if they did,
295 : : the document would not be storable as ODF.
296 : :
297 : : Also, a Hyperlink must not be nested within another Hyperlink,
298 : : and a Ruby must not be nested within another Ruby.
299 : :
300 : : The ODF export in xmloff will only put a hyperlink into a ruby, never a ruby
301 : : into a hyperlink.
302 : :
303 : : Unfortunately the UNO API for Hyperlink and Ruby consists of the properties
304 : : Hyperlink* and Ruby* of the css.text.CharacterProperties service. In other
305 : : words, they are treated as formatting attributes, not as content entites.
306 : : Furthermore, for API users it is not possible to easily test whether a certain
307 : : range would be overlapping with other nested attributes, and most importantly,
308 : : <em>which ones</em>, so we can hardly refuse to insert these in cases of
309 : : overlap.
310 : :
311 : : It is possible to split Hyperlink and Ruby into multiple portions, such that
312 : : the result is properly nested.
313 : :
314 : : meta and meta-field must not be split, because they have xml:id.
315 : :
316 : : These constraints result in the following design:
317 : :
318 : : RES_TXTATR_INETFMT:
319 : : always succeeds
320 : : inserts n attributes split at RES_TXTATR_CJK_RUBY, RES_TXTATR_META,
321 : : RES_TXTATR_METAFIELD
322 : : may replace existing RES_TXTATR_INETFMT at overlap
323 : : RES_TXTATR_CJK_RUBY:
324 : : always succeeds
325 : : inserts n attributes split at RES_TXTATR_META, RES_TXTATR_METAFIELD
326 : : may replace existing RES_TXTATR_CJK_RUBY at overlap
327 : : may split existing overlapping RES_TXTATR_INETFMT
328 : : RES_TXTATR_META:
329 : : may fail if overlapping existing RES_TXTATR_META/RES_TXTATR_METAFIELD
330 : : may split existing overlapping RES_TXTATR_INETFMT or RES_TXTATR_CJK_RUBY
331 : : inserts 1 attribute
332 : : RES_TXTATR_METAFIELD:
333 : : may fail if overlapping existing RES_TXTATR_META/RES_TXTATR_METAFIELD
334 : : may split existing overlapping RES_TXTATR_INETFMT or RES_TXTATR_CJK_RUBY
335 : : inserts 1 attribute
336 : :
337 : : The nesting is expressed by the position of the hints.
338 : : RES_TXTATR_META and RES_TXTATR_METAFIELD have a CH_TXTATR, and there can
339 : : only be one such hint starting and ending at a given position.
340 : : Only RES_TXTATR_INETFMT and RES_TXTATR_CJK_RUBY lack a CH_TXTATR.
341 : : The interpretation given is that RES_TXTATR_CJK_RUBY is always around
342 : : a RES_TXTATR_INETFMT at the same start and end position (which corresponds
343 : : with the UNO API).
344 : : Both of these are always around a nesting hint with CH_TXTATR at the same
345 : : start and end position (if they should be inside, then the start should be
346 : : after the CH_TXTATR).
347 : : It would probably be a bad idea to add another nesting hint without
348 : : CH_TXTATR; on the other hand, it would be difficult adding a CH_TXTATR to
349 : : RES_TXTATR_INETFMT and RES_TXTATR_CJK_RUBY, due to the overwriting and
350 : : splitting of exising hints that is necessary for backward compatibility.
351 : :
352 : : @param rNode the text node
353 : : @param rHint the hint to be inserted
354 : : @returns true iff hint was successfully inserted
355 : : */
356 : : bool
357 : 641 : SwpHints::TryInsertNesting( SwTxtNode & rNode, SwTxtAttrNesting & rNewHint )
358 : : {
359 : : // INVARIANT: the nestable hints in the array are properly nested
360 [ + - ]: 641 : const sal_uInt16 nNewWhich( rNewHint.Which() );
361 : 641 : const xub_StrLen nNewStart( *rNewHint.GetStart() );
362 [ + - ]: 641 : const xub_StrLen nNewEnd ( *rNewHint.GetEnd() );
363 : : //??? const bool bNoLengthAttribute( nNewStart == nNewEnd );
364 : 641 : const bool bNewSelfNestable( isSelfNestable(nNewWhich) );
365 : :
366 : : OSL_ENSURE( (RES_TXTATR_INETFMT == nNewWhich) ||
367 : : (RES_TXTATR_CJK_RUBY == nNewWhich) ||
368 : : (RES_TXTATR_META == nNewWhich) ||
369 : : (RES_TXTATR_METAFIELD == nNewWhich),
370 : : "TryInsertNesting: Expecting INETFMT or RUBY or META or METAFIELD" );
371 : :
372 [ + - ]: 641 : NestList_t OverlappingExisting; // existing hints to be split
373 [ + - ]: 641 : NestList_t OverwrittenExisting; // existing hints to be replaced
374 [ + - ]: 641 : NestList_t SplitNew; // new hints to be inserted
375 : :
376 [ + - ]: 641 : SplitNew.push_back(& rNewHint);
377 : :
378 : : // pass 1: split the inserted hint into fragments if necessary
379 [ + + ]: 4298 : for ( sal_uInt16 i = 0; i < GetEndCount(); ++i )
380 : : {
381 [ + - ]: 3661 : SwTxtAttr * const pOther = GetEnd(i);
382 : :
383 [ + + ]: 3661 : if (pOther->IsNesting())
384 : : {
385 [ + - ]: 2156 : const sal_uInt16 nOtherWhich( pOther->Which() );
386 : 2156 : const xub_StrLen nOtherStart( *(pOther)->GetStart() );
387 [ + - ]: 2156 : const xub_StrLen nOtherEnd ( *(pOther)->GetEnd() );
388 [ + + ]: 2156 : if (isOverlap(nNewStart, nNewEnd, nOtherStart, nOtherEnd ))
389 : : {
390 [ + + + - ]: 86 : switch (splitPolicy(nNewWhich, nOtherWhich))
391 : : {
392 : : case FAIL:
393 : : OSL_TRACE("cannot insert hint: overlap detected");
394 : : ::std::for_each(SplitNew.begin(), SplitNew.end(),
395 [ + - ]: 4 : TxtAttrDeleter(*rNode.GetDoc()));
396 : 4 : return false;
397 : : case SPLIT_NEW:
398 : : lcl_DoSplitNew(SplitNew, rNode, nNewStart,
399 [ + - ]: 60 : nOtherStart, nOtherEnd, pOther->HasDummyChar());
400 : 60 : break;
401 : : case SPLIT_OTHER:
402 : : OverlappingExisting.push_back(
403 [ + - ]: 22 : static_cast<SwTxtAttrNesting*>(pOther));
404 : 22 : break;
405 : : default:
406 : : OSL_FAIL("bad code monkey");
407 : 82 : break;
408 : : }
409 : : }
410 [ + + ]: 2070 : else if (isNestedAny(nNewStart, nNewEnd, nOtherStart, nOtherEnd))
411 : : {
412 [ + + ][ + + ]: 432 : if (!bNewSelfNestable && (nNewWhich == nOtherWhich))
413 : : {
414 : : // ruby and hyperlink: if there is nesting, _overwrite_
415 : : OverwrittenExisting.push_back(
416 [ + - ]: 226 : static_cast<SwTxtAttrNesting*>(pOther));
417 : : }
418 [ + + ][ + + ]: 206 : else if ((nNewStart == nOtherStart) && pOther->HasDummyChar())
[ + + ]
419 : : {
420 [ - + ]: 48 : if (rNewHint.HasDummyChar())
421 : : {
422 : : OSL_FAIL("ERROR: inserting duplicate CH_TXTATR hint");
423 : 0 : return false;
424 [ + + ]: 48 : } else if (nNewEnd < nOtherEnd) {
425 : : // other has dummy char, new is inside other, but
426 : : // new contains the other's dummy char?
427 : : // should be corrected because it may lead to problems
428 : : // in SwXMeta::createEnumeration
429 : : // SplitNew is sorted, so this is the first split
430 : 4 : xub_StrLen *const pStart(SplitNew.front()->GetStart());
431 : : OSL_ENSURE(*pStart == nNewStart, "how did that happen?");
432 : 432 : *pStart = nNewStart + 1;
433 : : }
434 : : }
435 : : }
436 : : }
437 : : }
438 : :
439 : : OSL_ENSURE(isSplittable(nNewWhich) || SplitNew.size() == 1,
440 : : "splitting the unsplittable ???");
441 : :
442 : : // pass 2: split existing hints that overlap/nest with new hint
443 : : // do not iterate over hints array, but over remembered set of overlapping
444 : : // hints, to keep things simple w.r.t. insertion/removal
445 : : // N.B: if there is a hint that splits the inserted hint, then
446 : : // that hint would also have already split any hint in OverlappingExisting
447 : : // so any hint in OverlappingExisting can be split at most by one hint
448 : : // in SplitNew, or even not at all (this is not true for existing hints
449 : : // that go _around_ new hint, which is the raison d'^etre for pass 4)
450 [ + - ][ + + ]: 1318 : for (NestList_t::iterator itOther = OverlappingExisting.begin();
451 : 659 : itOther != OverlappingExisting.end(); ++itOther)
452 : : {
453 : 22 : const xub_StrLen nOtherStart( *(*itOther)->GetStart() );
454 [ + - ]: 22 : const xub_StrLen nOtherEnd ( *(*itOther)->GetEnd() );
455 : :
456 [ + - ][ + + ]: 92 : for (NestList_t::iterator itNew = SplitNew.begin();
457 : 46 : itNew != SplitNew.end(); ++itNew)
458 : : {
459 : 24 : const xub_StrLen nSplitNewStart( *(*itNew)->GetStart() );
460 [ + - ]: 24 : const xub_StrLen nSplitNewEnd ( *(*itNew)->GetEnd() );
461 : : // 4 cases: within, around, overlap l, overlap r, (OTHER: no action)
462 : : const bool bRemoveOverlap(
463 [ + + ][ + - ]: 24 : !bNewSelfNestable && (nNewWhich == (*itOther)->Which()) );
[ + + ]
464 : :
465 [ + - + + : 24 : switch (ComparePosition(nSplitNewStart, nSplitNewEnd,
+ ]
466 : 24 : nOtherStart, nOtherEnd))
467 : : {
468 : : case POS_INSIDE:
469 : : {
470 : : OSL_ENSURE(!bRemoveOverlap,
471 : : "this one should be in OverwrittenExisting?");
472 : : }
473 : 2 : break;
474 : : case POS_OUTSIDE:
475 : : case POS_EQUAL:
476 : : {
477 : : OSL_FAIL("existing hint inside new hint: why?");
478 : : }
479 : 0 : break;
480 : : case POS_OVERLAP_BEFORE:
481 : : {
482 [ + - ]: 10 : Delete( *itOther ); // this also does NoteInHistory!
483 : 10 : *(*itOther)->GetStart() = nSplitNewEnd;
484 [ + - ]: 10 : InsertNesting( **itOther );
485 [ + + ]: 10 : if (!bRemoveOverlap)
486 : : {
487 [ - + ]: 6 : if ( USHRT_MAX == Count() )
488 : : {
489 : : OSL_FAIL("hints array full :-(");
490 : 0 : return false;
491 : : }
492 : : SwTxtAttrNesting * const pOtherLeft(
493 : 6 : MakeTxtAttrNesting( rNode, **itOther,
494 [ + - ]: 6 : nOtherStart, nSplitNewEnd ) );
495 [ + - ]: 6 : InsertNesting( *pOtherLeft );
496 : : }
497 : : }
498 : 10 : break;
499 : : case POS_OVERLAP_BEHIND:
500 : : {
501 [ + - ]: 10 : Delete( *itOther ); // this also does NoteInHistory!
502 [ + - ]: 10 : *(*itOther)->GetEnd() = nSplitNewStart;
503 [ + - ]: 10 : InsertNesting( **itOther );
504 [ + + ]: 10 : if (!bRemoveOverlap)
505 : : {
506 [ - + ]: 6 : if ( USHRT_MAX == Count() )
507 : : {
508 : : OSL_FAIL("hints array full :-(");
509 : 0 : return false;
510 : : }
511 : : SwTxtAttrNesting * const pOtherRight(
512 : 6 : MakeTxtAttrNesting( rNode, **itOther,
513 [ + - ]: 6 : nSplitNewStart, nOtherEnd ) );
514 [ + - ]: 6 : InsertNesting( *pOtherRight );
515 : : }
516 : : }
517 : 10 : break;
518 : : default:
519 : 2 : break; // overlap resolved by splitting new: nothing to do
520 : : }
521 : : }
522 : : }
523 : :
524 [ - + ]: 637 : if ( USHRT_MAX - SplitNew.size() <= Count() )
525 : : {
526 : : OSL_FAIL("hints array full :-(");
527 : 0 : return false;
528 : : }
529 : :
530 : : // pass 3: insert new hints
531 [ + - ][ + + ]: 2660 : for (NestList_t::iterator iter = SplitNew.begin();
532 : 1330 : iter != SplitNew.end(); ++iter)
533 : : {
534 [ + - ]: 693 : InsertNesting(**iter);
535 : : }
536 : :
537 : : // pass 4: handle overwritten hints
538 : : // RES_TXTATR_INETFMT and RES_TXTATR_CJK_RUBY should displace attributes
539 : : // of the same kind.
540 [ + - ][ + + ]: 1726 : for (NestList_t::iterator itOther = OverwrittenExisting.begin();
541 : 863 : itOther != OverwrittenExisting.end(); ++itOther)
542 : : {
543 : 226 : const xub_StrLen nOtherStart( *(*itOther)->GetStart() );
544 [ + - ]: 226 : const xub_StrLen nOtherEnd ( *(*itOther)->GetEnd() );
545 : :
546 : : // overwritten portion is given by start/end of inserted hint
547 [ + + ][ + - ]: 226 : if ((nNewStart <= nOtherStart) && (nOtherEnd <= nNewEnd))
548 : : {
549 [ + - ]: 212 : Delete(*itOther);
550 [ + - ]: 212 : rNode.DestroyAttr( *itOther );
551 : : }
552 : : else
553 : : {
554 : : OSL_ENSURE((nOtherStart < nNewStart) && (nNewEnd < nOtherEnd), "huh?");
555 : : // scenario: there is a RUBY, and contained within that a META;
556 : : // now a RUBY is inserted within the META => the exising RUBY is split:
557 : : // here it is not possible to simply insert the left/right fragment
558 : : // of the existing RUBY because they <em>overlap</em> with the META!
559 [ + - ]: 14 : Delete( *itOther ); // this also does NoteInHistory!
560 [ + - ]: 14 : *(*itOther)->GetEnd() = nNewStart;
561 [ + - ]: 14 : bool bSuccess( TryInsertNesting(rNode, **itOther) );
562 : : OSL_ENSURE(bSuccess, "recursive call 1 failed?");
563 : : SwTxtAttrNesting * const pOtherRight(
564 : : MakeTxtAttrNesting(
565 [ + - ]: 14 : rNode, **itOther, nNewEnd, nOtherEnd ) );
566 [ + - ]: 14 : bSuccess = TryInsertNesting(rNode, *pOtherRight);
567 : : OSL_ENSURE(bSuccess, "recursive call 2 failed?");
568 : : (void)bSuccess;
569 : : }
570 : :
571 : : }
572 : :
573 : 641 : return true;
574 : : }
575 : :
576 : :
577 : : // This function takes care for the following text attribute:
578 : : // RES_TXTATR_CHARFMT, RES_TXTATR_AUTOFMT
579 : : // These attributes have to be handled in a special way (Portion building).
580 : : //
581 : : // The new attribute will be split by any existing RES_TXTATR_AUTOFMT or
582 : : // RES_TXTATR_CHARFMT. The new attribute itself will
583 : : // split any existing RES_TXTATR_AUTOFMT or RES_TXTATR_CHARFMT.
584 : :
585 : 14834 : void SwpHints::BuildPortions( SwTxtNode& rNode, SwTxtAttr& rNewHint,
586 : : const SetAttrMode nMode )
587 : : {
588 [ + - ]: 14834 : const sal_uInt16 nWhich = rNewHint.Which();
589 : :
590 : 14834 : const xub_StrLen nThisStart = *rNewHint.GetStart();
591 [ + - ]: 14834 : const xub_StrLen nThisEnd = *rNewHint.GetEnd();
592 : 14834 : const bool bNoLengthAttribute = nThisStart == nThisEnd;
593 : :
594 [ + - ]: 14834 : std::vector<SwTxtAttr*> aInsDelHints;
595 : 14834 : std::vector<SwTxtAttr*>::iterator aIter;
596 : :
597 : : OSL_ENSURE( RES_TXTATR_CHARFMT == rNewHint.Which() ||
598 : : RES_TXTATR_AUTOFMT == rNewHint.Which(),
599 : : "Expecting CHARFMT or AUTOFMT" );
600 : :
601 : : //
602 : : // 2. Find the hints which cover the start and end position
603 : : // of the new hint. These hints have to be split into two portions:
604 : : //
605 [ + + ]: 14834 : if ( !bNoLengthAttribute ) // nothing to do for no length attributes
606 : : {
607 [ + + ]: 51578 : for ( sal_uInt16 i = 0; i < Count(); ++i )
608 : : {
609 [ + - ]: 38660 : SwTxtAttr* pOther = GetTextHint(i);
610 : :
611 [ + - ][ + + ]: 77251 : if ( RES_TXTATR_CHARFMT != pOther->Which() &&
[ + + ][ + + ]
612 [ + - ]: 38591 : RES_TXTATR_AUTOFMT != pOther->Which() )
613 : 17120 : continue;
614 : :
615 : 21540 : xub_StrLen nOtherStart = *pOther->GetStart();
616 [ + - ]: 21540 : const xub_StrLen nOtherEnd = *pOther->GetEnd();
617 : :
618 : : // Check if start of new attribute overlaps with pOther:
619 : : // Split pOther if necessary:
620 [ + + ][ + + ]: 21540 : if ( nOtherStart < nThisStart && nThisStart < nOtherEnd )
621 : : {
622 : 51 : SwTxtAttr* pNewAttr = MakeTxtAttr( *rNode.GetDoc(),
623 [ + - ]: 102 : pOther->GetAttr(), nOtherStart, nThisStart );
624 [ + - ][ - + ]: 51 : if ( RES_TXTATR_CHARFMT == pOther->Which() )
625 : 0 : static_cast<SwTxtCharFmt*>(pNewAttr)->SetSortNumber( static_cast<SwTxtCharFmt*>(pOther)->GetSortNumber() );
626 [ + - ]: 51 : aInsDelHints.push_back( pNewAttr );
627 : :
628 [ + - ]: 51 : NoteInHistory( pOther );
629 : 51 : *pOther->GetStart() = nThisStart;
630 [ + - ]: 51 : NoteInHistory( pOther, true );
631 : :
632 : 51 : nOtherStart = nThisStart;
633 : : }
634 : :
635 : : // Check if end of new attribute overlaps with pOther:
636 : : // Split pOther if necessary:
637 [ + + ][ + + ]: 21540 : if ( nOtherStart < nThisEnd && nThisEnd < nOtherEnd )
638 : : {
639 : 48 : SwTxtAttr* pNewAttr = MakeTxtAttr( *rNode.GetDoc(),
640 [ + - ]: 96 : pOther->GetAttr(), nOtherStart, nThisEnd );
641 [ + - ][ - + ]: 48 : if ( RES_TXTATR_CHARFMT == pOther->Which() )
642 : 0 : static_cast<SwTxtCharFmt*>(pNewAttr)->SetSortNumber( static_cast<SwTxtCharFmt*>(pOther)->GetSortNumber() );
643 [ + - ]: 48 : aInsDelHints.push_back( pNewAttr );
644 : :
645 [ + - ]: 48 : NoteInHistory( pOther );
646 : 48 : *pOther->GetStart() = nThisEnd;
647 [ + - ]: 48 : NoteInHistory( pOther, true );
648 : : }
649 : : }
650 : :
651 : : // Insert the newly created attributes:
652 [ + - ][ + + ]: 13017 : for ( aIter = aInsDelHints.begin(); aIter != aInsDelHints.end(); ++aIter )
653 : : {
654 [ + - ]: 99 : SwpHintsArray::Insert( *aIter );
655 [ + - ]: 99 : NoteInHistory( *aIter, true );
656 : : }
657 : : }
658 : :
659 : : #ifdef DBG_UTIL
660 : : if( !rNode.GetDoc()->IsInReading() )
661 : : CHECK;
662 : : #endif
663 : :
664 : : //
665 : : // 4. Split rNewHint into 1 ... n new hints:
666 : : //
667 [ + - ]: 14834 : std::set<xub_StrLen> aBounds;
668 [ + - ]: 14834 : aBounds.insert( nThisStart );
669 [ + - ]: 14834 : aBounds.insert( nThisEnd );
670 : :
671 [ + + ]: 14834 : if ( !bNoLengthAttribute ) // nothing to do for no length attributes
672 : : {
673 [ + + ]: 51677 : for ( sal_uInt16 i = 0; i < Count(); ++i )
674 : : {
675 [ + - ]: 38759 : const SwTxtAttr* pOther = GetTextHint(i);
676 : :
677 [ + - ][ + + ]: 77449 : if ( RES_TXTATR_CHARFMT != pOther->Which() &&
[ + + ][ + + ]
678 [ + - ]: 38690 : RES_TXTATR_AUTOFMT != pOther->Which() )
679 : 17120 : continue;
680 : :
681 : 21639 : const xub_StrLen nOtherStart = *pOther->GetStart();
682 [ + - ]: 21639 : const xub_StrLen nOtherEnd = *pOther->GetEnd();
683 : :
684 [ + - ]: 21639 : aBounds.insert( nOtherStart );
685 [ + - ]: 21639 : aBounds.insert( nOtherEnd );
686 : : }
687 : : }
688 : :
689 [ + - ]: 14834 : std::set<xub_StrLen>::iterator aStartIter = aBounds.lower_bound( nThisStart );
690 [ + - ]: 14834 : std::set<xub_StrLen>::iterator aEndIter = aBounds.upper_bound( nThisEnd );
691 [ + - ]: 14834 : xub_StrLen nPorStart = *aStartIter;
692 [ + - ]: 14834 : ++aStartIter;
693 : 14834 : bool bDestroyHint = true;
694 : :
695 : : //
696 : : // Insert the 1...n new parts of the new attribute:
697 : : //
698 [ + - ][ + + ]: 27806 : while ( aStartIter != aEndIter || bNoLengthAttribute )
[ + + ][ + + ]
699 : : {
700 : : OSL_ENSURE( bNoLengthAttribute || nPorStart < *aStartIter, "AUTOSTYLES: BuildPortion trouble" );
701 : :
702 [ + + ][ + - ]: 14888 : const xub_StrLen nPorEnd = bNoLengthAttribute ? nPorStart : *aStartIter;
703 : 14888 : aInsDelHints.clear();
704 : :
705 : : // Get all hints that are in [nPorStart, nPorEnd[:
706 [ + + ]: 58155 : for ( sal_uInt16 i = 0; i < Count(); ++i )
707 : : {
708 [ + - ]: 43471 : SwTxtAttr *pOther = GetTextHint(i);
709 : :
710 [ + - ][ + + ]: 86873 : if ( RES_TXTATR_CHARFMT != pOther->Which() &&
[ + + ][ + + ]
711 [ + - ]: 43402 : RES_TXTATR_AUTOFMT != pOther->Which() )
712 : 19847 : continue;
713 : :
714 : 23624 : const xub_StrLen nOtherStart = *pOther->GetStart();
715 : :
716 [ + + ]: 23624 : if ( nOtherStart > nPorStart )
717 : : break;
718 : :
719 [ + - ][ + - ]: 23420 : if ( pOther->GetEnd() && *pOther->GetEnd() == nPorEnd && nOtherStart == nPorStart )
[ + - ][ + + ]
[ + + ][ + + ]
720 : : {
721 : : OSL_ENSURE( *pOther->GetEnd() == nPorEnd, "AUTOSTYLES: BuildPortion trouble" );
722 [ + - ]: 23624 : aInsDelHints.push_back( pOther );
723 : : }
724 : : }
725 : :
726 : 14888 : SwTxtAttr* pNewAttr = 0;
727 [ + + ]: 14888 : if ( RES_TXTATR_CHARFMT == nWhich )
728 : : {
729 : : // pNewHint can be inserted after calculating the sort value.
730 : : // This should ensure, that pNewHint comes behind the already present
731 : : // character style
732 : 43 : sal_uInt16 nCharStyleCount = 0;
733 : 43 : aIter = aInsDelHints.begin();
734 [ + - ][ + + ]: 47 : while ( aIter != aInsDelHints.end() )
735 : : {
736 [ + - ][ - + ]: 4 : if ( RES_TXTATR_CHARFMT == (*aIter)->Which() )
737 : : {
738 : : // #i74589#
739 : 0 : const SwFmtCharFmt& rOtherCharFmt = (*aIter)->GetCharFmt();
740 : 0 : const SwFmtCharFmt& rThisCharFmt = rNewHint.GetCharFmt();
741 : 0 : const bool bSameCharFmt = rOtherCharFmt.GetCharFmt() == rThisCharFmt.GetCharFmt();
742 : :
743 : : // #i90311#
744 : : // Do not remove existing character format hint during XML import
745 [ # # ][ # # ]: 0 : if ( !rNode.GetDoc()->IsInXMLImport() &&
[ # # ][ # # ]
[ # # ]
746 : 0 : ( !( nsSetAttrMode::SETATTR_DONTREPLACE & nMode ) ||
747 : : bNoLengthAttribute ||
748 : : bSameCharFmt ) )
749 : : {
750 : : // Remove old hint
751 [ # # ]: 0 : Delete( *aIter );
752 [ # # ]: 0 : rNode.DestroyAttr( *aIter );
753 : : }
754 : : else
755 : 0 : ++nCharStyleCount;
756 : : }
757 : : else
758 : : {
759 : : // remove all attributes from auto styles, which are explicitly set in
760 : : // the new character format:
761 : : OSL_ENSURE( RES_TXTATR_AUTOFMT == (*aIter)->Which(), "AUTOSTYLES - Misc trouble" );
762 : 4 : SwTxtAttr* pOther = *aIter;
763 [ + - ]: 4 : boost::shared_ptr<SfxItemSet> pOldStyle = static_cast<const SwFmtAutoFmt&>(pOther->GetAttr()).GetStyleHandle();
764 : :
765 : : // For each attribute in the automatic style check if it
766 : : // is also set the the new character style:
767 : 4 : SfxItemSet aNewSet( *pOldStyle->GetPool(),
768 [ + - ]: 4 : aCharAutoFmtSetRange);
769 [ + - ]: 4 : SfxItemIter aItemIter( *pOldStyle );
770 : 4 : const SfxPoolItem* pItem = aItemIter.GetCurItem();
771 : 32 : while( sal_True )
772 : : {
773 [ + - ][ + - ]: 36 : if ( !CharFmt::IsItemIncluded( pItem->Which(), &rNewHint ) )
774 : : {
775 [ + - ]: 36 : aNewSet.Put( *pItem );
776 : : }
777 : :
778 [ + + ]: 36 : if( aItemIter.IsAtEnd() )
779 : 4 : break;
780 : :
781 [ + - ]: 32 : pItem = aItemIter.NextItem();
782 : : }
783 : :
784 : : // Remove old hint
785 [ + - ]: 4 : Delete( pOther );
786 [ + - ]: 4 : rNode.DestroyAttr( pOther );
787 : :
788 : : // Create new AutoStyle
789 [ + - ]: 4 : if ( aNewSet.Count() )
790 : : {
791 : 4 : pNewAttr = MakeTxtAttr( *rNode.GetDoc(),
792 [ + - ]: 4 : aNewSet, nPorStart, nPorEnd );
793 [ + - ]: 4 : SwpHintsArray::Insert( pNewAttr );
794 [ + - ]: 4 : NoteInHistory( pNewAttr, true );
795 [ + - ][ + - ]: 4 : }
[ + - ]
796 : : }
797 : 4 : ++aIter;
798 : : }
799 : :
800 : : // If there is no current hint and start and end of rNewHint
801 : : // is ok, we do not need to create a new txtattr.
802 [ + - ][ + - ]: 43 : if ( nPorStart == nThisStart &&
[ + - ]
803 : : nPorEnd == nThisEnd &&
804 : : !nCharStyleCount )
805 : : {
806 : 43 : pNewAttr = &rNewHint;
807 : 43 : bDestroyHint = false;
808 : : }
809 : : else
810 : : {
811 : 0 : pNewAttr = MakeTxtAttr( *rNode.GetDoc(), rNewHint.GetAttr(),
812 [ # # ]: 0 : nPorStart, nPorEnd );
813 : 43 : static_cast<SwTxtCharFmt*>(pNewAttr)->SetSortNumber( nCharStyleCount );
814 : : }
815 : : }
816 : : else
817 : : {
818 : : // Find the current autostyle. Mix attributes if necessary.
819 : 14845 : SwTxtAttr* pCurrentAutoStyle = 0;
820 : 14845 : SwTxtAttr* pCurrentCharFmt = 0;
821 : 14845 : aIter = aInsDelHints.begin();
822 [ + - ][ + + ]: 25790 : while ( aIter != aInsDelHints.end() )
823 : : {
824 [ + - ][ + + ]: 10945 : if ( RES_TXTATR_AUTOFMT == (*aIter)->Which() )
825 : 10876 : pCurrentAutoStyle = *aIter;
826 [ + - ][ + - ]: 69 : else if ( RES_TXTATR_CHARFMT == (*aIter)->Which() )
827 : 69 : pCurrentCharFmt = *aIter;
828 : 10945 : ++aIter;
829 : : }
830 : :
831 [ + - ]: 14845 : boost::shared_ptr<SfxItemSet> pNewStyle = static_cast<const SwFmtAutoFmt&>(rNewHint.GetAttr()).GetStyleHandle();
832 [ + + ]: 14845 : if ( pCurrentAutoStyle )
833 : : {
834 [ + - ]: 10876 : boost::shared_ptr<SfxItemSet> pCurrentStyle = static_cast<const SwFmtAutoFmt&>(pCurrentAutoStyle->GetAttr()).GetStyleHandle();
835 : :
836 : : // Merge attributes
837 [ + - ]: 10876 : SfxItemSet aNewSet( *pCurrentStyle );
838 [ + - ]: 10876 : aNewSet.Put( *pNewStyle );
839 : :
840 : : // #i75750# Remove attributes already set at whole paragraph
841 : : // #i81764# This should not be applied for no length attributes!!! <--
842 [ + + ][ + - ]: 10876 : if ( !bNoLengthAttribute && rNode.HasSwAttrSet() && aNewSet.Count() )
[ + + ][ + - ]
[ + + ]
843 : : {
844 [ + - ]: 1976 : SfxItemIter aIter2( aNewSet );
845 : 1976 : const SfxPoolItem* pItem = aIter2.GetCurItem();
846 [ + - ]: 1976 : const SfxItemSet& rWholeParaAttrSet = rNode.GetSwAttrSet();
847 : :
848 [ + - ][ + - ]: 4745 : do
[ + + ][ + + ]
849 : : {
850 : 4745 : const SfxPoolItem* pTmpItem = 0;
851 [ + - ][ + + ]: 4745 : if ( SFX_ITEM_SET == rWholeParaAttrSet.GetItemState( pItem->Which(), sal_False, &pTmpItem ) &&
[ - + ][ - + ]
852 : : pTmpItem == pItem )
853 : : {
854 : : // Do not clear item if the attribute is set in a character format:
855 [ # # ][ # # ]: 0 : if ( !pCurrentCharFmt || 0 == CharFmt::GetItem( *pCurrentCharFmt, pItem->Which() ) )
[ # # ][ # # ]
856 [ # # ]: 0 : aNewSet.ClearItem( pItem->Which() );
857 : : }
858 : : }
859 [ + - ]: 6721 : while (!aIter2.IsAtEnd() && 0 != (pItem = aIter2.NextItem()));
860 : : }
861 : :
862 : : // Remove old hint
863 [ + - ]: 10876 : Delete( pCurrentAutoStyle );
864 [ + - ]: 10876 : rNode.DestroyAttr( pCurrentAutoStyle );
865 : :
866 : : // Create new AutoStyle
867 [ + - ]: 10876 : if ( aNewSet.Count() )
868 : 10876 : pNewAttr = MakeTxtAttr( *rNode.GetDoc(), aNewSet,
869 [ + - ][ + - ]: 10876 : nPorStart, nPorEnd );
[ + - ]
870 : : }
871 : : else
872 : : {
873 : : // Remove any attributes which are already set at the whole paragraph:
874 : 3969 : bool bOptimizeAllowed = true;
875 : :
876 : 3969 : SfxItemSet* pNewSet = 0;
877 : : // #i75750# Remove attributes already set at whole paragraph
878 : : // #i81764# This should not be applied for no length attributes!!! <--
879 [ + + ][ + - ]: 3969 : if ( !bNoLengthAttribute && rNode.HasSwAttrSet() && pNewStyle->Count() )
[ + + ][ + - ]
[ + + ]
880 : : {
881 [ + - ]: 2275 : SfxItemIter aIter2( *pNewStyle );
882 : 2275 : const SfxPoolItem* pItem = aIter2.GetCurItem();
883 [ + - ]: 2275 : const SfxItemSet& rWholeParaAttrSet = rNode.GetSwAttrSet();
884 : :
885 [ + - ][ + - ]: 2422 : do
[ + + ][ + + ]
886 : : {
887 : 2422 : const SfxPoolItem* pTmpItem = 0;
888 [ + - ][ - + ]: 2422 : if ( SFX_ITEM_SET == rWholeParaAttrSet.GetItemState( pItem->Which(), sal_False, &pTmpItem ) &&
[ # # ][ - + ]
889 : : pTmpItem == pItem )
890 : : {
891 : : // Do not clear item if the attribute is set in a character format:
892 [ # # ][ # # ]: 0 : if ( !pCurrentCharFmt || 0 == CharFmt::GetItem( *pCurrentCharFmt, pItem->Which() ) )
[ # # ][ # # ]
893 : : {
894 [ # # ]: 0 : if ( !pNewSet )
895 [ # # ]: 0 : pNewSet = pNewStyle->Clone( sal_True );
896 [ # # ]: 0 : pNewSet->ClearItem( pItem->Which() );
897 : : }
898 : : }
899 : : }
900 : 2422 : while (!aIter2.IsAtEnd() && 0 != (pItem = aIter2.NextItem()));
901 : :
902 [ - + ]: 2275 : if ( pNewSet )
903 : : {
904 : 0 : bOptimizeAllowed = false;
905 [ # # ]: 0 : if ( pNewSet->Count() )
906 [ # # ][ # # ]: 0 : pNewStyle = rNode.getIDocumentStyleAccess().getAutomaticStyle( *pNewSet, IStyleAccess::AUTO_STYLE_CHAR );
[ # # ][ # # ]
907 : : else
908 [ # # ]: 0 : pNewStyle.reset();
909 : :
910 [ # # ][ # # ]: 0 : delete pNewSet;
911 [ + - ]: 2275 : }
912 : : }
913 : :
914 : : // Create new AutoStyle
915 : : // If there is no current hint and start and end of rNewHint
916 : : // is ok, we do not need to create a new txtattr.
917 [ + - ][ + + ]: 3969 : if ( bOptimizeAllowed &&
[ + - ]
918 : : nPorStart == nThisStart &&
919 : : nPorEnd == nThisEnd )
920 : : {
921 : 3939 : pNewAttr = &rNewHint;
922 : 3939 : bDestroyHint = false;
923 : : }
924 [ + - ]: 30 : else if ( pNewStyle.get() )
925 : : {
926 : 30 : pNewAttr = MakeTxtAttr( *rNode.GetDoc(), *pNewStyle,
927 [ + - ]: 30 : nPorStart, nPorEnd );
928 : : }
929 [ + - ]: 14845 : }
930 : : }
931 : :
932 [ + - ]: 14888 : if ( pNewAttr )
933 : : {
934 [ + - ]: 14888 : SwpHintsArray::Insert( pNewAttr );
935 : : // if ( bDestroyHint )
936 [ + - ]: 14888 : NoteInHistory( pNewAttr, true );
937 : : }
938 : :
939 [ + + ]: 14888 : if ( !bNoLengthAttribute )
940 : : {
941 [ + - ]: 12972 : nPorStart = *aStartIter;
942 [ + - ]: 12972 : ++aStartIter;
943 : : }
944 : : else
945 : 1916 : break;
946 : : }
947 : :
948 [ + + ]: 14834 : if ( bDestroyHint )
949 [ + - ]: 14834 : rNode.DestroyAttr( &rNewHint );
950 : 14834 : }
951 : :
952 : : /*************************************************************************
953 : : * SwTxtNode::MakeTxtAttr()
954 : : *************************************************************************/
955 : :
956 : 0 : SwTxtAttr* MakeRedlineTxtAttr( SwDoc & rDoc, SfxPoolItem & rAttr )
957 : : {
958 : : // this is intended _only_ for special-purpose redline attributes!
959 [ # # ]: 0 : switch (rAttr.Which())
960 : : {
961 : : case RES_CHRATR_COLOR:
962 : : case RES_CHRATR_WEIGHT:
963 : : case RES_CHRATR_CJK_WEIGHT:
964 : : case RES_CHRATR_CTL_WEIGHT:
965 : : case RES_CHRATR_POSTURE:
966 : : case RES_CHRATR_CJK_POSTURE:
967 : : case RES_CHRATR_CTL_POSTURE:
968 : : case RES_CHRATR_UNDERLINE:
969 : : case RES_CHRATR_CROSSEDOUT:
970 : : case RES_CHRATR_CASEMAP:
971 : : case RES_CHRATR_BACKGROUND:
972 : 0 : break;
973 : : default:
974 : : OSL_FAIL("unsupported redline attribute");
975 : 0 : break;
976 : : }
977 : :
978 : : // Put new attribute into pool
979 : : // FIXME: this const_cast is evil!
980 : : SfxPoolItem& rNew =
981 : 0 : const_cast<SfxPoolItem&>( rDoc.GetAttrPool().Put( rAttr ) );
982 [ # # ]: 0 : return new SwTxtAttrEnd( rNew, 0, 0 );
983 : : }
984 : :
985 : : // create new text attribute
986 : 30711 : SwTxtAttr* MakeTxtAttr( SwDoc & rDoc, SfxPoolItem& rAttr,
987 : : xub_StrLen const nStt, xub_StrLen const nEnd,
988 : : CopyOrNew_t const bIsCopy, SwTxtNode *const pTxtNode)
989 : : {
990 [ + + ]: 30711 : if ( isCHRATR(rAttr.Which()) )
991 : : {
992 : : // Somebody wants to build a SwTxtAttr for a character attribute.
993 : : // Sorry, this is not allowed any longer.
994 : : // You'll get a brand new autostyle attribute:
995 : 841 : SfxItemSet aItemSet( rDoc.GetAttrPool(),
996 [ + - ]: 841 : RES_CHRATR_BEGIN, RES_CHRATR_END );
997 [ + - ]: 841 : aItemSet.Put( rAttr );
998 [ + - ][ + - ]: 841 : return MakeTxtAttr( rDoc, aItemSet, nStt, nEnd );
999 : : }
1000 [ + + - + ]: 86122 : else if ( RES_TXTATR_AUTOFMT == rAttr.Which() &&
[ - + ]
1001 : : static_cast<const SwFmtAutoFmt&>(rAttr).GetStyleHandle()->
1002 [ + - ][ + + ]: 56252 : GetPool() != &rDoc.GetAttrPool() )
[ # # ]
1003 : : {
1004 : : // If the attribute is an auto-style which refers to a pool that is
1005 : : // different from rDoc's pool, we have to correct this:
1006 [ # # ]: 0 : const StylePool::SfxItemSet_Pointer_t pAutoStyle = static_cast<const SwFmtAutoFmt&>(rAttr).GetStyleHandle();
1007 : : ::std::auto_ptr<const SfxItemSet> pNewSet(
1008 [ # # ]: 0 : pAutoStyle->SfxItemSet::Clone( sal_True, &rDoc.GetAttrPool() ));
1009 [ # # ]: 0 : SwTxtAttr* pNew = MakeTxtAttr( rDoc, *pNewSet, nStt, nEnd );
1010 [ # # ][ # # ]: 0 : return pNew;
1011 : : }
1012 : :
1013 : : // Put new attribute into pool
1014 : : // FIXME: this const_cast is evil!
1015 : : SfxPoolItem& rNew =
1016 : 29870 : const_cast<SfxPoolItem&>( rDoc.GetAttrPool().Put( rAttr ) );
1017 : :
1018 : 29870 : SwTxtAttr* pNew = 0;
1019 [ + + + + : 29870 : switch( rNew.Which() )
+ + + + +
+ ]
1020 : : {
1021 : : case RES_TXTATR_CHARFMT:
1022 : : {
1023 : 43 : SwFmtCharFmt &rFmtCharFmt = (SwFmtCharFmt&) rNew;
1024 [ - + ]: 43 : if( !rFmtCharFmt.GetCharFmt() )
1025 : : {
1026 : 0 : rFmtCharFmt.SetCharFmt( rDoc.GetDfltCharFmt() );
1027 : : }
1028 : :
1029 [ + - ]: 43 : pNew = new SwTxtCharFmt( rFmtCharFmt, nStt, nEnd );
1030 : : }
1031 : 43 : break;
1032 : : case RES_TXTATR_INETFMT:
1033 [ + - ]: 115 : pNew = new SwTxtINetFmt( (SwFmtINetFmt&)rNew, nStt, nEnd );
1034 : 115 : break;
1035 : : case RES_TXTATR_FIELD:
1036 : : pNew = new SwTxtFld( static_cast<SwFmtFld &>(rNew), nStt,
1037 [ + - ]: 1549 : rDoc.IsClipBoard() );
1038 : 1549 : break;
1039 : : case RES_TXTATR_FLYCNT:
1040 : : {
1041 : : // erst hier wird das Frame-Format kopiert (mit Inhalt) !!
1042 [ + - ]: 970 : pNew = new SwTxtFlyCnt( (SwFmtFlyCnt&)rNew, nStt );
1043 : : // Kopie von einem Text-Attribut
1044 [ + + ]: 970 : if ( static_cast<const SwFmtFlyCnt &>(rAttr).GetTxtFlyCnt() )
1045 : : {
1046 : : // then the format must be copied
1047 : 3 : static_cast<SwTxtFlyCnt *>(pNew)->CopyFlyFmt( &rDoc );
1048 : : }
1049 : : }
1050 : 970 : break;
1051 : : case RES_TXTATR_FTN:
1052 [ + - ]: 72 : pNew = new SwTxtFtn( (SwFmtFtn&)rNew, nStt );
1053 : : // ggfs. SeqNo kopieren
1054 [ - + ]: 72 : if( ((SwFmtFtn&)rAttr).GetTxtFtn() )
1055 : 0 : ((SwTxtFtn*)pNew)->SetSeqNo( ((SwFmtFtn&)rAttr).GetTxtFtn()->GetSeqRefNo() );
1056 : 72 : break;
1057 : : case RES_TXTATR_REFMARK:
1058 : : pNew = nStt == nEnd
1059 [ + - ]: 55 : ? new SwTxtRefMark( (SwFmtRefMark&)rNew, nStt )
1060 [ + + ][ + - ]: 138 : : new SwTxtRefMark( (SwFmtRefMark&)rNew, nStt, &nEnd );
1061 : 83 : break;
1062 : : case RES_TXTATR_TOXMARK:
1063 [ + - ]: 78 : pNew = new SwTxtTOXMark( (SwTOXMark&)rNew, nStt, &nEnd );
1064 : 78 : break;
1065 : : case RES_TXTATR_CJK_RUBY:
1066 [ + - ]: 384 : pNew = new SwTxtRuby( (SwFmtRuby&)rNew, nStt, nEnd );
1067 : 384 : break;
1068 : : case RES_TXTATR_META:
1069 : : case RES_TXTATR_METAFIELD:
1070 : 194 : pNew = SwTxtMeta::CreateTxtMeta( rDoc.GetMetaFieldManager(), pTxtNode,
1071 : 194 : static_cast<SwFmtMeta&>(rNew), nStt, nEnd, bIsCopy );
1072 : 194 : break;
1073 : : default:
1074 : : OSL_ENSURE(RES_TXTATR_AUTOFMT == rNew.Which(), "unknown attribute");
1075 [ + - ]: 26382 : pNew = new SwTxtAttrEnd( rNew, nStt, nEnd );
1076 : 26382 : break;
1077 : : }
1078 : :
1079 : 30711 : return pNew;
1080 : : }
1081 : :
1082 : 25433 : SwTxtAttr* MakeTxtAttr( SwDoc & rDoc, const SfxItemSet& rSet,
1083 : : xub_StrLen nStt, xub_StrLen nEnd )
1084 : : {
1085 : 25433 : IStyleAccess& rStyleAccess = rDoc.GetIStyleAccess();
1086 [ + - ]: 25433 : const StylePool::SfxItemSet_Pointer_t pAutoStyle = rStyleAccess.getAutomaticStyle( rSet, IStyleAccess::AUTO_STYLE_CHAR );
1087 [ + - ]: 25433 : SwFmtAutoFmt aNewAutoFmt;
1088 [ + - ][ + - ]: 25433 : aNewAutoFmt.SetStyleHandle( pAutoStyle );
[ + - ]
1089 [ + - ]: 25433 : SwTxtAttr* pNew = MakeTxtAttr( rDoc, aNewAutoFmt, nStt, nEnd );
1090 [ + - ][ + - ]: 25433 : return pNew;
1091 : : }
1092 : :
1093 : :
1094 : : // loesche das Text-Attribut (muss beim Pool abgemeldet werden!)
1095 : 29767 : void SwTxtNode::DestroyAttr( SwTxtAttr* pAttr )
1096 : : {
1097 [ + - ]: 29767 : if( pAttr )
1098 : : {
1099 : : // einige Sachen muessen vorm Loeschen der "Format-Attribute" erfolgen
1100 : 29767 : SwDoc* pDoc = GetDoc();
1101 : 29767 : sal_uInt16 nDelMsg = 0;
1102 [ + - + + : 29767 : switch( pAttr->Which() )
+ + + + ]
1103 : : {
1104 : : case RES_TXTATR_FLYCNT:
1105 : : {
1106 : : // siehe auch die Anmerkung "Loeschen von Formaten
1107 : : // zeichengebundener Frames" in fesh.cxx, SwFEShell::DelFmt()
1108 : 883 : SwFrmFmt* pFmt = pAttr->GetFlyCnt().GetFrmFmt();
1109 [ + + ]: 883 : if( pFmt ) // vom Undo auf 0 gesetzt ??
1110 : 869 : pDoc->DelLayoutFmt( (SwFlyFrmFmt*)pFmt );
1111 : : }
1112 : 883 : break;
1113 : :
1114 : : case RES_CHRATR_HIDDEN:
1115 : 0 : SetCalcHiddenCharFlags();
1116 : 0 : break;
1117 : :
1118 : : case RES_TXTATR_FTN:
1119 : 69 : ((SwTxtFtn*)pAttr)->SetStartNode( 0 );
1120 : 69 : nDelMsg = RES_FOOTNOTE_DELETED;
1121 : 69 : break;
1122 : :
1123 : : case RES_TXTATR_FIELD:
1124 [ + + ]: 1546 : if( !pDoc->IsInDtor() )
1125 : : {
1126 : : // Wenn wir ein HiddenParaField sind, dann muessen wir
1127 : : // ggf. fuer eine Neuberechnung des Visible-Flags sorgen.
1128 : 38 : const SwField* pFld = pAttr->GetFld().GetFld();
1129 : :
1130 : : //JP 06-08-95: DDE-Felder bilden eine Ausnahme
1131 : : OSL_ENSURE( RES_DDEFLD == pFld->GetTyp()->Which() ||
1132 : : this == ((SwTxtFld*)pAttr)->GetpTxtNode(),
1133 : : "Wo steht denn dieses Feld?" );
1134 : :
1135 : : // bestimmte Felder mussen am Doc das Calculations-Flag updaten
1136 [ - + - + : 38 : switch( pFld->GetTyp()->Which() )
+ ]
1137 : : {
1138 : : case RES_HIDDENPARAFLD:
1139 : 0 : SetCalcHiddenParaField();
1140 : : // kein break !
1141 : : case RES_DBSETNUMBERFLD:
1142 : : case RES_GETEXPFLD:
1143 : : case RES_DBFLD:
1144 : : case RES_SETEXPFLD:
1145 : : case RES_HIDDENTXTFLD:
1146 : : case RES_DBNUMSETFLD:
1147 : : case RES_DBNEXTSETFLD:
1148 [ - + ][ # # ]: 2 : if( !pDoc->IsNewFldLst() && GetNodes().IsDocNodes() )
[ - + ]
1149 : 0 : pDoc->InsDelFldInFldLst( sal_False, *(SwTxtFld*)pAttr );
1150 : 2 : break;
1151 : : case RES_DDEFLD:
1152 [ # # # # ]: 0 : if( GetNodes().IsDocNodes() &&
[ # # ]
1153 : 0 : ((SwTxtFld*)pAttr)->GetpTxtNode() )
1154 : 0 : ((SwDDEFieldType*)pFld->GetTyp())->DecRefCnt();
1155 : 0 : break;
1156 : : case RES_POSTITFLD:
1157 : : {
1158 [ + - ]: 6 : const_cast<SwFmtFld&>(pAttr->GetFld()).Broadcast( SwFmtFldHint( &((SwTxtFld*)pAttr)->GetFld(), SWFMTFLD_REMOVED ) );
1159 : 38 : break;
1160 : : }
1161 : : }
1162 : : }
1163 : 1546 : nDelMsg = RES_FIELD_DELETED;
1164 : 1546 : break;
1165 : :
1166 : : case RES_TXTATR_TOXMARK:
1167 : 78 : static_cast<SwTOXMark&>(pAttr->GetAttr()).InvalidateTOXMark();
1168 : 78 : break;
1169 : :
1170 : : case RES_TXTATR_REFMARK:
1171 : 83 : nDelMsg = RES_REFMARK_DELETED;
1172 : 83 : break;
1173 : :
1174 : : case RES_TXTATR_META:
1175 : : case RES_TXTATR_METAFIELD:
1176 : 190 : static_cast<SwTxtMeta*>(pAttr)->ChgTxtNode(0);
1177 : 190 : break;
1178 : :
1179 : : default:
1180 : 26918 : break;
1181 : : }
1182 : :
1183 [ + + ][ + + ]: 29767 : if( nDelMsg && !pDoc->IsInDtor() && GetNodes().IsDocNodes() )
[ + - ][ + + ]
1184 : : {
1185 [ + - ]: 86 : SwPtrMsgPoolItem aMsgHint( nDelMsg, (void*)&pAttr->GetAttr() );
1186 [ + - ][ + - ]: 86 : pDoc->GetUnoCallBack()->ModifyNotification( &aMsgHint, &aMsgHint );
[ + - ]
1187 : : }
1188 : :
1189 : 29767 : SwTxtAttr::Destroy( pAttr, pDoc->GetAttrPool() );
1190 : : }
1191 : 29767 : }
1192 : :
1193 : : /*************************************************************************
1194 : : * SwTxtNode::Insert()
1195 : : *************************************************************************/
1196 : :
1197 : : SwTxtAttr*
1198 : 1039 : SwTxtNode::InsertItem( SfxPoolItem& rAttr,
1199 : : const xub_StrLen nStart, const xub_StrLen nEnd, const SetAttrMode nMode )
1200 : : {
1201 : : // character attributes will be inserted as automatic styles:
1202 : : OSL_ENSURE( !isCHRATR(rAttr.Which()), "AUTOSTYLES - "
1203 : : "SwTxtNode::InsertItem should not be called with character attributes");
1204 : :
1205 : 1039 : SwTxtAttr *const pNew = MakeTxtAttr( *GetDoc(), rAttr, nStart, nEnd,
1206 [ + + ]: 2078 : (nMode & nsSetAttrMode::SETATTR_IS_COPY) ? COPY : NEW, this );
1207 : :
1208 [ + - ]: 1039 : if ( pNew )
1209 : : {
1210 : 1039 : const bool bSuccess( InsertHint( pNew, nMode ) );
1211 : : // N.B.: also check that the hint is actually in the hints array,
1212 : : // because hints of certain types may be merged after successful
1213 : : // insertion, and thus destroyed!
1214 [ + + ][ + + ]: 1039 : if (!bSuccess || ( USHRT_MAX == m_pSwpHints->GetPos( pNew ) ))
[ + - ]
1215 : : {
1216 : 3 : return 0;
1217 : : }
1218 : : }
1219 : :
1220 : 1039 : return pNew;
1221 : : }
1222 : :
1223 : : // take ownership of pAttr; if insertion fails, delete pAttr
1224 : 19573 : bool SwTxtNode::InsertHint( SwTxtAttr * const pAttr, const SetAttrMode nMode )
1225 : : {
1226 : 19573 : sal_Bool bHiddenPara = sal_False;
1227 : :
1228 : : OSL_ENSURE( pAttr && *pAttr->GetStart() <= Len(), "StartIdx out of bounds!" );
1229 : : OSL_ENSURE( !pAttr->GetEnd() || (*pAttr->GetEnd() <= Len()),
1230 : : "EndIdx out of bounds!" );
1231 : :
1232 : : // translate from SetAttrMode to InsertMode (for hints with CH_TXTATR)
1233 : : const enum IDocumentContentOperations::InsertFlags nInsertFlags =
1234 : : (nMode & nsSetAttrMode::SETATTR_FORCEHINTEXPAND)
1235 : : ? static_cast<IDocumentContentOperations::InsertFlags>(
1236 : : IDocumentContentOperations::INS_FORCEHINTEXPAND |
1237 : : IDocumentContentOperations::INS_EMPTYEXPAND)
1238 [ + + ]: 19573 : : IDocumentContentOperations::INS_EMPTYEXPAND;
1239 : :
1240 : : // need this after TryInsertHint, when pAttr may be deleted
1241 : 19573 : const xub_StrLen nStart( *pAttr->GetStart() );
1242 : 19573 : const bool bDummyChar( pAttr->HasDummyChar() );
1243 [ + + ]: 19573 : if (bDummyChar)
1244 : : {
1245 : 2890 : sal_uInt16 nInsMode = nMode;
1246 [ + + + + ]: 2890 : switch( pAttr->Which() )
1247 : : {
1248 : : case RES_TXTATR_FLYCNT:
1249 : : {
1250 : 970 : SwTxtFlyCnt *pFly = (SwTxtFlyCnt *)pAttr;
1251 : 970 : SwFrmFmt* pFmt = pAttr->GetFlyCnt().GetFrmFmt();
1252 [ + + ]: 970 : if( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode) )
1253 : : {
1254 : : // Wir muessen zuerst einfuegen, da in SetAnchor()
1255 : : // dem FlyFrm GetStart() uebermittelt wird.
1256 : : //JP 11.05.98: falls das Anker-Attribut schon richtig
1257 : : // gesetzt ist, dann korrigiere dieses nach dem Einfuegen
1258 : : // des Zeichens. Sonst muesste das immer ausserhalb
1259 : : // erfolgen (Fehleranfaellig !)
1260 : 967 : const SwFmtAnchor* pAnchor = 0;
1261 : : pFmt->GetItemState( RES_ANCHOR, sal_False,
1262 [ + - ]: 967 : (const SfxPoolItem**)&pAnchor );
1263 : :
1264 [ + - ]: 967 : SwIndex aIdx( this, *pAttr->GetStart() );
1265 [ + - ]: 967 : const rtl::OUString c(GetCharOfTxtAttr(*pAttr));
1266 [ + - ][ + - ]: 967 : InsertText( c, aIdx, nInsertFlags );
[ + - ]
1267 : 967 : nInsMode |= nsSetAttrMode::SETATTR_NOTXTATRCHR;
1268 : :
1269 [ + - + - ]: 5802 : if (pAnchor &&
[ + - + -
+ - ][ + - ]
1270 : 967 : (FLY_AS_CHAR == pAnchor->GetAnchorId()) &&
1271 [ + - ]: 967 : pAnchor->GetCntntAnchor() &&
1272 [ + - ][ + - ]: 1934 : pAnchor->GetCntntAnchor()->nNode == *this &&
[ + - ][ + - ]
[ # # ]
1273 [ + - ]: 967 : pAnchor->GetCntntAnchor()->nContent == aIdx )
1274 : : {
1275 : : const_cast<SwIndex&>(
1276 [ + - ][ + - ]: 967 : pAnchor->GetCntntAnchor()->nContent)--;
1277 [ + - ]: 967 : }
1278 : : }
1279 : 970 : pFly->SetAnchor( this );
1280 : :
1281 : : // Format-Pointer kann sich im SetAnchor geaendert haben!
1282 : : // (Kopieren in andere Docs!)
1283 : 970 : pFmt = pAttr->GetFlyCnt().GetFrmFmt();
1284 : 970 : SwDoc *pDoc = pFmt->GetDoc();
1285 : :
1286 : : // OD 26.06.2003 #108784# - allow drawing objects in header/footer.
1287 : : // But don't allow control objects in header/footer
1288 [ - + ]: 1464 : if( RES_DRAWFRMFMT == pFmt->Which() &&
[ + + - + ]
1289 : 494 : pDoc->IsInHeaderFooter( pFmt->GetAnchor().GetCntntAnchor()->nNode ) )
1290 : : {
1291 : : SwDrawContact* pDrawContact =
1292 : 0 : static_cast<SwDrawContact*>(pFmt->FindContactObj());
1293 [ # # ][ # # : 0 : if ( pDrawContact &&
# # # # ]
1294 : 0 : pDrawContact->GetMaster() &&
1295 : 0 : ::CheckControlLayer( pDrawContact->GetMaster() ) )
1296 : : {
1297 : : // das soll nicht meoglich sein; hier verhindern
1298 : : // Der Dtor des TxtHints loescht nicht das Zeichen.
1299 : : // Wenn ein CH_TXTATR_.. vorliegt, dann muss man
1300 : : // dieses explizit loeschen
1301 [ # # ]: 0 : if( nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode )
1302 : : {
1303 : : // loesche das Zeichen aus dem String !
1304 : : OSL_ENSURE( ( CH_TXTATR_BREAKWORD ==
1305 : : m_Text.GetChar(*pAttr->GetStart() ) ||
1306 : : CH_TXTATR_INWORD ==
1307 : : m_Text.GetChar(*pAttr->GetStart())),
1308 : : "where is my attribute character?" );
1309 [ # # ]: 0 : m_Text.Erase( *pAttr->GetStart(), 1 );
1310 : : // Indizies Updaten
1311 [ # # ]: 0 : SwIndex aTmpIdx( this, *pAttr->GetStart() );
1312 [ # # ][ # # ]: 0 : Update( aTmpIdx, 1, sal_True );
1313 : : }
1314 : : // do not record deletion of Format!
1315 [ # # ][ # # ]: 0 : ::sw::UndoGuard const ug(pDoc->GetIDocumentUndoRedo());
1316 [ # # ]: 0 : DestroyAttr( pAttr );
1317 [ # # ]: 0 : return false;
1318 : : }
1319 : : }
1320 : 970 : break;
1321 : : }
1322 : :
1323 : : case RES_TXTATR_FTN :
1324 : : {
1325 : : // Fussnoten, man kommt an alles irgendwie heran.
1326 : : // CntntNode erzeugen und in die Inserts-Section stellen
1327 : 72 : SwDoc *pDoc = GetDoc();
1328 [ + - ]: 72 : SwNodes &rNodes = pDoc->GetNodes();
1329 : :
1330 : : // FussNote in nicht Content-/Redline-Bereich einfuegen ??
1331 [ - + ]: 72 : if( StartOfSectionIndex() < rNodes.GetEndOfAutotext().GetIndex() )
1332 : : {
1333 : : // das soll nicht meoglich sein; hier verhindern
1334 : : // Der Dtor des TxtHints loescht nicht das Zeichen.
1335 : : // Wenn ein CH_TXTATR_.. vorliegt, dann muss man
1336 : : // dieses explizit loeschen
1337 [ # # ]: 0 : if( nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode )
1338 : : {
1339 : : // loesche das Zeichen aus dem String !
1340 : : OSL_ENSURE( ( CH_TXTATR_BREAKWORD ==
1341 : : m_Text.GetChar(*pAttr->GetStart() ) ||
1342 : : CH_TXTATR_INWORD ==
1343 : : m_Text.GetChar(*pAttr->GetStart())),
1344 : : "where is my attribute character?" );
1345 [ # # ]: 0 : m_Text.Erase( *pAttr->GetStart(), 1 );
1346 : : // Indizies Updaten
1347 [ # # ]: 0 : SwIndex aTmpIdx( this, *pAttr->GetStart() );
1348 [ # # ][ # # ]: 0 : Update( aTmpIdx, 1, sal_True );
1349 : : }
1350 [ # # ]: 0 : DestroyAttr( pAttr );
1351 : 0 : return false;
1352 : : }
1353 : :
1354 : : // wird eine neue Fussnote eingefuegt ??
1355 : 72 : sal_Bool bNewFtn = 0 == ((SwTxtFtn*)pAttr)->GetStartNode();
1356 [ + - ]: 72 : if( bNewFtn )
1357 : : {
1358 [ + - ]: 72 : ((SwTxtFtn*)pAttr)->MakeNewTextSection( GetNodes() );
1359 : 72 : SwRegHistory* pHist = GetpSwpHints()
1360 [ + + ]: 72 : ? GetpSwpHints()->GetHistory() : 0;
1361 [ + + ]: 72 : if( pHist )
1362 : 34 : pHist->ChangeNodeIndex( GetIndex() );
1363 : : }
1364 [ # # ][ # # ]: 0 : else if ( !GetpSwpHints() || !GetpSwpHints()->IsInSplitNode() )
[ # # ]
1365 : : {
1366 : : // loesche alle Frames der Section, auf die der StartNode zeigt
1367 : : sal_uLong nSttIdx =
1368 : 0 : ((SwTxtFtn*)pAttr)->GetStartNode()->GetIndex();
1369 [ # # ]: 0 : sal_uLong nEndIdx = rNodes[ nSttIdx++ ]->EndOfSectionIndex();
1370 : : SwCntntNode* pCNd;
1371 [ # # ]: 0 : for( ; nSttIdx < nEndIdx; ++nSttIdx )
1372 [ # # ][ # # ]: 0 : if( 0 != ( pCNd = rNodes[ nSttIdx ]->GetCntntNode() ))
1373 [ # # ]: 0 : pCNd->DelFrms();
1374 : : }
1375 : :
1376 [ + - ]: 72 : if( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode) )
1377 : : {
1378 : : // Wir muessen zuerst einfuegen, da sonst gleiche Indizes
1379 : : // entstehen koennen und das Attribut im _SortArr_ am
1380 : : // Dokument nicht eingetrage wird.
1381 [ + - ]: 72 : SwIndex aNdIdx( this, *pAttr->GetStart() );
1382 [ + - ]: 72 : const rtl::OUString c(GetCharOfTxtAttr(*pAttr));
1383 [ + - ][ + - ]: 72 : InsertText( c, aNdIdx, nInsertFlags );
[ + - ]
1384 [ + - ]: 72 : nInsMode |= nsSetAttrMode::SETATTR_NOTXTATRCHR;
1385 : : }
1386 : :
1387 : : // Wir tragen uns am FtnIdx-Array des Docs ein ...
1388 : 72 : SwTxtFtn* pTxtFtn = 0;
1389 [ - + ]: 72 : if( !bNewFtn )
1390 : : {
1391 : : // eine alte Ftn wird umgehaengt (z.B. SplitNode)
1392 [ # # ]: 0 : for( sal_uInt16 n = 0; n < pDoc->GetFtnIdxs().size(); ++n )
1393 [ # # ][ # # ]: 0 : if( pAttr == pDoc->GetFtnIdxs()[n] )
1394 : : {
1395 : : // neuen Index zuweisen, dafuer aus dem SortArray
1396 : : // loeschen und neu eintragen
1397 [ # # ]: 0 : pTxtFtn = pDoc->GetFtnIdxs()[n];
1398 [ # # ][ # # ]: 0 : pDoc->GetFtnIdxs().erase( pDoc->GetFtnIdxs().begin() + n );
1399 : 0 : break;
1400 : : }
1401 : : // wenn ueber Undo der StartNode gesetzt wurde, kann
1402 : : // der Index noch gar nicht in der Verwaltung stehen !!
1403 : : }
1404 [ + - ]: 72 : if( !pTxtFtn )
1405 : 72 : pTxtFtn = (SwTxtFtn*)pAttr;
1406 : :
1407 : : // fuers Update der Nummern und zum Sortieren
1408 : : // muss der Node gesetzt sein.
1409 : 72 : ((SwTxtFtn*)pAttr)->ChgTxtNode( this );
1410 : :
1411 : : // FussNote im Redline-Bereich NICHT ins FtnArray einfuegen!
1412 [ + - ]: 72 : if( StartOfSectionIndex() > rNodes.GetEndOfRedlines().GetIndex() )
1413 : : {
1414 [ + - ]: 72 : const bool bSuccess = pDoc->GetFtnIdxs().insert(pTxtFtn).second;
1415 : : OSL_ENSURE( bSuccess, "FtnIdx not inserted." );
1416 : : (void) bSuccess; // unused in non-debug
1417 : : }
1418 [ + - ]: 72 : SwNodeIndex aTmpIndex( *this );
1419 [ + - ]: 72 : pDoc->GetFtnIdxs().UpdateFtn( aTmpIndex);
1420 [ + - ][ + - ]: 72 : ((SwTxtFtn*)pAttr)->SetSeqRefNo();
1421 : : }
1422 : 72 : break;
1423 : :
1424 : : case RES_TXTATR_FIELD:
1425 : : {
1426 : : // fuer HiddenParaFields Benachrichtigungsmechanismus
1427 : : // anwerfen
1428 [ - + ]: 1549 : if( RES_HIDDENPARAFLD ==
1429 : 1549 : pAttr->GetFld().GetFld()->GetTyp()->Which() )
1430 : 0 : bHiddenPara = sal_True;
1431 : : }
1432 : 1549 : break;
1433 : :
1434 : : }
1435 : : // Fuer SwTxtHints ohne Endindex werden CH_TXTATR_..
1436 : : // eingefuegt, aStart muss danach um einen zurueckgesetzt werden.
1437 : : // Wenn wir im SwTxtNode::Copy stehen, so wurde das Zeichen bereits
1438 : : // mitkopiert. In solchem Fall ist SETATTR_NOTXTATRCHR angegeben worden.
1439 [ + + ]: 2890 : if( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nInsMode) )
1440 : : {
1441 [ + - ]: 1848 : SwIndex aIdx( this, *pAttr->GetStart() );
1442 [ + - ][ + - ]: 1848 : InsertText( rtl::OUString(GetCharOfTxtAttr(*pAttr)), aIdx, nInsertFlags );
[ + - ][ + - ]
1443 : :
1444 : : // adjust end of hint to account for inserted CH_TXTATR
1445 [ + - ]: 1848 : xub_StrLen * const pEnd(pAttr->GetEnd());
1446 [ + + ]: 1848 : if (pEnd)
1447 : : {
1448 : 194 : *pEnd = *pEnd + 1;
1449 [ + - ]: 1848 : }
1450 : : }
1451 : : }
1452 : :
1453 : 19573 : GetOrCreateSwpHints();
1454 : :
1455 : : // 4263: AttrInsert durch TextInsert => kein Adjust
1456 : 19573 : const bool bRet = m_pSwpHints->TryInsertHint( pAttr, *this, nMode );
1457 : :
1458 [ + - ][ + + ]: 19573 : if (!bRet && bDummyChar)
1459 : : {
1460 : : // undo insertion of dummy character
1461 : : // N.B. cannot insert the dummy character after inserting the hint,
1462 : : // because if the hint has no extent it will be moved in InsertText,
1463 : : // resulting in infinite recursion
1464 [ + - ]: 4 : if ( !(nsSetAttrMode::SETATTR_NOTXTATRCHR & nMode) )
1465 : : {
1466 : : OSL_ENSURE( ( CH_TXTATR_BREAKWORD == m_Text.GetChar(nStart) ||
1467 : : CH_TXTATR_INWORD == m_Text.GetChar(nStart) ),
1468 : : "where is my attribute character?" );
1469 [ + - ]: 4 : SwIndex aIdx( this, nStart );
1470 [ + - ][ + - ]: 4 : EraseText( aIdx, 1 );
1471 : : }
1472 : : }
1473 : :
1474 [ - + ]: 19573 : if ( bHiddenPara )
1475 : : {
1476 : 0 : SetCalcHiddenParaField();
1477 : : }
1478 : :
1479 : 19573 : return bRet;
1480 : : }
1481 : :
1482 : :
1483 : : /*************************************************************************
1484 : : * SwTxtNode::DeleteAttribute()
1485 : : *************************************************************************/
1486 : :
1487 : 10 : void SwTxtNode::DeleteAttribute( SwTxtAttr * const pAttr )
1488 : : {
1489 [ - + ]: 10 : if ( !HasHints() )
1490 : : {
1491 : : OSL_FAIL("DeleteAttribute called, but text node without hints?");
1492 : 10 : return;
1493 : : }
1494 : :
1495 [ + - ]: 10 : if ( pAttr->HasDummyChar() )
1496 : : {
1497 : : // Unbedingt Copy-konstruieren!
1498 [ + - ]: 10 : const SwIndex aIdx( this, *pAttr->GetStart() );
1499 : : // erase the CH_TXTATR, which will also delete pAttr
1500 [ + - ][ + - ]: 10 : EraseText( aIdx, 1 );
1501 : : }
1502 : : else
1503 : : {
1504 : : // create MsgHint before start/end become invalid
1505 : : SwUpdateAttr aHint(
1506 [ # # ][ # # ]: 0 : *pAttr->GetStart(), *pAttr->GetEnd(), pAttr->Which() );
[ # # ]
1507 [ # # ]: 0 : m_pSwpHints->Delete( pAttr );
1508 [ # # ]: 0 : SwTxtAttr::Destroy( pAttr, GetDoc()->GetAttrPool() );
1509 [ # # ]: 0 : NotifyClients( 0, &aHint );
1510 : :
1511 [ # # ][ # # ]: 0 : TryDeleteSwpHints();
1512 : : }
1513 : : }
1514 : :
1515 : : /*************************************************************************
1516 : : * SwTxtNode::DeleteAttributes()
1517 : : *************************************************************************/
1518 : :
1519 : : //FIXME: this does NOT respect SORT NUMBER (for CHARFMT)!
1520 : 20 : void SwTxtNode::DeleteAttributes( const sal_uInt16 nWhich,
1521 : : const xub_StrLen nStart, const xub_StrLen nEnd )
1522 : : {
1523 [ - + ]: 20 : if ( !HasHints() )
1524 : 20 : return;
1525 : :
1526 [ + + ][ + - ]: 42 : for ( sal_uInt16 nPos = 0; m_pSwpHints && nPos < m_pSwpHints->Count(); nPos++ )
[ + + ]
1527 : : {
1528 : 24 : SwTxtAttr * const pTxtHt = m_pSwpHints->GetTextHint( nPos );
1529 : 24 : const xub_StrLen nHintStart = *(pTxtHt->GetStart());
1530 [ + + ]: 24 : if (nStart < nHintStart)
1531 : : {
1532 : 2 : break; // sorted by start
1533 : : }
1534 [ + + ][ + - ]: 22 : else if ( (nStart == nHintStart) && (nWhich == pTxtHt->Which()) )
[ + + ]
1535 : : {
1536 [ - + ]: 20 : if ( nWhich == RES_CHRATR_HIDDEN )
1537 : : {
1538 : : OSL_FAIL("hey, that's a CHRATR! how did that get in?");
1539 : 0 : SetCalcHiddenCharFlags();
1540 : : }
1541 [ - + ]: 20 : else if ( nWhich == RES_TXTATR_CHARFMT )
1542 : : {
1543 : : // Check if character format contains hidden attribute:
1544 : 0 : const SwCharFmt* pFmt = pTxtHt->GetCharFmt().GetCharFmt();
1545 : : const SfxPoolItem* pItem;
1546 [ # # ][ # # ]: 0 : if ( SFX_ITEM_SET == pFmt->GetItemState( RES_CHRATR_HIDDEN, sal_True, &pItem ) )
1547 : 0 : SetCalcHiddenCharFlags();
1548 : : }
1549 : : // #i75430# Recalc hidden flags if necessary
1550 [ - + ]: 20 : else if ( nWhich == RES_TXTATR_AUTOFMT )
1551 : : {
1552 : : // Check if auto style contains hidden attribute:
1553 : 0 : const SfxPoolItem* pHiddenItem = CharFmt::GetItem( *pTxtHt, RES_CHRATR_HIDDEN );
1554 [ # # ]: 0 : if ( pHiddenItem )
1555 : 0 : SetCalcHiddenCharFlags();
1556 : : }
1557 : :
1558 : 20 : xub_StrLen const * const pEndIdx = pTxtHt->GetEnd();
1559 : :
1560 [ + - ]: 20 : if ( pTxtHt->HasDummyChar() )
1561 : : {
1562 : : // Unbedingt Copy-konstruieren!
1563 [ + - ]: 20 : const SwIndex aIdx( this, nStart );
1564 : : // erase the CH_TXTATR, which will also delete pTxtHt
1565 [ + - ][ + - ]: 20 : EraseText( aIdx, 1 );
1566 : : }
1567 [ # # ]: 0 : else if( *pEndIdx == nEnd )
1568 : : {
1569 : : // den MsgHint jetzt fuettern, weil gleich sind
1570 : : // Start und End weg.
1571 : : // Das CalcVisibleFlag bei HiddenParaFields entfaellt,
1572 : : // da dies das Feld im Dtor selbst erledigt.
1573 [ # # ]: 0 : SwUpdateAttr aHint( nStart, *pEndIdx, nWhich );
1574 [ # # ]: 0 : m_pSwpHints->DeleteAtPos( nPos ); // gefunden, loeschen,
1575 [ # # ]: 0 : SwTxtAttr::Destroy( pTxtHt, GetDoc()->GetAttrPool() );
1576 [ # # ][ # # ]: 0 : NotifyClients( 0, &aHint );
1577 : : }
1578 : : }
1579 : : }
1580 : 20 : TryDeleteSwpHints();
1581 : : }
1582 : :
1583 : : /*************************************************************************
1584 : : * SwTxtNode::DelSoftHyph()
1585 : : *************************************************************************/
1586 : :
1587 : 0 : void SwTxtNode::DelSoftHyph( const xub_StrLen nStt, const xub_StrLen nEnd )
1588 : : {
1589 : 0 : xub_StrLen nFndPos = nStt, nEndPos = nEnd;
1590 [ # # ][ # # ]: 0 : while( STRING_NOTFOUND !=
[ # # ]
1591 : 0 : ( nFndPos = m_Text.Search( CHAR_SOFTHYPHEN, nFndPos )) &&
1592 : : nFndPos < nEndPos )
1593 : : {
1594 [ # # ]: 0 : const SwIndex aIdx( this, nFndPos );
1595 [ # # ]: 0 : EraseText( aIdx, 1 );
1596 : 0 : --nEndPos;
1597 [ # # ]: 0 : }
1598 : 0 : }
1599 : :
1600 : : // setze diese Attribute am TextNode. Wird der gesamte Bereich umspannt,
1601 : : // dann setze sie nur im AutoAttrSet (SwCntntNode:: SetAttr)
1602 : 24508 : sal_Bool SwTxtNode::SetAttr( const SfxItemSet& rSet, xub_StrLen nStt,
1603 : : xub_StrLen nEnd, const SetAttrMode nMode )
1604 : : {
1605 [ - + ]: 24508 : if( !rSet.Count() )
1606 : 0 : return sal_False;
1607 : :
1608 : : // teil die Sets auf (fuer Selektion in Nodes)
1609 : 24508 : const SfxItemSet* pSet = &rSet;
1610 [ + - ]: 24508 : SfxItemSet aTxtSet( *rSet.GetPool(), RES_TXTATR_BEGIN, RES_TXTATR_END-1 );
1611 : :
1612 : : // gesamter Bereich
1613 [ + + ][ + + ]: 24508 : if ( !nStt && (nEnd == m_Text.Len()) &&
[ + + ][ + + ]
1614 : 14488 : !(nMode & nsSetAttrMode::SETATTR_NOFORMATATTR ) )
1615 : : {
1616 : : // sind am Node schon Zeichenvorlagen gesetzt, muss man diese Attribute
1617 : : // (rSet) immer als TextAttribute setzen, damit sie angezeigt werden.
1618 : 10264 : int bHasCharFmts = sal_False;
1619 [ + + ]: 10264 : if ( HasHints() )
1620 : : {
1621 [ + + ]: 6734 : for ( sal_uInt16 n = 0; n < m_pSwpHints->Count(); ++n )
1622 : : {
1623 [ + - ][ + + ]: 5672 : if ( (*m_pSwpHints)[ n ]->IsCharFmtAttr() )
1624 : : {
1625 : 108 : bHasCharFmts = sal_True;
1626 : 108 : break;
1627 : : }
1628 : : }
1629 : : }
1630 : :
1631 [ + + ]: 10264 : if( !bHasCharFmts )
1632 : : {
1633 [ + - ]: 10156 : aTxtSet.Put( rSet );
1634 : : // If there are any character attributes in rSet,
1635 : : // we want to set them at the paragraph:
1636 [ + + ]: 10156 : if( aTxtSet.Count() != rSet.Count() )
1637 : : {
1638 [ + - ]: 9738 : sal_Bool bRet = SetAttr( rSet );
1639 [ + - ]: 9738 : if( !aTxtSet.Count() )
1640 : 9738 : return bRet;
1641 : : }
1642 : :
1643 : : // check for auto style:
1644 : : const SfxPoolItem* pItem;
1645 [ + - ]: 418 : const bool bAutoStyle = SFX_ITEM_SET == aTxtSet.GetItemState( RES_TXTATR_AUTOFMT, sal_False, &pItem );
1646 [ + + ]: 418 : if ( bAutoStyle )
1647 : : {
1648 [ + - ]: 6 : boost::shared_ptr<SfxItemSet> pAutoStyleSet = static_cast<const SwFmtAutoFmt*>(pItem)->GetStyleHandle();
1649 [ + - ]: 6 : sal_Bool bRet = SetAttr( *pAutoStyleSet );
1650 [ + - ]: 6 : if( 1 == aTxtSet.Count() )
1651 [ + - ][ - + ]: 6 : return bRet;
1652 : : }
1653 : :
1654 : : // Continue with the text attributes:
1655 : 10156 : pSet = &aTxtSet;
1656 : : }
1657 : : }
1658 : :
1659 [ + - ]: 14764 : GetOrCreateSwpHints();
1660 : :
1661 [ + - ]: 14764 : SfxItemSet aCharSet( *rSet.GetPool(), aCharAutoFmtSetRange );
1662 : :
1663 : 14764 : sal_uInt16 nCount = 0;
1664 [ + - ]: 14764 : SfxItemIter aIter( *pSet );
1665 : 14764 : const SfxPoolItem* pItem = aIter.GetCurItem();
1666 : :
1667 : 0 : do
1668 : : {
1669 [ + - ][ + - ]: 14764 : if ( pItem && (reinterpret_cast<SfxPoolItem*>(-1) != pItem))
1670 : : {
1671 : 14764 : const sal_uInt16 nWhich = pItem->Which();
1672 : : OSL_ENSURE( isCHRATR(nWhich) || isTXTATR(nWhich),
1673 : : "SwTxtNode::SetAttr(): unknown attribute" );
1674 [ + - ][ + - ]: 14764 : if ( isCHRATR(nWhich) || isTXTATR(nWhich) )
[ + + ]
1675 : : {
1676 [ + + - + ]: 14807 : if ((RES_TXTATR_CHARFMT == nWhich) &&
[ - + ]
1677 : 43 : (GetDoc()->GetDfltCharFmt() ==
1678 : 43 : static_cast<const SwFmtCharFmt*>(pItem)->GetCharFmt()))
1679 : : {
1680 [ # # ]: 0 : SwIndex aIndex( this, nStt );
1681 [ # # ]: 0 : RstAttr( aIndex, nEnd - nStt, RES_TXTATR_CHARFMT, 0 );
1682 [ # # ][ # # ]: 0 : DontExpandFmt( aIndex );
1683 : : }
1684 : : else
1685 : : {
1686 [ + + ][ + + ]: 14764 : if (isCHRATR(nWhich) ||
[ + + ]
1687 : : (RES_TXTATR_UNKNOWN_CONTAINER == nWhich))
1688 : : {
1689 [ + - ]: 12330 : aCharSet.Put( *pItem );
1690 : : }
1691 : : else
1692 : : {
1693 : :
1694 : 2434 : SwTxtAttr *const pNew = MakeTxtAttr( *GetDoc(),
1695 [ + - ]: 2434 : const_cast<SfxPoolItem&>(*pItem), nStt, nEnd );
1696 [ + - ]: 2434 : if ( pNew )
1697 : : {
1698 [ + + ][ + - ]: 2434 : if ( nEnd != nStt && !pNew->GetEnd() )
[ - + ][ - + ]
1699 : : {
1700 : : OSL_FAIL("Attribut without end, but area marked");
1701 [ # # ]: 0 : DestroyAttr( pNew ); // do not insert
1702 : : }
1703 [ + - ][ + + ]: 2434 : else if ( InsertHint( pNew, nMode ) )
1704 : : {
1705 : 2430 : ++nCount;
1706 : : }
1707 : : }
1708 : : }
1709 : : }
1710 : : }
1711 : : }
1712 [ + - ]: 14764 : if ( aIter.IsAtEnd() )
1713 : 14764 : break;
1714 [ # # ]: 0 : pItem = aIter.NextItem();
1715 : : } while( true );
1716 : :
1717 [ + + ]: 14764 : if ( aCharSet.Count() )
1718 : : {
1719 [ + - ]: 12330 : SwTxtAttr* pTmpNew = MakeTxtAttr( *GetDoc(), aCharSet, nStt, nEnd );
1720 [ + - ][ + - ]: 12330 : if ( InsertHint( pTmpNew, nMode ) )
1721 : : {
1722 : 12330 : ++nCount;
1723 : : }
1724 : : }
1725 : :
1726 [ + - ]: 14764 : TryDeleteSwpHints();
1727 : :
1728 [ + + ][ + - ]: 24508 : return nCount ? sal_True : sal_False;
[ + - ][ + - ]
1729 : : }
1730 : :
1731 : 34 : void lcl_MergeAttr( SfxItemSet& rSet, const SfxPoolItem& rAttr )
1732 : : {
1733 [ + + ]: 34 : if ( RES_TXTATR_AUTOFMT == rAttr.Which() )
1734 : : {
1735 [ + - ]: 8 : const SfxItemSet* pCFSet = CharFmt::GetItemSet( rAttr );
1736 [ + - ]: 8 : if ( !pCFSet )
1737 : 34 : return;
1738 [ + - ]: 8 : SfxWhichIter aIter( *pCFSet );
1739 [ + - ]: 8 : sal_uInt16 nWhich = aIter.FirstWhich();
1740 [ + + ]: 344 : while( nWhich )
1741 : : {
1742 [ + + ][ + + ]: 664 : if( ( nWhich < RES_CHRATR_END ||
[ + + ][ + + ]
1743 : : RES_TXTATR_UNKNOWN_CONTAINER == nWhich ) &&
1744 [ + - ]: 328 : ( SFX_ITEM_SET == pCFSet->GetItemState( nWhich, sal_True ) ) )
1745 [ + - ][ + - ]: 88 : rSet.Put( pCFSet->Get( nWhich ) );
1746 [ + - ]: 336 : nWhich = aIter.NextWhich();
1747 [ + - ]: 8 : }
1748 : : }
1749 : : else
1750 : 26 : rSet.Put( rAttr );
1751 : : }
1752 : :
1753 : 17859 : void lcl_MergeAttr_ExpandChrFmt( SfxItemSet& rSet, const SfxPoolItem& rAttr )
1754 : : {
1755 [ + + + + : 52360 : if( RES_TXTATR_CHARFMT == rAttr.Which() ||
+ + ][ + + ]
1756 : 17426 : RES_TXTATR_INETFMT == rAttr.Which() ||
1757 : 17075 : RES_TXTATR_AUTOFMT == rAttr.Which() )
1758 : : {
1759 : 14917 : const SfxItemSet* pCFSet = CharFmt::GetItemSet( rAttr );
1760 : :
1761 [ + + ]: 14917 : if ( pCFSet )
1762 : : {
1763 [ + - ]: 14810 : SfxWhichIter aIter( *pCFSet );
1764 [ + - ]: 14810 : sal_uInt16 nWhich = aIter.FirstWhich();
1765 [ + + ]: 636153 : while( nWhich )
1766 : : {
1767 [ + + + + ]: 1256819 : if( ( nWhich < RES_CHRATR_END ||
[ + + ][ + + ]
[ + + ]
1768 : 28943 : ( RES_TXTATR_AUTOFMT == rAttr.Which() && RES_TXTATR_UNKNOWN_CONTAINER == nWhich ) ) &&
1769 [ + - ]: 606533 : ( SFX_ITEM_SET == pCFSet->GetItemState( nWhich, sal_True ) ) )
1770 [ + - ][ + - ]: 67541 : rSet.Put( pCFSet->Get( nWhich ) );
1771 [ + - ]: 621343 : nWhich = aIter.NextWhich();
1772 [ + - ]: 14810 : }
1773 : : }
1774 : : }
1775 : :
1776 : : // aufnehmen als MergeWert (falls noch nicht gesetzt neu setzen!)
1777 : :
1778 : : /* wenn mehrere Attribute ueberlappen gewinnt der letze !!
1779 : : z.B
1780 : : 1234567890123456789
1781 : : |------------| Font1
1782 : : |------| Font2
1783 : : ^ ^
1784 : : |--| Abfragebereich: -> Gueltig ist Font2
1785 : : */
1786 : 17859 : rSet.Put( rAttr );
1787 : 17859 : }
1788 : :
1789 : : struct SwPoolItemEndPair
1790 : : {
1791 : : public:
1792 : : const SfxPoolItem* mpItem;
1793 : : xub_StrLen mnEndPos;
1794 : :
1795 : 3500 : SwPoolItemEndPair() : mpItem( 0 ), mnEndPos( 0 ) {};
1796 : : };
1797 : :
1798 : 704 : void lcl_MergeListLevelIndentAsLRSpaceItem( const SwTxtNode& rTxtNode,
1799 : : SfxItemSet& rSet )
1800 : : {
1801 [ - + ]: 704 : if ( rTxtNode.AreListLevelIndentsApplicable() )
1802 : : {
1803 : 0 : const SwNumRule* pRule = rTxtNode.GetNumRule();
1804 [ # # ][ # # ]: 0 : if ( pRule && rTxtNode.GetActualListLevel() >= 0 )
[ # # ]
1805 : : {
1806 : 0 : const SwNumFmt& rFmt = pRule->Get(static_cast<sal_uInt16>(rTxtNode.GetActualListLevel()));
1807 [ # # ]: 0 : if ( rFmt.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
1808 : : {
1809 [ # # ]: 0 : SvxLRSpaceItem aLR( RES_LR_SPACE );
1810 [ # # ][ # # ]: 0 : aLR.SetTxtLeft( rFmt.GetIndentAt() );
1811 [ # # ][ # # ]: 0 : aLR.SetTxtFirstLineOfst( static_cast<short>(rFmt.GetFirstLineIndent()) );
1812 [ # # ][ # # ]: 0 : rSet.Put( aLR );
1813 : : }
1814 : : }
1815 : : }
1816 : 704 : }
1817 : :
1818 : : // erfrage die Attribute vom TextNode ueber den Bereich
1819 : 74450 : sal_Bool SwTxtNode::GetAttr( SfxItemSet& rSet, xub_StrLen nStt, xub_StrLen nEnd,
1820 : : sal_Bool bOnlyTxtAttr, sal_Bool bGetFromChrFmt,
1821 : : const bool bMergeIndentValuesOfNumRule ) const
1822 : : {
1823 [ + + ]: 74450 : if( HasHints() )
1824 : : {
1825 : : /* stelle erstmal fest, welche Text-Attribut in dem Bereich gueltig
1826 : : * sind. Dabei gibt es folgende Faelle:
1827 : : * UnEindeutig wenn: (wenn != Format-Attribut)
1828 : : * - das Attribut liegt vollstaendig im Bereich
1829 : : * - das Attributende liegt im Bereich
1830 : : * - der Attributanfang liegt im Bereich:
1831 : : * Eindeutig (im Set mergen):
1832 : : * - das Attrib umfasst den Bereich
1833 : : * nichts tun:
1834 : : * das Attribut liegt ausserhalb des Bereiches
1835 : : */
1836 : :
1837 : : void (*fnMergeAttr)( SfxItemSet&, const SfxPoolItem& )
1838 : : = bGetFromChrFmt ? &lcl_MergeAttr_ExpandChrFmt
1839 [ + + ]: 22731 : : &lcl_MergeAttr;
1840 : :
1841 : : // dann besorge mal die Auto-(Fmt)Attribute
1842 [ + - ]: 22731 : SfxItemSet aFmtSet( *rSet.GetPool(), rSet.GetRanges() );
1843 [ + + ]: 22731 : if( !bOnlyTxtAttr )
1844 : : {
1845 [ + - ]: 22706 : SwCntntNode::GetAttr( aFmtSet );
1846 [ + + ]: 22706 : if ( bMergeIndentValuesOfNumRule )
1847 : : {
1848 [ + - ]: 388 : lcl_MergeListLevelIndentAsLRSpaceItem( *this, aFmtSet );
1849 : : }
1850 : : }
1851 : :
1852 : 22731 : const sal_uInt16 nSize = m_pSwpHints->Count();
1853 : :
1854 [ + + ]: 22731 : if( nStt == nEnd ) // kein Bereich:
1855 : : {
1856 [ + + ]: 374037 : for (sal_uInt16 n = 0; n < nSize; ++n)
1857 : : {
1858 [ + - ]: 360867 : const SwTxtAttr* pHt = (*m_pSwpHints)[n];
1859 : 360867 : const xub_StrLen nAttrStart = *pHt->GetStart();
1860 [ + + ]: 360867 : if( nAttrStart > nEnd ) // ueber den Bereich hinaus
1861 : 188 : break;
1862 : :
1863 [ + - ]: 360679 : const xub_StrLen* pAttrEnd = pHt->GetEnd();
1864 [ + + ]: 360679 : if ( ! pAttrEnd ) // no attributes without end
1865 : 350359 : continue;
1866 : :
1867 [ + + + + ]: 15294 : if( ( nAttrStart < nStt &&
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
1868 : 4974 : ( pHt->DontExpand() ? nStt < *pAttrEnd
1869 : : : nStt <= *pAttrEnd )) ||
1870 : : ( nStt == nAttrStart &&
1871 : : ( nAttrStart == *pAttrEnd || !nStt )))
1872 [ + - ]: 8246 : (*fnMergeAttr)( rSet, pHt->GetAttr() );
1873 : : }
1874 : : }
1875 : : else // es ist ein Bereich definiert
1876 : : {
1877 : : // #i75299#
1878 : 9561 : ::std::auto_ptr< std::vector< SwPoolItemEndPair > > pAttrArr;
1879 : :
1880 : : const sal_uInt16 coArrSz = static_cast<sal_uInt16>(RES_TXTATR_WITHEND_END) -
1881 : 9561 : static_cast<sal_uInt16>(RES_CHRATR_BEGIN);
1882 : :
1883 [ + + ]: 27934 : for (sal_uInt16 n = 0; n < nSize; ++n)
1884 : : {
1885 [ + - ]: 18821 : const SwTxtAttr* pHt = (*m_pSwpHints)[n];
1886 : 18821 : const xub_StrLen nAttrStart = *pHt->GetStart();
1887 [ + + ]: 18821 : if( nAttrStart > nEnd ) // ueber den Bereich hinaus
1888 : 448 : break;
1889 : :
1890 [ + - ]: 18373 : const xub_StrLen* pAttrEnd = pHt->GetEnd();
1891 [ + + ]: 18373 : if ( ! pAttrEnd ) // no attributes without end
1892 : 794 : continue;
1893 : :
1894 : 17579 : sal_Bool bChkInvalid = sal_False;
1895 [ + + ]: 17579 : if( nAttrStart <= nStt ) // vor oder genau Start
1896 : : {
1897 [ + + ]: 16668 : if( *pAttrEnd <= nStt ) // liegt davor
1898 : 6973 : continue;
1899 : :
1900 [ + + ]: 9695 : if( nEnd <= *pAttrEnd ) // hinter oder genau Ende
1901 [ + - ]: 9647 : (*fnMergeAttr)( aFmtSet, pHt->GetAttr() );
1902 : : else
1903 : : // else if( pHt->GetAttr() != aFmtSet.Get( pHt->Which() ) )
1904 : : // uneindeutig
1905 : 48 : bChkInvalid = sal_True;
1906 : : }
1907 [ + + ]: 911 : else if( nAttrStart < nEnd // reicht in den Bereich
1908 : : )// && pHt->GetAttr() != aFmtSet.Get( pHt->Which() ) )
1909 : 115 : bChkInvalid = sal_True;
1910 : :
1911 [ + + ]: 10606 : if( bChkInvalid )
1912 : : {
1913 : : // uneindeutig ?
1914 : 163 : ::std::auto_ptr< SfxItemIter > pItemIter;
1915 : 163 : const SfxPoolItem* pItem = 0;
1916 : :
1917 [ + + ][ + - ]: 163 : if ( RES_TXTATR_AUTOFMT == pHt->Which() )
1918 : : {
1919 [ + - ]: 21 : const SfxItemSet* pAutoSet = CharFmt::GetItemSet( pHt->GetAttr() );
1920 [ + - ]: 21 : if ( pAutoSet )
1921 : : {
1922 [ + - ][ + - ]: 21 : pItemIter.reset( new SfxItemIter( *pAutoSet ) );
1923 : 21 : pItem = pItemIter->GetCurItem();
1924 : : }
1925 : : }
1926 : : else
1927 : 142 : pItem = &pHt->GetAttr();
1928 : :
1929 : 163 : const sal_uInt16 nHintEnd = *pAttrEnd;
1930 : :
1931 [ + + ]: 347 : while ( pItem )
1932 : : {
1933 : 184 : const sal_uInt16 nHintWhich = pItem->Which();
1934 : : OSL_ENSURE(!isUNKNOWNATR(nHintWhich),
1935 : : "SwTxtNode::GetAttr(): unknown attribute?");
1936 : :
1937 [ + + ]: 184 : if ( !pAttrArr.get() )
1938 : : {
1939 : : pAttrArr.reset(
1940 [ + - ][ + - ]: 70 : new std::vector< SwPoolItemEndPair >(coArrSz));
1941 : : }
1942 : :
1943 : 184 : std::vector< SwPoolItemEndPair >::iterator pPrev = pAttrArr->begin();
1944 [ + - ]: 326 : if (isCHRATR(nHintWhich) ||
[ + + + - ]
1945 : 142 : isTXTATR_WITHEND(nHintWhich))
1946 : : {
1947 : 184 : pPrev += nHintWhich - RES_CHRATR_BEGIN;
1948 : : }
1949 : : else
1950 : : {
1951 : 0 : pPrev = pAttrArr->end();
1952 : : }
1953 : :
1954 [ + - ][ + - ]: 184 : if( pPrev != pAttrArr->end() )
1955 : : {
1956 [ + + ]: 184 : if( !pPrev->mpItem )
1957 : : {
1958 [ + - ][ + - ]: 91 : if ( bOnlyTxtAttr || *pItem != aFmtSet.Get( nHintWhich ) )
[ + - ][ + - ]
[ + - ]
1959 : : {
1960 [ + + ]: 91 : if( nAttrStart > nStt )
1961 : : {
1962 [ + - ]: 45 : rSet.InvalidateItem( nHintWhich );
1963 : 45 : pPrev->mpItem = (SfxPoolItem*)-1;
1964 : : }
1965 : : else
1966 : : {
1967 : 46 : pPrev->mpItem = pItem;
1968 : 46 : pPrev->mnEndPos = nHintEnd;
1969 : : }
1970 : : }
1971 : : }
1972 [ + + ]: 93 : else if( (SfxPoolItem*)-1 != pPrev->mpItem )
1973 : : {
1974 [ + + ][ + + ]: 42 : if( pPrev->mnEndPos == nAttrStart &&
[ + + ]
1975 [ + - ]: 12 : *pPrev->mpItem == *pItem )
1976 : : {
1977 : 6 : pPrev->mpItem = pItem;
1978 : 6 : pPrev->mnEndPos = nHintEnd;
1979 : : }
1980 : : else
1981 : : {
1982 [ + - ]: 24 : rSet.InvalidateItem( nHintWhich );
1983 : 24 : pPrev->mpItem = (SfxPoolItem*)-1;
1984 : : }
1985 : : }
1986 : : }
1987 : :
1988 : 226 : pItem = ( pItemIter.get() && !pItemIter->IsAtEnd() )
1989 [ + - ]: 226 : ? pItemIter->NextItem() : 0;
[ + + + + ]
1990 [ + - ]: 163 : } // end while
1991 : : }
1992 : : }
1993 : :
1994 [ + + ]: 9561 : if ( pAttrArr.get() )
1995 : : {
1996 [ + + ]: 3570 : for (sal_uInt16 n = 0; n < coArrSz; ++n)
1997 : : {
1998 : 3500 : const SwPoolItemEndPair& rItemPair = (*pAttrArr)[ n ];
1999 [ + + ][ + + ]: 3500 : if( (0 != rItemPair.mpItem) && ((SfxPoolItem*)-1 != rItemPair.mpItem) )
2000 : : {
2001 : : const sal_uInt16 nWh =
2002 : 22 : static_cast<sal_uInt16>(n + RES_CHRATR_BEGIN);
2003 : :
2004 [ - + ]: 22 : if( nEnd <= rItemPair.mnEndPos ) // hinter oder genau Ende
2005 : : {
2006 [ # # ][ # # ]: 0 : if( *rItemPair.mpItem != aFmtSet.Get( nWh ) )
[ # # ]
2007 [ # # ]: 0 : (*fnMergeAttr)( rSet, *rItemPair.mpItem );
2008 : : }
2009 : : else
2010 : : // uneindeutig
2011 [ + - ]: 22 : rSet.InvalidateItem( nWh );
2012 : : }
2013 : : }
2014 : 9561 : }
2015 : : }
2016 [ + + ]: 22731 : if( aFmtSet.Count() )
2017 : : {
2018 : : // aus dem Format-Set alle entfernen, die im TextSet auch gesetzt sind
2019 [ + - ]: 9865 : aFmtSet.Differentiate( rSet );
2020 : : // jetzt alle zusammen "mergen"
2021 [ + - ]: 9865 : rSet.Put( aFmtSet );
2022 [ + - ]: 22731 : }
2023 : : }
2024 [ + + ]: 51719 : else if( !bOnlyTxtAttr )
2025 : : {
2026 : : // dann besorge mal die Auto-(Fmt)Attribute
2027 : 51699 : SwCntntNode::GetAttr( rSet );
2028 [ + + ]: 51699 : if ( bMergeIndentValuesOfNumRule )
2029 : : {
2030 : 316 : lcl_MergeListLevelIndentAsLRSpaceItem( *this, rSet );
2031 : : }
2032 : : }
2033 : :
2034 [ + + ]: 74450 : return rSet.Count() ? sal_True : sal_False;
2035 : : }
2036 : :
2037 : :
2038 : : namespace
2039 : : {
2040 : :
2041 : : typedef std::pair<sal_uInt16, sal_uInt16> AttrSpan_t;
2042 : : typedef std::multimap<AttrSpan_t, const SwTxtAttr*> AttrSpanMap_t;
2043 : :
2044 : :
2045 : : struct IsAutoStyle
2046 : : {
2047 : : bool
2048 : 0 : operator()(const AttrSpanMap_t::value_type& i_rAttrSpan)
2049 : : const
2050 : : {
2051 [ # # ][ # # ]: 0 : return i_rAttrSpan.second && i_rAttrSpan.second->Which() == RES_TXTATR_AUTOFMT;
2052 : : }
2053 : : };
2054 : :
2055 : :
2056 : : /** Removes from io_rAttrSet all items that are set by style on the
2057 : : given span.
2058 : : */
2059 : : struct RemovePresentAttrs
2060 : : {
2061 : 0 : RemovePresentAttrs(SfxItemSet& io_rAttrSet)
2062 : 0 : : m_rAttrSet(io_rAttrSet)
2063 : : {
2064 : 0 : }
2065 : :
2066 : : void
2067 : 0 : operator()(const AttrSpanMap_t::value_type& i_rAttrSpan)
2068 : : const
2069 : : {
2070 [ # # ]: 0 : if (!i_rAttrSpan.second)
2071 : : {
2072 : 0 : return;
2073 : : }
2074 : :
2075 : 0 : const SwTxtAttr* const pAutoStyle(i_rAttrSpan.second);
2076 [ # # ]: 0 : SfxItemIter aIter(m_rAttrSet);
2077 : 0 : const SfxPoolItem* pItem(aIter.GetCurItem());
2078 [ # # ]: 0 : while (pItem)
2079 : : {
2080 : 0 : const sal_uInt16 nWhich(pItem->Which());
2081 [ # # ][ # # ]: 0 : if (CharFmt::IsItemIncluded(nWhich, pAutoStyle))
2082 : : {
2083 [ # # ]: 0 : m_rAttrSet.ClearItem(nWhich);
2084 : : }
2085 : :
2086 [ # # ]: 0 : if (aIter.IsAtEnd())
2087 : : {
2088 : 0 : break;
2089 : : }
2090 [ # # ]: 0 : pItem = aIter.NextItem();
2091 [ # # ]: 0 : }
2092 : : }
2093 : :
2094 : : private:
2095 : : SfxItemSet& m_rAttrSet;
2096 : : };
2097 : :
2098 : :
2099 : : /** Collects all style-covered spans from i_rHints to o_rSpanMap. In
2100 : : addition inserts dummy spans with pointer to format equal to 0 for
2101 : : all gaps (i.e. spans not covered by any style). This simplifies
2102 : : creation of autostyles for all needed spans, but it means all code
2103 : : that tries to access the pointer has to check if it's non-null!
2104 : : */
2105 : : void
2106 : 0 : lcl_CollectHintSpans(const SwpHints& i_rHints, const sal_uInt16 nLength,
2107 : : AttrSpanMap_t& o_rSpanMap)
2108 : : {
2109 : 0 : sal_uInt16 nLastEnd(0);
2110 : :
2111 [ # # ]: 0 : for (sal_uInt16 i(0); i != i_rHints.Count(); ++i)
2112 : : {
2113 [ # # ]: 0 : const SwTxtAttr* const pHint(i_rHints[i]);
2114 [ # # ]: 0 : const sal_uInt16 nWhich(pHint->Which());
2115 [ # # ][ # # ]: 0 : if (nWhich == RES_TXTATR_CHARFMT || nWhich == RES_TXTATR_AUTOFMT)
2116 : : {
2117 [ # # ][ # # ]: 0 : const AttrSpan_t aSpan(*pHint->GetStart(), *pHint->GetEnd());
2118 [ # # ]: 0 : o_rSpanMap.insert(AttrSpanMap_t::value_type(aSpan, pHint));
2119 : :
2120 : : // < not != because there may be multiple CHARFMT at same range
2121 [ # # ]: 0 : if (nLastEnd < aSpan.first)
2122 : : {
2123 : : // insert dummy span covering the gap
2124 : : o_rSpanMap.insert(AttrSpanMap_t::value_type(
2125 [ # # ][ # # ]: 0 : AttrSpan_t(nLastEnd, aSpan.first), 0));
[ # # ]
2126 : : }
2127 : :
2128 : 0 : nLastEnd = aSpan.second;
2129 : : }
2130 : : }
2131 : :
2132 : : // no hints at the end (special case: no hints at all in i_rHints)
2133 [ # # ][ # # ]: 0 : if (nLastEnd != nLength && nLength != 0)
2134 : : {
2135 : : o_rSpanMap.insert(
2136 [ # # ][ # # ]: 0 : AttrSpanMap_t::value_type(AttrSpan_t(nLastEnd, nLength), 0));
[ # # ]
2137 : : }
2138 : 0 : }
2139 : :
2140 : :
2141 : : void
2142 : 0 : lcl_FillWhichIds(const SfxItemSet& i_rAttrSet, std::vector<sal_uInt16>& o_rClearIds)
2143 : : {
2144 [ # # ]: 0 : o_rClearIds.reserve(i_rAttrSet.Count());
2145 [ # # ]: 0 : SfxItemIter aIter(i_rAttrSet);
2146 : 0 : const SfxPoolItem* pItem(aIter.GetCurItem());
2147 [ # # ]: 0 : while (pItem)
2148 : : {
2149 [ # # ]: 0 : o_rClearIds.push_back(pItem->Which());
2150 : :
2151 [ # # ]: 0 : if (aIter.IsAtEnd())
2152 : : {
2153 : 0 : break;
2154 : : }
2155 [ # # ]: 0 : pItem = aIter.NextItem();
2156 [ # # ]: 0 : }
2157 : 0 : }
2158 : :
2159 : : struct SfxItemSetClearer
2160 : : {
2161 : : SfxItemSet & m_rItemSet;
2162 : 489 : SfxItemSetClearer(SfxItemSet & rItemSet) : m_rItemSet(rItemSet) { }
2163 : 0 : void operator()(sal_uInt16 const nWhich) { m_rItemSet.ClearItem(nWhich); }
2164 : : };
2165 : :
2166 : : }
2167 : :
2168 : :
2169 : : /** Does the hard work of SwTxtNode::FmtToTxtAttr: the real conversion
2170 : : of items to automatic styles.
2171 : : */
2172 : : void
2173 : 3933 : SwTxtNode::impl_FmtToTxtAttr(const SfxItemSet& i_rAttrSet)
2174 : : {
2175 : : typedef AttrSpanMap_t::iterator AttrSpanMap_iterator_t;
2176 [ + - ]: 3933 : AttrSpanMap_t aAttrSpanMap;
2177 : :
2178 [ + - ]: 3933 : if (i_rAttrSet.Count() == 0)
2179 : : {
2180 : 3933 : return;
2181 : : }
2182 : :
2183 : : // 1. Identify all spans in hints' array
2184 : :
2185 [ # # ]: 0 : lcl_CollectHintSpans(*m_pSwpHints, m_Text.Len(), aAttrSpanMap);
2186 : :
2187 : : // 2. Go through all spans and insert new attrs
2188 : :
2189 : 0 : AttrSpanMap_iterator_t aCurRange(aAttrSpanMap.begin());
2190 : 0 : const AttrSpanMap_iterator_t aEnd(aAttrSpanMap.end());
2191 [ # # ]: 0 : while (aCurRange != aEnd)
2192 : : {
2193 : : typedef std::pair<AttrSpanMap_iterator_t, AttrSpanMap_iterator_t>
2194 : : AttrSpanMapRange_t;
2195 [ # # ]: 0 : AttrSpanMapRange_t aRange(aAttrSpanMap.equal_range(aCurRange->first));
2196 : :
2197 : : // 2a. Collect attributes to insert
2198 : :
2199 [ # # ]: 0 : SfxItemSet aCurSet(i_rAttrSet);
2200 [ # # ]: 0 : std::for_each(aRange.first, aRange.second, RemovePresentAttrs(aCurSet));
2201 : :
2202 : : // 2b. Insert automatic style containing the collected attributes
2203 : :
2204 [ # # ]: 0 : if (aCurSet.Count() != 0)
2205 : : {
2206 : : AttrSpanMap_iterator_t aAutoStyleIt(
2207 [ # # ]: 0 : std::find_if(aRange.first, aRange.second, IsAutoStyle()));
2208 [ # # ]: 0 : if (aAutoStyleIt != aRange.second)
2209 : : {
2210 : : // there already is an automatic style on that span:
2211 : : // create new one and remove the original one
2212 : 0 : SwTxtAttr* const pAutoStyle(const_cast<SwTxtAttr*>(aAutoStyleIt->second));
2213 : : const boost::shared_ptr<SfxItemSet> pOldStyle(
2214 : : static_cast<const SwFmtAutoFmt&>(
2215 [ # # ]: 0 : pAutoStyle->GetAttr()).GetStyleHandle());
2216 [ # # ]: 0 : aCurSet.Put(*pOldStyle);
2217 : :
2218 : : // remove the old hint
2219 [ # # ]: 0 : m_pSwpHints->Delete(pAutoStyle);
2220 [ # # ][ # # ]: 0 : DestroyAttr(pAutoStyle);
2221 : : }
2222 : : m_pSwpHints->Insert(
2223 : 0 : MakeTxtAttr(*GetDoc(), aCurSet,
2224 [ # # ][ # # ]: 0 : aCurRange->first.first, aCurRange->first.second));
2225 : : }
2226 : :
2227 : 0 : aCurRange = aRange.second;
2228 [ # # ]: 0 : }
2229 : :
2230 : : // 3. Clear items from the node
2231 [ # # ]: 0 : std::vector<sal_uInt16> aClearedIds;
2232 [ # # ]: 0 : lcl_FillWhichIds(i_rAttrSet, aClearedIds);
2233 [ # # ][ - + ]: 3933 : ClearItemsFromAttrSet(aClearedIds);
2234 : : }
2235 : :
2236 : 3933 : void SwTxtNode::FmtToTxtAttr( SwTxtNode* pNd )
2237 : : {
2238 [ + - ]: 3933 : SfxItemSet aThisSet( GetDoc()->GetAttrPool(), aCharFmtSetRange );
2239 [ + - ][ + + ]: 3933 : if( HasSwAttrSet() && GetpSwAttrSet()->Count() )
[ + - ][ + - ]
[ + + ]
2240 [ + - ][ + - ]: 15 : aThisSet.Put( *GetpSwAttrSet() );
2241 : :
2242 [ + - ]: 3933 : GetOrCreateSwpHints();
2243 : :
2244 [ + + ]: 3933 : if( pNd == this )
2245 : : {
2246 [ + - ]: 3444 : impl_FmtToTxtAttr(aThisSet);
2247 : : }
2248 : : else
2249 : : {
2250 : : // There are five possible combinations of items from this and
2251 : : // pNd (pNd is the 'main' node):
2252 : : //
2253 : : // case pNd this action
2254 : : // ----------------------------------------------------
2255 : : // 1 - - do nothing
2256 : : // 2 - a convert item to attr of this
2257 : : // 3 a - convert item to attr of pNd
2258 : : // 4 a a clear item in this
2259 : : // 5 a b convert item to attr of this
2260 : :
2261 [ + - ]: 489 : SfxItemSet aNdSet( pNd->GetDoc()->GetAttrPool(), aCharFmtSetRange );
2262 [ + - ][ + + ]: 489 : if( pNd->HasSwAttrSet() && pNd->GetpSwAttrSet()->Count() )
[ + - ][ + - ]
[ + + ]
2263 [ + - ][ + - ]: 342 : aNdSet.Put( *pNd->GetpSwAttrSet() );
2264 : :
2265 [ + - ]: 489 : pNd->GetOrCreateSwpHints();
2266 : :
2267 [ + - ]: 489 : std::vector<sal_uInt16> aProcessedIds;
2268 : :
2269 [ - + ]: 489 : if( aThisSet.Count() )
2270 : : {
2271 [ # # ]: 0 : SfxItemIter aIter( aThisSet );
2272 : 0 : const SfxPoolItem* pItem = aIter.GetCurItem(), *pNdItem = 0;
2273 [ # # ]: 0 : SfxItemSet aConvertSet( GetDoc()->GetAttrPool(), aCharFmtSetRange );
2274 [ # # ]: 0 : std::vector<sal_uInt16> aClearWhichIds;
2275 : :
2276 : 0 : while( true )
2277 : : {
2278 [ # # ][ # # ]: 0 : if( SFX_ITEM_SET == aNdSet.GetItemState( pItem->Which(), sal_False, &pNdItem ) )
2279 : : {
2280 [ # # ][ # # ]: 0 : if (*pItem == *pNdItem) // 4
2281 : : {
2282 [ # # ]: 0 : aClearWhichIds.push_back( pItem->Which() );
2283 : : }
2284 : : else // 5
2285 : : {
2286 [ # # ]: 0 : aConvertSet.Put(*pItem);
2287 : : }
2288 [ # # ]: 0 : aProcessedIds.push_back(pItem->Which());
2289 : : }
2290 : : else // 2
2291 : : {
2292 [ # # ]: 0 : aConvertSet.Put(*pItem);
2293 : : }
2294 : :
2295 [ # # ]: 0 : if( aIter.IsAtEnd() )
2296 : 0 : break;
2297 [ # # ]: 0 : pItem = aIter.NextItem();
2298 : : }
2299 : :
2300 : : // 4/ clear items of this that are set with the same value on pNd
2301 [ # # ]: 0 : ClearItemsFromAttrSet( aClearWhichIds );
2302 : :
2303 : : // 2, 5/ convert all other items to attrs
2304 [ # # ][ # # ]: 0 : impl_FmtToTxtAttr(aConvertSet);
[ # # ]
2305 : : }
2306 : :
2307 : : {
2308 : : std::for_each(aProcessedIds.begin(), aProcessedIds.end(),
2309 [ + - ]: 489 : SfxItemSetClearer(aNdSet));
2310 : :
2311 : : // 3/ convert items to attrs
2312 [ + - ]: 489 : pNd->impl_FmtToTxtAttr(aNdSet);
2313 : :
2314 [ - + ]: 489 : if( aNdSet.Count() )
2315 : : {
2316 [ # # ]: 0 : SwFmtChg aTmp1( pNd->GetFmtColl() );
2317 [ # # ][ # # ]: 0 : pNd->NotifyClients( &aTmp1, &aTmp1 );
2318 : : }
2319 [ + - ]: 489 : }
2320 : : }
2321 : :
2322 : 3933 : SetCalcHiddenCharFlags();
2323 : :
2324 [ + - ][ + - ]: 3933 : pNd->TryDeleteSwpHints();
2325 : 3933 : }
2326 : :
2327 : : /*************************************************************************
2328 : : * SwpHints::CalcFlags()
2329 : : *************************************************************************/
2330 : :
2331 : 16694 : void SwpHints::CalcFlags()
2332 : : {
2333 : 16694 : m_bDDEFields = m_bFootnote = false;
2334 : 16694 : const sal_uInt16 nSize = Count();
2335 : : const SwTxtAttr* pAttr;
2336 [ + + ]: 374840 : for( sal_uInt16 nPos = 0; nPos < nSize; ++nPos )
2337 : : {
2338 [ + + + ]: 358146 : switch( ( pAttr = (*this)[ nPos ])->Which() )
2339 : : {
2340 : : case RES_TXTATR_FTN:
2341 : 120 : m_bFootnote = true;
2342 [ - + ]: 120 : if ( m_bDDEFields )
2343 : 0 : return;
2344 : 120 : break;
2345 : : case RES_TXTATR_FIELD:
2346 : : {
2347 : 343634 : const SwField* pFld = pAttr->GetFld().GetFld();
2348 [ - + ]: 343634 : if( RES_DDEFLD == pFld->GetTyp()->Which() )
2349 : : {
2350 : 0 : m_bDDEFields = true;
2351 [ # # ]: 0 : if ( m_bFootnote )
2352 : 0 : return;
2353 : : }
2354 : : }
2355 : 343634 : break;
2356 : : }
2357 : : }
2358 : : }
2359 : :
2360 : : /*************************************************************************
2361 : : * SwpHints::CalcVisibleFlag()
2362 : : *************************************************************************/
2363 : :
2364 : 268 : bool SwpHints::CalcHiddenParaField()
2365 : : {
2366 : 268 : m_bCalcHiddenParaField = false;
2367 : 268 : bool bOldHasHiddenParaField = m_bHasHiddenParaField;
2368 : 268 : bool bNewHasHiddenParaField = false;
2369 : 268 : const sal_uInt16 nSize = Count();
2370 : : const SwTxtAttr *pTxtHt;
2371 : :
2372 [ + + ]: 536 : for( sal_uInt16 nPos = 0; nPos < nSize; ++nPos )
2373 : : {
2374 : 268 : pTxtHt = (*this)[ nPos ];
2375 : 268 : const sal_uInt16 nWhich = pTxtHt->Which();
2376 : :
2377 [ + - ]: 268 : if( RES_TXTATR_FIELD == nWhich )
2378 : : {
2379 : 268 : const SwFmtFld& rFld = pTxtHt->GetFld();
2380 [ - + ]: 268 : if( RES_HIDDENPARAFLD == rFld.GetFld()->GetTyp()->Which() )
2381 : : {
2382 [ # # ]: 0 : if( !((SwHiddenParaField*)rFld.GetFld())->IsHidden() )
2383 : : {
2384 : 0 : SetHiddenParaField(false);
2385 : 0 : return bOldHasHiddenParaField != bNewHasHiddenParaField;
2386 : : }
2387 : : else
2388 : : {
2389 : 0 : bNewHasHiddenParaField = true;
2390 : : }
2391 : : }
2392 : : }
2393 : : }
2394 : 268 : SetHiddenParaField( bNewHasHiddenParaField );
2395 : 268 : return bOldHasHiddenParaField != bNewHasHiddenParaField;
2396 : : }
2397 : :
2398 : :
2399 : : /*************************************************************************
2400 : : * SwpHints::NoteInHistory()
2401 : : *************************************************************************/
2402 : :
2403 : 32356 : void SwpHints::NoteInHistory( SwTxtAttr *pAttr, const bool bNew )
2404 : : {
2405 [ + + ]: 32356 : if ( m_pHistory ) { m_pHistory->AddHint( pAttr, bNew ); }
2406 : 32356 : }
2407 : :
2408 : : /*************************************************************************
2409 : : * SwpHints::MergePortions( )
2410 : : *************************************************************************/
2411 : :
2412 : 13860 : bool SwpHints::MergePortions( SwTxtNode& rNode )
2413 : : {
2414 [ + + ]: 13860 : if ( !Count() )
2415 : 8 : return false;
2416 : :
2417 : : // sort before merging
2418 [ + - ]: 13852 : SwpHintsArray::Resort();
2419 : :
2420 : 13852 : bool bRet = false;
2421 : : typedef std::multimap< int, SwTxtAttr* > PortionMap;
2422 [ + - ]: 13852 : PortionMap aPortionMap;
2423 : 13852 : xub_StrLen nLastPorStart = STRING_LEN;
2424 : 13852 : sal_uInt16 i = 0;
2425 : 13852 : int nKey = 0;
2426 : :
2427 : : // get portions by start position:
2428 [ + + ]: 57026 : for ( i = 0; i < Count(); ++i )
2429 : : {
2430 [ + - ]: 43174 : SwTxtAttr *pHt = GetTextHint( i );
2431 [ + - ][ + + ]: 86232 : if ( RES_TXTATR_CHARFMT != pHt->Which() &&
[ + + ][ + + ]
2432 [ + - ]: 43058 : RES_TXTATR_AUTOFMT != pHt->Which() )
2433 : : //&&
2434 : : //RES_TXTATR_INETFMT != pHt->Which() )
2435 : 17268 : continue;
2436 : :
2437 : 25906 : const xub_StrLen nPorStart = *pHt->GetStart();
2438 [ + + ][ + + ]: 25906 : if ( nPorStart != nLastPorStart && nLastPorStart != STRING_LEN )
2439 : 12081 : ++nKey;
2440 : 25906 : nLastPorStart = nPorStart;
2441 [ + - ]: 25906 : aPortionMap.insert( std::pair< const int, SwTxtAttr* >( nKey, pHt ) );
2442 : : }
2443 : :
2444 : : // check if portion i can be merged with portion i+1:
2445 : 13852 : i = 0;
2446 : 13852 : int j = i + 1;
2447 [ + + ]: 40139 : while ( i <= nKey )
2448 : : {
2449 [ + - ]: 26287 : std::pair< PortionMap::iterator, PortionMap::iterator > aRange1 = aPortionMap.equal_range( i );
2450 [ + - ]: 26287 : std::pair< PortionMap::iterator, PortionMap::iterator > aRange2 = aPortionMap.equal_range( j );
2451 : 26287 : PortionMap::iterator aIter1 = aRange1.first;
2452 : 26287 : PortionMap::iterator aIter2 = aRange2.first;
2453 : :
2454 : 26287 : bool bMerge = true;
2455 [ + - ]: 26287 : const sal_uInt16 nAttributesInPor1 = static_cast<sal_uInt16>(std::distance( aRange1.first, aRange1.second ));
2456 [ + - ]: 26287 : const sal_uInt16 nAttributesInPor2 = static_cast<sal_uInt16>(std::distance( aRange2.first, aRange2.second ));
2457 : :
2458 [ + + ][ + + ]: 26287 : if ( nAttributesInPor1 == nAttributesInPor2 && nAttributesInPor1 != 0 )
2459 : : {
2460 [ + + ]: 12435 : while ( aIter1 != aRange1.second )
2461 : : {
2462 : 12081 : const SwTxtAttr* p1 = (*aIter1).second;
2463 : 12081 : const SwTxtAttr* p2 = (*aIter2).second;
2464 [ + + ][ + - ]: 12081 : if ( *p1->GetEnd() < *p2->GetStart() || p1->Which() != p2->Which() || !(*p1 == *p2) )
[ + - ][ + - ]
[ + - ][ + + ]
[ + + ][ + - ]
2465 : : {
2466 : 11727 : bMerge = false;
2467 : 11727 : break;
2468 : : }
2469 : 354 : ++aIter1;
2470 : 354 : ++aIter2;
2471 : 12081 : }
2472 : : }
2473 : : else
2474 : : {
2475 : 14206 : bMerge = false;
2476 : : }
2477 : :
2478 [ + + ]: 26287 : if ( bMerge )
2479 : : {
2480 : : // erase all elements with key i + 1
2481 : 354 : xub_StrLen nNewPortionEnd = 0;
2482 [ + + ]: 708 : for ( aIter2 = aRange2.first; aIter2 != aRange2.second; ++aIter2 )
2483 : : {
2484 : 354 : SwTxtAttr* p2 = (*aIter2).second;
2485 [ + - ]: 354 : nNewPortionEnd = *p2->GetEnd();
2486 : :
2487 : 354 : const sal_uInt16 nCountBeforeDelete = Count();
2488 [ + - ]: 354 : Delete( p2 );
2489 : :
2490 : : // robust: check if deletion actually took place before destroying attribute:
2491 [ + - ]: 354 : if ( Count() < nCountBeforeDelete )
2492 [ + - ]: 354 : rNode.DestroyAttr( p2 );
2493 : : }
2494 [ + - ]: 354 : aPortionMap.erase( aRange2.first, aRange2.second );
2495 : 354 : ++j;
2496 : :
2497 : : // change all attributes with key i
2498 [ + - ]: 354 : aRange1 = aPortionMap.equal_range( i );
2499 [ + + ]: 708 : for ( aIter1 = aRange1.first; aIter1 != aRange1.second; ++aIter1 )
2500 : : {
2501 : 354 : SwTxtAttr* p1 = (*aIter1).second;
2502 [ + - ]: 354 : NoteInHistory( p1 );
2503 [ + - ]: 354 : *p1->GetEnd() = nNewPortionEnd;
2504 [ + - ]: 354 : NoteInHistory( p1, true );
2505 : 354 : bRet = true;
2506 : : }
2507 : : }
2508 : : else
2509 : : {
2510 : 25933 : ++i;
2511 : 26287 : j = i + 1;
2512 : : }
2513 : : }
2514 : :
2515 [ + + ]: 13852 : if ( bRet )
2516 : : {
2517 [ + - ]: 354 : SwpHintsArray::Resort();
2518 : : }
2519 : :
2520 : 13860 : return bRet;
2521 : : }
2522 : :
2523 : : // check if there is already a character format and adjust the sort numbers
2524 : 9 : void lcl_CheckSortNumber( const SwpHints& rHints, SwTxtCharFmt& rNewCharFmt )
2525 : : {
2526 : 9 : const xub_StrLen nHtStart = *rNewCharFmt.GetStart();
2527 : 9 : const xub_StrLen nHtEnd = *rNewCharFmt.GetEnd();
2528 : 9 : sal_uInt16 nSortNumber = 0;
2529 : :
2530 [ + - ]: 9 : for ( sal_uInt16 i = 0; i < rHints.Count(); ++i )
2531 : : {
2532 : 9 : const SwTxtAttr* pOtherHt = rHints[i];
2533 : :
2534 : 9 : const xub_StrLen nOtherStart = *pOtherHt->GetStart();
2535 : :
2536 [ + - ]: 9 : if ( nOtherStart > nHtStart )
2537 : 9 : break;
2538 : :
2539 [ # # ]: 0 : if ( RES_TXTATR_CHARFMT == pOtherHt->Which() )
2540 : : {
2541 : 0 : const xub_StrLen nOtherEnd = *pOtherHt->GetEnd();
2542 : :
2543 [ # # ][ # # ]: 0 : if ( nOtherStart == nHtStart && nOtherEnd == nHtEnd )
2544 : : {
2545 : 0 : const sal_uInt16 nOtherSortNum = static_cast<const SwTxtCharFmt*>(pOtherHt)->GetSortNumber();
2546 : 0 : nSortNumber = nOtherSortNum + 1;
2547 : : }
2548 : : }
2549 : : }
2550 : :
2551 [ - + ]: 9 : if ( nSortNumber > 0 )
2552 : 0 : rNewCharFmt.SetSortNumber( nSortNumber );
2553 : 9 : }
2554 : :
2555 : : /*************************************************************************
2556 : : * SwpHints::Insert()
2557 : : *************************************************************************/
2558 : :
2559 : : /*
2560 : : * Try to insert the new hint.
2561 : : * Depending on the type of the hint, this either always succeeds, or may fail.
2562 : : * Depending on the type of the hint, other hints may be deleted or
2563 : : * overwritten.
2564 : : * The return value indicates successful insertion.
2565 : : */
2566 : 19573 : bool SwpHints::TryInsertHint( SwTxtAttr* const pHint, SwTxtNode &rNode,
2567 : : const SetAttrMode nMode )
2568 : : {
2569 [ - + ]: 19573 : if ( USHRT_MAX == Count() ) // we're sorry, this flight is overbooked...
2570 : : {
2571 : : OSL_FAIL("hints array full :-(");
2572 : 0 : return false;
2573 : : }
2574 : :
2575 : : // Felder bilden eine Ausnahme:
2576 : : // 1) Sie koennen nie ueberlappen
2577 : : // 2) Wenn zwei Felder genau aneinander liegen,
2578 : : // sollen sie nicht zu einem verschmolzen werden.
2579 : : // Wir koennen also auf die while-Schleife verzichten
2580 : :
2581 : 19573 : xub_StrLen *pHtEnd = pHint->GetEnd();
2582 : 19573 : sal_uInt16 nWhich = pHint->Which();
2583 : :
2584 [ + + + + : 19573 : switch( nWhich )
+ + + + +
- + ]
2585 : : {
2586 : : case RES_TXTATR_CHARFMT:
2587 : : {
2588 : : // Check if character format contains hidden attribute:
2589 : 52 : const SwCharFmt* pFmt = pHint->GetCharFmt().GetCharFmt();
2590 : : const SfxPoolItem* pItem;
2591 [ - + ][ + - ]: 52 : if ( SFX_ITEM_SET == pFmt->GetItemState( RES_CHRATR_HIDDEN, sal_True, &pItem ) )
2592 : 0 : rNode.SetCalcHiddenCharFlags();
2593 : :
2594 : 52 : ((SwTxtCharFmt*)pHint)->ChgTxtNode( &rNode );
2595 : : break;
2596 : : }
2597 : : // #i75430# Recalc hidden flags if necessary
2598 : : case RES_TXTATR_AUTOFMT:
2599 : : {
2600 : : // Check if auto style contains hidden attribute:
2601 : 16156 : const SfxPoolItem* pHiddenItem = CharFmt::GetItem( *pHint, RES_CHRATR_HIDDEN );
2602 [ + + ]: 16156 : if ( pHiddenItem )
2603 : 11 : rNode.SetCalcHiddenCharFlags();
2604 : 16156 : break;
2605 : : }
2606 : : case RES_TXTATR_INETFMT:
2607 : 89 : static_cast<SwTxtINetFmt*>(pHint)->InitINetFmt(rNode);
2608 : 89 : break;
2609 : : case RES_TXTATR_FIELD:
2610 : : {
2611 : 1549 : sal_Bool bDelFirst = 0 != ((SwTxtFld*)pHint)->GetpTxtNode();
2612 : 1549 : ((SwTxtFld*)pHint)->ChgTxtNode( &rNode );
2613 : 1549 : SwDoc* pDoc = rNode.GetDoc();
2614 : 1549 : const SwField* pFld = ((SwTxtFld*)pHint)->GetFld().GetFld();
2615 : :
2616 [ + + ]: 1549 : if( !pDoc->IsNewFldLst() )
2617 : : {
2618 : : // was fuer ein Feld ist es denn ??
2619 : : // bestimmte Felder mussen am Doc das Calculations-Flag updaten
2620 [ - - + ]: 4 : switch( pFld->GetTyp()->Which() )
2621 : : {
2622 : : case RES_DBFLD:
2623 : : case RES_SETEXPFLD:
2624 : : case RES_HIDDENPARAFLD:
2625 : : case RES_HIDDENTXTFLD:
2626 : : case RES_DBNUMSETFLD:
2627 : : case RES_DBNEXTSETFLD:
2628 : : {
2629 [ # # ]: 0 : if( bDelFirst )
2630 : 0 : pDoc->InsDelFldInFldLst( sal_False, *(SwTxtFld*)pHint );
2631 [ # # ]: 0 : if( rNode.GetNodes().IsDocNodes() )
2632 : 0 : pDoc->InsDelFldInFldLst( sal_True, *(SwTxtFld*)pHint );
2633 : : }
2634 : 0 : break;
2635 : : case RES_DDEFLD:
2636 [ # # ]: 0 : if( rNode.GetNodes().IsDocNodes() )
2637 : 0 : ((SwDDEFieldType*)pFld->GetTyp())->IncRefCnt();
2638 : 4 : break;
2639 : : }
2640 : : }
2641 : :
2642 : : // gehts ins normale Nodes-Array?
2643 [ + - ]: 1549 : if( rNode.GetNodes().IsDocNodes() )
2644 : : {
2645 : 1549 : sal_Bool bInsFldType = sal_False;
2646 [ + - - + : 1549 : switch( pFld->GetTyp()->Which() )
+ ]
2647 : : {
2648 : : case RES_SETEXPFLD:
2649 : 3 : bInsFldType = ((SwSetExpFieldType*)pFld->GetTyp())->IsDeleted();
2650 [ - + ]: 3 : if( nsSwGetSetExpType::GSE_SEQ & ((SwSetExpFieldType*)pFld->GetTyp())->GetType() )
2651 : : {
2652 : : // bevor die ReferenzNummer gesetzt wird, sollte
2653 : : // das Feld am richtigen FeldTypen haengen!
2654 : : SwSetExpFieldType* pFldType = (SwSetExpFieldType*)
2655 : 0 : pDoc->InsertFldType( *pFld->GetTyp() );
2656 [ # # ]: 0 : if( pFldType != pFld->GetTyp() )
2657 : : {
2658 : : SwFmtFld* pFmtFld = (SwFmtFld*)&((SwTxtFld*)pHint)
2659 : 0 : ->GetFld();
2660 : 0 : pFmtFld->RegisterToFieldType( *pFldType );
2661 : 0 : pFmtFld->GetFld()->ChgTyp( pFldType );
2662 : : }
2663 : 0 : pFldType->SetSeqRefNo( *(SwSetExpField*)pFld );
2664 : : }
2665 : 3 : break;
2666 : : case RES_USERFLD:
2667 : 0 : bInsFldType = ((SwUserFieldType*)pFld->GetTyp())->IsDeleted();
2668 : 0 : break;
2669 : :
2670 : : case RES_DDEFLD:
2671 [ # # ]: 0 : if( pDoc->IsNewFldLst() )
2672 : 0 : ((SwDDEFieldType*)pFld->GetTyp())->IncRefCnt();
2673 : 0 : bInsFldType = ((SwDDEFieldType*)pFld->GetTyp())->IsDeleted();
2674 : 0 : break;
2675 : :
2676 : : case RES_POSTITFLD:
2677 [ + - ]: 27 : if ( pDoc->GetDocShell() )
2678 [ + - ]: 27 : pDoc->GetDocShell()->Broadcast( SwFmtFldHint( &((SwTxtFld*)pHint)->GetFld(), SWFMTFLD_INSERTED ) );
2679 : 27 : break;
2680 : : }
2681 [ - + ]: 1549 : if( bInsFldType )
2682 : 0 : pDoc->InsDeletedFldType( *pFld->GetTyp() );
2683 : : }
2684 : : }
2685 : 1549 : break;
2686 : : case RES_TXTATR_FTN :
2687 : 72 : ((SwTxtFtn*)pHint)->ChgTxtNode( &rNode );
2688 : 72 : break;
2689 : : case RES_TXTATR_REFMARK:
2690 : 83 : ((SwTxtRefMark*)pHint)->ChgTxtNode( &rNode );
2691 [ + - ]: 83 : if( rNode.GetNodes().IsDocNodes() )
2692 : : {
2693 : : // search for a reference with the same name
2694 : : SwTxtAttr* pTmpHt;
2695 : : xub_StrLen *pTmpHtEnd, *pTmpHintEnd;
2696 [ + + ]: 194 : for( sal_uInt16 n = 0, nEnd = Count(); n < nEnd; ++n )
2697 : : {
2698 [ + + - + ]: 177 : if (RES_TXTATR_REFMARK == (pTmpHt = GetTextHint(n))->Which() &&
[ # # ][ # # ]
[ - + ]
2699 : 66 : pHint->GetAttr() == pTmpHt->GetAttr() &&
2700 : 0 : 0 != ( pTmpHtEnd = pTmpHt->GetEnd() ) &&
2701 : 0 : 0 != ( pTmpHintEnd = pHint->GetEnd() ) )
2702 : : {
2703 : : SwComparePosition eCmp = ::ComparePosition(
2704 : 0 : *pTmpHt->GetStart(), *pTmpHtEnd,
2705 : 0 : *pHint->GetStart(), *pTmpHintEnd );
2706 : 0 : sal_Bool bDelOld = sal_True, bChgStart = sal_False, bChgEnd = sal_False;
2707 [ # # # # : 0 : switch( eCmp )
# ]
2708 : : {
2709 : : case POS_BEFORE:
2710 : 0 : case POS_BEHIND: bDelOld = sal_False; break;
2711 : :
2712 : 0 : case POS_OUTSIDE: bChgStart = bChgEnd = sal_True; break;
2713 : :
2714 : : case POS_COLLIDE_END:
2715 : 0 : case POS_OVERLAP_BEFORE: bChgStart = sal_True; break;
2716 : : case POS_COLLIDE_START:
2717 : 0 : case POS_OVERLAP_BEHIND: bChgEnd = sal_True; break;
2718 : 0 : default: break;
2719 : : }
2720 : :
2721 [ # # ]: 0 : if( bChgStart )
2722 : 0 : *pHint->GetStart() = *pTmpHt->GetStart();
2723 [ # # ]: 0 : if( bChgEnd )
2724 : 0 : *pTmpHintEnd = *pTmpHtEnd;
2725 : :
2726 [ # # ]: 0 : if( bDelOld )
2727 : : {
2728 : 0 : NoteInHistory( pTmpHt );
2729 : 0 : rNode.DestroyAttr( Cut( n-- ) );
2730 : 0 : --nEnd;
2731 : : }
2732 : : }
2733 : : }
2734 : : }
2735 : 83 : break;
2736 : : case RES_TXTATR_TOXMARK:
2737 : 78 : ((SwTxtTOXMark*)pHint)->ChgTxtNode( &rNode );
2738 : 78 : break;
2739 : :
2740 : : case RES_TXTATR_CJK_RUBY:
2741 : 330 : static_cast<SwTxtRuby*>(pHint)->InitRuby(rNode);
2742 : 330 : break;
2743 : :
2744 : : case RES_TXTATR_META:
2745 : : case RES_TXTATR_METAFIELD:
2746 : 194 : static_cast<SwTxtMeta *>(pHint)->ChgTxtNode( &rNode );
2747 : 194 : break;
2748 : :
2749 : : case RES_CHRATR_HIDDEN:
2750 : 0 : rNode.SetCalcHiddenCharFlags();
2751 : 0 : break;
2752 : : }
2753 : :
2754 [ + + ]: 19573 : if( nsSetAttrMode::SETATTR_DONTEXPAND & nMode )
2755 : 352 : pHint->SetDontExpand( sal_True );
2756 : :
2757 : : // SwTxtAttrs ohne Ende werden sonderbehandelt:
2758 : : // Sie werden natuerlich in das Array insertet, aber sie werden nicht
2759 : : // in die pPrev/Next/On/Off-Verkettung aufgenommen.
2760 : : // Der Formatierer erkennt diese TxtHints an dem CH_TXTATR_.. im Text !
2761 : 19573 : xub_StrLen nHtStart = *pHint->GetStart();
2762 [ + + ]: 19573 : if( !pHtEnd )
2763 : : {
2764 : 2696 : SwpHintsArray::Insert( pHint );
2765 : 2696 : CalcFlags();
2766 : : #ifdef DBG_UTIL
2767 : : if( !rNode.GetDoc()->IsInReading() )
2768 : : CHECK;
2769 : : #endif
2770 : : // ... und die Abhaengigen benachrichtigen
2771 [ + + ]: 2696 : if ( rNode.GetDepends() )
2772 : : {
2773 [ + - ]: 2195 : SwUpdateAttr aHint( nHtStart, nHtStart, nWhich );
2774 [ + - ][ + - ]: 2195 : rNode.ModifyNotification( 0, &aHint );
2775 : : }
2776 : 2696 : return true;
2777 : : }
2778 : :
2779 : : // ----------------------------------------------------------------
2780 : : // Ab hier gibt es nur noch pHint mit einem EndIdx !!!
2781 : :
2782 [ - + ]: 16877 : if( *pHtEnd < nHtStart )
2783 : : {
2784 : : OSL_ENSURE( *pHtEnd >= nHtStart,
2785 : : "+SwpHints::Insert: invalid hint, end < start" );
2786 : :
2787 : : // Wir drehen den Quatsch einfach um:
2788 : 0 : *pHint->GetStart() = *pHtEnd;
2789 : 0 : *pHtEnd = nHtStart;
2790 : 0 : nHtStart = *pHint->GetStart();
2791 : : }
2792 : :
2793 : : // I need this value later on for notification but the pointer may become invalid
2794 : 16877 : const xub_StrLen nHintEnd = *pHtEnd;
2795 : 16877 : const bool bNoHintAdjustMode = (nsSetAttrMode::SETATTR_NOHINTADJUST & nMode);
2796 : :
2797 : : // handle nesting attributes: inserting may fail due to overlap!
2798 [ + + ]: 16877 : if (pHint->IsNesting())
2799 : : {
2800 : : const bool bRet(
2801 : 613 : TryInsertNesting(rNode, *static_cast<SwTxtAttrNesting*>(pHint)));
2802 [ + + ]: 613 : if (!bRet) return false;
2803 : : }
2804 : : // Currently REFMARK and TOXMARK have OverlapAllowed set to true.
2805 : : // These attributes may be inserted directly.
2806 : : // Also attributes without length may be inserted directly.
2807 : : // SETATTR_NOHINTADJUST is set e.g., during undo.
2808 : : // Portion building in not necessary during XML import.
2809 : : else
2810 [ + + + + : 46014 : if ( !bNoHintAdjustMode &&
+ + ][ + + ]
[ + - ][ + + ]
2811 : 14903 : !pHint->IsOverlapAllowedAttr() &&
2812 : 14847 : !rNode.GetDoc()->IsInXMLImport() &&
2813 : : ( RES_TXTATR_AUTOFMT == nWhich ||
2814 : : RES_TXTATR_CHARFMT == nWhich ) )
2815 : : {
2816 : : OSL_ENSURE( nWhich != RES_TXTATR_AUTOFMT ||
2817 : : static_cast<const SwFmtAutoFmt&>(pHint->GetAttr()).GetStyleHandle()->GetPool() ==
2818 : : &rNode.GetDoc()->GetAttrPool(),
2819 : : "AUTOSTYLES - Pool mismatch" );
2820 : :
2821 : 14834 : BuildPortions( rNode, *pHint, nMode );
2822 : :
2823 [ + + ]: 14834 : if ( nHtStart < nHintEnd ) // skip merging for 0-length attributes
2824 : 12918 : MergePortions( rNode );
2825 : : }
2826 : : else
2827 : : {
2828 : : // There may be more than one character style at the current position.
2829 : : // Take care of the sort number.
2830 : : // Special case ruby portion: During import, the ruby attribute is set
2831 : : // multiple times
2832 : : // Special case hyperlink: During import, the ruby attribute is set
2833 : : // multiple times
2834 : : // FME 2007-11-08 #i82989# in NOHINTADJUST mode, we want to insert
2835 : : // character attributes directly
2836 [ + + ][ - + ]: 1430 : if ( ( RES_TXTATR_CHARFMT == nWhich && !bNoHintAdjustMode ) )
2837 : : {
2838 : 0 : BuildPortions( rNode, *pHint, nMode );
2839 : : }
2840 : : else
2841 : : {
2842 : : // #i82989# Check sort numbers in NoHintAdjustMode
2843 [ + + ]: 1430 : if ( RES_TXTATR_CHARFMT == nWhich )
2844 : 9 : lcl_CheckSortNumber( *this, *static_cast<SwTxtCharFmt*>(pHint) );
2845 : :
2846 : 1430 : SwpHintsArray::Insert( pHint );
2847 : 1430 : NoteInHistory( pHint, true );
2848 : : }
2849 : : }
2850 : :
2851 : : // ... und die Abhaengigen benachrichtigen
2852 [ + + ]: 16873 : if ( rNode.GetDepends() )
2853 : : {
2854 [ + + ][ + - ]: 8848 : SwUpdateAttr aHint( nHtStart, nHtStart == nHintEnd ? nHintEnd + 1 : nHintEnd, nWhich );
2855 [ + - ][ + - ]: 8848 : rNode.ModifyNotification( 0, &aHint );
2856 : : }
2857 : :
2858 : : #ifdef DBG_UTIL
2859 : : if( !bNoHintAdjustMode && !rNode.GetDoc()->IsInReading() )
2860 : : CHECK;
2861 : : #endif
2862 : :
2863 : 19573 : return true;
2864 : : }
2865 : :
2866 : : /*************************************************************************
2867 : : * SwpHints::DeleteAtPos()
2868 : : *************************************************************************/
2869 : :
2870 : 13998 : void SwpHints::DeleteAtPos( const sal_uInt16 nPos )
2871 : : {
2872 : 13998 : SwTxtAttr *pHint = GetTextHint(nPos);
2873 : : // ChainDelete( pHint );
2874 : 13998 : NoteInHistory( pHint );
2875 : 13998 : SwpHintsArray::DeleteAtPos( nPos );
2876 : :
2877 [ + + ]: 13998 : if( RES_TXTATR_FIELD == pHint->Which() )
2878 : : {
2879 : 38 : SwFieldType* pFldTyp = ((SwTxtFld*)pHint)->GetFld().GetFld()->GetTyp();
2880 [ - + ]: 38 : if( RES_DDEFLD == pFldTyp->Which() )
2881 : : {
2882 : 0 : const SwTxtNode* pNd = ((SwTxtFld*)pHint)->GetpTxtNode();
2883 [ # # ][ # # ]: 0 : if( pNd && pNd->GetNodes().IsDocNodes() )
[ # # ]
2884 : 0 : ((SwDDEFieldType*)pFldTyp)->DecRefCnt();
2885 : 0 : ((SwTxtFld*)pHint)->ChgTxtNode( 0 );
2886 : : }
2887 [ + + ]: 38 : else if( RES_POSTITFLD == pFldTyp->Which() )
2888 : : {
2889 [ + - ]: 6 : const_cast<SwFmtFld&>(((SwTxtFld*)pHint)->GetFld()).Broadcast( SwFmtFldHint( &((SwTxtFld*)pHint)->GetFld(), SWFMTFLD_REMOVED ) );
2890 : : }
2891 [ - + # # ]: 32 : else if ( m_bHasHiddenParaField &&
[ - + ]
2892 : 0 : RES_HIDDENPARAFLD == pFldTyp->Which() )
2893 : : {
2894 : 0 : m_bCalcHiddenParaField = true;
2895 : : }
2896 : : }
2897 : :
2898 : 13998 : CalcFlags();
2899 : : CHECK;
2900 : 13998 : }
2901 : :
2902 : : // Ist der Hint schon bekannt, dann suche die Position und loesche ihn.
2903 : : // Ist er nicht im Array, so gibt es ein OSL_ENSURE(!!
2904 : :
2905 : 11480 : void SwpHints::Delete( SwTxtAttr* pTxtHt )
2906 : : {
2907 : : // Attr 2.0: SwpHintsArr::Delete( pTxtHt );
2908 : 11480 : const sal_uInt16 nPos = GetStartOf( pTxtHt );
2909 : : OSL_ENSURE( USHRT_MAX != nPos, "Attribut nicht im Attribut-Array!" );
2910 [ + - ]: 11480 : if( USHRT_MAX != nPos )
2911 : 11480 : DeleteAtPos( nPos );
2912 : 11480 : }
2913 : :
2914 : 0 : void SwTxtNode::ClearSwpHintsArr( bool bDelFields )
2915 : : {
2916 [ # # ]: 0 : if ( HasHints() )
2917 : : {
2918 : 0 : sal_uInt16 nPos = 0;
2919 [ # # ]: 0 : while ( nPos < m_pSwpHints->Count() )
2920 : : {
2921 : 0 : SwTxtAttr* pDel = m_pSwpHints->GetTextHint( nPos );
2922 : 0 : bool bDel = false;
2923 : :
2924 [ # # # ]: 0 : switch( pDel->Which() )
2925 : : {
2926 : : case RES_TXTATR_FLYCNT:
2927 : : case RES_TXTATR_FTN:
2928 : 0 : break;
2929 : :
2930 : : case RES_TXTATR_FIELD:
2931 [ # # ]: 0 : if( bDelFields )
2932 : 0 : bDel = true;
2933 : 0 : break;
2934 : : default:
2935 : 0 : bDel = true; break;
2936 : : }
2937 : :
2938 [ # # ]: 0 : if( bDel )
2939 : : {
2940 : 0 : m_pSwpHints->SwpHintsArray::DeleteAtPos( nPos );
2941 : 0 : DestroyAttr( pDel );
2942 : : }
2943 : : else
2944 : 0 : ++nPos;
2945 : : }
2946 : : }
2947 : 0 : }
2948 : :
2949 : 287207 : sal_uInt16 SwTxtNode::GetLang( const xub_StrLen nBegin, const xub_StrLen nLen,
2950 : : sal_uInt16 nScript ) const
2951 : : {
2952 : 287207 : sal_uInt16 nRet = LANGUAGE_DONTKNOW;
2953 : :
2954 [ + + ]: 287207 : if ( ! nScript )
2955 : : {
2956 [ + - ]: 184306 : nScript = pBreakIt->GetRealScriptOfText( m_Text, nBegin );
2957 : : }
2958 : :
2959 : : // #i91465# Consider nScript if pSwpHints == 0
2960 : 287207 : const sal_uInt16 nWhichId = GetWhichOfScript( RES_CHRATR_LANGUAGE, nScript );
2961 : :
2962 [ + + ]: 287207 : if ( HasHints() )
2963 : : {
2964 : 10382 : const xub_StrLen nEnd = nBegin + nLen;
2965 [ + + ]: 33348 : for ( sal_uInt16 i = 0, nSize = m_pSwpHints->Count(); i < nSize; ++i )
2966 : : {
2967 : : // ist der Attribut-Anfang schon groesser als der Idx ?
2968 : 22966 : const SwTxtAttr *pHt = m_pSwpHints->operator[](i);
2969 : 22966 : const xub_StrLen nAttrStart = *pHt->GetStart();
2970 [ + + ]: 22966 : if( nEnd < nAttrStart )
2971 : 2699 : break;
2972 : :
2973 : 20267 : const sal_uInt16 nWhich = pHt->Which();
2974 : :
2975 [ + + + + ]: 43762 : if( nWhichId == nWhich ||
[ + + ]
[ + - + + ]
2976 : 23495 : ( ( pHt->IsCharFmtAttr() || RES_TXTATR_AUTOFMT == nWhich ) && CharFmt::IsItemIncluded( nWhichId, pHt ) ) )
2977 : : {
2978 : 1473 : const xub_StrLen *pEndIdx = pHt->GetEnd();
2979 : : // Ueberlappt das Attribut den Bereich?
2980 : :
2981 [ + + ][ + + ]: 2465 : if( pEndIdx &&
[ + + ]
[ + + + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + - ]
2982 : : nLen ? ( nAttrStart < nEnd && nBegin < *pEndIdx )
2983 : : : (( nAttrStart < nBegin &&
2984 : 992 : ( pHt->DontExpand() ? nBegin < *pEndIdx
2985 : : : nBegin <= *pEndIdx )) ||
2986 : : ( nBegin == nAttrStart &&
2987 : : ( nAttrStart == *pEndIdx || !nBegin ))) )
2988 : : {
2989 : 718 : const SfxPoolItem* pItem = CharFmt::GetItem( *pHt, nWhichId );
2990 : 718 : sal_uInt16 nLng = ((SvxLanguageItem*)pItem)->GetLanguage();
2991 : :
2992 : : // Umfasst das Attribut den Bereich komplett?
2993 [ + - ][ + - ]: 718 : if( nAttrStart <= nBegin && nEnd <= *pEndIdx )
2994 : 718 : nRet = nLng;
2995 [ # # ]: 0 : else if( LANGUAGE_DONTKNOW == nRet )
2996 : 718 : nRet = nLng; // partielle Ueberlappung, der 1. gewinnt
2997 : : }
2998 : : }
2999 : : }
3000 : : }
3001 [ + + ]: 287207 : if( LANGUAGE_DONTKNOW == nRet )
3002 : : {
3003 : 286489 : nRet = ((SvxLanguageItem&)GetSwAttrSet().Get( nWhichId )).GetLanguage();
3004 [ - + ]: 286489 : if( LANGUAGE_DONTKNOW == nRet )
3005 : 0 : nRet = static_cast<sal_uInt16>(GetAppLanguage());
3006 : : }
3007 : 287207 : return nRet;
3008 : : }
3009 : :
3010 : :
3011 : 2887 : sal_Unicode GetCharOfTxtAttr( const SwTxtAttr& rAttr )
3012 : : {
3013 : 2887 : sal_Unicode cRet = CH_TXTATR_BREAKWORD;
3014 [ + + - ]: 2887 : switch ( rAttr.Which() )
3015 : : {
3016 : : case RES_TXTATR_REFMARK:
3017 : : case RES_TXTATR_TOXMARK:
3018 : 105 : cRet = CH_TXTATR_INWORD;
3019 : 105 : break;
3020 : :
3021 : : case RES_TXTATR_FIELD:
3022 : : case RES_TXTATR_FLYCNT:
3023 : : case RES_TXTATR_FTN:
3024 : : case RES_TXTATR_META:
3025 : : case RES_TXTATR_METAFIELD:
3026 : : {
3027 : 2782 : cRet = CH_TXTATR_BREAKWORD;
3028 : :
3029 : : // #i78149: PostIt fields should not break words for spell and grammar checking
3030 [ + + + + ]: 4331 : if (rAttr.Which() == RES_TXTATR_FIELD &&
[ + + ]
3031 : 1549 : RES_POSTITFLD == rAttr.GetFld().GetFld()->GetTyp()->Which())
3032 : 27 : cRet = CH_TXTATR_INWORD;
3033 : : }
3034 : 2782 : break;
3035 : :
3036 : : default:
3037 : : OSL_FAIL("GetCharOfTxtAttr: unknown attr");
3038 : 0 : break;
3039 : : }
3040 : 2887 : return cRet;
3041 : : }
3042 : :
3043 : :
3044 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|