1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <i18nutil/searchopt.hxx>
21 #include <i18nlangtag/languagetag.hxx>
22 #include <vcl/textdata.hxx>
23 #include <vcl/xtextedt.hxx>
24 #include <vcl/svapp.hxx>
25 #include <vcl/settings.hxx>
26 #include <unotools/textsearch.hxx>
27 #include <com/sun/star/util/SearchFlags.hpp>
28 
29 using namespace ::com::sun::star;
30 
31 const std::wstring gaGroupChars = L"(){}[]";
32 
ExtTextEngine()33 ExtTextEngine::ExtTextEngine()
34 {
35 }
36 
~ExtTextEngine()37 ExtTextEngine::~ExtTextEngine()
38 {
39 }
40 
MatchGroup(const TextPaM & rCursor) const41 TextSelection ExtTextEngine::MatchGroup( const TextPaM& rCursor ) const
42 {
43     TextSelection aSel( rCursor );
44     const sal_Int32 nPos = rCursor.GetIndex();
45     sal_uInt32 nPara = rCursor.GetPara();
46     const sal_uInt32 nParas = GetParagraphCount();
47     if ( ( nPara < nParas ) && ( nPos < GetTextLen( nPara ) ) )
48     {
49         size_t nMatchIndex = gaGroupChars.find( GetText( rCursor.GetPara() )[ nPos ] );
50         if ( nMatchIndex != std::wstring::npos )
51         {
52             if ( ( nMatchIndex % 2 ) == 0 )
53             {
54                 // search forwards
55                 sal_Unicode nSC = gaGroupChars[ nMatchIndex ];
56                 sal_Unicode nEC = gaGroupChars[ nMatchIndex+1 ];
57 
58                 sal_Int32 nCur = nPos+1;
59                 sal_uInt16 nLevel = 1;
60                 while ( nLevel && ( nPara < nParas ) )
61                 {
62                     OUString aStr = GetText( nPara );
63                     while ( nCur < aStr.getLength() )
64                     {
65                         if ( aStr[nCur] == nSC )
66                             nLevel++;
67                         else if ( aStr[nCur] == nEC )
68                         {
69                             nLevel--;
70                             if ( !nLevel )
71                                 break;  // while nCur...
72                         }
73                         nCur++;
74                     }
75 
76                     if ( nLevel )
77                     {
78                         nPara++;
79                         nCur = 0;
80                     }
81                 }
82                 if ( nLevel == 0 )  // found
83                 {
84                     aSel.GetStart() = rCursor;
85                     aSel.GetEnd() = TextPaM( nPara, nCur+1 );
86                 }
87             }
88             else
89             {
90                 // search backwards
91                 sal_Unicode nEC = gaGroupChars[ nMatchIndex ];
92                 sal_Unicode nSC = gaGroupChars[ nMatchIndex-1 ];
93 
94                 sal_Int32 nCur = rCursor.GetIndex()-1;
95                 sal_uInt16 nLevel = 1;
96                 while ( nLevel )
97                 {
98                     if ( GetTextLen( nPara ) )
99                     {
100                         OUString aStr = GetText( nPara );
101                         while ( nCur )
102                         {
103                             if ( aStr[nCur] == nSC )
104                             {
105                                 nLevel--;
106                                 if ( !nLevel )
107                                     break;  // while nCur...
108                             }
109                             else if ( aStr[nCur] == nEC )
110                                 nLevel++;
111 
112                             nCur--;
113                         }
114                     }
115 
116                     if ( nLevel )
117                     {
118                         if ( nPara )
119                         {
120                             nPara--;
121                             nCur = GetTextLen( nPara )-1;   // no matter if negative, as if Len()
122                         }
123                         else
124                             break;
125                     }
126                 }
127 
128                 if ( nLevel == 0 )  // found
129                 {
130                     aSel.GetStart() = rCursor;
131                     ++aSel.GetStart().GetIndex();   // behind the char
132                     aSel.GetEnd() = TextPaM( nPara, nCur );
133                 }
134             }
135         }
136     }
137     return aSel;
138 }
139 
Search(TextSelection & rSel,const i18nutil::SearchOptions & rSearchOptions,bool bForward)140 bool ExtTextEngine::Search( TextSelection& rSel, const i18nutil::SearchOptions& rSearchOptions, bool bForward )
141 {
142     TextSelection aSel( rSel );
143     aSel.Justify();
144 
145     bool bSearchInSelection = (0 != (rSearchOptions.searchFlag & util::SearchFlags::REG_NOT_BEGINOFLINE) );
146 
147     TextPaM aStartPaM( aSel.GetEnd() );
148     if ( aSel.HasRange() && ( ( bSearchInSelection && bForward ) || ( !bSearchInSelection && !bForward ) ) )
149     {
150         aStartPaM = aSel.GetStart();
151     }
152 
153     bool bFound = false;
154     sal_uInt32 nEndNode;
155 
156     if ( bSearchInSelection )
157         nEndNode = bForward ? aSel.GetEnd().GetPara() : aSel.GetStart().GetPara();
158     else
159         nEndNode = bForward ? (GetParagraphCount()-1) : 0;
160 
161     const sal_uInt32 nStartNode = aStartPaM.GetPara();
162 
163     i18nutil::SearchOptions aOptions( rSearchOptions );
164     aOptions.Locale = Application::GetSettings().GetLanguageTag().getLocale();
165     utl::TextSearch aSearcher( utl::TextSearch::UpgradeToSearchOptions2(aOptions) );
166 
167     // iterate over the paragraphs
168     for ( sal_uInt32 nNode = nStartNode;
169             bForward ?  ( nNode <= nEndNode) : ( nNode >= nEndNode );
170             bForward ? nNode++ : nNode-- )
171     {
172         OUString aText = GetText( nNode );
173         sal_Int32 nStartPos = 0;
174         sal_Int32 nEndPos = aText.getLength();
175         if ( nNode == nStartNode )
176         {
177             if ( bForward )
178                 nStartPos = aStartPaM.GetIndex();
179             else
180                 nEndPos = aStartPaM.GetIndex();
181         }
182         if ( ( nNode == nEndNode ) && bSearchInSelection )
183         {
184             if ( bForward )
185                 nEndPos = aSel.GetEnd().GetIndex();
186             else
187                 nStartPos = aSel.GetStart().GetIndex();
188         }
189 
190         if ( bForward )
191             bFound = aSearcher.SearchForward( aText, &nStartPos, &nEndPos );
192         else
193             bFound = aSearcher.SearchBackward( aText, &nEndPos, &nStartPos );
194 
195         if ( bFound )
196         {
197             rSel.GetStart().GetPara() = nNode;
198             rSel.GetStart().GetIndex() = nStartPos;
199             rSel.GetEnd().GetPara() = nNode;
200             rSel.GetEnd().GetIndex() = nEndPos;
201             // Select over the paragraph?
202             // FIXME  This should be max long...
203             if( nEndPos == -1)
204             {
205                 if ( (rSel.GetEnd().GetPara()+1) < GetParagraphCount() )
206                 {
207                     rSel.GetEnd().GetPara()++;
208                     rSel.GetEnd().GetIndex() = 0;
209                 }
210                 else
211                 {
212                     rSel.GetEnd().GetIndex() = nStartPos;
213                     bFound = false;
214                 }
215             }
216 
217             break;
218         }
219 
220         if ( !bForward && !nNode )  // if searching backwards, if nEndNode == 0:
221             break;
222     }
223 
224     return bFound;
225 }
226 
227 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
228