1*9f62ea84SAndrew Rist /************************************************************** 2*9f62ea84SAndrew Rist * 3*9f62ea84SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 4*9f62ea84SAndrew Rist * or more contributor license agreements. See the NOTICE file 5*9f62ea84SAndrew Rist * distributed with this work for additional information 6*9f62ea84SAndrew Rist * regarding copyright ownership. The ASF licenses this file 7*9f62ea84SAndrew Rist * to you under the Apache License, Version 2.0 (the 8*9f62ea84SAndrew Rist * "License"); you may not use this file except in compliance 9*9f62ea84SAndrew Rist * with the License. You may obtain a copy of the License at 10*9f62ea84SAndrew Rist * 11*9f62ea84SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12*9f62ea84SAndrew Rist * 13*9f62ea84SAndrew Rist * Unless required by applicable law or agreed to in writing, 14*9f62ea84SAndrew Rist * software distributed under the License is distributed on an 15*9f62ea84SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*9f62ea84SAndrew Rist * KIND, either express or implied. See the License for the 17*9f62ea84SAndrew Rist * specific language governing permissions and limitations 18*9f62ea84SAndrew Rist * under the License. 19*9f62ea84SAndrew Rist * 20*9f62ea84SAndrew Rist *************************************************************/ 21*9f62ea84SAndrew Rist 22*9f62ea84SAndrew Rist 23cdf0e10cSrcweir 24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 25cdf0e10cSrcweir #include "precompiled_vcl.hxx" 26cdf0e10cSrcweir 27cdf0e10cSrcweir #include "vcl/quickselectionengine.hxx" 28cdf0e10cSrcweir #include "vcl/event.hxx" 29cdf0e10cSrcweir #include "vcl/timer.hxx" 30cdf0e10cSrcweir #include "vcl/i18nhelp.hxx" 31cdf0e10cSrcweir #include "vcl/svapp.hxx" 32cdf0e10cSrcweir 33cdf0e10cSrcweir #include <boost/optional.hpp> 34cdf0e10cSrcweir 35cdf0e10cSrcweir //........................................................................ 36cdf0e10cSrcweir namespace vcl 37cdf0e10cSrcweir { 38cdf0e10cSrcweir //........................................................................ 39cdf0e10cSrcweir 40cdf0e10cSrcweir //==================================================================== 41cdf0e10cSrcweir //= QuickSelectionEngine_Data 42cdf0e10cSrcweir //==================================================================== 43cdf0e10cSrcweir struct QuickSelectionEngine_Data 44cdf0e10cSrcweir { 45cdf0e10cSrcweir ISearchableStringList& rEntryList; 46cdf0e10cSrcweir String sCurrentSearchString; 47cdf0e10cSrcweir ::boost::optional< sal_Unicode > aSingleSearchChar; 48cdf0e10cSrcweir Timer aSearchTimeout; 49cdf0e10cSrcweir QuickSelectionEngine_Datavcl::QuickSelectionEngine_Data50cdf0e10cSrcweir QuickSelectionEngine_Data( ISearchableStringList& _entryList ) 51cdf0e10cSrcweir :rEntryList( _entryList ) 52cdf0e10cSrcweir ,sCurrentSearchString() 53cdf0e10cSrcweir ,aSingleSearchChar() 54cdf0e10cSrcweir ,aSearchTimeout() 55cdf0e10cSrcweir { 56cdf0e10cSrcweir aSearchTimeout.SetTimeout( 2500 ); 57cdf0e10cSrcweir aSearchTimeout.SetTimeoutHdl( LINK( this, QuickSelectionEngine_Data, SearchStringTimeout ) ); 58cdf0e10cSrcweir } 59cdf0e10cSrcweir ~QuickSelectionEngine_Datavcl::QuickSelectionEngine_Data60cdf0e10cSrcweir ~QuickSelectionEngine_Data() 61cdf0e10cSrcweir { 62cdf0e10cSrcweir aSearchTimeout.Stop(); 63cdf0e10cSrcweir } 64cdf0e10cSrcweir 65cdf0e10cSrcweir DECL_LINK( SearchStringTimeout, Timer* ); 66cdf0e10cSrcweir }; 67cdf0e10cSrcweir 68cdf0e10cSrcweir //-------------------------------------------------------------------- 69cdf0e10cSrcweir namespace 70cdf0e10cSrcweir { lcl_reset(QuickSelectionEngine_Data & _data)71cdf0e10cSrcweir static void lcl_reset( QuickSelectionEngine_Data& _data ) 72cdf0e10cSrcweir { 73cdf0e10cSrcweir _data.sCurrentSearchString.Erase(); 74cdf0e10cSrcweir _data.aSingleSearchChar.reset(); 75cdf0e10cSrcweir _data.aSearchTimeout.Stop(); 76cdf0e10cSrcweir } 77cdf0e10cSrcweir } 78cdf0e10cSrcweir 79cdf0e10cSrcweir //-------------------------------------------------------------------- 80cdf0e10cSrcweir IMPL_LINK( QuickSelectionEngine_Data, SearchStringTimeout, Timer*, /*EMPTYARG*/ ) 81cdf0e10cSrcweir { 82cdf0e10cSrcweir lcl_reset( *this ); 83cdf0e10cSrcweir return 1; 84cdf0e10cSrcweir } 85cdf0e10cSrcweir 86cdf0e10cSrcweir //-------------------------------------------------------------------- findMatchingEntry(const String & _searchString,QuickSelectionEngine_Data & _engineData)87cdf0e10cSrcweir static StringEntryIdentifier findMatchingEntry( const String& _searchString, QuickSelectionEngine_Data& _engineData ) 88cdf0e10cSrcweir { 89cdf0e10cSrcweir const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetLocaleI18nHelper(); 90cdf0e10cSrcweir // TODO: do we really need the Window's settings here? The original code used it ... 91cdf0e10cSrcweir 92cdf0e10cSrcweir String sEntryText; 93cdf0e10cSrcweir // get the "current + 1" entry 94cdf0e10cSrcweir StringEntryIdentifier pSearchEntry = _engineData.rEntryList.CurrentEntry( sEntryText ); 95cdf0e10cSrcweir if ( pSearchEntry ) 96cdf0e10cSrcweir pSearchEntry = _engineData.rEntryList.NextEntry( pSearchEntry, sEntryText ); 97cdf0e10cSrcweir // loop 'til we find another matching entry 98cdf0e10cSrcweir StringEntryIdentifier pStartedWith = pSearchEntry; 99cdf0e10cSrcweir while ( pSearchEntry ) 100cdf0e10cSrcweir { 101cdf0e10cSrcweir if ( rI18nHelper.MatchString( _searchString, sEntryText ) != 0 ) 102cdf0e10cSrcweir break; 103cdf0e10cSrcweir 104cdf0e10cSrcweir pSearchEntry = _engineData.rEntryList.NextEntry( pSearchEntry, sEntryText ); 105cdf0e10cSrcweir if ( pSearchEntry == pStartedWith ) 106cdf0e10cSrcweir pSearchEntry = NULL; 107cdf0e10cSrcweir } 108cdf0e10cSrcweir 109cdf0e10cSrcweir return pSearchEntry; 110cdf0e10cSrcweir } 111cdf0e10cSrcweir 112cdf0e10cSrcweir //==================================================================== 113cdf0e10cSrcweir //= QuickSelectionEngine 114cdf0e10cSrcweir //==================================================================== 115cdf0e10cSrcweir //-------------------------------------------------------------------- QuickSelectionEngine(ISearchableStringList & _entryList)116cdf0e10cSrcweir QuickSelectionEngine::QuickSelectionEngine( ISearchableStringList& _entryList ) 117cdf0e10cSrcweir :m_pData( new QuickSelectionEngine_Data( _entryList ) ) 118cdf0e10cSrcweir { 119cdf0e10cSrcweir } 120cdf0e10cSrcweir 121cdf0e10cSrcweir //-------------------------------------------------------------------- ~QuickSelectionEngine()122cdf0e10cSrcweir QuickSelectionEngine::~QuickSelectionEngine() 123cdf0e10cSrcweir { 124cdf0e10cSrcweir } 125cdf0e10cSrcweir 126cdf0e10cSrcweir //-------------------------------------------------------------------- HandleKeyEvent(const KeyEvent & _keyEvent)127cdf0e10cSrcweir bool QuickSelectionEngine::HandleKeyEvent( const KeyEvent& _keyEvent ) 128cdf0e10cSrcweir { 129cdf0e10cSrcweir xub_Unicode c = _keyEvent.GetCharCode(); 130cdf0e10cSrcweir 131cdf0e10cSrcweir if ( ( c >= 32 ) && ( c != 127 ) && !_keyEvent.GetKeyCode().IsMod2() ) 132cdf0e10cSrcweir { 133cdf0e10cSrcweir m_pData->sCurrentSearchString += c; 134cdf0e10cSrcweir OSL_TRACE( "QuickSelectionEngine::HandleKeyEvent: searching for %s", ByteString( m_pData->sCurrentSearchString, RTL_TEXTENCODING_UTF8 ).GetBuffer() ); 135cdf0e10cSrcweir 136cdf0e10cSrcweir if ( m_pData->sCurrentSearchString.Len() == 1 ) 137cdf0e10cSrcweir { // first character in the search -> remmeber 138cdf0e10cSrcweir m_pData->aSingleSearchChar.reset( c ); 139cdf0e10cSrcweir } 140cdf0e10cSrcweir else if ( m_pData->sCurrentSearchString.Len() > 1 ) 141cdf0e10cSrcweir { 142cdf0e10cSrcweir if ( !!m_pData->aSingleSearchChar && ( *m_pData->aSingleSearchChar != c ) ) 143cdf0e10cSrcweir // we already have a "single char", but the current one is different -> reset 144cdf0e10cSrcweir m_pData->aSingleSearchChar.reset(); 145cdf0e10cSrcweir } 146cdf0e10cSrcweir 147cdf0e10cSrcweir XubString aSearchTemp( m_pData->sCurrentSearchString ); 148cdf0e10cSrcweir 149cdf0e10cSrcweir StringEntryIdentifier pMatchingEntry = findMatchingEntry( aSearchTemp, *m_pData ); 150cdf0e10cSrcweir OSL_TRACE( "QuickSelectionEngine::HandleKeyEvent: found %p", pMatchingEntry ); 151cdf0e10cSrcweir if ( !pMatchingEntry && ( aSearchTemp.Len() > 1 ) && !!m_pData->aSingleSearchChar ) 152cdf0e10cSrcweir { 153cdf0e10cSrcweir // if there's only one letter in the search string, use a different search mode 154cdf0e10cSrcweir aSearchTemp = *m_pData->aSingleSearchChar; 155cdf0e10cSrcweir pMatchingEntry = findMatchingEntry( aSearchTemp, *m_pData ); 156cdf0e10cSrcweir } 157cdf0e10cSrcweir 158cdf0e10cSrcweir if ( pMatchingEntry ) 159cdf0e10cSrcweir { 160cdf0e10cSrcweir m_pData->rEntryList.SelectEntry( pMatchingEntry ); 161cdf0e10cSrcweir m_pData->aSearchTimeout.Start(); 162cdf0e10cSrcweir } 163cdf0e10cSrcweir else 164cdf0e10cSrcweir { 165cdf0e10cSrcweir lcl_reset( *m_pData ); 166cdf0e10cSrcweir } 167cdf0e10cSrcweir 168cdf0e10cSrcweir return true; 169cdf0e10cSrcweir } 170cdf0e10cSrcweir return false; 171cdf0e10cSrcweir } 172cdf0e10cSrcweir 173cdf0e10cSrcweir //-------------------------------------------------------------------- Reset()174cdf0e10cSrcweir void QuickSelectionEngine::Reset() 175cdf0e10cSrcweir { 176cdf0e10cSrcweir lcl_reset( *m_pData ); 177cdf0e10cSrcweir } 178cdf0e10cSrcweir 179cdf0e10cSrcweir //........................................................................ 180cdf0e10cSrcweir } // namespace vcl 181cdf0e10cSrcweir //........................................................................ 182