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