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