xref: /aoo41x/main/sw/source/core/text/frminf.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 
31 
32 #include <pam.hxx>          // GetSpaces
33 #include <txtcfg.hxx>
34 #include <frminf.hxx>		// SwTxtFrminfo
35 #include <itrtxt.hxx>       // SwTxtMargin
36 
37 /*************************************************************************
38  *					 SwTxtMargin::GetTxtStart()
39  *************************************************************************/
40 
41 xub_StrLen SwTxtMargin::GetTxtStart() const
42 {
43 	const XubString &rTxt = GetInfo().GetTxt();
44     const xub_StrLen nTmpPos = nStart;
45     const xub_StrLen nEnd = nTmpPos + pCurr->GetLen();
46 	xub_StrLen i;
47 
48     for( i = nTmpPos; i < nEnd; ++i )
49 	{
50 		const xub_Unicode aChar = rTxt.GetChar( i );
51 		if( CH_TAB != aChar && ' ' != aChar )
52 			return i;
53 	}
54 	return i;
55 }
56 
57 /*************************************************************************
58  *					 SwTxtMargin::GetTxtEnd()
59  *************************************************************************/
60 
61 xub_StrLen SwTxtMargin::GetTxtEnd() const
62 {
63 	const XubString &rTxt = GetInfo().GetTxt();
64     const xub_StrLen nTmpPos = nStart;
65     const xub_StrLen nEnd = nTmpPos + pCurr->GetLen();
66 	long i;
67     for( i = nEnd - 1; i >= nTmpPos; --i )
68 	{
69         xub_Unicode aChar = rTxt.GetChar( static_cast<xub_StrLen>(i) );
70 		if( CH_TAB != aChar && CH_BREAK != aChar && ' ' != aChar )
71             return static_cast<xub_StrLen>(i + 1);
72 	}
73     return static_cast<xub_StrLen>(i + 1);
74 }
75 
76 /*************************************************************************
77  *					 SwTxtFrmInfo::IsOneLine()
78  *************************************************************************/
79 
80 // Passt der Absatz in eine Zeile?
81 sal_Bool SwTxtFrmInfo::IsOneLine() const
82 {
83 	const SwLineLayout *pLay = pFrm->GetPara();
84 	if( !pLay )
85 		return sal_False;
86 	else
87 	{
88 		// 6575: bei Follows natuerlich sal_False
89 		if( pFrm->GetFollow() )
90 			return sal_False;
91 		pLay = pLay->GetNext();
92 		while( pLay )
93 		{
94 			if( pLay->GetLen() )
95 				return sal_False;
96 			pLay = pLay->GetNext();
97 		}
98 		return sal_True;
99 	}
100 }
101 
102 /*************************************************************************
103  *					 SwTxtFrmInfo::IsFilled()
104  *************************************************************************/
105 
106 // Ist die Zeile zu X% gefuellt?
107 sal_Bool SwTxtFrmInfo::IsFilled( const sal_uInt8 nPercent ) const
108 {
109 	const SwLineLayout *pLay = pFrm->GetPara();
110 	if( !pLay )
111 		return sal_False;
112 	else
113 	{
114 		long nWidth = pFrm->Prt().Width();
115 		nWidth *= nPercent;
116 		nWidth /= 100;
117 		return KSHORT(nWidth) <= pLay->Width();
118 	}
119 }
120 
121 /*************************************************************************
122  *					 SwTxtFrmInfo::GetLineStart()
123  *************************************************************************/
124 
125 // Wo beginnt der Text (ohne whitespaces)? ( Dokument global )
126 SwTwips SwTxtFrmInfo::GetLineStart( const SwTxtCursor &rLine ) const
127 {
128     xub_StrLen nTxtStart = rLine.GetTxtStart();
129 	SwTwips nStart;
130 	if( rLine.GetStart() == nTxtStart )
131 		nStart = rLine.GetLineStart();
132 	else
133 	{
134 		SwRect aRect;
135 		if( ((SwTxtCursor&)rLine).GetCharRect( &aRect, nTxtStart ) )
136 			nStart = aRect.Left();
137 		else
138 			nStart = rLine.GetLineStart();
139 	}
140 	return nStart;
141 }
142 
143 
144 /*************************************************************************
145  *					 SwTxtFrmInfo::GetLineStart()
146  *************************************************************************/
147 
148 // Wo beginnt der Text (ohne whitespaces)? (rel. im Frame)
149 SwTwips SwTxtFrmInfo::GetLineStart() const
150 {
151 	SwTxtSizeInfo aInf( (SwTxtFrm*)pFrm );
152 	SwTxtCursor aLine( (SwTxtFrm*)pFrm, &aInf );
153 	return GetLineStart( aLine ) - pFrm->Frm().Left() -	pFrm->Prt().Left();
154 }
155 
156 // errechne die Position des Zeichens und gebe die Mittelposition zurueck
157 SwTwips SwTxtFrmInfo::GetCharPos( xub_StrLen nChar, sal_Bool bCenter ) const
158 {
159     SWRECTFN( pFrm )
160     SwFrmSwapper aSwapper( pFrm, sal_True );
161 
162     SwTxtSizeInfo aInf( (SwTxtFrm*)pFrm );
163 	SwTxtCursor aLine( (SwTxtFrm*)pFrm, &aInf );
164 
165 	SwTwips nStt, nNext;
166 	SwRect aRect;
167 	if( ((SwTxtCursor&)aLine).GetCharRect( &aRect, nChar ) )
168     {
169         if ( bVert )
170             pFrm->SwitchHorizontalToVertical( aRect );
171 
172         nStt = (aRect.*fnRect->fnGetLeft)();
173     }
174 	else
175 		nStt = aLine.GetLineStart();
176 
177 	if( !bCenter )
178         return nStt - (pFrm->Frm().*fnRect->fnGetLeft)();
179 
180 	if( ((SwTxtCursor&)aLine).GetCharRect( &aRect, nChar+1 ) )
181     {
182         if ( bVert )
183             pFrm->SwitchHorizontalToVertical( aRect );
184 
185         nNext = (aRect.*fnRect->fnGetLeft)();
186     }
187 	else
188 		nNext = aLine.GetLineStart();
189 
190     return (( nNext + nStt ) / 2 ) - (pFrm->Frm().*fnRect->fnGetLeft)();
191 }
192 
193 /*************************************************************************
194  *					 SwTxtFrmInfo::GetSpaces()
195  *************************************************************************/
196 
197 SwPaM *AddPam( SwPaM *pPam, const SwTxtFrm* pTxtFrm,
198 				const xub_StrLen nPos, const xub_StrLen nLen )
199 {
200 	if( nLen )
201 	{
202 		// Es koennte auch der erste sein.
203 		if( pPam->HasMark() )
204 		{
205 			// liegt die neue Position genau hinter der aktuellen, dann
206 			// erweiter den Pam einfach
207 			if( nPos == pPam->GetPoint()->nContent.GetIndex() )
208 			{
209 				pPam->GetPoint()->nContent += nLen;
210 				return pPam;
211 			}
212 			pPam = new SwPaM( *pPam );
213 		}
214 
215 		SwIndex &rContent = pPam->GetPoint()->nContent;
216 		rContent.Assign( (SwTxtNode*)pTxtFrm->GetTxtNode(), nPos );
217 		pPam->SetMark();
218 		rContent += nLen;
219 	}
220 	return pPam;
221 }
222 
223 // Sammelt die whitespaces am Zeilenbeginn und -ende im Pam
224 void SwTxtFrmInfo::GetSpaces( SwPaM &rPam, sal_Bool bWithLineBreak ) const
225 {
226 	SwTxtSizeInfo aInf( (SwTxtFrm*)pFrm );
227 	SwTxtMargin aLine( (SwTxtFrm*)pFrm, &aInf );
228 	SwPaM *pPam = &rPam;
229 	sal_Bool bFirstLine = sal_True;
230 	do {
231 
232 		if( aLine.GetCurr()->GetLen() )
233 		{
234 			xub_StrLen nPos = aLine.GetTxtStart();
235 			// Bug 49649: von der ersten Line die Blanks/Tabs NICHT
236 			//				mit selektieren
237 			if( !bFirstLine && nPos > aLine.GetStart() )
238 				pPam = AddPam( pPam, pFrm, aLine.GetStart(),
239 								nPos - aLine.GetStart() );
240 
241 			// Bug 49649: von der letzten Line die Blanks/Tabs NICHT
242 			//				mit selektieren
243 			if( aLine.GetNext() )
244 			{
245 				nPos = aLine.GetTxtEnd();
246 
247 				if( nPos < aLine.GetEnd() )
248 				{
249 					MSHORT nOff = !bWithLineBreak && CH_BREAK ==
250 								aLine.GetInfo().GetChar( aLine.GetEnd() - 1 )
251 								? 1 : 0;
252 					pPam = AddPam( pPam, pFrm, nPos, aLine.GetEnd() - nPos - nOff );
253 				}
254 			}
255 		}
256 		bFirstLine = sal_False;
257 	}
258 	while( aLine.Next() );
259 }
260 
261 /*************************************************************************
262  *					 SwTxtFrmInfo::IsBullet()
263  *************************************************************************/
264 
265 // Ist an der Textposition ein Bullet/Symbol etc?
266 // Fonts: CharSet, SYMBOL und DONTKNOW
267 sal_Bool SwTxtFrmInfo::IsBullet( xub_StrLen nTxtStart ) const
268 {
269 	SwTxtSizeInfo aInf( (SwTxtFrm*)pFrm );
270 	SwTxtMargin aLine( (SwTxtFrm*)pFrm, &aInf );
271 	aInf.SetIdx( nTxtStart );
272 	return aLine.IsSymbol( nTxtStart );
273 }
274 
275 /*************************************************************************
276  *					 SwTxtFrmInfo::GetFirstIndent()
277  *************************************************************************/
278 
279 // Ermittelt Erstzeileneinzug
280 // Voraussetzung fuer pos. oder neg. EZE ist, dass alle
281 // Zeilen ausser der ersten Zeile den selben linken Rand haben.
282 // Wir wollen nicht so knauserig sein und arbeiten mit einer Toleranz
283 // von TOLERANCE Twips.
284 
285 #define TOLERANCE 20
286 
287 SwTwips SwTxtFrmInfo::GetFirstIndent() const
288 {
289 	SwTxtSizeInfo aInf( (SwTxtFrm*)pFrm );
290 	SwTxtCursor aLine( (SwTxtFrm*)pFrm, &aInf );
291 	const SwTwips nFirst = GetLineStart( aLine );
292 	if( !aLine.Next() )
293 		return 0;
294 
295 	SwTwips nLeft = GetLineStart( aLine );
296 	while( aLine.Next() )
297 	{
298 		if( aLine.GetCurr()->GetLen() )
299 		{
300 			const SwTwips nCurrLeft = GetLineStart( aLine );
301 			if( nLeft + TOLERANCE < nCurrLeft ||
302 				nLeft - TOLERANCE > nCurrLeft )
303 				return 0;
304 		}
305 	}
306 
307 	// Vorerst wird nur +1, -1 und 0 returnt.
308 	if( nLeft == nFirst )
309 		return 0;
310 	else
311 		if( nLeft > nFirst )
312 			return -1;
313 		else
314 			return +1;
315 }
316 
317 /*************************************************************************
318  *					 SwTxtFrmInfo::GetBigIndent()
319  *************************************************************************/
320 
321 KSHORT SwTxtFrmInfo::GetBigIndent( xub_StrLen& rFndPos,
322 									const SwTxtFrm *pNextFrm ) const
323 {
324 	SwTxtSizeInfo aInf( (SwTxtFrm*)pFrm );
325 	SwTxtCursor aLine( (SwTxtFrm*)pFrm, &aInf );
326 	SwTwips nNextIndent = 0;
327 
328 	if( pNextFrm )
329 	{
330 		// ich bin einzeilig
331 		SwTxtSizeInfo aNxtInf( (SwTxtFrm*)pNextFrm );
332 		SwTxtCursor aNxtLine( (SwTxtFrm*)pNextFrm, &aNxtInf );
333 		nNextIndent = GetLineStart( aNxtLine );
334 	}
335 	else
336 	{
337 		// ich bin mehrzeilig
338 		if( aLine.Next() )
339 		{
340 			nNextIndent = GetLineStart( aLine );
341 			aLine.Prev();
342 		}
343 	}
344 
345 	if( nNextIndent <= GetLineStart( aLine ) )
346 		return 0;
347 
348 	const Point aPoint( nNextIndent, aLine.Y() );
349 	rFndPos = aLine.GetCrsrOfst( 0, aPoint, sal_False );
350 	if( 1 >= rFndPos )
351 		return 0;
352 
353 	// steht vor einem "nicht Space"
354 	const XubString& rTxt = aInf.GetTxt();
355 	xub_Unicode aChar = rTxt.GetChar( rFndPos );
356 	if( CH_TAB == aChar || CH_BREAK == aChar || ' ' == aChar ||
357 		(( CH_TXTATR_BREAKWORD == aChar || CH_TXTATR_INWORD == aChar ) &&
358 			aInf.HasHint( rFndPos ) ) )
359 		return 0;
360 
361 	// und hinter einem "Space"
362 	aChar = rTxt.GetChar( rFndPos - 1 );
363 	if( CH_TAB != aChar && CH_BREAK != aChar &&
364 		( ( CH_TXTATR_BREAKWORD != aChar && CH_TXTATR_INWORD != aChar ) ||
365 			!aInf.HasHint( rFndPos - 1 ) ) &&
366 		// mehr als 2 Blanks !!
367 		( ' ' != aChar || ' ' != rTxt.GetChar( rFndPos - 2 ) ) )
368 		return 0;
369 
370 	SwRect aRect;
371 	return aLine.GetCharRect( &aRect, rFndPos )
372 			? KSHORT( aRect.Left() - pFrm->Frm().Left() - pFrm->Prt().Left())
373 			: 0;
374 }
375 
376 
377 
378