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_vcl.hxx" 26 27 #include "vcl/quickselectionengine.hxx" 28 #include "vcl/event.hxx" 29 #include "vcl/timer.hxx" 30 #include "vcl/i18nhelp.hxx" 31 #include "vcl/svapp.hxx" 32 33 #include <boost/optional.hpp> 34 35 //........................................................................ 36 namespace vcl 37 { 38 //........................................................................ 39 40 //==================================================================== 41 //= QuickSelectionEngine_Data 42 //==================================================================== 43 struct QuickSelectionEngine_Data 44 { 45 ISearchableStringList& rEntryList; 46 String sCurrentSearchString; 47 ::boost::optional< sal_Unicode > aSingleSearchChar; 48 Timer aSearchTimeout; 49 QuickSelectionEngine_Datavcl::QuickSelectionEngine_Data50 QuickSelectionEngine_Data( ISearchableStringList& _entryList ) 51 :rEntryList( _entryList ) 52 ,sCurrentSearchString() 53 ,aSingleSearchChar() 54 ,aSearchTimeout() 55 { 56 aSearchTimeout.SetTimeout( 2500 ); 57 aSearchTimeout.SetTimeoutHdl( LINK( this, QuickSelectionEngine_Data, SearchStringTimeout ) ); 58 } 59 ~QuickSelectionEngine_Datavcl::QuickSelectionEngine_Data60 ~QuickSelectionEngine_Data() 61 { 62 aSearchTimeout.Stop(); 63 } 64 65 DECL_LINK( SearchStringTimeout, Timer* ); 66 }; 67 68 //-------------------------------------------------------------------- 69 namespace 70 { lcl_reset(QuickSelectionEngine_Data & _data)71 static void lcl_reset( QuickSelectionEngine_Data& _data ) 72 { 73 _data.sCurrentSearchString.Erase(); 74 _data.aSingleSearchChar.reset(); 75 _data.aSearchTimeout.Stop(); 76 } 77 } 78 79 //-------------------------------------------------------------------- 80 IMPL_LINK( QuickSelectionEngine_Data, SearchStringTimeout, Timer*, /*EMPTYARG*/ ) 81 { 82 lcl_reset( *this ); 83 return 1; 84 } 85 86 //-------------------------------------------------------------------- findMatchingEntry(const String & _searchString,QuickSelectionEngine_Data & _engineData)87 static StringEntryIdentifier findMatchingEntry( const String& _searchString, QuickSelectionEngine_Data& _engineData ) 88 { 89 const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetLocaleI18nHelper(); 90 // TODO: do we really need the Window's settings here? The original code used it ... 91 92 String sEntryText; 93 // get the "current + 1" entry 94 StringEntryIdentifier pSearchEntry = _engineData.rEntryList.CurrentEntry( sEntryText ); 95 if ( pSearchEntry ) 96 pSearchEntry = _engineData.rEntryList.NextEntry( pSearchEntry, sEntryText ); 97 // loop 'til we find another matching entry 98 StringEntryIdentifier pStartedWith = pSearchEntry; 99 while ( pSearchEntry ) 100 { 101 if ( rI18nHelper.MatchString( _searchString, sEntryText ) != 0 ) 102 break; 103 104 pSearchEntry = _engineData.rEntryList.NextEntry( pSearchEntry, sEntryText ); 105 if ( pSearchEntry == pStartedWith ) 106 pSearchEntry = NULL; 107 } 108 109 return pSearchEntry; 110 } 111 112 //==================================================================== 113 //= QuickSelectionEngine 114 //==================================================================== 115 //-------------------------------------------------------------------- QuickSelectionEngine(ISearchableStringList & _entryList)116 QuickSelectionEngine::QuickSelectionEngine( ISearchableStringList& _entryList ) 117 :m_pData( new QuickSelectionEngine_Data( _entryList ) ) 118 { 119 } 120 121 //-------------------------------------------------------------------- ~QuickSelectionEngine()122 QuickSelectionEngine::~QuickSelectionEngine() 123 { 124 } 125 126 //-------------------------------------------------------------------- HandleKeyEvent(const KeyEvent & _keyEvent)127 bool QuickSelectionEngine::HandleKeyEvent( const KeyEvent& _keyEvent ) 128 { 129 xub_Unicode c = _keyEvent.GetCharCode(); 130 131 if ( ( c >= 32 ) && ( c != 127 ) && !_keyEvent.GetKeyCode().IsMod2() ) 132 { 133 m_pData->sCurrentSearchString += c; 134 OSL_TRACE( "QuickSelectionEngine::HandleKeyEvent: searching for %s", ByteString( m_pData->sCurrentSearchString, RTL_TEXTENCODING_UTF8 ).GetBuffer() ); 135 136 if ( m_pData->sCurrentSearchString.Len() == 1 ) 137 { // first character in the search -> remmeber 138 m_pData->aSingleSearchChar.reset( c ); 139 } 140 else if ( m_pData->sCurrentSearchString.Len() > 1 ) 141 { 142 if ( !!m_pData->aSingleSearchChar && ( *m_pData->aSingleSearchChar != c ) ) 143 // we already have a "single char", but the current one is different -> reset 144 m_pData->aSingleSearchChar.reset(); 145 } 146 147 XubString aSearchTemp( m_pData->sCurrentSearchString ); 148 149 StringEntryIdentifier pMatchingEntry = findMatchingEntry( aSearchTemp, *m_pData ); 150 OSL_TRACE( "QuickSelectionEngine::HandleKeyEvent: found %p", pMatchingEntry ); 151 if ( !pMatchingEntry && ( aSearchTemp.Len() > 1 ) && !!m_pData->aSingleSearchChar ) 152 { 153 // if there's only one letter in the search string, use a different search mode 154 aSearchTemp = *m_pData->aSingleSearchChar; 155 pMatchingEntry = findMatchingEntry( aSearchTemp, *m_pData ); 156 } 157 158 if ( pMatchingEntry ) 159 { 160 m_pData->rEntryList.SelectEntry( pMatchingEntry ); 161 m_pData->aSearchTimeout.Start(); 162 } 163 else 164 { 165 lcl_reset( *m_pData ); 166 } 167 168 return true; 169 } 170 return false; 171 } 172 173 //-------------------------------------------------------------------- Reset()174 void QuickSelectionEngine::Reset() 175 { 176 lcl_reset( *m_pData ); 177 } 178 179 //........................................................................ 180 } // namespace vcl 181 //........................................................................ 182