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