xref: /trunk/main/svtools/source/edit/xtextedt.cxx (revision 5900e8ec)
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_svtools.hxx"
26 
27 #include <svtools/xtextedt.hxx>
28 #include <vcl/svapp.hxx>  // International
29 #include <unotools/textsearch.hxx>
30 #include <com/sun/star/util/SearchOptions.hpp>
31 #include <com/sun/star/util/SearchFlags.hpp>
32 
33 using namespace ::com::sun::star;
34 
35 
36 
37 // -------------------------------------------------------------------------
38 // class ExtTextEngine
39 // -------------------------------------------------------------------------
ExtTextEngine()40 ExtTextEngine::ExtTextEngine() : maGroupChars( String::CreateFromAscii( "(){}[]", 6 ) )
41 {
42 }
43 
~ExtTextEngine()44 ExtTextEngine::~ExtTextEngine()
45 {
46 }
47 
MatchGroup(const TextPaM & rCursor) const48 TextSelection ExtTextEngine::MatchGroup( const TextPaM& rCursor ) const
49 {
50 	TextSelection aSel( rCursor );
51 	sal_uInt16 nPos = rCursor.GetIndex();
52 	sal_uLong nPara = rCursor.GetPara();
53 	sal_uLong nParas = GetParagraphCount();
54 	if ( ( nPara < nParas ) && ( nPos < GetTextLen( nPara ) ) )
55 	{
56 		sal_uInt16 nMatchChar = maGroupChars.Search( GetText( rCursor.GetPara() ).GetChar( nPos ) );
57 		if ( nMatchChar != STRING_NOTFOUND )
58 		{
59 			if ( ( nMatchChar % 2 ) == 0 )
60 			{
61 				// Vorwaerts suchen...
62 				sal_Unicode nSC = maGroupChars.GetChar( nMatchChar );
63 				sal_Unicode nEC = maGroupChars.GetChar( nMatchChar+1 );
64 
65 				sal_uInt16 nCur = nPos+1;
66 				sal_uInt16 nLevel = 1;
67 				while ( nLevel && ( nPara < nParas ) )
68 				{
69 					XubString aStr = GetText( nPara );
70 					while ( nCur < aStr.Len() )
71 					{
72 						if ( aStr.GetChar( nCur ) == nSC )
73 							nLevel++;
74 						else if ( aStr.GetChar( nCur ) == nEC )
75 						{
76 							nLevel--;
77 							if ( !nLevel )
78 								break;	// while nCur...
79 						}
80 						nCur++;
81 					}
82 
83 					if ( nLevel )
84 					{
85 						nPara++;
86 						nCur = 0;
87 					}
88 				}
89 				if ( nLevel == 0 )	// gefunden
90 				{
91 					aSel.GetStart() = rCursor;
92 					aSel.GetEnd() = TextPaM( nPara, nCur+1 );
93 				}
94 			}
95 			else
96 			{
97 				// Rueckwaerts suchen...
98 				xub_Unicode nEC = maGroupChars.GetChar( nMatchChar );
99 				xub_Unicode nSC = maGroupChars.GetChar( nMatchChar-1 );
100 
101 				sal_uInt16 nCur = rCursor.GetIndex()-1;
102 				sal_uInt16 nLevel = 1;
103 				while ( nLevel )
104 				{
105 					if ( GetTextLen( nPara ) )
106 					{
107 						XubString aStr = GetText( nPara );
108 						while ( nCur )
109 						{
110 							if ( aStr.GetChar( nCur ) == nSC )
111 							{
112 								nLevel--;
113 								if ( !nLevel )
114 									break;	// while nCur...
115 							}
116 							else if ( aStr.GetChar( nCur ) == nEC )
117 								nLevel++;
118 
119 							nCur--;
120 						}
121 					}
122 
123 					if ( nLevel )
124 					{
125 						if ( nPara )
126 						{
127 							nPara--;
128 							nCur = GetTextLen( nPara )-1;	// egal ob negativ, weil if Len()
129 						}
130 						else
131 							break;
132 					}
133 				}
134 
135 				if ( nLevel == 0 )	// gefunden
136 				{
137 					aSel.GetStart() = rCursor;
138 					aSel.GetStart().GetIndex()++;	// hinter das Zeichen
139 					aSel.GetEnd() = TextPaM( nPara, nCur );
140 				}
141 			}
142 		}
143 	}
144 	return aSel;
145 }
146 
Search(TextSelection & rSel,const util::SearchOptions & rSearchOptions,sal_Bool bForward)147 sal_Bool ExtTextEngine::Search( TextSelection& rSel, const util::SearchOptions& rSearchOptions, sal_Bool bForward )
148 {
149 	TextSelection aSel( rSel );
150 	aSel.Justify();
151 
152 	sal_Bool bSearchInSelection = (0 != (rSearchOptions.searchFlag & util::SearchFlags::REG_NOT_BEGINOFLINE) );
153 
154 	TextPaM aStartPaM( aSel.GetEnd() );
155 	if ( aSel.HasRange() && ( ( bSearchInSelection && bForward ) || ( !bSearchInSelection && !bForward ) ) )
156 	{
157 		aStartPaM = aSel.GetStart();
158 	}
159 
160 	bool bFound = false;
161 	sal_uLong nStartNode, nEndNode;
162 
163 	if ( bSearchInSelection )
164 		nEndNode = bForward ? aSel.GetEnd().GetPara() : aSel.GetStart().GetPara();
165 	else
166 		nEndNode = bForward ? (GetParagraphCount()-1) : 0;
167 
168 	nStartNode = aStartPaM.GetPara();
169 
170 	util::SearchOptions aOptions( rSearchOptions );
171 	aOptions.Locale = Application::GetSettings().GetLocale();
172 	utl::TextSearch aSearcher( rSearchOptions );
173 
174 	// ueber die Absaetze iterieren...
175 	for ( sal_uLong nNode = nStartNode;
176 			bForward ?  ( nNode <= nEndNode) : ( nNode >= nEndNode );
177 			bForward ? nNode++ : nNode-- )
178 	{
179 		String aText = GetText( nNode );
180 		sal_uInt16 nStartPos = 0;
181 		sal_uInt16 nEndPos = aText.Len();
182 		if ( nNode == nStartNode )
183 		{
184 			if ( bForward )
185 				nStartPos = aStartPaM.GetIndex();
186 			else
187 				nEndPos = aStartPaM.GetIndex();
188 		}
189 		if ( ( nNode == nEndNode ) && bSearchInSelection )
190 		{
191 			if ( bForward )
192 				nEndPos = aSel.GetEnd().GetIndex();
193 			else
194 				nStartPos = aSel.GetStart().GetIndex();
195 		}
196 
197 		if ( bForward )
198 			bFound = aSearcher.SearchFrwrd( aText, &nStartPos, &nEndPos );
199 		else
200 			bFound = aSearcher.SearchBkwrd( aText, &nEndPos, &nStartPos );
201 
202 		if ( bFound )
203 		{
204 			rSel.GetStart().GetPara() = nNode;
205 			rSel.GetStart().GetIndex() = nStartPos;
206 			rSel.GetEnd().GetPara() = nNode;
207 			rSel.GetEnd().GetIndex() = nEndPos;
208 			// Ueber den Absatz selektieren?
209 			// Select over the paragraph?
210 			// FIXME  This should be max long...
211 			if( nEndPos == sal::static_int_cast<sal_uInt16>(-1) ) // sal_uInt16 for 0 and -1 !
212 			{
213 				if ( (rSel.GetEnd().GetPara()+1) < GetParagraphCount() )
214 				{
215 					rSel.GetEnd().GetPara()++;
216 					rSel.GetEnd().GetIndex() = 0;
217 				}
218 				else
219 				{
220 					rSel.GetEnd().GetIndex() = nStartPos;
221 					bFound = false;
222 				}
223 			}
224 
225 			break;
226 		}
227 
228 		if ( !bForward && !nNode )	// Bei rueckwaertsuche, wenn nEndNode = 0:
229 			break;
230 	}
231 
232 	return bFound;
233 }
234 
235 
236 // -------------------------------------------------------------------------
237 // class ExtTextView
238 // -------------------------------------------------------------------------
ExtTextView(ExtTextEngine * pEng,Window * pWindow)239 ExtTextView::ExtTextView( ExtTextEngine* pEng, Window* pWindow )
240 	: TextView( pEng, pWindow )
241 {
242 }
243 
~ExtTextView()244 ExtTextView::~ExtTextView()
245 {
246 }
247 
MatchGroup()248 sal_Bool ExtTextView::MatchGroup()
249 {
250 	TextSelection aTmpSel( GetSelection() );
251 	aTmpSel.Justify();
252 	if ( ( aTmpSel.GetStart().GetPara() != aTmpSel.GetEnd().GetPara() ) ||
253 		 ( ( aTmpSel.GetEnd().GetIndex() - aTmpSel.GetStart().GetIndex() ) > 1 ) )
254 	{
255 		return sal_False;
256 	}
257 
258 	TextSelection aMatchSel = ((ExtTextEngine*)GetTextEngine())->MatchGroup( aTmpSel.GetStart() );
259 	if ( aMatchSel.HasRange() )
260 		SetSelection( aMatchSel );
261 
262 	return aMatchSel.HasRange() ? sal_True : sal_False;
263 }
264 
Search(const util::SearchOptions & rSearchOptions,sal_Bool bForward)265 sal_Bool ExtTextView::Search( const util::SearchOptions& rSearchOptions, sal_Bool bForward )
266 {
267 	sal_Bool bFound = sal_False;
268 	TextSelection aSel( GetSelection() );
269 	if ( ((ExtTextEngine*)GetTextEngine())->Search( aSel, rSearchOptions, bForward ) )
270 	{
271 		bFound = sal_True;
272 		// Erstmal den Anfang des Wortes als Selektion einstellen,
273 		// damit das ganze Wort in den sichtbaren Bereich kommt.
274 		SetSelection( aSel.GetStart() );
275 		ShowCursor( sal_True, sal_False );
276 	}
277 	else
278 	{
279 		aSel = GetSelection().GetEnd();
280 	}
281 
282 	SetSelection( aSel );
283 	ShowCursor();
284 
285 	return bFound;
286 }
287 
Replace(const util::SearchOptions & rSearchOptions,sal_Bool bAll,sal_Bool bForward)288 sal_uInt16 ExtTextView::Replace( const util::SearchOptions& rSearchOptions, sal_Bool bAll, sal_Bool bForward )
289 {
290 	sal_uInt16 nFound = 0;
291 
292 	if ( !bAll )
293 	{
294 		if ( GetSelection().HasRange() )
295 		{
296 			InsertText( rSearchOptions.replaceString );
297 			nFound = 1;
298 			Search( rSearchOptions, bForward );	// gleich zum naechsten
299 		}
300 		else
301 		{
302 			if( Search( rSearchOptions, bForward ) )
303 				nFound = 1;
304 		}
305 	}
306 	else
307 	{
308 		// Der Writer ersetzt alle, vom Anfang bis Ende...
309 
310 		ExtTextEngine* pTextEngine = (ExtTextEngine*)GetTextEngine();
311 
312 		// HideSelection();
313 		TextSelection aSel;
314 
315 		sal_Bool bSearchInSelection = (0 != (rSearchOptions.searchFlag & util::SearchFlags::REG_NOT_BEGINOFLINE) );
316 		if ( bSearchInSelection )
317 		{
318 			aSel = GetSelection();
319 			aSel.Justify();
320 		}
321 
322 		TextSelection aSearchSel( aSel );
323 
324 		sal_Bool bFound = pTextEngine->Search( aSel, rSearchOptions, sal_True );
325 		if ( bFound )
326 			pTextEngine->UndoActionStart();
327 		while ( bFound )
328 		{
329 			nFound++;
330 
331 			TextPaM aNewStart = pTextEngine->ImpInsertText( aSel, rSearchOptions.replaceString );
332 			aSel = aSearchSel;
333 			aSel.GetStart() = aNewStart;
334 			bFound = pTextEngine->Search( aSel, rSearchOptions, sal_True );
335 		}
336 		if ( nFound )
337 		{
338 			SetSelection( aSel.GetStart() );
339 			pTextEngine->FormatAndUpdate( this );
340 			pTextEngine->UndoActionEnd();
341 		}
342 	}
343 	return nFound;
344 }
345 
ImpIndentBlock(sal_Bool bRight)346 sal_Bool ExtTextView::ImpIndentBlock( sal_Bool bRight )
347 {
348 	sal_Bool bDone = sal_False;
349 
350 	TextSelection aSel = GetSelection();
351 	aSel.Justify();
352 
353 	HideSelection();
354 	GetTextEngine()->UndoActionStart();
355 
356 	sal_uLong nStartPara = aSel.GetStart().GetPara();
357 	sal_uLong nEndPara = aSel.GetEnd().GetPara();
358 	if ( aSel.HasRange() && !aSel.GetEnd().GetIndex() )
359 	{
360 		nEndPara--;	// den dann nicht einruecken...
361 	}
362 
363 	for ( sal_uLong nPara = nStartPara; nPara <= nEndPara; nPara++ )
364 	{
365 		if ( bRight )
366 		{
367 			// Tabs hinzufuegen
368 			GetTextEngine()->ImpInsertText( TextPaM( nPara, 0 ), '\t' );
369 			bDone = sal_True;
370 		}
371 		else
372 		{
373 			// Tabs/Blanks entfernen
374 			String aText = GetTextEngine()->GetText( nPara );
375 			if ( aText.Len() && (
376 					( aText.GetChar( 0 ) == '\t' ) ||
377 					( aText.GetChar( 0 ) == ' ' ) ) )
378 			{
379 				GetTextEngine()->ImpDeleteText( TextSelection( TextPaM( nPara, 0 ), TextPaM( nPara, 1 ) ) );
380 				bDone = sal_True;
381 			}
382 		}
383 	}
384 
385 	GetTextEngine()->UndoActionEnd();
386 
387 	sal_Bool bRange = aSel.HasRange();
388 	if ( bRight )
389 	{
390 		aSel.GetStart().GetIndex()++;
391 		if ( bRange && ( aSel.GetEnd().GetPara() == nEndPara ) )
392 			aSel.GetEnd().GetIndex()++;
393 	}
394 	else
395 	{
396 		if ( aSel.GetStart().GetIndex() )
397 			aSel.GetStart().GetIndex()--;
398 		if ( bRange && aSel.GetEnd().GetIndex() )
399 			aSel.GetEnd().GetIndex()--;
400 	}
401 
402 	ImpSetSelection( aSel );
403 	GetTextEngine()->FormatAndUpdate( this );
404 
405 	return bDone;
406 }
407 
IndentBlock()408 sal_Bool ExtTextView::IndentBlock()
409 {
410 	return ImpIndentBlock( sal_True );
411 }
412 
UnindentBlock()413 sal_Bool ExtTextView::UnindentBlock()
414 {
415 	return ImpIndentBlock( sal_False );
416 }
417 
418