1*cdf0e10cSrcweir /*************************************************************************
2*cdf0e10cSrcweir * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3*cdf0e10cSrcweir *
4*cdf0e10cSrcweir * Copyright 2009 by Sun Microsystems, Inc.
5*cdf0e10cSrcweir *
6*cdf0e10cSrcweir * OpenOffice.org - a multi-platform office productivity suite
7*cdf0e10cSrcweir *
8*cdf0e10cSrcweir * This file is part of OpenOffice.org.
9*cdf0e10cSrcweir *
10*cdf0e10cSrcweir * OpenOffice.org is free software: you can redistribute it and/or modify
11*cdf0e10cSrcweir * it under the terms of the GNU Lesser General Public License version 3
12*cdf0e10cSrcweir * only, as published by the Free Software Foundation.
13*cdf0e10cSrcweir *
14*cdf0e10cSrcweir * OpenOffice.org is distributed in the hope that it will be useful,
15*cdf0e10cSrcweir * but WITHOUT ANY WARRANTY; without even the implied warranty of
16*cdf0e10cSrcweir * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17*cdf0e10cSrcweir * GNU Lesser General Public License version 3 for more details
18*cdf0e10cSrcweir * (a copy is included in the LICENSE file that accompanied this code).
19*cdf0e10cSrcweir *
20*cdf0e10cSrcweir * You should have received a copy of the GNU Lesser General Public License
21*cdf0e10cSrcweir * version 3 along with OpenOffice.org.  If not, see
22*cdf0e10cSrcweir * <http://www.openoffice.org/license.html>
23*cdf0e10cSrcweir * for a copy of the LGPLv3 License.
24*cdf0e10cSrcweir ************************************************************************/
25*cdf0e10cSrcweir 
26*cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
27*cdf0e10cSrcweir #include "precompiled_vcl.hxx"
28*cdf0e10cSrcweir 
29*cdf0e10cSrcweir #include "vcl/quickselectionengine.hxx"
30*cdf0e10cSrcweir #include "vcl/event.hxx"
31*cdf0e10cSrcweir #include "vcl/timer.hxx"
32*cdf0e10cSrcweir #include "vcl/i18nhelp.hxx"
33*cdf0e10cSrcweir #include "vcl/svapp.hxx"
34*cdf0e10cSrcweir 
35*cdf0e10cSrcweir #include <boost/optional.hpp>
36*cdf0e10cSrcweir 
37*cdf0e10cSrcweir //........................................................................
38*cdf0e10cSrcweir namespace vcl
39*cdf0e10cSrcweir {
40*cdf0e10cSrcweir //........................................................................
41*cdf0e10cSrcweir 
42*cdf0e10cSrcweir 	//====================================================================
43*cdf0e10cSrcweir 	//= QuickSelectionEngine_Data
44*cdf0e10cSrcweir 	//====================================================================
45*cdf0e10cSrcweir     struct QuickSelectionEngine_Data
46*cdf0e10cSrcweir     {
47*cdf0e10cSrcweir         ISearchableStringList&              rEntryList;
48*cdf0e10cSrcweir         String                              sCurrentSearchString;
49*cdf0e10cSrcweir         ::boost::optional< sal_Unicode >    aSingleSearchChar;
50*cdf0e10cSrcweir         Timer                               aSearchTimeout;
51*cdf0e10cSrcweir 
52*cdf0e10cSrcweir         QuickSelectionEngine_Data( ISearchableStringList& _entryList )
53*cdf0e10cSrcweir             :rEntryList( _entryList )
54*cdf0e10cSrcweir             ,sCurrentSearchString()
55*cdf0e10cSrcweir             ,aSingleSearchChar()
56*cdf0e10cSrcweir             ,aSearchTimeout()
57*cdf0e10cSrcweir         {
58*cdf0e10cSrcweir 	        aSearchTimeout.SetTimeout( 2500 );
59*cdf0e10cSrcweir 	        aSearchTimeout.SetTimeoutHdl( LINK( this, QuickSelectionEngine_Data, SearchStringTimeout ) );
60*cdf0e10cSrcweir         }
61*cdf0e10cSrcweir 
62*cdf0e10cSrcweir         ~QuickSelectionEngine_Data()
63*cdf0e10cSrcweir         {
64*cdf0e10cSrcweir 	        aSearchTimeout.Stop();
65*cdf0e10cSrcweir         }
66*cdf0e10cSrcweir 
67*cdf0e10cSrcweir 	    DECL_LINK( SearchStringTimeout, Timer* );
68*cdf0e10cSrcweir     };
69*cdf0e10cSrcweir 
70*cdf0e10cSrcweir     //--------------------------------------------------------------------
71*cdf0e10cSrcweir     namespace
72*cdf0e10cSrcweir     {
73*cdf0e10cSrcweir         static void lcl_reset( QuickSelectionEngine_Data& _data )
74*cdf0e10cSrcweir         {
75*cdf0e10cSrcweir             _data.sCurrentSearchString.Erase();
76*cdf0e10cSrcweir             _data.aSingleSearchChar.reset();
77*cdf0e10cSrcweir             _data.aSearchTimeout.Stop();
78*cdf0e10cSrcweir         }
79*cdf0e10cSrcweir     }
80*cdf0e10cSrcweir 
81*cdf0e10cSrcweir 	//--------------------------------------------------------------------
82*cdf0e10cSrcweir     IMPL_LINK( QuickSelectionEngine_Data, SearchStringTimeout, Timer*, /*EMPTYARG*/ )
83*cdf0e10cSrcweir     {
84*cdf0e10cSrcweir         lcl_reset( *this );
85*cdf0e10cSrcweir 	    return 1;
86*cdf0e10cSrcweir     }
87*cdf0e10cSrcweir 
88*cdf0e10cSrcweir 	//--------------------------------------------------------------------
89*cdf0e10cSrcweir     static StringEntryIdentifier findMatchingEntry( const String& _searchString, QuickSelectionEngine_Data& _engineData )
90*cdf0e10cSrcweir     {
91*cdf0e10cSrcweir         const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetLocaleI18nHelper();
92*cdf0e10cSrcweir             // TODO: do we really need the Window's settings here? The original code used it ...
93*cdf0e10cSrcweir 
94*cdf0e10cSrcweir         String sEntryText;
95*cdf0e10cSrcweir         // get the "current + 1" entry
96*cdf0e10cSrcweir         StringEntryIdentifier pSearchEntry = _engineData.rEntryList.CurrentEntry( sEntryText );
97*cdf0e10cSrcweir         if ( pSearchEntry )
98*cdf0e10cSrcweir             pSearchEntry = _engineData.rEntryList.NextEntry( pSearchEntry, sEntryText );
99*cdf0e10cSrcweir         // loop 'til we find another matching entry
100*cdf0e10cSrcweir         StringEntryIdentifier pStartedWith = pSearchEntry;
101*cdf0e10cSrcweir         while ( pSearchEntry )
102*cdf0e10cSrcweir         {
103*cdf0e10cSrcweir             if ( rI18nHelper.MatchString( _searchString, sEntryText ) != 0 )
104*cdf0e10cSrcweir                 break;
105*cdf0e10cSrcweir 
106*cdf0e10cSrcweir             pSearchEntry = _engineData.rEntryList.NextEntry( pSearchEntry, sEntryText );
107*cdf0e10cSrcweir             if ( pSearchEntry == pStartedWith )
108*cdf0e10cSrcweir                 pSearchEntry = NULL;
109*cdf0e10cSrcweir         }
110*cdf0e10cSrcweir 
111*cdf0e10cSrcweir         return pSearchEntry;
112*cdf0e10cSrcweir     }
113*cdf0e10cSrcweir 
114*cdf0e10cSrcweir     //====================================================================
115*cdf0e10cSrcweir 	//= QuickSelectionEngine
116*cdf0e10cSrcweir 	//====================================================================
117*cdf0e10cSrcweir 	//--------------------------------------------------------------------
118*cdf0e10cSrcweir     QuickSelectionEngine::QuickSelectionEngine( ISearchableStringList& _entryList )
119*cdf0e10cSrcweir         :m_pData( new QuickSelectionEngine_Data( _entryList ) )
120*cdf0e10cSrcweir     {
121*cdf0e10cSrcweir     }
122*cdf0e10cSrcweir 
123*cdf0e10cSrcweir 	//--------------------------------------------------------------------
124*cdf0e10cSrcweir     QuickSelectionEngine::~QuickSelectionEngine()
125*cdf0e10cSrcweir     {
126*cdf0e10cSrcweir     }
127*cdf0e10cSrcweir 
128*cdf0e10cSrcweir     //--------------------------------------------------------------------
129*cdf0e10cSrcweir     bool QuickSelectionEngine::HandleKeyEvent( const KeyEvent& _keyEvent )
130*cdf0e10cSrcweir     {
131*cdf0e10cSrcweir         xub_Unicode c = _keyEvent.GetCharCode();
132*cdf0e10cSrcweir 
133*cdf0e10cSrcweir         if ( ( c >= 32 ) && ( c != 127 ) && !_keyEvent.GetKeyCode().IsMod2() )
134*cdf0e10cSrcweir         {
135*cdf0e10cSrcweir             m_pData->sCurrentSearchString += c;
136*cdf0e10cSrcweir             OSL_TRACE( "QuickSelectionEngine::HandleKeyEvent: searching for %s", ByteString( m_pData->sCurrentSearchString, RTL_TEXTENCODING_UTF8 ).GetBuffer() );
137*cdf0e10cSrcweir 
138*cdf0e10cSrcweir             if ( m_pData->sCurrentSearchString.Len() == 1 )
139*cdf0e10cSrcweir             {   // first character in the search -> remmeber
140*cdf0e10cSrcweir                 m_pData->aSingleSearchChar.reset( c );
141*cdf0e10cSrcweir             }
142*cdf0e10cSrcweir             else if ( m_pData->sCurrentSearchString.Len() > 1 )
143*cdf0e10cSrcweir             {
144*cdf0e10cSrcweir                 if ( !!m_pData->aSingleSearchChar && ( *m_pData->aSingleSearchChar != c ) )
145*cdf0e10cSrcweir                     // we already have a "single char", but the current one is different -> reset
146*cdf0e10cSrcweir                     m_pData->aSingleSearchChar.reset();
147*cdf0e10cSrcweir             }
148*cdf0e10cSrcweir 
149*cdf0e10cSrcweir             XubString aSearchTemp( m_pData->sCurrentSearchString );
150*cdf0e10cSrcweir 
151*cdf0e10cSrcweir             StringEntryIdentifier pMatchingEntry = findMatchingEntry( aSearchTemp, *m_pData );
152*cdf0e10cSrcweir             OSL_TRACE( "QuickSelectionEngine::HandleKeyEvent: found %p", pMatchingEntry );
153*cdf0e10cSrcweir             if ( !pMatchingEntry && ( aSearchTemp.Len() > 1 ) && !!m_pData->aSingleSearchChar )
154*cdf0e10cSrcweir             {
155*cdf0e10cSrcweir                 // if there's only one letter in the search string, use a different search mode
156*cdf0e10cSrcweir                 aSearchTemp = *m_pData->aSingleSearchChar;
157*cdf0e10cSrcweir                 pMatchingEntry = findMatchingEntry( aSearchTemp, *m_pData );
158*cdf0e10cSrcweir             }
159*cdf0e10cSrcweir 
160*cdf0e10cSrcweir             if ( pMatchingEntry )
161*cdf0e10cSrcweir             {
162*cdf0e10cSrcweir                 m_pData->rEntryList.SelectEntry( pMatchingEntry );
163*cdf0e10cSrcweir                 m_pData->aSearchTimeout.Start();
164*cdf0e10cSrcweir             }
165*cdf0e10cSrcweir             else
166*cdf0e10cSrcweir             {
167*cdf0e10cSrcweir                 lcl_reset( *m_pData );
168*cdf0e10cSrcweir             }
169*cdf0e10cSrcweir 
170*cdf0e10cSrcweir             return true;
171*cdf0e10cSrcweir         }
172*cdf0e10cSrcweir         return false;
173*cdf0e10cSrcweir     }
174*cdf0e10cSrcweir 
175*cdf0e10cSrcweir     //--------------------------------------------------------------------
176*cdf0e10cSrcweir     void QuickSelectionEngine::Reset()
177*cdf0e10cSrcweir     {
178*cdf0e10cSrcweir         lcl_reset( *m_pData );
179*cdf0e10cSrcweir     }
180*cdf0e10cSrcweir 
181*cdf0e10cSrcweir //........................................................................
182*cdf0e10cSrcweir } // namespace vcl
183*cdf0e10cSrcweir //........................................................................
184