1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26
27
28 #include <hintids.hxx>
29 #include <editeng/charscaleitem.hxx>
30 #include <txtatr.hxx>
31 #include <sfx2/printer.hxx>
32 #include <svx/svdobj.hxx>
33 #include <vcl/window.hxx>
34 #include <vcl/svapp.hxx>
35 #include <fmtanchr.hxx>
36 #include <fmtfsize.hxx>
37 #include <fmtornt.hxx>
38 #include <fmtflcnt.hxx>
39 #include <fmtcntnt.hxx>
40 #include <fmtftn.hxx>
41 #include <frmatr.hxx>
42 #include <frmfmt.hxx>
43 #include <fmtfld.hxx>
44 #include <doc.hxx>
45 #include <viewsh.hxx> // ViewShell
46 #include <rootfrm.hxx>
47 #include <docary.hxx>
48 #include <ndtxt.hxx>
49 #include <dcontact.hxx>
50 #include <fldbas.hxx> // SwField
51 #include <pam.hxx> // SwPosition (lcl_MinMaxNode)
52 #include <itratr.hxx>
53 #include <htmltbl.hxx>
54 #include <swtable.hxx>
55 #include <redlnitr.hxx>
56 #include <fmtsrnd.hxx>
57 #include <itrtxt.hxx>
58 #include <breakit.hxx>
59 #include <com/sun/star/i18n/WordType.hpp>
60 #include <com/sun/star/i18n/ScriptType.hdl>
61 #include <editeng/lrspitem.hxx>
62 #include <switerator.hxx>
63
64 using namespace ::com::sun::star::i18n;
65 using namespace ::com::sun::star;
66
67 /*************************************************************************
68 * SwAttrIter::Chg()
69 *************************************************************************/
70
Chg(SwTxtAttr * pHt)71 void SwAttrIter::Chg( SwTxtAttr *pHt )
72 {
73 ASSERT( pHt && pFnt, "No attribute of font available for change");
74 if( pRedln && pRedln->IsOn() )
75 pRedln->ChangeTxtAttr( pFnt, *pHt, sal_True );
76 else
77 aAttrHandler.PushAndChg( *pHt, *pFnt );
78 nChgCnt++;
79 }
80
81 /*************************************************************************
82 * SwAttrIter::Rst()
83 *************************************************************************/
84
Rst(SwTxtAttr * pHt)85 void SwAttrIter::Rst( SwTxtAttr *pHt )
86 {
87 ASSERT( pHt && pFnt, "No attribute of font available for reset");
88 // get top from stack after removing pHt
89 if( pRedln && pRedln->IsOn() )
90 pRedln->ChangeTxtAttr( pFnt, *pHt, sal_False );
91 else
92 aAttrHandler.PopAndChg( *pHt, *pFnt );
93 nChgCnt--;
94 }
95
96 /*************************************************************************
97 * virtual SwAttrIter::~SwAttrIter()
98 *************************************************************************/
99
~SwAttrIter()100 SwAttrIter::~SwAttrIter()
101 {
102 delete pRedln;
103 delete pFnt;
104 }
105
106 /*************************************************************************
107 * SwAttrIter::GetAttr()
108 *
109 * Liefert fuer eine Position das Attribut, wenn das Attribut genau auf
110 * der Position nPos liegt und kein EndIndex besitzt.
111 * GetAttr() wird fuer Attribute benoetigt, die die Formatierung beeinflussen
112 * sollen, ohne dabei den Inhalt des Strings zu veraendern. Solche "entarteten"
113 * Attribute sind z.B. Felder (die expandierten Text bereit halten) und
114 * zeilengebundene Frames. Um Mehrdeutigkeiten zwischen verschiedenen
115 * solcher Attribute zu vermeiden, werden beim Anlegen eines Attributs
116 * an der Startposition ein Sonderzeichen in den String einfuegt.
117 * Der Formatierer stoesst auf das Sonderzeichen und holt sich per
118 * GetAttr() das entartete Attribut.
119 *************************************************************************/
120
GetAttr(const xub_StrLen nPosition) const121 SwTxtAttr *SwAttrIter::GetAttr( const xub_StrLen nPosition ) const
122 {
123 return (m_pTxtNode) ? m_pTxtNode->GetTxtAttrForCharAt(nPosition) : 0;
124 }
125
126 /*************************************************************************
127 * SwAttrIter::SeekAndChg()
128 *************************************************************************/
129
SeekAndChgAttrIter(const xub_StrLen nNewPos,OutputDevice * pOut)130 sal_Bool SwAttrIter::SeekAndChgAttrIter( const xub_StrLen nNewPos, OutputDevice* pOut )
131 {
132 sal_Bool bChg = nStartIndex && nNewPos == nPos ? pFnt->IsFntChg() : Seek( nNewPos );
133 if ( pLastOut != pOut )
134 {
135 pLastOut = pOut;
136 pFnt->SetFntChg( sal_True );
137 bChg = sal_True;
138 }
139 if( bChg )
140 {
141 // wenn der Aenderungszaehler auf Null ist, kennen wir die MagicNo
142 // des gewuenschten Fonts ...
143 if ( !nChgCnt && !nPropFont )
144 pFnt->SetMagic( aMagicNo[ pFnt->GetActual() ],
145 aFntIdx[ pFnt->GetActual() ], pFnt->GetActual() );
146 pFnt->ChgPhysFnt( pShell, *pOut );
147 }
148 return bChg;
149 }
150
IsSymbol(const xub_StrLen nNewPos)151 sal_Bool SwAttrIter::IsSymbol( const xub_StrLen nNewPos )
152 {
153 Seek( nNewPos );
154 if ( !nChgCnt && !nPropFont )
155 pFnt->SetMagic( aMagicNo[ pFnt->GetActual() ],
156 aFntIdx[ pFnt->GetActual() ], pFnt->GetActual() );
157 return pFnt->IsSymbol( pShell );
158 }
159
160 /*************************************************************************
161 * SwAttrIter::SeekStartAndChg()
162 *************************************************************************/
163
SeekStartAndChgAttrIter(OutputDevice * pOut,const sal_Bool bParaFont)164 sal_Bool SwAttrIter::SeekStartAndChgAttrIter( OutputDevice* pOut, const sal_Bool bParaFont )
165 {
166 if ( pRedln && pRedln->ExtOn() )
167 pRedln->LeaveExtend( *pFnt, 0 );
168
169 // reset font to its original state
170 aAttrHandler.Reset();
171 aAttrHandler.ResetFont( *pFnt );
172
173 nStartIndex = nEndIndex = nPos = nChgCnt = 0;
174 if( nPropFont )
175 pFnt->SetProportion( nPropFont );
176 if( pRedln )
177 {
178 pRedln->Clear( pFnt );
179 if( !bParaFont )
180 nChgCnt = nChgCnt + pRedln->Seek( *pFnt, 0, STRING_LEN );
181 else
182 pRedln->Reset();
183 }
184
185 if ( pHints && !bParaFont )
186 {
187 SwTxtAttr *pTxtAttr;
188 // Solange wir noch nicht am Ende des StartArrays angekommen sind &&
189 // das TextAttribut an Position 0 beginnt ...
190 while ( ( nStartIndex < pHints->GetStartCount() ) &&
191 !(*(pTxtAttr=pHints->GetStart(nStartIndex))->GetStart()) )
192 {
193 // oeffne die TextAttribute
194 Chg( pTxtAttr );
195 nStartIndex++;
196 }
197 }
198
199 sal_Bool bChg = pFnt->IsFntChg();
200 if ( pLastOut != pOut )
201 {
202 pLastOut = pOut;
203 pFnt->SetFntChg( sal_True );
204 bChg = sal_True;
205 }
206 if( bChg )
207 {
208 // wenn der Aenderungszaehler auf Null ist, kennen wir die MagicNo
209 // des gewuenschten Fonts ...
210 if ( !nChgCnt && !nPropFont )
211 pFnt->SetMagic( aMagicNo[ pFnt->GetActual() ],
212 aFntIdx[ pFnt->GetActual() ], pFnt->GetActual() );
213 pFnt->ChgPhysFnt( pShell, *pOut );
214 }
215 return bChg;
216 }
217
218 /*************************************************************************
219 * SwAttrIter::SeekFwd()
220 *************************************************************************/
221
222 // AMA: Neuer AttrIter Nov 94
223
SeekFwd(const xub_StrLen nNewPos)224 void SwAttrIter::SeekFwd( const xub_StrLen nNewPos )
225 {
226 SwTxtAttr *pTxtAttr;
227
228 if ( nStartIndex ) // wenn ueberhaupt schon Attribute geoeffnet wurden...
229 {
230 // Schliesse Attr, die z. Z. geoeffnet sind, vor nNewPos+1 aber enden.
231
232 // Solange wir noch nicht am Ende des EndArrays angekommen sind &&
233 // das TextAttribut vor oder an der neuen Position endet ...
234 while ( ( nEndIndex < pHints->GetEndCount() ) &&
235 (*(pTxtAttr=pHints->GetEnd(nEndIndex))->GetAnyEnd()<=nNewPos))
236 {
237 // schliesse die TextAttribute, deren StartPos vor
238 // oder an der alten nPos lag, die z.Z. geoeffnet sind.
239 if (*pTxtAttr->GetStart() <= nPos) Rst( pTxtAttr );
240 nEndIndex++;
241 }
242 }
243 else // ueberlies die nicht geoeffneten Enden
244 {
245 while ( ( nEndIndex < pHints->GetEndCount() ) &&
246 (*(pTxtAttr=pHints->GetEnd(nEndIndex))->GetAnyEnd()<=nNewPos))
247 {
248 nEndIndex++;
249 }
250 }
251 // Solange wir noch nicht am Ende des StartArrays angekommen sind &&
252 // das TextAttribut vor oder an der neuen Position beginnt ...
253 while ( ( nStartIndex < pHints->GetStartCount() ) &&
254 (*(pTxtAttr=pHints->GetStart(nStartIndex))->GetStart()<=nNewPos))
255 {
256 // oeffne die TextAttribute, deren Ende hinter der neuen Position liegt
257 if ( *pTxtAttr->GetAnyEnd() > nNewPos ) Chg( pTxtAttr );
258 nStartIndex++;
259 }
260
261 }
262
263 /*************************************************************************
264 * SwAttrIter::Seek()
265 *************************************************************************/
266
Seek(const xub_StrLen nNewPos)267 sal_Bool SwAttrIter::Seek( const xub_StrLen nNewPos )
268 {
269 if ( pRedln && pRedln->ExtOn() )
270 pRedln->LeaveExtend( *pFnt, nNewPos );
271
272 if( pHints )
273 {
274 if( !nNewPos || nNewPos < nPos )
275 {
276 if( pRedln )
277 pRedln->Clear( NULL );
278
279 // reset font to its original state
280 aAttrHandler.Reset();
281 aAttrHandler.ResetFont( *pFnt );
282
283 if( nPropFont )
284 pFnt->SetProportion( nPropFont );
285 nStartIndex = nEndIndex = nPos = 0;
286 nChgCnt = 0;
287
288 // Achtung!
289 // resetting the font here makes it necessary to apply any
290 // changes for extended input directly to the font
291 if ( pRedln && pRedln->ExtOn() )
292 {
293 pRedln->UpdateExtFont( *pFnt );
294 ++nChgCnt;
295 }
296 }
297 SeekFwd( nNewPos );
298 }
299
300 pFnt->SetActual( SwScriptInfo::WhichFont( nNewPos, 0, pScriptInfo ) );
301
302 if( pRedln )
303 nChgCnt = nChgCnt + pRedln->Seek( *pFnt, nNewPos, nPos );
304 nPos = nNewPos;
305
306 if( nPropFont )
307 pFnt->SetProportion( nPropFont );
308
309 return pFnt->IsFntChg();
310 }
311
312 /*************************************************************************
313 * SwAttrIter::GetNextAttr()
314 *************************************************************************/
315
GetNextAttr() const316 xub_StrLen SwAttrIter::GetNextAttr( ) const
317 {
318 xub_StrLen nNext = STRING_LEN;
319 if( pHints )
320 {
321 if (pHints->GetStartCount() > nStartIndex) // Gibt es noch Starts?
322 nNext = (*pHints->GetStart(nStartIndex)->GetStart());
323 if (pHints->GetEndCount() > nEndIndex) // Gibt es noch Enden?
324 {
325 xub_StrLen nNextEnd = (*pHints->GetEnd(nEndIndex)->GetAnyEnd());
326 if ( nNextEnd<nNext ) nNext = nNextEnd; // Wer ist naeher?
327 }
328 }
329 if (m_pTxtNode!=NULL) {
330 //TODO maybe use hints like FieldHints for this instead of looking at the text...
331 int l=(nNext<m_pTxtNode->Len()?nNext:m_pTxtNode->Len());
332 sal_uInt16 p=nPos;
333 const sal_Unicode *txt=m_pTxtNode->GetTxt().GetBuffer();
334 while(p<l && txt[p]!=CH_TXT_ATR_FIELDSTART && txt[p]!=CH_TXT_ATR_FIELDEND && txt[p]!=CH_TXT_ATR_FORMELEMENT) p++;
335 if ((p<l && p>nPos) || nNext<=p)
336 nNext=p;
337 else
338 nNext=p+1;
339 }
340 if( pRedln )
341 return pRedln->GetNextRedln( nNext );
342 return nNext;
343 }
344
345 #if OSL_DEBUG_LEVEL > 1
346 /*************************************************************************
347 * SwAttrIter::Dump()
348 *************************************************************************/
349
Dump(SvStream &) const350 void SwAttrIter::Dump( SvStream &/*rOS*/ ) const
351 {
352 // Noch nicht an den neuen Attributiterator angepasst ...
353 }
354
355 #endif
356
357 class SwMinMaxArgs
358 {
359 public:
360 OutputDevice* pOut;
361 ViewShell* pSh;
362 sal_uLong &rMin;
363 sal_uLong &rMax;
364 sal_uLong &rAbsMin;
365 long nRowWidth;
366 long nWordWidth;
367 long nWordAdd;
368 xub_StrLen nNoLineBreak;
SwMinMaxArgs(OutputDevice * pOutI,ViewShell * pShI,sal_uLong & rMinI,sal_uLong & rMaxI,sal_uLong & rAbsI)369 SwMinMaxArgs( OutputDevice* pOutI, ViewShell* pShI, sal_uLong& rMinI, sal_uLong &rMaxI, sal_uLong &rAbsI )
370 : pOut( pOutI ), pSh( pShI ), rMin( rMinI ), rMax( rMaxI ), rAbsMin( rAbsI )
371 { nRowWidth = nWordWidth = nWordAdd = 0; nNoLineBreak = STRING_LEN; }
Minimum(long nNew)372 void Minimum( long nNew ) { if( (long)rMin < nNew ) rMin = nNew; }
NewWord()373 void NewWord() { nWordAdd = nWordWidth = 0; }
374 };
375
lcl_MinMaxString(SwMinMaxArgs & rArg,SwFont * pFnt,const XubString & rTxt,xub_StrLen nIdx,xub_StrLen nEnd)376 sal_Bool lcl_MinMaxString( SwMinMaxArgs& rArg, SwFont* pFnt, const XubString &rTxt,
377 xub_StrLen nIdx, xub_StrLen nEnd )
378 {
379 sal_Bool bRet = sal_False;
380 while( nIdx < nEnd )
381 {
382 xub_StrLen nStop = nIdx;
383 sal_Bool bClear;
384 LanguageType eLang = pFnt->GetLanguage();
385 if( pBreakIt->GetBreakIter().is() )
386 {
387 bClear = CH_BLANK == rTxt.GetChar( nStop );
388 Boundary aBndry( pBreakIt->GetBreakIter()->getWordBoundary( rTxt, nIdx,
389 pBreakIt->GetLocale( eLang ),
390 WordType::DICTIONARY_WORD, sal_True ) );
391 nStop = (xub_StrLen)aBndry.endPos;
392 if( nIdx <= aBndry.startPos && nIdx && nIdx-1 != rArg.nNoLineBreak )
393 rArg.NewWord();
394 if( nStop == nIdx )
395 ++nStop;
396 if( nStop > nEnd )
397 nStop = nEnd;
398 }
399 else
400 {
401 while( nStop < nEnd && CH_BLANK != rTxt.GetChar( nStop ) )
402 ++nStop;
403 bClear = nStop == nIdx;
404 if ( bClear )
405 {
406 rArg.NewWord();
407 while( nStop < nEnd && CH_BLANK == rTxt.GetChar( nStop ) )
408 ++nStop;
409 }
410 }
411
412 SwDrawTextInfo aDrawInf( rArg.pSh, *rArg.pOut, 0, rTxt, nIdx, nStop - nIdx );
413 long nAktWidth = pFnt->_GetTxtSize( aDrawInf ).Width();
414 rArg.nRowWidth += nAktWidth;
415 if( bClear )
416 rArg.NewWord();
417 else
418 {
419 rArg.nWordWidth += nAktWidth;
420 if( (long)rArg.rAbsMin < rArg.nWordWidth )
421 rArg.rAbsMin = rArg.nWordWidth;
422 rArg.Minimum( rArg.nWordWidth + rArg.nWordAdd );
423 bRet = sal_True;
424 }
425 nIdx = nStop;
426 }
427 return bRet;
428 }
429
IsSymbol(const xub_StrLen nBegin) const430 sal_Bool SwTxtNode::IsSymbol( const xub_StrLen nBegin ) const//swmodtest 080307
431 {
432 SwScriptInfo aScriptInfo;
433 SwAttrIter aIter( *(SwTxtNode*)this, aScriptInfo );
434 aIter.Seek( nBegin );
435 return aIter.GetFnt()->IsSymbol(
436 const_cast<ViewShell *>(getIDocumentLayoutAccess()->GetCurrentViewShell()) );//swmod 080311
437 }
438
439 class SwMinMaxNodeArgs
440 {
441 public:
442 sal_uLong nMaxWidth; // Summe aller Rahmenbreite
443 long nMinWidth; // Breitester Rahmen
444 long nLeftRest; // noch nicht von Rahmen ueberdeckter Platz im l. Rand
445 long nRightRest; // noch nicht von Rahmen ueberdeckter Platz im r. Rand
446 long nLeftDiff; // Min/Max-Differenz des Rahmens im linken Rand
447 long nRightDiff; // Min/Max-Differenz des Rahmens im rechten Rand
448 sal_uLong nIndx; // Indexnummer des Nodes
Minimum(long nNew)449 void Minimum( long nNew ) { if( nNew > nMinWidth ) nMinWidth = nNew; }
450 };
451
lcl_MinMaxNode(const SwFrmFmtPtr & rpNd,void * pArgs)452 sal_Bool lcl_MinMaxNode( const SwFrmFmtPtr& rpNd, void* pArgs )
453 {
454 const SwFmtAnchor& rFmtA = ((SwFrmFmt*)rpNd)->GetAnchor();
455
456 bool bCalculate = false;
457 if ((FLY_AT_PARA == rFmtA.GetAnchorId()) ||
458 (FLY_AT_CHAR == rFmtA.GetAnchorId()))
459 {
460 bCalculate = true;
461 }
462
463 if (bCalculate)
464 {
465 const SwMinMaxNodeArgs *pIn = (const SwMinMaxNodeArgs*)pArgs;
466 const SwPosition *pPos = rFmtA.GetCntntAnchor();
467 ASSERT(pPos && pIn, "Unexpected NULL arguments");
468 if (!pPos || !pIn || pIn->nIndx != pPos->nNode.GetIndex())
469 bCalculate = false;
470 }
471
472 if (bCalculate)
473 {
474 long nMin, nMax;
475 SwHTMLTableLayout *pLayout = 0;
476 MSHORT nWhich = ((SwFrmFmt*)rpNd)->Which();
477 if( RES_DRAWFRMFMT != nWhich )
478 {
479 // Enthaelt der Rahmen zu Beginn oder am Ende eine Tabelle?
480 const SwNodes& rNodes = static_cast<SwFrmFmt*>(rpNd)->GetDoc()->GetNodes();
481 const SwFmtCntnt& rFlyCntnt = ((SwFrmFmt*)rpNd)->GetCntnt();
482 sal_uLong nStt = rFlyCntnt.GetCntntIdx()->GetIndex();
483 SwTableNode* pTblNd = rNodes[nStt+1]->GetTableNode();
484 if( !pTblNd )
485 {
486 SwNode *pNd = rNodes[nStt];
487 pNd = rNodes[pNd->EndOfSectionIndex()-1];
488 if( pNd->IsEndNode() )
489 pTblNd = pNd->StartOfSectionNode()->GetTableNode();
490 }
491
492 if( pTblNd )
493 pLayout = pTblNd->GetTable().GetHTMLTableLayout();
494 }
495
496 const SwFmtHoriOrient& rOrient = ((SwFrmFmt*)rpNd)->GetHoriOrient();
497 sal_Int16 eHoriOri = rOrient.GetHoriOrient();
498
499 long nDiff;
500 if( pLayout )
501 {
502 nMin = pLayout->GetMin();
503 nMax = pLayout->GetMax();
504 nDiff = nMax - nMin;
505 }
506 else
507 {
508 if( RES_DRAWFRMFMT == nWhich )
509 {
510 const SdrObject* pSObj = rpNd->FindSdrObject();
511 if( pSObj )
512 nMin = pSObj->GetCurrentBoundRect().GetWidth();
513 else
514 nMin = 0;
515
516 }
517 else
518 {
519 const SwFmtFrmSize &rSz = ( (SwFrmFmt*)rpNd )->GetFrmSize();
520 nMin = rSz.GetWidth();
521 }
522 nMax = nMin;
523 nDiff = 0;
524 }
525
526 const SvxLRSpaceItem &rLR = ( (SwFrmFmt*)rpNd )->GetLRSpace();
527 nMin += rLR.GetLeft();
528 nMin += rLR.GetRight();
529 nMax += rLR.GetLeft();
530 nMax += rLR.GetRight();
531
532 if( SURROUND_THROUGHT == ((SwFrmFmt*)rpNd)->GetSurround().GetSurround() )
533 {
534 ( (SwMinMaxNodeArgs*)pArgs )->Minimum( nMin );
535 return sal_True;
536 }
537
538 // Rahmen, die recht bzw. links ausgerichtet sind, gehen nur
539 // teilweise in die Max-Berechnung ein, da der Rand schon berueck-
540 // sichtigt wird. Nur wenn die Rahmen in den Textkoerper ragen,
541 // wird dieser Teil hinzuaddiert.
542 switch( eHoriOri )
543 {
544 case text::HoriOrientation::RIGHT:
545 {
546 if( nDiff )
547 {
548 ((SwMinMaxNodeArgs*)pArgs)->nRightRest -=
549 ((SwMinMaxNodeArgs*)pArgs)->nRightDiff;
550 ((SwMinMaxNodeArgs*)pArgs)->nRightDiff = nDiff;
551 }
552 if( text::RelOrientation::FRAME != rOrient.GetRelationOrient() )
553 {
554 if( ((SwMinMaxNodeArgs*)pArgs)->nRightRest > 0 )
555 ((SwMinMaxNodeArgs*)pArgs)->nRightRest = 0;
556 }
557 ((SwMinMaxNodeArgs*)pArgs)->nRightRest -= nMin;
558 break;
559 }
560 case text::HoriOrientation::LEFT:
561 {
562 if( nDiff )
563 {
564 ((SwMinMaxNodeArgs*)pArgs)->nLeftRest -=
565 ((SwMinMaxNodeArgs*)pArgs)->nLeftDiff;
566 ((SwMinMaxNodeArgs*)pArgs)->nLeftDiff = nDiff;
567 }
568 if( text::RelOrientation::FRAME != rOrient.GetRelationOrient() &&
569 ((SwMinMaxNodeArgs*)pArgs)->nLeftRest < 0 )
570 ((SwMinMaxNodeArgs*)pArgs)->nLeftRest = 0;
571 ((SwMinMaxNodeArgs*)pArgs)->nLeftRest -= nMin;
572 break;
573 }
574 default:
575 {
576 ( (SwMinMaxNodeArgs*)pArgs )->nMaxWidth += nMax;
577 ( (SwMinMaxNodeArgs*)pArgs )->Minimum( nMin );
578 }
579 }
580 }
581 return sal_True;
582 }
583
584 #define FLYINCNT_MIN_WIDTH 284
585
586 // changing this method very likely requires changing of
587 // "GetScalingOfSelectedText"
GetMinMaxSize(sal_uLong nIndex,sal_uLong & rMin,sal_uLong & rMax,sal_uLong & rAbsMin,OutputDevice * pOut) const588 void SwTxtNode::GetMinMaxSize( sal_uLong nIndex, sal_uLong& rMin, sal_uLong &rMax,
589 sal_uLong& rAbsMin, OutputDevice* pOut ) const
590 {
591 ViewShell* pSh = 0;
592 GetDoc()->GetEditShell( &pSh );
593 if( !pOut )
594 {
595 if( pSh )
596 pOut = pSh->GetWin();
597 if( !pOut )
598 pOut = GetpApp()->GetDefaultDevice();
599 }
600
601 MapMode aOldMap( pOut->GetMapMode() );
602 pOut->SetMapMode( MapMode( MAP_TWIP ) );
603
604 rMin = 0;
605 rMax = 0;
606 rAbsMin = 0;
607
608 const SvxLRSpaceItem &rSpace = GetSwAttrSet().GetLRSpace();
609 long nLROffset = rSpace.GetTxtLeft() + GetLeftMarginWithNum( sal_True );
610 short nFLOffs;
611 // Bei Numerierung ist ein neg. Erstzeileneinzug vermutlich
612 // bereits gefuellt...
613 if( !GetFirstLineOfsWithNum( nFLOffs ) || nFLOffs > nLROffset )
614 nLROffset = nFLOffs;
615
616 SwMinMaxNodeArgs aNodeArgs;
617 aNodeArgs.nMinWidth = 0;
618 aNodeArgs.nMaxWidth = 0;
619 aNodeArgs.nLeftRest = nLROffset;
620 aNodeArgs.nRightRest = rSpace.GetRight();
621 aNodeArgs.nLeftDiff = 0;
622 aNodeArgs.nRightDiff = 0;
623 if( nIndex )
624 {
625 SwSpzFrmFmts* pTmp = (SwSpzFrmFmts*)GetDoc()->GetSpzFrmFmts();
626 if( pTmp )
627 {
628 aNodeArgs.nIndx = nIndex;
629 pTmp->ForEach( &lcl_MinMaxNode, &aNodeArgs );
630 }
631 }
632 if( aNodeArgs.nLeftRest < 0 )
633 aNodeArgs.Minimum( nLROffset - aNodeArgs.nLeftRest );
634 aNodeArgs.nLeftRest -= aNodeArgs.nLeftDiff;
635 if( aNodeArgs.nLeftRest < 0 )
636 aNodeArgs.nMaxWidth -= aNodeArgs.nLeftRest;
637
638 if( aNodeArgs.nRightRest < 0 )
639 aNodeArgs.Minimum( rSpace.GetRight() - aNodeArgs.nRightRest );
640 aNodeArgs.nRightRest -= aNodeArgs.nRightDiff;
641 if( aNodeArgs.nRightRest < 0 )
642 aNodeArgs.nMaxWidth -= aNodeArgs.nRightRest;
643
644 SwScriptInfo aScriptInfo;
645 SwAttrIter aIter( *(SwTxtNode*)this, aScriptInfo );
646 xub_StrLen nIdx = 0;
647 aIter.SeekAndChgAttrIter( nIdx, pOut );
648 xub_StrLen nLen = m_Text.Len();
649 long nAktWidth = 0;
650 MSHORT nAdd = 0;
651 SwMinMaxArgs aArg( pOut, pSh, rMin, rMax, rAbsMin );
652 while( nIdx < nLen )
653 {
654 xub_StrLen nNextChg = aIter.GetNextAttr();
655 xub_StrLen nStop = aScriptInfo.NextScriptChg( nIdx );
656 if( nNextChg > nStop )
657 nNextChg = nStop;
658 SwTxtAttr *pHint = NULL;
659 xub_Unicode cChar = CH_BLANK;
660 nStop = nIdx;
661 while( nStop < nLen && nStop < nNextChg &&
662 CH_TAB != ( cChar = m_Text.GetChar( nStop ) ) &&
663 CH_BREAK != cChar && CHAR_HARDBLANK != cChar &&
664 CHAR_HARDHYPHEN != cChar && CHAR_SOFTHYPHEN != cChar &&
665 !pHint )
666 {
667 if( ( CH_TXTATR_BREAKWORD != cChar && CH_TXTATR_INWORD != cChar )
668 || ( 0 == ( pHint = aIter.GetAttr( nStop ) ) ) )
669 ++nStop;
670 }
671 if ( lcl_MinMaxString( aArg, aIter.GetFnt(), m_Text, nIdx, nStop ) )
672 {
673 nAdd = 20;
674 }
675 nIdx = nStop;
676 aIter.SeekAndChgAttrIter( nIdx, pOut );
677 switch( cChar )
678 {
679 case CH_BREAK :
680 {
681 if( (long)rMax < aArg.nRowWidth )
682 rMax = aArg.nRowWidth;
683 aArg.nRowWidth = 0;
684 aArg.NewWord();
685 aIter.SeekAndChgAttrIter( ++nIdx, pOut );
686 }
687 break;
688 case CH_TAB :
689 {
690 aArg.NewWord();
691 aIter.SeekAndChgAttrIter( ++nIdx, pOut );
692 }
693 break;
694 case CHAR_SOFTHYPHEN:
695 ++nIdx;
696 break;
697 case CHAR_HARDBLANK:
698 case CHAR_HARDHYPHEN:
699 {
700 XubString sTmp( cChar );
701 SwDrawTextInfo aDrawInf( const_cast<ViewShell *>(getIDocumentLayoutAccess()->GetCurrentViewShell()),
702 *pOut, 0, sTmp, 0, 1, 0, sal_False );//swmod 080311
703 nAktWidth = aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
704 aArg.nWordWidth += nAktWidth;
705 aArg.nRowWidth += nAktWidth;
706 if( (long)rAbsMin < aArg.nWordWidth )
707 rAbsMin = aArg.nWordWidth;
708 aArg.Minimum( aArg.nWordWidth + aArg.nWordAdd );
709 aArg.nNoLineBreak = nIdx++;
710 }
711 break;
712 case CH_TXTATR_BREAKWORD:
713 case CH_TXTATR_INWORD:
714 {
715 if( !pHint )
716 break;
717 long nOldWidth = aArg.nWordWidth;
718 long nOldAdd = aArg.nWordAdd;
719 aArg.NewWord();
720
721 switch( pHint->Which() )
722 {
723 case RES_TXTATR_FLYCNT :
724 {
725 SwFrmFmt *pFrmFmt = pHint->GetFlyCnt().GetFrmFmt();
726 const SvxLRSpaceItem &rLR = pFrmFmt->GetLRSpace();
727 if( RES_DRAWFRMFMT == pFrmFmt->Which() )
728 {
729 const SdrObject* pSObj = pFrmFmt->FindSdrObject();
730 if( pSObj )
731 nAktWidth = pSObj->GetCurrentBoundRect().GetWidth();
732 else
733 nAktWidth = 0;
734 }
735 else
736 {
737 const SwFmtFrmSize& rTmpSize = pFrmFmt->GetFrmSize();
738 if( RES_FLYFRMFMT == pFrmFmt->Which()
739 && rTmpSize.GetWidthPercent() )
740 {
741 /*-----------------24.01.97 14:09----------------------------------------------
742 * Hier ein HACK fuer folgende Situation: In dem Absatz befindet sich
743 * ein Textrahmen mit relativer Groesse. Dann nehmen wir mal als minimale
744 * Breite 0,5 cm und als maximale KSHRT_MAX.
745 * Sauberer und vielleicht spaeter notwendig waere es, ueber den Inhalt
746 * des Textrahmens zu iterieren und GetMinMaxSize rekursiv zu rufen.
747 * --------------------------------------------------------------------------*/
748 nAktWidth = FLYINCNT_MIN_WIDTH; // 0,5 cm
749 if( (long)rMax < KSHRT_MAX )
750 rMax = KSHRT_MAX;
751 }
752 else
753 nAktWidth = pFrmFmt->GetFrmSize().GetWidth();
754 }
755 nAktWidth += rLR.GetLeft();
756 nAktWidth += rLR.GetRight();
757 aArg.nWordAdd = nOldWidth + nOldAdd;
758 aArg.nWordWidth = nAktWidth;
759 aArg.nRowWidth += nAktWidth;
760 if( (long)rAbsMin < aArg.nWordWidth )
761 rAbsMin = aArg.nWordWidth;
762 aArg.Minimum( aArg.nWordWidth + aArg.nWordAdd );
763 break;
764 }
765 case RES_TXTATR_FTN :
766 {
767 const XubString aTxt = pHint->GetFtn().GetNumStr();
768 if( lcl_MinMaxString( aArg, aIter.GetFnt(), aTxt, 0,
769 aTxt.Len() ) )
770 nAdd = 20;
771 break;
772 }
773
774 case RES_TXTATR_FIELD :
775 case RES_TXTATR_ANNOTATION :
776 {
777 SwField *pFld = (SwField*)pHint->GetFmtFld().GetField();
778 const String aTxt = pFld->ExpandField(true);
779 if( lcl_MinMaxString( aArg, aIter.GetFnt(), aTxt, 0,
780 aTxt.Len() ) )
781 nAdd = 20;
782 break;
783 }
784
785 default: aArg.nWordWidth = nOldWidth;
786 aArg.nWordAdd = nOldAdd;
787
788 }
789 aIter.SeekAndChgAttrIter( ++nIdx, pOut );
790 }
791 break;
792 }
793 }
794 if( (long)rMax < aArg.nRowWidth )
795 rMax = aArg.nRowWidth;
796
797 nLROffset += rSpace.GetRight();
798
799 rAbsMin += nLROffset;
800 rAbsMin += nAdd;
801 rMin += nLROffset;
802 rMin += nAdd;
803 if( (long)rMin < aNodeArgs.nMinWidth )
804 rMin = aNodeArgs.nMinWidth;
805 if( (long)rAbsMin < aNodeArgs.nMinWidth )
806 rAbsMin = aNodeArgs.nMinWidth;
807 rMax += aNodeArgs.nMaxWidth;
808 rMax += nLROffset;
809 rMax += nAdd;
810 if( rMax < rMin ) // z.B. Rahmen mit Durchlauf gehen zunaechst nur
811 rMax = rMin; // in das Minimum ein
812 pOut->SetMapMode( aOldMap );
813 }
814
815 /*************************************************************************
816 * SwTxtNode::GetScalingOfSelectedText()
817 *
818 * Calculates the width of the text part specified by nStt and nEnd,
819 * the height of the line containing nStt is devided by this width,
820 * indicating the scaling factor, if the text part is rotated.
821 * Having CH_BREAKs in the text part, this method returns the scaling
822 * factor for the longest of the text parts separated by the CH_BREAKs.
823 *
824 * changing this method very likely requires changing of "GetMinMaxSize"
825 *************************************************************************/
826
GetScalingOfSelectedText(xub_StrLen nStt,xub_StrLen nEnd) const827 sal_uInt16 SwTxtNode::GetScalingOfSelectedText( xub_StrLen nStt, xub_StrLen nEnd )
828 const
829 {
830 ViewShell* pSh = NULL;
831 OutputDevice* pOut = NULL;
832 GetDoc()->GetEditShell( &pSh );
833
834 if ( pSh )
835 pOut = &pSh->GetRefDev();
836 else
837 {
838 //Zugriff ueber StarONE, es muss keine Shell existieren oder aktiv sein.
839 if ( getIDocumentSettingAccess()->get(IDocumentSettingAccess::HTML_MODE) )
840 pOut = GetpApp()->GetDefaultDevice();
841 else
842 pOut = getIDocumentDeviceAccess()->getReferenceDevice( true );
843 }
844
845 ASSERT( pOut, "GetScalingOfSelectedText without outdev" )
846
847 MapMode aOldMap( pOut->GetMapMode() );
848 pOut->SetMapMode( MapMode( MAP_TWIP ) );
849
850 if ( nStt == nEnd )
851 {
852 if ( !pBreakIt->GetBreakIter().is() )
853 return 100;
854
855 SwScriptInfo aScriptInfo;
856 SwAttrIter aIter( *(SwTxtNode*)this, aScriptInfo );
857 aIter.SeekAndChgAttrIter( nStt, pOut );
858
859 Boundary aBound =
860 pBreakIt->GetBreakIter()->getWordBoundary( GetTxt(), nStt,
861 pBreakIt->GetLocale( aIter.GetFnt()->GetLanguage() ),
862 WordType::DICTIONARY_WORD, sal_True );
863
864 if ( nStt == aBound.startPos )
865 {
866 // cursor is at left or right border of word
867 pOut->SetMapMode( aOldMap );
868 return 100;
869 }
870
871 nStt = (xub_StrLen)aBound.startPos;
872 nEnd = (xub_StrLen)aBound.endPos;
873
874 if ( nStt == nEnd )
875 {
876 pOut->SetMapMode( aOldMap );
877 return 100;
878 }
879 }
880
881 SwScriptInfo aScriptInfo;
882 SwAttrIter aIter( *(SwTxtNode*)this, aScriptInfo );
883
884 // We do not want scaling attributes to be considered during this
885 // calculation. For this, we push a temporary scaling attribute with
886 // scaling value 100 and priority flag on top of the scaling stack
887 SwAttrHandler& rAH = aIter.GetAttrHandler();
888 SvxCharScaleWidthItem aItem(100, RES_CHRATR_SCALEW);
889 SwTxtAttrEnd aAttr( aItem, nStt, nEnd );
890 aAttr.SetPriorityAttr( sal_True );
891 rAH.PushAndChg( aAttr, *(aIter.GetFnt()) );
892
893 xub_StrLen nIdx = nStt;
894
895 sal_uLong nWidth = 0;
896 sal_uLong nProWidth = 0;
897
898 while( nIdx < nEnd )
899 {
900 aIter.SeekAndChgAttrIter( nIdx, pOut );
901
902 // scan for end of portion
903 xub_StrLen nNextChg = aIter.GetNextAttr();
904 xub_StrLen nStop = aScriptInfo.NextScriptChg( nIdx );
905 if( nNextChg > nStop )
906 nNextChg = nStop;
907
908 nStop = nIdx;
909 xub_Unicode cChar = CH_BLANK;
910 SwTxtAttr* pHint = NULL;
911
912 // stop at special characters in [ nIdx, nNextChg ]
913 while( nStop < nEnd && nStop < nNextChg )
914 {
915 cChar = m_Text.GetChar( nStop );
916 if (
917 CH_TAB == cChar ||
918 CH_BREAK == cChar ||
919 CHAR_HARDBLANK == cChar ||
920 CHAR_HARDHYPHEN == cChar ||
921 CHAR_SOFTHYPHEN == cChar ||
922 (
923 (CH_TXTATR_BREAKWORD == cChar || CH_TXTATR_INWORD == cChar) &&
924 (0 == (pHint = aIter.GetAttr(nStop)))
925 )
926 )
927 {
928 break;
929 }
930 else
931 ++nStop;
932 }
933
934 // calculate text widths up to cChar
935 if ( nStop > nIdx )
936 {
937 SwDrawTextInfo aDrawInf( pSh, *pOut, 0, GetTxt(), nIdx, nStop - nIdx );
938 nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
939 }
940
941 nIdx = nStop;
942 aIter.SeekAndChgAttrIter( nIdx, pOut );
943
944 if ( cChar == CH_BREAK )
945 {
946 nWidth = Max( nWidth, nProWidth );
947 nProWidth = 0;
948 nIdx++;
949 }
950 else if ( cChar == CH_TAB )
951 {
952 // tab receives width of one space
953 XubString sTmp( CH_BLANK );
954 SwDrawTextInfo aDrawInf( pSh, *pOut, 0, sTmp, 0, 1 );
955 nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
956 nIdx++;
957 }
958 else if ( cChar == CHAR_SOFTHYPHEN )
959 ++nIdx;
960 else if ( cChar == CHAR_HARDBLANK || cChar == CHAR_HARDHYPHEN )
961 {
962 XubString sTmp( cChar );
963 SwDrawTextInfo aDrawInf( pSh, *pOut, 0, sTmp, 0, 1 );
964 nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
965 nIdx++;
966 }
967 else if ( pHint && ( cChar == CH_TXTATR_BREAKWORD || CH_TXTATR_INWORD ) )
968 {
969 switch( pHint->Which() )
970 {
971 case RES_TXTATR_FTN :
972 {
973 const XubString aTxt = pHint->GetFtn().GetNumStr();
974 SwDrawTextInfo aDrawInf( pSh, *pOut, 0, aTxt, 0, aTxt.Len() );
975
976 nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
977 break;
978 }
979
980 case RES_TXTATR_FIELD :
981 case RES_TXTATR_ANNOTATION :
982 {
983 SwField *pFld = (SwField*)pHint->GetFmtFld().GetField();
984 String const aTxt = pFld->ExpandField(true);
985 SwDrawTextInfo aDrawInf( pSh, *pOut, 0, aTxt, 0, aTxt.Len() );
986
987 nProWidth += aIter.GetFnt()->_GetTxtSize( aDrawInf ).Width();
988 break;
989 }
990
991 default:
992 {
993 // any suggestions for a default action?
994 }
995 } // end of switch
996 nIdx++;
997 } // end of while
998 }
999
1000 nWidth = Max( nWidth, nProWidth );
1001
1002 // search for a text frame this node belongs to
1003 SwIterator<SwTxtFrm,SwTxtNode> aFrmIter( *this );
1004 SwTxtFrm* pFrm = 0;
1005 for( SwTxtFrm* pTmpFrm = aFrmIter.First(); pTmpFrm; pTmpFrm = aFrmIter.Next() )
1006 {
1007 if ( pTmpFrm->GetOfst() <= nStt &&
1008 ( !pTmpFrm->GetFollow() ||
1009 pTmpFrm->GetFollow()->GetOfst() > nStt ) )
1010 {
1011 pFrm = pTmpFrm;
1012 break;
1013 }
1014 }
1015
1016 // search for the line containing nStt
1017 if ( pFrm && pFrm->HasPara() )
1018 {
1019 SwTxtInfo aInf( pFrm );
1020 SwTxtIter aLine( pFrm, &aInf );
1021 aLine.CharToLine( nStt );
1022 pOut->SetMapMode( aOldMap );
1023 return (sal_uInt16)( nWidth ?
1024 ( ( 100 * aLine.GetCurr()->Height() ) / nWidth ) : 0 );
1025 }
1026 // no frame or no paragraph, we take the height of the character
1027 // at nStt as line height
1028
1029 aIter.SeekAndChgAttrIter( nStt, pOut );
1030 pOut->SetMapMode( aOldMap );
1031
1032 SwDrawTextInfo aDrawInf( pSh, *pOut, 0, GetTxt(), nStt, 1 );
1033 return (sal_uInt16)
1034 ( nWidth ? ((100 * aIter.GetFnt()->_GetTxtSize( aDrawInf ).Height()) / nWidth ) : 0 );
1035 }
1036
GetWidthOfLeadingTabs() const1037 sal_uInt16 SwTxtNode::GetWidthOfLeadingTabs() const
1038 {
1039 sal_uInt16 nRet = 0;
1040
1041 xub_StrLen nIdx = 0;
1042 sal_Unicode cCh;
1043
1044 while ( nIdx < GetTxt().Len() &&
1045 ( '\t' == ( cCh = GetTxt().GetChar( nIdx ) ) ||
1046 ' ' == cCh ) )
1047 ++nIdx;
1048
1049 if ( nIdx > 0 )
1050 {
1051 SwPosition aPos( *this );
1052 aPos.nContent += nIdx;
1053
1054 // Find the non-follow text frame:
1055 SwIterator<SwTxtFrm,SwTxtNode> aIter( *this );
1056 for( SwTxtFrm* pFrm = aIter.First(); pFrm; pFrm = aIter.Next() )
1057 {
1058 // Only consider master frames:
1059 if ( !pFrm->IsFollow() )
1060 {
1061 SWRECTFN( pFrm )
1062 SwRect aRect;
1063 pFrm->GetCharRect( aRect, aPos );
1064 nRet = (sal_uInt16)
1065 ( pFrm->IsRightToLeft() ?
1066 (pFrm->*fnRect->fnGetPrtRight)() - (aRect.*fnRect->fnGetRight)() :
1067 (aRect.*fnRect->fnGetLeft)() - (pFrm->*fnRect->fnGetPrtLeft)() );
1068 break;
1069 }
1070 }
1071 }
1072
1073 return nRet;
1074 }
1075