Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <ctype.h>
21 :
22 : #include <com/sun/star/i18n/ScriptType.hpp>
23 : #include <i18npool/mslangid.hxx>
24 : #include <hintids.hxx> // CH_TXTATR
25 : #include <EnhancedPDFExportHelper.hxx>
26 : #include <SwPortionHandler.hxx>
27 : #include <porlay.hxx>
28 : #include <inftxt.hxx>
29 : #include <guess.hxx> // SwTxtGuess, line break
30 : #include <porglue.hxx>
31 : #include <portab.hxx> // pLastTab->
32 : #include <porfld.hxx> // SwFldPortion
33 : #include <wrong.hxx>
34 : #include <viewsh.hxx>
35 : #include <IDocumentSettingAccess.hxx>
36 : #include <viewopt.hxx> // SwViewOptions
37 :
38 : #include <IMark.hxx>
39 : #include <pam.hxx>
40 : #include <doc.hxx>
41 : #include <xmloff/odffields.hxx>
42 :
43 : using namespace ::sw::mark;
44 : using namespace ::com::sun::star;
45 : using namespace ::com::sun::star::i18n::ScriptType;
46 :
47 : /*************************************************************************
48 : * lcl_AddSpace
49 : * Returns for how many characters an extra space has to be added
50 : * (for justified alignment).
51 : *************************************************************************/
52 :
53 16 : static sal_uInt16 lcl_AddSpace( const SwTxtSizeInfo &rInf, const XubString* pStr,
54 : const SwLinePortion& rPor )
55 : {
56 : xub_StrLen nPos, nEnd;
57 16 : const SwScriptInfo* pSI = 0;
58 :
59 16 : if ( pStr )
60 : {
61 : // passing a string means we are inside a field
62 0 : nPos = 0;
63 0 : nEnd = pStr->Len();
64 : }
65 : else
66 : {
67 16 : nPos = rInf.GetIdx();
68 16 : nEnd = rInf.GetIdx() + rPor.GetLen();
69 16 : pStr = &rInf.GetTxt();
70 16 : pSI = &((SwParaPortion*)rInf.GetParaPortion())->GetScriptInfo();
71 : }
72 :
73 16 : sal_uInt16 nCnt = 0;
74 16 : sal_uInt8 nScript = 0;
75 :
76 : // If portion consists of Asian characters and language is not
77 : // Korean, we add extra space to each character.
78 : // first we get the script type
79 16 : if ( pSI )
80 16 : nScript = pSI->ScriptType( nPos );
81 0 : else if ( pBreakIt->GetBreakIter().is() )
82 0 : nScript = (sal_uInt8)pBreakIt->GetBreakIter()->getScriptType( *pStr, nPos );
83 :
84 : // Note: rInf.GetIdx() can differ from nPos,
85 : // e.g., when rPor is a field portion. nPos referes to the string passed
86 : // to the function, rInf.GetIdx() referes to the original string.
87 :
88 : // We try to find out which justification mode is required. This is done by
89 : // evaluating the script type and the language attribute set for this portion
90 :
91 : // Asian Justification: Each character get some extra space
92 16 : if ( nEnd > nPos && ASIAN == nScript )
93 : {
94 : LanguageType aLang =
95 0 : rInf.GetTxtFrm()->GetTxtNode()->GetLang( rInf.GetIdx(), 1, nScript );
96 :
97 0 : if (MsLangId::isKorean(aLang))
98 : {
99 0 : const SwLinePortion* pPor = rPor.GetPortion();
100 0 : if ( pPor && ( pPor->IsKernPortion() ||
101 0 : pPor->IsControlCharPortion() ||
102 0 : pPor->IsPostItsPortion() ) )
103 0 : pPor = pPor->GetPortion();
104 :
105 0 : nCnt += nEnd - nPos;
106 :
107 0 : if ( !pPor || pPor->IsHolePortion() || pPor->InFixMargGrp() ||
108 0 : pPor->IsBreakPortion() )
109 0 : --nCnt;
110 :
111 0 : return nCnt;
112 : }
113 : }
114 :
115 : // Kashida Justification: Insert Kashidas
116 16 : if ( nEnd > nPos && pSI && COMPLEX == nScript )
117 : {
118 2 : if ( SwScriptInfo::IsArabicText( *pStr, nPos, nEnd - nPos ) && pSI->CountKashida() )
119 : {
120 0 : const sal_uInt16 nKashRes = pSI->KashidaJustify( 0, 0, nPos, nEnd - nPos );
121 : // i60591: need to check result of KashidaJustify
122 : // determine if kashida justification is applicable
123 0 : if( nKashRes != STRING_LEN )
124 0 : return nKashRes;
125 : }
126 : }
127 :
128 : // Thai Justification: Each character cell gets some extra space
129 16 : if ( nEnd > nPos && COMPLEX == nScript )
130 : {
131 : LanguageType aLang =
132 2 : rInf.GetTxtFrm()->GetTxtNode()->GetLang( rInf.GetIdx(), 1, nScript );
133 :
134 2 : if ( LANGUAGE_THAI == aLang )
135 : {
136 0 : nCnt = SwScriptInfo::ThaiJustify( *pStr, 0, 0, nPos, nEnd - nPos );
137 :
138 0 : const SwLinePortion* pPor = rPor.GetPortion();
139 0 : if ( pPor && ( pPor->IsKernPortion() ||
140 0 : pPor->IsControlCharPortion() ||
141 0 : pPor->IsPostItsPortion() ) )
142 0 : pPor = pPor->GetPortion();
143 :
144 0 : if ( nCnt && ( ! pPor || pPor->IsHolePortion() || pPor->InFixMargGrp() ) )
145 0 : --nCnt;
146 :
147 0 : return nCnt;
148 : }
149 : }
150 :
151 : // Here starts the good old "Look for blanks and add space to them" part.
152 : // Note: We do not want to add space to an isolated latin blank in front
153 : // of some complex characters in RTL environment
154 : const bool bDoNotAddSpace =
155 : LATIN == nScript && ( nEnd == nPos + 1 ) && pSI &&
156 : ( i18n::ScriptType::COMPLEX ==
157 0 : pSI->ScriptType( nPos + 1 ) ) &&
158 16 : rInf.GetTxtFrm() && rInf.GetTxtFrm()->IsRightToLeft();
159 :
160 16 : if ( bDoNotAddSpace )
161 0 : return nCnt;
162 :
163 1247 : for ( ; nPos < nEnd; ++nPos )
164 : {
165 1231 : if( CH_BLANK == pStr->GetChar( nPos ) )
166 163 : ++nCnt;
167 : }
168 :
169 : // We still have to examine the next character:
170 : // If the next character is ASIAN and not KOREAN we have
171 : // to add an extra space
172 : // nPos referes to the original string, even if a field string has
173 : // been passed to this function
174 16 : nPos = rInf.GetIdx() + rPor.GetLen();
175 16 : if ( nPos < rInf.GetTxt().Len() )
176 : {
177 16 : sal_uInt8 nNextScript = 0;
178 16 : const SwLinePortion* pPor = rPor.GetPortion();
179 16 : if ( pPor && pPor->IsKernPortion() )
180 0 : pPor = pPor->GetPortion();
181 :
182 16 : if ( ! pBreakIt->GetBreakIter().is() || ! pPor || pPor->InFixMargGrp() )
183 2 : return nCnt;
184 :
185 : // next character is inside a field?
186 14 : if ( CH_TXTATR_BREAKWORD == rInf.GetChar( nPos ) && pPor->InExpGrp() )
187 : {
188 0 : bool bOldOnWin = rInf.OnWin();
189 0 : ((SwTxtSizeInfo &)rInf).SetOnWin( false );
190 :
191 0 : XubString aStr;
192 0 : pPor->GetExpTxt( rInf, aStr );
193 0 : ((SwTxtSizeInfo &)rInf).SetOnWin( bOldOnWin );
194 :
195 0 : nNextScript = (sal_uInt8)pBreakIt->GetBreakIter()->getScriptType( aStr, 0 );
196 : }
197 : else
198 14 : nNextScript = (sal_uInt8)pBreakIt->GetBreakIter()->getScriptType( rInf.GetTxt(), nPos );
199 :
200 14 : if( ASIAN == nNextScript )
201 : {
202 : LanguageType aLang =
203 0 : rInf.GetTxtFrm()->GetTxtNode()->GetLang( nPos, 1, nNextScript );
204 :
205 0 : if (MsLangId::isKorean(aLang))
206 0 : ++nCnt;
207 : }
208 : }
209 :
210 14 : return nCnt;
211 : }
212 :
213 : /*************************************************************************
214 : * class SwTxtPortion
215 : *************************************************************************/
216 :
217 60 : SwTxtPortion::SwTxtPortion( const SwLinePortion &rPortion )
218 60 : : SwLinePortion( rPortion )
219 : {
220 60 : SetWhichPor( POR_TXT );
221 60 : }
222 :
223 : /*************************************************************************
224 : * SwTxtPortion::BreakCut()
225 : *************************************************************************/
226 :
227 19 : void SwTxtPortion::BreakCut( SwTxtFormatInfo &rInf, const SwTxtGuess &rGuess )
228 : {
229 : // The word/char is larger than the line
230 : // Special case 1: The word is larger than the line
231 : // We truncate ...
232 19 : const KSHORT nLineWidth = (KSHORT)(rInf.Width() - rInf.X());
233 19 : xub_StrLen nLen = rGuess.CutPos() - rInf.GetIdx();
234 19 : if( nLen )
235 : {
236 : // special case: guess does not always provide the correct
237 : // width, only in common cases.
238 18 : if ( !rGuess.BreakWidth() )
239 : {
240 6 : rInf.SetLen( nLen );
241 6 : SetLen( nLen );
242 6 : CalcTxtSize( rInf );
243 :
244 : // changing these values requires also changing them in
245 : // guess.cxx
246 6 : KSHORT nItalic = 0;
247 6 : if( ITALIC_NONE != rInf.GetFont()->GetItalic() && !rInf.NotEOL() )
248 : {
249 0 : nItalic = Height() / 12;
250 : }
251 6 : Width( Width() + nItalic );
252 : }
253 : else
254 : {
255 12 : Width( rGuess.BreakWidth() );
256 12 : SetLen( nLen );
257 : }
258 : }
259 : // special case: first character does not fit to line
260 1 : else if ( rGuess.CutPos() == rInf.GetLineStart() )
261 : {
262 1 : SetLen( 1 );
263 1 : Width( nLineWidth );
264 : }
265 : else
266 : {
267 0 : SetLen( 0 );
268 0 : Width( 0 );
269 : }
270 19 : }
271 :
272 : /*************************************************************************
273 : * SwTxtPortion::BreakUnderflow()
274 : *************************************************************************/
275 :
276 0 : void SwTxtPortion::BreakUnderflow( SwTxtFormatInfo &rInf )
277 : {
278 0 : Truncate();
279 0 : Height( 0 );
280 0 : Width( 0 );
281 0 : SetLen( 0 );
282 0 : SetAscent( 0 );
283 0 : rInf.SetUnderFlow( this );
284 0 : }
285 :
286 : /*************************************************************************
287 : * SwTxtPortion::_Format()
288 : *************************************************************************/
289 :
290 0 : static bool lcl_HasContent( const SwFldPortion& rFld, SwTxtFormatInfo &rInf )
291 : {
292 0 : String aTxt;
293 0 : return rFld.GetExpTxt( rInf, aTxt ) && aTxt.Len();
294 : }
295 :
296 680 : sal_Bool SwTxtPortion::_Format( SwTxtFormatInfo &rInf )
297 : {
298 : // 5744: If only the hypen does not fit anymore, we still need to wrap
299 : // the word, or else return sal_True!
300 680 : if( rInf.IsUnderFlow() && rInf.GetSoftHyphPos() )
301 : {
302 : // soft hyphen portion has triggered an underflow event because
303 : // of an alternative spelling position
304 0 : sal_Bool bFull = sal_False;
305 0 : const sal_Bool bHyph = rInf.ChgHyph( sal_True );
306 0 : if( rInf.IsHyphenate() )
307 : {
308 0 : SwTxtGuess aGuess;
309 : // check for alternative spelling left from the soft hyphen
310 : // this should usually be true but
311 0 : aGuess.AlternativeSpelling( rInf, rInf.GetSoftHyphPos() - 1 );
312 0 : bFull = CreateHyphen( rInf, aGuess );
313 0 : OSL_ENSURE( bFull, "Problem with hyphenation!!!" );
314 : }
315 0 : rInf.ChgHyph( bHyph );
316 0 : rInf.SetSoftHyphPos( 0 );
317 0 : return bFull;
318 : }
319 :
320 680 : SwTxtGuess aGuess;
321 680 : const sal_Bool bFull = !aGuess.Guess( *this, rInf, Height() );
322 :
323 : // these are the possible cases:
324 : // A Portion fits to current line
325 : // B Portion does not fit to current line but a possible line break
326 : // within the portion has been found by the break iterator, 2 subcases
327 : // B1 break is hyphen
328 : // B2 break is word end
329 : // C Portion does not fit to current line and no possible line break
330 : // has been found by break iterator, 2 subcases:
331 : // C1 break iterator found a possible line break in portion before us
332 : // ==> this break is used (underflow)
333 : // C2 break iterator does not found a possible line break at all:
334 : // ==> line break
335 :
336 : // case A: line not yet full
337 680 : if ( !bFull )
338 : {
339 595 : Width( aGuess.BreakWidth() );
340 : // Vorsicht !
341 595 : if( !InExpGrp() || InFldGrp() )
342 587 : SetLen( rInf.GetLen() );
343 :
344 595 : short nKern = rInf.GetFont()->CheckKerning();
345 595 : if( nKern > 0 && rInf.Width() < rInf.X() + Width() + nKern )
346 : {
347 0 : nKern = (short)(rInf.Width() - rInf.X() - Width() - 1);
348 0 : if( nKern < 0 )
349 0 : nKern = 0;
350 : }
351 595 : if( nKern )
352 1 : new SwKernPortion( *this, nKern );
353 : }
354 : // special case: hanging portion
355 85 : else if( bFull && aGuess.GetHangingPortion() )
356 : {
357 0 : Width( aGuess.BreakWidth() );
358 0 : SetLen( aGuess.BreakPos() - rInf.GetIdx() );
359 0 : Insert( aGuess.GetHangingPortion() );
360 0 : aGuess.GetHangingPortion()->SetAscent( GetAscent() );
361 0 : aGuess.ClearHangingPortion();
362 : }
363 : // breakPos >= index
364 85 : else if ( aGuess.BreakPos() >= rInf.GetIdx() && aGuess.BreakPos() != STRING_LEN )
365 : {
366 : // case B1
367 73 : if( aGuess.HyphWord().is() && aGuess.BreakPos() > rInf.GetLineStart()
368 0 : && ( aGuess.BreakPos() > rInf.GetIdx() ||
369 0 : ( rInf.GetLast() && ! rInf.GetLast()->IsFlyPortion() ) ) )
370 : {
371 0 : CreateHyphen( rInf, aGuess );
372 0 : if ( rInf.GetFly() )
373 0 : rInf.GetRoot()->SetMidHyph( sal_True );
374 : else
375 0 : rInf.GetRoot()->SetEndHyph( sal_True );
376 : }
377 : // case C1
378 : // - Footnote portions with fake line start (i.e., not at beginning of line)
379 : // should keep together with the text portion. (Note: no keep together
380 : // with only footnote portions.
381 : // - TabPortions not at beginning of line should keep together with the
382 : // text portion, if they are not followed by a blank
383 : // (work around different definition of tab stop character - breaking or
384 : // non breaking character - in compatibility mode)
385 292 : else if ( ( IsFtnPortion() && rInf.IsFakeLineStart() &&
386 : //
387 0 : rInf.IsOtherThanFtnInside() ) ||
388 73 : ( rInf.GetLast() &&
389 73 : rInf.GetTxtFrm()->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::TAB_COMPAT) &&
390 73 : rInf.GetLast()->InTabGrp() &&
391 0 : rInf.GetLineStart() + rInf.GetLast()->GetLen() < rInf.GetIdx() &&
392 0 : aGuess.BreakPos() == rInf.GetIdx() &&
393 0 : CH_BLANK != rInf.GetChar( rInf.GetIdx() ) &&
394 0 : 0x3000 != rInf.GetChar( rInf.GetIdx() ) ) )
395 0 : BreakUnderflow( rInf );
396 : // case B2
397 186 : else if( rInf.GetIdx() > rInf.GetLineStart() ||
398 71 : aGuess.BreakPos() > rInf.GetIdx() ||
399 : // this is weird: during formatting the follow of a field
400 : // the values rInf.GetIdx and rInf.GetLineStart are replaced
401 : // IsFakeLineStart indicates GetIdx > GetLineStart
402 7 : rInf.IsFakeLineStart() ||
403 7 : rInf.GetFly() ||
404 7 : rInf.IsFirstMulti() ||
405 7 : ( rInf.GetLast() &&
406 7 : ( rInf.GetLast()->IsFlyPortion() ||
407 7 : ( rInf.GetLast()->InFldGrp() &&
408 0 : ! rInf.GetLast()->InNumberGrp() &&
409 0 : ! rInf.GetLast()->IsErgoSumPortion() &&
410 0 : lcl_HasContent(*((SwFldPortion*)rInf.GetLast()),rInf ) ) ) ) )
411 : {
412 66 : if ( rInf.X() + aGuess.BreakWidth() <= rInf.Width() )
413 66 : Width( aGuess.BreakWidth() );
414 : else
415 : // this actually should not happen
416 0 : Width( KSHORT(rInf.Width() - rInf.X()) );
417 :
418 66 : SetLen( aGuess.BreakPos() - rInf.GetIdx() );
419 :
420 : OSL_ENSURE( aGuess.BreakStart() >= aGuess.FieldDiff(),
421 : "Trouble with expanded field portions during line break" );
422 66 : const xub_StrLen nRealStart = aGuess.BreakStart() - aGuess.FieldDiff();
423 66 : if( aGuess.BreakPos() < nRealStart && !InExpGrp() )
424 : {
425 8 : SwHolePortion *pNew = new SwHolePortion( *this );
426 8 : pNew->SetLen( nRealStart - aGuess.BreakPos() );
427 8 : Insert( pNew );
428 : }
429 : }
430 : else // case C2, last exit
431 7 : BreakCut( rInf, aGuess );
432 : }
433 : // breakPos < index or no breakpos at all
434 : else
435 : {
436 12 : bool bFirstPor = rInf.GetLineStart() == rInf.GetIdx();
437 12 : if( aGuess.BreakPos() != STRING_LEN &&
438 0 : aGuess.BreakPos() != rInf.GetLineStart() &&
439 0 : ( !bFirstPor || rInf.GetFly() || rInf.GetLast()->IsFlyPortion() ||
440 0 : rInf.IsFirstMulti() ) &&
441 0 : ( !rInf.GetLast()->IsBlankPortion() || ((SwBlankPortion*)
442 0 : rInf.GetLast())->MayUnderFlow( rInf, rInf.GetIdx()-1, sal_True )))
443 : { // case C1 (former BreakUnderflow())
444 0 : BreakUnderflow( rInf );
445 : }
446 : else
447 : // case C2, last exit
448 12 : BreakCut( rInf, aGuess );
449 : }
450 :
451 680 : return bFull;
452 : }
453 :
454 : /*************************************************************************
455 : * virtual SwTxtPortion::Format()
456 : *************************************************************************/
457 :
458 :
459 :
460 680 : sal_Bool SwTxtPortion::Format( SwTxtFormatInfo &rInf )
461 : {
462 : #if OSL_DEBUG_LEVEL > 1
463 : const XubString aDbgTxt( rInf.GetTxt().Copy( rInf.GetIdx(), rInf.GetLen() ) );
464 : #endif
465 :
466 680 : if( rInf.X() > rInf.Width() || (!GetLen() && !InExpGrp()) )
467 : {
468 0 : Height( 0 );
469 0 : Width( 0 );
470 0 : SetLen( 0 );
471 0 : SetAscent( 0 );
472 0 : SetPortion( NULL ); // ????
473 0 : return sal_True;
474 : }
475 :
476 : OSL_ENSURE( rInf.RealWidth() || (rInf.X() == rInf.Width()),
477 : "SwTxtPortion::Format: missing real width" );
478 : OSL_ENSURE( Height(), "SwTxtPortion::Format: missing height" );
479 :
480 680 : return _Format( rInf );
481 : }
482 :
483 : /*************************************************************************
484 : * virtual SwTxtPortion::FormatEOL()
485 : *************************************************************************/
486 :
487 : // Format end of line
488 : // 5083: We can have awkward cases e.g.:
489 : // "from {Santa}"
490 : // Santa wraps, "from " turns into "from" and " " in a justified
491 : // paragraph, in which the glue gets expanded instead of merged
492 : // with the MarginPortion.
493 : //
494 : // rInf.nIdx points to the next word, nIdx-1 is the portion's last char
495 :
496 9 : void SwTxtPortion::FormatEOL( SwTxtFormatInfo &rInf )
497 : {
498 20 : if( ( !GetPortion() || ( GetPortion()->IsKernPortion() &&
499 10 : !GetPortion()->GetPortion() ) ) && GetLen() &&
500 1 : rInf.GetIdx() < rInf.GetTxt().Len() &&
501 0 : 1 < rInf.GetIdx() && ' ' == rInf.GetChar( rInf.GetIdx() - 1 )
502 0 : && !rInf.GetLast()->IsHolePortion() )
503 : {
504 : // calculate number of blanks
505 0 : xub_StrLen nX = rInf.GetIdx() - 1;
506 0 : sal_uInt16 nHoleLen = 1;
507 0 : while( nX && nHoleLen < GetLen() && CH_BLANK == rInf.GetChar( --nX ) )
508 0 : nHoleLen++;
509 :
510 : // First set ourselves and the insert, because there could be
511 : // a SwLineLayout
512 : KSHORT nBlankSize;
513 0 : if( nHoleLen == GetLen() )
514 0 : nBlankSize = Width();
515 : else
516 0 : nBlankSize = nHoleLen * rInf.GetTxtSize(OUString(' ')).Width();
517 0 : Width( Width() - nBlankSize );
518 0 : rInf.X( rInf.X() - nBlankSize );
519 0 : SetLen( GetLen() - nHoleLen );
520 0 : SwLinePortion *pHole = new SwHolePortion( *this );
521 0 : ( (SwHolePortion *)pHole )->SetBlankWidth( nBlankSize );
522 0 : ( (SwHolePortion *)pHole )->SetLen( nHoleLen );
523 0 : Insert( pHole );
524 : }
525 9 : }
526 :
527 : /*************************************************************************
528 : * virtual SwTxtPortion::GetCrsrOfst()
529 : *************************************************************************/
530 0 : xub_StrLen SwTxtPortion::GetCrsrOfst( const KSHORT nOfst ) const
531 : {
532 : OSL_ENSURE( !this, "SwTxtPortion::GetCrsrOfst: don't use this method!" );
533 0 : return SwLinePortion::GetCrsrOfst( nOfst );
534 : }
535 :
536 : /*************************************************************************
537 : * virtual SwTxtPortion::GetTxtSize()
538 : *************************************************************************/
539 : // The GetTxtSize() assumes that the own length is correct
540 :
541 6 : SwPosSize SwTxtPortion::GetTxtSize( const SwTxtSizeInfo &rInf ) const
542 : {
543 6 : return rInf.GetTxtSize();
544 : }
545 :
546 : /*************************************************************************
547 : * virtual SwTxtPortion::Paint()
548 : *************************************************************************/
549 431 : void SwTxtPortion::Paint( const SwTxtPaintInfo &rInf ) const
550 : {
551 431 : if (rInf.OnWin() && 1==rInf.GetLen() && CH_TXT_ATR_FIELDEND==rInf.GetTxt().GetChar(rInf.GetIdx()))
552 : {
553 0 : rInf.DrawBackBrush( *this );
554 0 : const OUString aTxt(CH_TXT_ATR_SUBST_FIELDEND);
555 0 : rInf.DrawText( aTxt, *this, 0, aTxt.getLength(), false );
556 : }
557 431 : else if (rInf.OnWin() && 1==rInf.GetLen() && CH_TXT_ATR_FIELDSTART==rInf.GetTxt().GetChar(rInf.GetIdx()))
558 : {
559 0 : rInf.DrawBackBrush( *this );
560 0 : const OUString aTxt(CH_TXT_ATR_SUBST_FIELDSTART);
561 0 : rInf.DrawText( aTxt, *this, 0, aTxt.getLength(), false );
562 : }
563 431 : else if( GetLen() )
564 : {
565 393 : rInf.DrawBackBrush( *this );
566 :
567 : // do we have to repaint a post it portion?
568 393 : if( rInf.OnWin() && pPortion && !pPortion->Width() )
569 12 : pPortion->PrePaint( rInf, this );
570 :
571 393 : const SwWrongList *pWrongList = rInf.GetpWrongList();
572 393 : const SwWrongList *pGrammarCheckList = rInf.GetGrammarCheckList();
573 : // SMARTTAGS
574 393 : const SwWrongList *pSmarttags = rInf.GetSmartTags();
575 :
576 393 : const bool bWrong = 0 != pWrongList;
577 393 : const bool bGrammarCheck = 0 != pGrammarCheckList;
578 393 : const bool bSmartTags = 0 != pSmarttags;
579 :
580 393 : if ( bWrong || bSmartTags || bGrammarCheck )
581 0 : rInf.DrawMarkedText( *this, rInf.GetLen(), sal_False, bWrong, bSmartTags, bGrammarCheck );
582 : else
583 393 : rInf.DrawText( *this, rInf.GetLen(), sal_False );
584 : }
585 431 : }
586 :
587 : /*************************************************************************
588 : * virtual SwTxtPortion::GetExpTxt()
589 : *************************************************************************/
590 :
591 :
592 :
593 0 : sal_Bool SwTxtPortion::GetExpTxt( const SwTxtSizeInfo &, XubString & ) const
594 : {
595 0 : return sal_False;
596 : }
597 :
598 : /*************************************************************************
599 : * xub_StrLen SwTxtPortion::GetSpaceCnt()
600 : * long SwTxtPortion::CalcSpacing()
601 : * Are responsible for the justified paragraph. They calculate the blank
602 : * count and the resulting added space.
603 : *************************************************************************/
604 :
605 8 : xub_StrLen SwTxtPortion::GetSpaceCnt( const SwTxtSizeInfo &rInf,
606 : xub_StrLen& rCharCnt ) const
607 : {
608 8 : xub_StrLen nCnt = 0;
609 8 : xub_StrLen nPos = 0;
610 8 : if ( InExpGrp() )
611 : {
612 0 : if( !IsBlankPortion() && !InNumberGrp() && !IsCombinedPortion() )
613 : {
614 : // OnWin() likes to return a blank instead of an empty string from
615 : // time to time. We cannot use that here at all, however.
616 0 : bool bOldOnWin = rInf.OnWin();
617 0 : ((SwTxtSizeInfo &)rInf).SetOnWin( false );
618 :
619 0 : XubString aStr;
620 0 : GetExpTxt( rInf, aStr );
621 0 : ((SwTxtSizeInfo &)rInf).SetOnWin( bOldOnWin );
622 :
623 0 : nCnt = nCnt + lcl_AddSpace( rInf, &aStr, *this );
624 0 : nPos = aStr.Len();
625 : }
626 : }
627 8 : else if( !IsDropPortion() )
628 : {
629 8 : nCnt = nCnt + lcl_AddSpace( rInf, 0, *this );
630 8 : nPos = GetLen();
631 : }
632 8 : rCharCnt = rCharCnt + nPos;
633 8 : return nCnt;
634 : }
635 :
636 8 : long SwTxtPortion::CalcSpacing( long nSpaceAdd, const SwTxtSizeInfo &rInf ) const
637 : {
638 8 : xub_StrLen nCnt = 0;
639 :
640 8 : if ( InExpGrp() )
641 : {
642 0 : if( !IsBlankPortion() && !InNumberGrp() && !IsCombinedPortion() )
643 : {
644 : // OnWin() likes to return a blank instead of an empty string from
645 : // time to time. We cannot use that here at all, however.
646 0 : bool bOldOnWin = rInf.OnWin();
647 0 : ((SwTxtSizeInfo &)rInf).SetOnWin( false );
648 :
649 0 : XubString aStr;
650 0 : GetExpTxt( rInf, aStr );
651 0 : ((SwTxtSizeInfo &)rInf).SetOnWin( bOldOnWin );
652 0 : if( nSpaceAdd > 0 )
653 0 : nCnt = nCnt + lcl_AddSpace( rInf, &aStr, *this );
654 : else
655 : {
656 0 : nSpaceAdd = -nSpaceAdd;
657 0 : nCnt = aStr.Len();
658 0 : }
659 : }
660 : }
661 8 : else if( !IsDropPortion() )
662 : {
663 8 : if( nSpaceAdd > 0 )
664 8 : nCnt = nCnt + lcl_AddSpace( rInf, 0, *this );
665 : else
666 : {
667 0 : nSpaceAdd = -nSpaceAdd;
668 0 : nCnt = GetLen();
669 0 : SwLinePortion* pPor = GetPortion();
670 :
671 : // we do not want an extra space in front of margin portions
672 0 : if ( nCnt )
673 : {
674 0 : while ( pPor && !pPor->Width() && ! pPor->IsHolePortion() )
675 0 : pPor = pPor->GetPortion();
676 :
677 0 : if ( !pPor || pPor->InFixMargGrp() || pPor->IsHolePortion() )
678 0 : --nCnt;
679 : }
680 : }
681 : }
682 :
683 8 : return nCnt * nSpaceAdd / SPACING_PRECISION_FACTOR;
684 : }
685 :
686 : /*************************************************************************
687 : * virtual SwTxtPortion::HandlePortion()
688 : *************************************************************************/
689 :
690 8 : void SwTxtPortion::HandlePortion( SwPortionHandler& rPH ) const
691 : {
692 8 : rPH.Text( GetLen(), GetWhichPor(), Height(), Width() );
693 8 : }
694 :
695 : /*************************************************************************
696 : * class SwHolePortion
697 : *************************************************************************/
698 :
699 :
700 :
701 8 : SwHolePortion::SwHolePortion( const SwTxtPortion &rPor )
702 8 : : nBlankWidth( 0 )
703 : {
704 8 : SetLen( 1 );
705 8 : Height( rPor.Height() );
706 8 : SetAscent( rPor.GetAscent() );
707 8 : SetWhichPor( POR_HOLE );
708 8 : }
709 :
710 8 : SwLinePortion *SwHolePortion::Compress() { return this; }
711 :
712 : /*************************************************************************
713 : * virtual SwHolePortion::Paint()
714 : *************************************************************************/
715 :
716 :
717 :
718 4 : void SwHolePortion::Paint( const SwTxtPaintInfo &rInf ) const
719 : {
720 : // #i16816# tagged pdf support
721 4 : if( rInf.GetVsh() && rInf.GetVsh()->GetViewOptions()->IsPDFExport() &&
722 0 : SwTaggedPDFHelper::IsExportTaggedPDF( *rInf.GetOut()) )
723 : {
724 0 : const OUString aTxt( ' ' );
725 0 : rInf.DrawText( aTxt, *this, 0, 1, false );
726 : }
727 4 : }
728 :
729 : /*************************************************************************
730 : * virtual SwHolePortion::Format()
731 : *************************************************************************/
732 :
733 :
734 :
735 0 : sal_Bool SwHolePortion::Format( SwTxtFormatInfo &rInf )
736 : {
737 0 : return rInf.IsFull() || rInf.X() >= rInf.Width();
738 : }
739 :
740 : /*************************************************************************
741 : * virtual SwHolePortion::HandlePortion()
742 : *************************************************************************/
743 :
744 0 : void SwHolePortion::HandlePortion( SwPortionHandler& rPH ) const
745 : {
746 0 : rPH.Text( GetLen(), GetWhichPor() );
747 0 : }
748 :
749 8 : void SwFieldMarkPortion::Paint( const SwTxtPaintInfo & /*rInf*/) const
750 : {
751 : // These shouldn't be painted!
752 : // SwTxtPortion::Paint(rInf);
753 8 : }
754 :
755 12 : sal_Bool SwFieldMarkPortion::Format( SwTxtFormatInfo & )
756 : {
757 12 : sal_Bool ret=0;
758 12 : Width(0);
759 12 : return ret;
760 : }
761 :
762 : namespace {
763 0 : static sal_Int32 getCurrentListIndex( IFieldmark* pBM,
764 : OUString* io_pCurrentText = NULL )
765 : {
766 0 : const IFieldmark::parameter_map_t* const pParameters = pBM->GetParameters();
767 0 : sal_Int32 nCurrentIdx = 0;
768 0 : const IFieldmark::parameter_map_t::const_iterator pResult = pParameters->find(OUString(RTL_CONSTASCII_USTRINGPARAM(ODF_FORMDROPDOWN_RESULT)));
769 0 : if(pResult != pParameters->end())
770 0 : pResult->second >>= nCurrentIdx;
771 0 : if(io_pCurrentText)
772 : {
773 0 : const IFieldmark::parameter_map_t::const_iterator pListEntries = pParameters->find(OUString(RTL_CONSTASCII_USTRINGPARAM(ODF_FORMDROPDOWN_LISTENTRY)));
774 0 : if(pListEntries != pParameters->end())
775 : {
776 0 : uno::Sequence< OUString > vListEntries;
777 0 : pListEntries->second >>= vListEntries;
778 0 : if(nCurrentIdx < vListEntries.getLength())
779 0 : *io_pCurrentText = vListEntries[nCurrentIdx];
780 : }
781 : }
782 0 : return nCurrentIdx;
783 : }
784 : }
785 :
786 : //FIXME Fieldbk
787 0 : void SwFieldFormPortion::Paint( const SwTxtPaintInfo& rInf ) const
788 : {
789 0 : SwTxtNode* pNd = const_cast<SwTxtNode*>(rInf.GetTxtFrm()->GetTxtNode());
790 0 : const SwDoc *doc=pNd->GetDoc();
791 0 : SwIndex aIndex( pNd, rInf.GetIdx() );
792 0 : SwPosition aPosition(*pNd, aIndex);
793 :
794 0 : IFieldmark* pBM = doc->getIDocumentMarkAccess( )->getFieldmarkFor( aPosition );
795 :
796 : OSL_ENSURE( pBM,
797 : "SwFieldFormPortion::Paint(..)"
798 : " - Where is my form field bookmark???");
799 :
800 0 : if ( pBM != NULL )
801 : {
802 0 : if ( pBM->GetFieldname( ) == ODF_FORMCHECKBOX )
803 : { // a checkbox...
804 0 : ICheckboxFieldmark* pCheckboxFm = dynamic_cast< ICheckboxFieldmark* >(pBM);
805 0 : bool checked = pCheckboxFm->IsChecked();
806 0 : rInf.DrawCheckBox(*this, checked);
807 : }
808 0 : else if ( pBM->GetFieldname( ) == ODF_FORMDROPDOWN )
809 : { // a list...
810 0 : OUString aTxt;
811 0 : getCurrentListIndex( pBM, &aTxt );
812 0 : rInf.DrawViewOpt( *this, POR_FLD );
813 0 : rInf.DrawText( aTxt, *this, 0, aTxt.getLength(), false );
814 : }
815 : else
816 : {
817 : assert(0); // unknown type...
818 : }
819 0 : }
820 0 : }
821 :
822 1 : sal_Bool SwFieldFormPortion::Format( SwTxtFormatInfo & rInf )
823 : {
824 1 : sal_Bool ret = 0;
825 1 : SwTxtNode *pNd = const_cast < SwTxtNode * >( rInf.GetTxtFrm( )->GetTxtNode( ) );
826 1 : const SwDoc *doc = pNd->GetDoc( );
827 1 : SwIndex aIndex( pNd, rInf.GetIdx( ) );
828 1 : SwPosition aPosition( *pNd, aIndex );
829 1 : IFieldmark *pBM = doc->getIDocumentMarkAccess( )->getFieldmarkFor( aPosition );
830 : OSL_ENSURE( pBM != NULL, "Where is my form field bookmark???" );
831 1 : if ( pBM != NULL )
832 : {
833 1 : if ( pBM->GetFieldname( ) == ODF_FORMCHECKBOX )
834 : {
835 1 : Width( rInf.GetTxtHeight( ) );
836 1 : Height( rInf.GetTxtHeight( ) );
837 1 : SetAscent( rInf.GetAscent( ) );
838 : }
839 0 : else if ( pBM->GetFieldname( ) == ODF_FORMDROPDOWN )
840 : {
841 0 : OUString aTxt;
842 0 : getCurrentListIndex( pBM, &aTxt );
843 0 : SwPosSize aPosSize = rInf.GetTxtSize( aTxt );
844 0 : Width( aPosSize.Width( ) );
845 0 : Height( aPosSize.Height( ) );
846 0 : SetAscent( rInf.GetAscent( ) );
847 : }
848 : else
849 : {
850 : assert( 0 ); // unknown type...
851 : }
852 : }
853 1 : return ret;
854 : }
855 :
856 :
857 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|