1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_editeng.hxx"
30 #include <editeng/hangulhanja.hxx>
31 #include <vcl/msgbox.hxx>
32 #include <vcl/button.hxx>
33 #include <unotools/lingucfg.hxx>
34 #include <unotools/linguprops.hxx>
35 
36 #include <set>
37 #include <map>
38 #include <com/sun/star/uno/Sequence.hxx>
39 #include <com/sun/star/i18n/XBreakIterator.hpp>
40 #include <com/sun/star/i18n/ScriptType.hpp>
41 #include <com/sun/star/i18n/UnicodeScript.hpp>
42 #include <com/sun/star/i18n/XTextConversion.hpp>
43 #include <com/sun/star/i18n/XExtendedTextConversion.hpp>
44 #include <com/sun/star/i18n/TextConversionType.hpp>
45 #include <com/sun/star/i18n/TextConversionOption.hpp>
46 #include <com/sun/star/i18n/WordType.hpp>
47 #include <vcl/stdtext.hxx>
48 #include <unotools/charclass.hxx>
49 
50 #include <editeng/edtdlg.hxx>
51 #include <editeng/editrids.hrc>
52 #include <editeng/unolingu.hxx>
53 
54 #define HHC HangulHanjaConversion
55 
56 //.............................................................................
57 namespace editeng
58 {
59 //.............................................................................
60 
61 	using namespace ::com::sun::star::uno;
62 	using namespace ::com::sun::star::i18n;
63     using namespace ::com::sun::star::i18n::TextConversionOption;
64     using namespace ::com::sun::star::i18n::TextConversionType;
65 	using namespace ::com::sun::star::lang;
66 /*
67 	using HangulHanjaConversion::ReplacementAction;
68 	using HangulHanjaConversion::eExchange;
69 	using HangulHanjaConversion::eReplacementBracketed;
70 	using HangulHanjaConversion::eOriginalBracketed;
71 	using HangulHanjaConversion::eReplacementAbove;
72 	using HangulHanjaConversion::eOriginalAbove;
73 	using HangulHanjaConversion::eReplacementBelow;
74 	using HangulHanjaConversion::eOriginalBelow;
75 
76 	using HangulHanjaConversion::eHangulToHanja;
77 	using HangulHanjaConversion::eHanjaToHangul;
78 
79 	using HangulHanjaConversion::eSimpleConversion;
80 	using HangulHanjaConversion::eHangulBracketed;
81 	using HangulHanjaConversion::eHanjaBracketed;
82 	using HangulHanjaConversion::eRubyHanjaAbove;
83 	using HangulHanjaConversion::eRubyHanjaBelow;
84 	using HangulHanjaConversion::eRubyHangulAbove;
85 	using HangulHanjaConversion::eRubyHangulBelow;
86 
87 	using ::com::sun::star::i18n::TextConversionType::TO_HANJA;
88 	using ::com::sun::star::i18n::TextConversionType::TO_HANGUL;
89 	using ::com::sun::star::i18n::TextConversionOption::CHARACTER_BY_CHARACTER;
90 	using ::com::sun::star::i18n::TextConversionOption::NONE;
91 */
92 	//=========================================================================
93 	//= HangulHanjaConversion_Impl
94 	//=========================================================================
95     //using HangulHanjaConversion::ConversionFormat;
96 
97 	class HangulHanjaConversion_Impl
98 	{
99 	private:
100 		typedef	::std::set< ::rtl::OUString, ::std::less< ::rtl::OUString > >					StringBag;
101 		typedef ::std::map< ::rtl::OUString, ::rtl::OUString, ::std::less< ::rtl::OUString > >	StringMap;
102 
103 	private:
104         StringBag               m_sIgnoreList;
105         StringMap               m_aChangeList;
106         static StringMap        m_aRecentlyUsedList;
107 
108 		// general
109 		AbstractHangulHanjaConversionDialog* //CHINA001 HangulHanjaConversionDialog*
110 								m_pConversionDialog;	// the dialog to display for user interaction
111 		Window*					m_pUIParent;			// the parent window for any UI we raise
112 		Reference< XMultiServiceFactory >
113 								m_xORB;					// the service factory to use
114 		Reference< XTextConversion >
115 								m_xConverter;			// the text conversion service
116         Locale                  m_aSourceLocale;        // the locale we're working with
117 
118         // additions for Chinese simplified / traditional conversion
119 		HHC::ConversionType     m_eConvType;		// conversion type (Hangul/Hanja, simplified/traditional Chinese,...)
120 		LanguageType            m_nSourceLang;      // just a 'copy' of m_aSourceLocale in order in order to
121                                                     // save the applications from always converting to this
122                                                     // type in their implementations
123         LanguageType            m_nTargetLang;      // target language of new replacement text
124         const Font*             m_pTargetFont;      // target font of new replacement text
125         sal_Int32               m_nConvOptions;     // text conversion options (as used by 'getConversions')
126         sal_Bool                m_bIsInteractive;   // specifies if the conversion requires user interaction
127                                                     // (and likeley a specialised dialog) or if it is to run
128                                                     // automatically without any user interaction.
129                                                     // True for Hangul / Hanja conversion
130                                                     // False for Chinese simlified / traditional conversion
131 
132 		HangulHanjaConversion*	m_pAntiImpl;			// our "anti-impl" instance
133 
134 		// options
135         sal_Bool                    m_bByCharacter;                 // are we in "by character" mode currently?
136         HHC::ConversionFormat       m_eConversionFormat;            // the current format for the conversion
137         HHC::ConversionDirection    m_ePrimaryConversionDirection;  // the primary conversion direction
138         HHC::ConversionDirection    m_eCurrentConversionDirection;  // the primary conversion direction
139 
140         //options from Hangul/Hanja Options dialog (also saved to configuration)
141         bool                    m_bIgnorePostPositionalWord;
142         bool                    m_bShowRecentlyUsedFirst;
143         bool                    m_bAutoReplaceUnique;
144 
145 		// state
146         ::rtl::OUString                m_sCurrentPortion;      // the text which we are currently working on
147         LanguageType            m_nCurrentPortionLang;  // language of m_sCurrentPortion found
148 		sal_Int32				m_nCurrentStartIndex;	// the start index within m_sCurrentPortion of the current convertible portion
149 		sal_Int32				m_nCurrentEndIndex;		// the end index (excluding) within m_sCurrentPortion of the current convertible portion
150 		sal_Int32				m_nReplacementBaseIndex;// index which ReplaceUnit-calls need to be relative to
151         sal_Int32               m_nCurrentConversionOption;
152         sal_Int16               m_nCurrentConversionType;
153         Sequence< ::rtl::OUString >
154 								m_aCurrentSuggestions;	// the suggestions for the current unit
155 														// (means for the text [m_nCurrentStartIndex, m_nCurrentEndIndex) in m_sCurrentPortion)
156         sal_Bool                m_bTryBothDirections;   // specifies if other conversion directions should be tried when looking for convertible characters
157 
158 
159 	public:
160 		HangulHanjaConversion_Impl(
161 			Window* _pUIParent,
162 			const Reference< XMultiServiceFactory >& _rxORB,
163             const Locale& _rSourceLocale,
164             const Locale& _rTargetLocale,
165             const Font* _pTargetFont,
166             sal_Int32 _nConvOptions,
167             sal_Bool _bIsInteractive,
168 			HangulHanjaConversion* _pAntiImpl );
169 
170 	public:
171 
172 		static void			SetUseSavedConversionDirectionState( sal_Bool bVal );
173 
174 				void		DoDocumentConversion( );
175 
176 		inline	sal_Bool	IsByCharacter( ) const { return m_bByCharacter; }
177 
178 		inline	sal_Bool	IsValid() const { return m_xConverter.is(); }
179 
180         inline LanguageType GetSourceLang() const   { return m_nSourceLang; }
181         inline LanguageType GetTargetLang() const   { return m_nTargetLang; }
182         inline const Font * GetTargetFont() const   { return m_pTargetFont; }
183         inline sal_Int32    GetConvOptions() const  { return m_nConvOptions; }
184         inline sal_Bool     IsInteractive() const   { return m_bIsInteractive; }
185 
186 	protected:
187 		void	createDialog();
188 
189 		/** continue with the conversion, return <TRUE/> if and only if the complete conversion is done
190 			@param _bRepeatCurrentUnit
191 				if <TRUE/>, an implNextConvertible will be called initially to advance to the next convertible.
192 				if <FALSE/>, the method will initially work with the current convertible unit
193 		*/
194 		sal_Bool ContinueConversion( bool _bRepeatCurrentUnit );
195 
196 	private:
197         DECL_LINK( OnOptionsChanged, void* );
198 		DECL_LINK( OnIgnore, void* );
199 		DECL_LINK( OnIgnoreAll, void* );
200 		DECL_LINK( OnChange, void* );
201 		DECL_LINK( OnChangeAll, void* );
202 		DECL_LINK( OnByCharClicked, CheckBox* );
203 		DECL_LINK( OnConversionTypeChanged, void* );
204 		DECL_LINK( OnFind, void* );
205 
206 		/** proceed, after the current convertible has been handled
207 
208 			<p><b>Attention:</b>
209 				When returning from this method, the dialog may have been deleted!</p>
210 
211 			@param _bRepeatCurrentUnit
212 				will be passed to the <member>ContinueConversion</member> call
213 		*/
214 		void	implProceed( bool _bRepeatCurrentUnit );
215 
216 		// change the current convertible, and do _not_ proceed
217 		void	implChange( const ::rtl::OUString& _rChangeInto );
218 
219 		/** find the next convertible piece of text, with possibly advancing to the next portion
220 
221 			@see HangulHanjaConversion::GetNextPortion
222 		*/
223 		sal_Bool	implNextConvertible( bool _bRepeatUnit );
224 
225 		/** find the next convertible unit within the current portion
226 			@param _bRepeatUnit
227 				if <TRUE/>, the search will start at the beginning of the current unit,
228 				if <FALSE/>, it will start at the end of the current unit
229 		*/
230 		bool		implNextConvertibleUnit( const sal_Int32 _nStartAt );
231 
232 		/** retrieves the next portion, with setting the index members properly
233 			@return
234 				<TRUE/> if and only if there is a next portion
235 		*/
236 		bool		implRetrieveNextPortion( );
237 
238 		/** determine the ConversionDirection for m_sCurrentPortion
239 			@return
240 				<FALSE/> if and only if something went wrong
241 		*/
242 		bool		implGetConversionDirectionForCurrentPortion( HHC::ConversionDirection& rDirection );
243 
244         /** member m_aCurrentSuggestions and m_nCurrentEndIndex are updated according to the other settings and current dictionaries
245 
246             if _bAllowSearchNextConvertibleText is true _nStartAt is used as starting point to search the next
247             convertible text portion. This may result in changing of the member m_nCurrentStartIndex additionally.
248 
249             @return
250 				<TRUE/> if Suggestions were found
251         */
252         bool        implUpdateSuggestions( const bool _bAllowSearchNextConvertibleText=false, const sal_Int32 _nStartAt=-1 );
253 
254         /** reads the options from Hangul/Hanja Options dialog that are saved to configuration
255         */
256         void implReadOptionsFromConfiguration();
257 
258         /** get the string currently considered to be replaced or ignored
259         */
260         ::rtl::OUString GetCurrentUnit() const;
261 
262         /** read options from configuration, update suggestion list and dialog content
263         */
264         void implUpdateData();
265 
266         /** get the conversion direction dependent from m_eConvType and m_eCurrentConversionDirection
267             in case of switching the direction is allowed this can be triggered with parameter bSwitchDirection
268         */
269         sal_Int16 implGetConversionType( bool bSwitchDirection=false ) const;
270 	};
271 
272 	//=========================================================================
273 	//= HangulHanjaConversion_Impl
274 	//=========================================================================
275     //-------------------------------------------------------------------------
276     // static member initialization
277     HangulHanjaConversion_Impl::StringMap HangulHanjaConversion_Impl::m_aRecentlyUsedList = HangulHanjaConversion_Impl::StringMap();
278 
279 	//-------------------------------------------------------------------------
280 	HangulHanjaConversion_Impl::HangulHanjaConversion_Impl( Window* _pUIParent,
281         const Reference< XMultiServiceFactory >& _rxORB,
282         const Locale& _rSourceLocale,
283         const Locale& _rTargetLocale,
284         const Font* _pTargetFont,
285         sal_Int32 _nOptions,
286         sal_Bool _bIsInteractive,
287         HangulHanjaConversion* _pAntiImpl )
288 : m_pConversionDialog( NULL )
289 , m_pUIParent( _pUIParent )
290 , m_xORB( _rxORB )
291 , m_aSourceLocale( _rSourceLocale )
292 , m_nSourceLang( SvxLocaleToLanguage( _rSourceLocale ) )
293 , m_nTargetLang( SvxLocaleToLanguage( _rTargetLocale ) )
294 , m_pTargetFont( _pTargetFont )
295 , m_bIsInteractive( _bIsInteractive )
296 , m_pAntiImpl( _pAntiImpl )
297 , m_nCurrentPortionLang( LANGUAGE_NONE )
298 , m_nCurrentStartIndex( 0 )
299 , m_nCurrentEndIndex( 0 )
300 , m_nReplacementBaseIndex( 0 )
301 , m_nCurrentConversionOption( TextConversionOption::NONE )
302 , m_nCurrentConversionType( -1 ) // not yet known
303 , m_bTryBothDirections( sal_True )
304 	{
305         implReadOptionsFromConfiguration();
306 
307 		DBG_ASSERT( m_xORB.is(), "HangulHanjaConversion_Impl::HangulHanjaConversion_Impl: no ORB!" );
308 
309 		// determine conversion type
310 		if (m_nSourceLang == LANGUAGE_KOREAN && m_nTargetLang == LANGUAGE_KOREAN)
311             m_eConvType = HHC::eConvHangulHanja;
312 		else if ( (m_nSourceLang == LANGUAGE_CHINESE_TRADITIONAL && m_nTargetLang == LANGUAGE_CHINESE_SIMPLIFIED)  ||
313 				 (m_nSourceLang == LANGUAGE_CHINESE_SIMPLIFIED  && m_nTargetLang == LANGUAGE_CHINESE_TRADITIONAL) )
314             m_eConvType = HHC::eConvSimplifiedTraditional;
315 		else
316 		{
317 			DBG_ERROR( "failed to determine conversion type from languages" );
318 		}
319 
320 		// set remaining conversion parameters to their default values
321 		m_nConvOptions		= _nOptions;
322 		m_bByCharacter		= 0 != (_nOptions & CHARACTER_BY_CHARACTER);
323         m_eConversionFormat = HHC::eSimpleConversion;
324         m_ePrimaryConversionDirection = HHC::eHangulToHanja;	// used for eConvHangulHanja
325         m_eCurrentConversionDirection = HHC::eHangulToHanja;	// used for eConvHangulHanja
326 
327 		if ( m_xORB.is() )
328 		{
329 			::rtl::OUString sTextConversionService( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.i18n.TextConversion" ) );
330 			m_xConverter = m_xConverter.query( m_xORB->createInstance( sTextConversionService ) );
331 			if ( !m_xConverter.is() )
332 				ShowServiceNotAvailableError( m_pUIParent, sTextConversionService, sal_True );
333 		}
334 
335 	}
336 
337 	//-------------------------------------------------------------------------
338 	void HangulHanjaConversion_Impl::createDialog()
339 	{
340 		DBG_ASSERT( m_bIsInteractive, "createDialog when the conversion should not be interactive?" );
341 		if ( m_bIsInteractive && !m_pConversionDialog )
342 		{
343 			EditAbstractDialogFactory* pFact = EditAbstractDialogFactory::Create();
344 			if(pFact)
345 			{
346 				m_pConversionDialog = pFact->CreateHangulHanjaConversionDialog(m_pUIParent, m_ePrimaryConversionDirection );
347 				DBG_ASSERT(m_pConversionDialog, "Dialogdiet fail!");//CHINA001
348 
349                 m_pConversionDialog->EnableRubySupport( m_pAntiImpl->HasRubySupport() );
350 
351 				m_pConversionDialog->SetByCharacter( m_bByCharacter );
352 				m_pConversionDialog->SetConversionFormat( m_eConversionFormat );
353                 m_pConversionDialog->SetConversionDirectionState( m_bTryBothDirections, m_ePrimaryConversionDirection );
354 
355 				// the handlers
356                 m_pConversionDialog->SetOptionsChangedHdl( LINK( this, HangulHanjaConversion_Impl, OnOptionsChanged ) );
357 				m_pConversionDialog->SetIgnoreHdl( LINK( this, HangulHanjaConversion_Impl, OnIgnore ) );
358 				m_pConversionDialog->SetIgnoreAllHdl( LINK( this, HangulHanjaConversion_Impl, OnIgnoreAll ) );
359 				m_pConversionDialog->SetChangeHdl( LINK( this, HangulHanjaConversion_Impl, OnChange ) );
360 				m_pConversionDialog->SetChangeAllHdl( LINK( this, HangulHanjaConversion_Impl, OnChangeAll ) );
361 				m_pConversionDialog->SetClickByCharacterHdl( LINK( this, HangulHanjaConversion_Impl, OnByCharClicked ) );
362 				m_pConversionDialog->SetConversionFormatChangedHdl( LINK( this, HangulHanjaConversion_Impl, OnConversionTypeChanged ) );
363 				m_pConversionDialog->SetFindHdl( LINK( this, HangulHanjaConversion_Impl, OnFind ) );
364 			}
365 		}
366 	}
367 
368     //-------------------------------------------------------------------------
369     sal_Int16 HangulHanjaConversion_Impl::implGetConversionType( bool bSwitchDirection ) const
370     {
371         sal_Int16 nConversionType = -1;
372         if (m_eConvType == HHC::eConvHangulHanja)
373             nConversionType = HHC::eHangulToHanja == ( m_eCurrentConversionDirection && !bSwitchDirection ) ? TO_HANJA : TO_HANGUL;
374         else if (m_eConvType == HHC::eConvSimplifiedTraditional)
375             nConversionType = LANGUAGE_CHINESE_SIMPLIFIED == m_nTargetLang ? TO_SCHINESE : TO_TCHINESE;
376         DBG_ASSERT( nConversionType != -1, "unexpected conversion type" );
377         return nConversionType;
378     }
379 
380     //-------------------------------------------------------------------------
381     bool HangulHanjaConversion_Impl::implUpdateSuggestions( bool _bAllowSearchNextConvertibleText, const sal_Int32 _nStartAt )
382     {
383         // parameters for the converter
384         sal_Int32 nStartSearch = m_nCurrentStartIndex;
385         if( _bAllowSearchNextConvertibleText )
386             nStartSearch = _nStartAt;
387 
388         sal_Int32 nLength = m_sCurrentPortion.getLength() - nStartSearch;
389         m_nCurrentConversionType = implGetConversionType();
390         m_nCurrentConversionOption = IsByCharacter() ? CHARACTER_BY_CHARACTER : NONE;
391         if( m_bIgnorePostPositionalWord )
392             m_nCurrentConversionOption = m_nCurrentConversionOption | IGNORE_POST_POSITIONAL_WORD;
393 
394 		// no need to check both directions for chinese conversion (saves time)
395 		if (m_eConvType == HHC::eConvSimplifiedTraditional)
396 			m_bTryBothDirections = sal_False;
397 
398         sal_Bool bFoundAny = sal_True;
399 		try
400 		{
401 			TextConversionResult aResult = m_xConverter->getConversions(
402 				m_sCurrentPortion,
403 				nStartSearch,
404 				nLength,
405                 m_aSourceLocale,
406                 m_nCurrentConversionType,
407                 m_nCurrentConversionOption
408 			);
409             sal_Bool bFoundPrimary = aResult.Boundary.startPos < aResult.Boundary.endPos;
410 			bFoundAny = bFoundPrimary;
411 
412 			if ( m_bTryBothDirections )
413 			{	// see if we find another convertible when assuming the other direction
414 				TextConversionResult aSecondResult = m_xConverter->getConversions(
415 					m_sCurrentPortion,
416 					nStartSearch,
417 					nLength,
418                     m_aSourceLocale,
419                     implGetConversionType( true ), // switched!
420                     m_nCurrentConversionOption
421 				);
422 				if ( aSecondResult.Boundary.startPos < aSecondResult.Boundary.endPos )
423 				{	// we indeed found such a convertible
424 
425 					// in case the first attempt (with the original conversion direction)
426 					// didn't find anything
427 					if	(	!bFoundPrimary
428 						// or if the second location is _before_ the first one
429 						||	( aSecondResult.Boundary.startPos < aResult.Boundary.startPos )
430 						)
431 					{
432 						// then use the second finding
433 						aResult = aSecondResult;
434 
435 						// our current conversion direction changed now
436                         m_eCurrentConversionDirection = ( HHC::eHangulToHanja == m_eCurrentConversionDirection )
437                             ? HHC::eHanjaToHangul : HHC::eHangulToHanja;
438 						bFoundAny = sal_True;
439 					}
440 				}
441 			}
442 
443             if( _bAllowSearchNextConvertibleText )
444             {
445                 //this might change the current position
446 			    m_aCurrentSuggestions = aResult.Candidates;
447 			    m_nCurrentStartIndex = aResult.Boundary.startPos;
448 			    m_nCurrentEndIndex = aResult.Boundary.endPos;
449             }
450             else
451             {
452                 //the change of starting position is not allowed
453                 if( m_nCurrentStartIndex == aResult.Boundary.startPos
454                     && aResult.Boundary.endPos != aResult.Boundary.startPos )
455                 {
456                     m_aCurrentSuggestions = aResult.Candidates;
457                     m_nCurrentEndIndex = aResult.Boundary.endPos;
458                 }
459                 else
460                 {
461                     m_aCurrentSuggestions.realloc( 0 );
462                     if( m_sCurrentPortion.getLength() >= m_nCurrentStartIndex+1 )
463                         m_nCurrentEndIndex = m_nCurrentStartIndex+1;
464                 }
465             }
466 
467             //put recently used string to front:
468             if( m_bShowRecentlyUsedFirst && m_aCurrentSuggestions.getLength()>1 )
469             {
470                 ::rtl::OUString sCurrentUnit( GetCurrentUnit() );
471                 StringMap::const_iterator aRecentlyUsed = m_aRecentlyUsedList.find( sCurrentUnit );
472                 bool bUsedBefore = aRecentlyUsed != m_aRecentlyUsedList.end();
473                 if( bUsedBefore && m_aCurrentSuggestions[0] != aRecentlyUsed->second )
474                 {
475                     sal_Int32 nCount = m_aCurrentSuggestions.getLength();
476                     Sequence< ::rtl::OUString > aTmp(nCount);
477                     aTmp[0]=aRecentlyUsed->second;
478                     sal_Int32 nDiff = 1;
479                     for( sal_Int32 n=1; n<nCount; n++)//we had 0 already
480                     {
481                         if( nDiff && m_aCurrentSuggestions[n-nDiff]==aRecentlyUsed->second )
482                             nDiff=0;
483                         aTmp[n]=m_aCurrentSuggestions[n-nDiff];
484                     }
485                     m_aCurrentSuggestions = aTmp;
486                 }
487             }
488 		}
489 		catch( const Exception& )
490 		{
491 			DBG_ERROR( "HangulHanjaConversion_Impl::implNextConvertibleUnit: caught an exception!" );
492 
493 			//!!! at least we want to move on in the text in order
494 			//!!! to avoid an endless loop...
495 			return false;
496 		}
497         return bFoundAny;
498     }
499 
500 	//-------------------------------------------------------------------------
501 	bool HangulHanjaConversion_Impl::implNextConvertibleUnit( const sal_Int32 _nStartAt )
502 	{
503 		m_aCurrentSuggestions.realloc( 0 );
504 
505 		// ask the TextConversion service for the next convertible piece of text
506 
507 		// get current values from dialog
508 		if( m_eConvType == HHC::eConvHangulHanja && m_pConversionDialog )
509 		{
510 			m_bTryBothDirections = m_pConversionDialog->GetUseBothDirections();
511 			HHC::ConversionDirection eDialogDirection = HHC::eHangulToHanja;
512 			eDialogDirection = m_pConversionDialog->GetDirection( eDialogDirection );
513 
514 			if( !m_bTryBothDirections && eDialogDirection != m_eCurrentConversionDirection )
515 			{
516 				m_eCurrentConversionDirection = eDialogDirection;
517 			}
518 
519 			// save curently used value for possible later use
520 			m_pAntiImpl->m_bTryBothDirectionsSave = m_bTryBothDirections;
521 			m_pAntiImpl->m_ePrimaryConversionDirectionSave = m_eCurrentConversionDirection;
522 		}
523 
524 		bool bFoundAny = implUpdateSuggestions( true, _nStartAt );
525 
526         return  bFoundAny &&
527                 (m_nCurrentStartIndex < m_sCurrentPortion.getLength());
528 	}
529 
530 	//-------------------------------------------------------------------------
531 	bool HangulHanjaConversion_Impl::implRetrieveNextPortion( )
532 	{
533         sal_Bool bAllowImplicitChanges = m_eConvType == HHC::eConvSimplifiedTraditional;
534 
535 		m_sCurrentPortion = ::rtl::OUString();
536         m_nCurrentPortionLang = LANGUAGE_NONE;
537         m_pAntiImpl->GetNextPortion( m_sCurrentPortion, m_nCurrentPortionLang, bAllowImplicitChanges );
538 		m_nReplacementBaseIndex = 0;
539 		m_nCurrentStartIndex = m_nCurrentEndIndex = 0;
540 
541 		bool bRet = 0 != m_sCurrentPortion.getLength();
542 
543 		if (m_eConvType == HHC::eConvHangulHanja && m_bTryBothDirections)
544 			implGetConversionDirectionForCurrentPortion( m_eCurrentConversionDirection );
545 
546 		return bRet;
547 	}
548 
549 	//-------------------------------------------------------------------------
550 	sal_Bool HangulHanjaConversion_Impl::implNextConvertible( bool _bRepeatUnit )
551 	{
552 		if ( _bRepeatUnit || ( m_nCurrentEndIndex < m_sCurrentPortion.getLength() ) )
553 		{
554 			if ( implNextConvertibleUnit(
555 						_bRepeatUnit
556 					?	( IsByCharacter() ? m_nCurrentStartIndex : m_nCurrentStartIndex )
557 					:	m_nCurrentEndIndex
558 				) )
559 				return sal_True;
560 		}
561 
562 		// no convertible text in the current portion anymore
563 		// -> advance to the next portion
564 		do
565 		{
566 			// next portion
567 			if ( implRetrieveNextPortion( ) )
568 			{	// there is a next portion
569 				// -> find the next convertible unit in the current portion
570 				if ( implNextConvertibleUnit( 0 ) )
571 					return sal_True;
572 			}
573 		}
574 		while ( m_sCurrentPortion.getLength() );
575 
576 		// no more portions
577 		return sal_False;
578 	}
579 
580 	//-------------------------------------------------------------------------
581     ::rtl::OUString HangulHanjaConversion_Impl::GetCurrentUnit() const
582     {
583         DBG_ASSERT( m_nCurrentStartIndex < m_sCurrentPortion.getLength(),
584 			"HangulHanjaConversion_Impl::GetCurrentUnit: invalid index into current portion!" );
585         DBG_ASSERT( m_nCurrentEndIndex <= m_sCurrentPortion.getLength(),
586 			"HangulHanjaConversion_Impl::GetCurrentUnit: invalid index into current portion!" );
587 		DBG_ASSERT( m_nCurrentStartIndex <= m_nCurrentEndIndex,
588 			"HangulHanjaConversion_Impl::GetCurrentUnit: invalid interval!" );
589 
590         ::rtl::OUString sCurrentUnit = m_sCurrentPortion.copy( m_nCurrentStartIndex, m_nCurrentEndIndex - m_nCurrentStartIndex );
591         return sCurrentUnit;
592     }
593 
594     //-------------------------------------------------------------------------
595 	sal_Bool HangulHanjaConversion_Impl::ContinueConversion( bool _bRepeatCurrentUnit )
596 	{
597 		sal_Bool bNeedUserInteraction = sal_False;	// when we leave here, do we need user interaction?
598 		sal_Bool bDocumentDone = sal_False;			// did we already check the whole document?
599 
600 		while ( !bDocumentDone && !bNeedUserInteraction && implNextConvertible( _bRepeatCurrentUnit ) )
601 		{
602 			::rtl::OUString sCurrentUnit( GetCurrentUnit() );
603 
604 			// do we need to ignore it?
605 			sal_Bool bAlwaysIgnoreThis = m_sIgnoreList.end() != m_sIgnoreList.find( sCurrentUnit );
606 
607 			// do we need to change it?
608 			StringMap::const_iterator aChangeListPos = m_aChangeList.find( sCurrentUnit );
609 			sal_Bool bAlwaysChangeThis = m_aChangeList.end() != aChangeListPos;
610 
611 			// do we automatically change this?
612 			sal_Bool bAutoChange = m_bAutoReplaceUnique && m_aCurrentSuggestions.getLength() == 1;
613 
614             if (!m_bIsInteractive)
615 			{
616                 // silent conversion (e.g. for simplified/traditional Chinese)...
617                 if(m_aCurrentSuggestions.getLength()>0)
618 				    implChange( m_aCurrentSuggestions.getConstArray()[0] );
619 			}
620 			else if (bAutoChange)
621 			{
622 				implChange( m_aCurrentSuggestions.getConstArray()[0] );
623 			}
624 			else if ( bAlwaysChangeThis )
625 			{
626 				implChange( aChangeListPos->second );
627 			}
628 			else if ( !bAlwaysIgnoreThis )
629 			{
630 				// here we need to ask the user for what to do with the text
631 				// for this, allow derivees to highlight the current text unit in a possible document view
632 				m_pAntiImpl->HandleNewUnit( m_nCurrentStartIndex - m_nReplacementBaseIndex, m_nCurrentEndIndex - m_nReplacementBaseIndex );
633 
634                 DBG_ASSERT( m_pConversionDialog, "we should always have a dialog here!" );
635                 if( m_pConversionDialog )
636 				    m_pConversionDialog->SetCurrentString( sCurrentUnit, m_aCurrentSuggestions );
637 
638 				// do not look for the next convertible: We have to wait for the user to interactivly
639 				// decide what happens with the current convertible
640 				bNeedUserInteraction = sal_True;
641 			}
642 		}
643 
644 		/*
645 		if ( bDocumentDone )
646 			return sal_True;			// we explicitly know that the complete document is done
647 		else if ( bNeedUserInteraction )
648 			return sal_False;			// the doc is not done, we found a convertible, but need the user to decide
649 		else
650 			return sal_True;			// we did not find a next convertible, so the document is implicitly done
651 		*/
652 
653 		return	bDocumentDone || !bNeedUserInteraction;
654 	}
655 
656 	//-------------------------------------------------------------------------
657 	bool HangulHanjaConversion_Impl::implGetConversionDirectionForCurrentPortion( HHC::ConversionDirection& rDirection )
658 	{
659 		// - For eConvHangulHanja the direction is determined by
660 		// the first encountered Korean character.
661 		// - For eConvSimplifiedTraditional the conversion direction
662 		// is already specified by the source language.
663 
664 		bool bSuccess = true;
665 
666         if (m_eConvType == HHC::eConvHangulHanja)
667 		{
668 			bSuccess = false;
669 			try
670 			{
671 				// get the break iterator service
672 				::rtl::OUString sBreakIteratorService( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.i18n.BreakIterator" ) );
673 				Reference< XInterface > xBI( m_xORB->createInstance( ::rtl::OUString( sBreakIteratorService ) ) );
674 				Reference< XBreakIterator > xBreakIter( xBI, UNO_QUERY );
675 				if ( !xBreakIter.is() )
676 				{
677 					ShowServiceNotAvailableError( m_pUIParent, sBreakIteratorService, sal_True );
678 				}
679 				else
680 				{
681 					sal_Int32 nNextAsianScript = xBreakIter->beginOfScript( m_sCurrentPortion, m_nCurrentStartIndex, com::sun::star::i18n::ScriptType::ASIAN );
682 					if ( -1 == nNextAsianScript )
683 						nNextAsianScript = xBreakIter->nextScript( m_sCurrentPortion, m_nCurrentStartIndex, com::sun::star::i18n::ScriptType::ASIAN );
684 					if ( ( nNextAsianScript >= m_nCurrentStartIndex ) && ( nNextAsianScript < m_sCurrentPortion.getLength() ) )
685 					{	// found asian text
686 
687 						// determine if it's Hangul
688 						CharClass aCharClassificaton( m_xORB, m_aSourceLocale );
689 						sal_Int16 nScript = aCharClassificaton.getScript( m_sCurrentPortion, sal::static_int_cast< sal_uInt16 >(nNextAsianScript) );
690 						if	(	( UnicodeScript_kHangulJamo == nScript )
691 							||	( UnicodeScript_kHangulCompatibilityJamo == nScript )
692 							||	( UnicodeScript_kHangulSyllable == nScript )
693 							)
694 						{
695 							rDirection = HHC::eHangulToHanja;
696 						}
697 						else
698 						{
699 							rDirection = HHC::eHanjaToHangul;
700 						}
701 
702 						bSuccess = true;
703 					}
704 				}
705 			}
706 			catch( const Exception& )
707 			{
708 				DBG_ERROR( "HangulHanjaConversion_Impl::implGetConversionDirectionForCurrentPortion: caught an exception!" );
709 			}
710 		}
711 
712 		return bSuccess;
713 	}
714 
715 	//-------------------------------------------------------------------------
716 	void HangulHanjaConversion_Impl::DoDocumentConversion( )
717 	{
718 		// clear the change-all list - it's to be re-initialized for every single document
719         {
720             StringMap aEmpty;
721             m_aChangeList.swap( aEmpty );
722         }
723 
724 		// first of all, we need to guess the direction of our conversion - it is determined by the first
725 		// hangul or hanja character in the first text
726 		if ( !implRetrieveNextPortion() )
727 		{
728             DBG_WARNING( "HangulHanjaConversion_Impl::DoDocumentConversion: why did you call me if you do have nothing to convert?" );
729 			// nothing to do
730 			return;
731 		}
732 		if( m_eConvType == HHC::eConvHangulHanja )
733 		{
734 			//init conversion direction from saved value
735 			HHC::ConversionDirection eDirection = HHC::eHangulToHanja;
736 			if(!implGetConversionDirectionForCurrentPortion( eDirection ))
737 				// something went wrong, has already been asserted
738 				return;
739 
740 			if (m_pAntiImpl->IsUseSavedConversionDirectionState())
741 			{
742 				m_ePrimaryConversionDirection = m_pAntiImpl->m_ePrimaryConversionDirectionSave;
743 				m_bTryBothDirections = m_pAntiImpl->m_bTryBothDirectionsSave;
744 				if( m_bTryBothDirections )
745 					m_eCurrentConversionDirection = eDirection;
746 				else
747 					m_eCurrentConversionDirection = m_ePrimaryConversionDirection;
748 			}
749 			else
750 			{
751 				m_ePrimaryConversionDirection = eDirection;
752 				m_eCurrentConversionDirection = eDirection;
753 			}
754 		}
755 
756 		if (m_bIsInteractive  &&  m_eConvType == HHC::eConvHangulHanja)
757 		{
758 			//always open dialog if at least having a hangul or hanja text portion
759 			createDialog();
760 			if(m_pAntiImpl->IsUseSavedConversionDirectionState())
761 				ContinueConversion( sal_False );
762 			else
763 				implUpdateData();
764 			m_pConversionDialog->Execute();
765 			DELETEZ( m_pConversionDialog );
766 		}
767 		else
768 		{
769 #ifdef DBG_UTIL
770 			sal_Bool bCompletelyDone =
771 #endif
772 			ContinueConversion( sal_False );
773 			DBG_ASSERT( bCompletelyDone, "HangulHanjaConversion_Impl::DoDocumentConversion: ContinueConversion should have returned true here!" );
774 		}
775 	}
776 
777 	//-------------------------------------------------------------------------
778 	void HangulHanjaConversion_Impl::implProceed( bool _bRepeatCurrentUnit )
779 	{
780 		if ( ContinueConversion( _bRepeatCurrentUnit ) )
781 		{	// we're done with the whole document
782             DBG_ASSERT( !m_bIsInteractive || m_pConversionDialog, "HangulHanjaConversion_Impl::implProceed: we should not reach this here without dialog!" );
783 			if ( m_pConversionDialog )
784 				m_pConversionDialog->EndDialog( RET_OK );
785 		}
786 	}
787 
788 	//-------------------------------------------------------------------------
789 	void HangulHanjaConversion_Impl::implChange( const ::rtl::OUString& _rChangeInto )
790 	{
791         if( !_rChangeInto.getLength() )
792             return;
793 
794 		// translate the conversion format into a replacement action
795 		// this translation depends on whether we have a Hangul original, or a Hanja original
796 
797         HHC::ReplacementAction eAction( HHC::eExchange );
798 
799 		if (m_eConvType == HHC::eConvHangulHanja)
800 		{
801 			// is the original we're about to change in Hangul?
802 			sal_Bool bOriginalIsHangul = HHC::eHangulToHanja == m_eCurrentConversionDirection;
803 
804 			switch ( m_eConversionFormat )
805 			{
806 				case HHC::eSimpleConversion: eAction = HHC::eExchange; break;
807 				case HHC::eHangulBracketed:  eAction = bOriginalIsHangul ? HHC::eOriginalBracketed : HHC::eReplacementBracketed; break;
808 				case HHC::eHanjaBracketed:   eAction = bOriginalIsHangul ? HHC::eReplacementBracketed : HHC::eOriginalBracketed; break;
809 				case HHC::eRubyHanjaAbove:   eAction = bOriginalIsHangul ? HHC::eReplacementAbove : HHC::eOriginalAbove; break;
810 				case HHC::eRubyHanjaBelow:   eAction = bOriginalIsHangul ? HHC::eReplacementBelow : HHC::eOriginalBelow; break;
811 				case HHC::eRubyHangulAbove:  eAction = bOriginalIsHangul ? HHC::eOriginalAbove : HHC::eReplacementAbove; break;
812 				case HHC::eRubyHangulBelow:  eAction = bOriginalIsHangul ? HHC::eOriginalBelow : HHC::eReplacementBelow; break;
813 				default:
814 					DBG_ERROR( "HangulHanjaConversion_Impl::implChange: invalid/unexpected conversion format!" );
815 			}
816 		}
817 
818 		// the proper indicies (the wrapper implementation needs indicies relative to the
819 		// previous replacement)
820 		DBG_ASSERT( ( m_nReplacementBaseIndex <= m_nCurrentStartIndex ) && ( m_nReplacementBaseIndex <= m_nCurrentEndIndex ),
821 			"HangulHanjaConversion_Impl::implChange: invalid replacement base!" );
822 
823 		sal_Int32 nStartIndex = m_nCurrentStartIndex - m_nReplacementBaseIndex;
824 		sal_Int32 nEndIndex = m_nCurrentEndIndex - m_nReplacementBaseIndex;
825 
826         //remind this decision
827         m_aRecentlyUsedList[ GetCurrentUnit() ] = _rChangeInto;
828 
829         LanguageType *pNewUnitLang = 0;
830         LanguageType  nNewUnitLang = LANGUAGE_NONE;
831         if (m_eConvType == HHC::eConvSimplifiedTraditional)
832         {
833             // check if language needs to be changed
834             if ( m_pAntiImpl->GetTargetLanguage() == LANGUAGE_CHINESE_TRADITIONAL &&
835                 !m_pAntiImpl->IsTraditional( m_nCurrentPortionLang ))
836                 nNewUnitLang = LANGUAGE_CHINESE_TRADITIONAL;
837             else if ( m_pAntiImpl->GetTargetLanguage() == LANGUAGE_CHINESE_SIMPLIFIED &&
838                      !m_pAntiImpl->IsSimplified( m_nCurrentPortionLang ))
839                 nNewUnitLang = LANGUAGE_CHINESE_SIMPLIFIED;
840             if (nNewUnitLang != LANGUAGE_NONE)
841                 pNewUnitLang = &nNewUnitLang;
842         }
843 
844         // according to FT we should not (yet) bother about Hangul/Hanja conversion here
845         //
846         // aOffsets is needed in ReplaceUnit below in order to to find out
847         // exactly which characters are really changed in order to keep as much
848         // from attributation for the text as possible.
849         Sequence< sal_Int32 > aOffsets;
850         Reference< XExtendedTextConversion > xExtConverter( m_xConverter, UNO_QUERY );
851         if (m_eConvType == HHC::eConvSimplifiedTraditional && xExtConverter.is())
852 		{
853             try
854             {
855                 ::rtl::OUString aConvText = xExtConverter->getConversionWithOffset(
856                     m_sCurrentPortion,
857                     m_nCurrentStartIndex,
858                     m_nCurrentEndIndex - m_nCurrentStartIndex,
859                     m_aSourceLocale,
860                     m_nCurrentConversionType,
861                     m_nCurrentConversionOption,
862                     aOffsets
863                 );
864             }
865             catch( const Exception& )
866             {
867                 DBG_ERROR( "HangulHanjaConversion_Impl::implChange: caught unexpected exception!" );
868                 aOffsets.realloc(0);
869             }
870 		}
871 
872         // do the replacement
873         m_pAntiImpl->ReplaceUnit( nStartIndex, nEndIndex, m_sCurrentPortion,
874                 _rChangeInto, aOffsets, eAction, pNewUnitLang );
875 
876 
877 		// adjust the replacement base
878 		m_nReplacementBaseIndex = m_nCurrentEndIndex;
879 	}
880 
881     //-------------------------------------------------------------------------
882     void HangulHanjaConversion_Impl::implReadOptionsFromConfiguration()
883     {
884         SvtLinguConfig	aLngCfg;
885         aLngCfg.GetProperty( UPH_IS_IGNORE_POST_POSITIONAL_WORD ) >>= m_bIgnorePostPositionalWord;
886         aLngCfg.GetProperty( UPH_IS_SHOW_ENTRIES_RECENTLY_USED_FIRST ) >>= m_bShowRecentlyUsedFirst;
887         aLngCfg.GetProperty( UPH_IS_AUTO_REPLACE_UNIQUE_ENTRIES ) >>= m_bAutoReplaceUnique;
888     }
889 
890     //-------------------------------------------------------------------------
891     void HangulHanjaConversion_Impl::implUpdateData()
892     {
893         implReadOptionsFromConfiguration();
894         implUpdateSuggestions();
895 
896         if(m_pConversionDialog)
897         {
898             ::rtl::OUString sCurrentUnit( GetCurrentUnit() );
899 
900             m_pConversionDialog->SetCurrentString( sCurrentUnit, m_aCurrentSuggestions );
901             m_pConversionDialog->FocusSuggestion();
902         }
903 
904         m_pAntiImpl->HandleNewUnit( m_nCurrentStartIndex - m_nReplacementBaseIndex, m_nCurrentEndIndex - m_nReplacementBaseIndex );
905     }
906 
907     //-------------------------------------------------------------------------
908 	IMPL_LINK( HangulHanjaConversion_Impl, OnOptionsChanged, void*, EMPTYARG )
909 	{
910         //options and dictionaries might have been changed
911         //-> update our internal settings and the dialog
912         implUpdateData();
913 
914         return 0L;
915 	}
916 
917 	//-------------------------------------------------------------------------
918 	IMPL_LINK( HangulHanjaConversion_Impl, OnIgnore, void*, EMPTYARG )
919 	{
920 		// simply ignore, and proceed
921 		implProceed( sal_False );
922 		return 0L;
923 	}
924 
925 	//-------------------------------------------------------------------------
926 	IMPL_LINK( HangulHanjaConversion_Impl, OnIgnoreAll, void*, EMPTYARG )
927 	{
928 		DBG_ASSERT( m_pConversionDialog, "HangulHanjaConversion_Impl::OnIgnoreAll: no dialog! How this?" );
929 
930 		if ( m_pConversionDialog )
931 		{
932 			String sCurrentUnit = m_pConversionDialog->GetCurrentString();
933 			DBG_ASSERT( m_sIgnoreList.end() == m_sIgnoreList.find( sCurrentUnit ),
934 				"HangulHanjaConversion_Impl, OnIgnoreAll: shouldn't this have been ignored before" );
935 
936 			// put into the "ignore all" list
937 			m_sIgnoreList.insert( sCurrentUnit );
938 
939 			// and proceed
940 			implProceed( sal_False );
941 		}
942 
943 		return 0L;
944 	}
945 
946 	//-------------------------------------------------------------------------
947 	IMPL_LINK( HangulHanjaConversion_Impl, OnChange, void*, EMPTYARG )
948 	{
949 		// change
950         DBG_ASSERT( m_pConversionDialog, "we should always have a dialog here!" );
951         if( m_pConversionDialog )
952 		    implChange( m_pConversionDialog->GetCurrentSuggestion( ) );
953 		// and proceed
954 		implProceed( sal_False );
955 
956 		return 0L;
957 	}
958 
959 	//-------------------------------------------------------------------------
960 	IMPL_LINK( HangulHanjaConversion_Impl, OnChangeAll, void*, EMPTYARG )
961 	{
962 		DBG_ASSERT( m_pConversionDialog, "HangulHanjaConversion_Impl::OnChangeAll: no dialog! How this?" );
963 		if ( m_pConversionDialog )
964 		{
965 			::rtl::OUString sCurrentUnit( m_pConversionDialog->GetCurrentString() );
966 			::rtl::OUString sChangeInto( m_pConversionDialog->GetCurrentSuggestion( ) );
967 
968             if( sChangeInto.getLength() )
969             {
970 			    // change the current occurence
971 			    implChange( sChangeInto );
972 
973 			    // put into the "change all" list
974 			    m_aChangeList.insert( StringMap::value_type( sCurrentUnit, sChangeInto ) );
975             }
976 
977 			// and proceed
978 			implProceed( sal_False );
979 		}
980 
981 		return 0L;
982 	}
983 
984 	//-------------------------------------------------------------------------
985 	IMPL_LINK( HangulHanjaConversion_Impl, OnByCharClicked, CheckBox*, _pBox )
986 	{
987 		m_bByCharacter = _pBox->IsChecked();
988 
989 		// continue conversion, without advancing to the next unit, but instead continuing with the current unit
990 		implProceed( sal_True );
991 		return 0L;
992 	}
993 
994 	//-------------------------------------------------------------------------
995 	IMPL_LINK( HangulHanjaConversion_Impl, OnConversionTypeChanged, void*, EMPTYARG )
996 	{
997         DBG_ASSERT( m_pConversionDialog, "we should always have a dialog here!" );
998         if( m_pConversionDialog )
999 		    m_eConversionFormat = m_pConversionDialog->GetConversionFormat( );
1000 		return 0L;
1001 	}
1002 
1003 	//-------------------------------------------------------------------------
1004 	IMPL_LINK( HangulHanjaConversion_Impl, OnFind, void*, EMPTYARG )
1005 	{
1006 		DBG_ASSERT( m_pConversionDialog, "HangulHanjaConversion_Impl::OnFind: where did this come from?" );
1007 		if ( m_pConversionDialog )
1008 		{
1009 			try
1010 			{
1011 				::rtl::OUString sNewOriginal( m_pConversionDialog->GetCurrentSuggestion( ) );
1012 				Sequence< ::rtl::OUString > aSuggestions;
1013 
1014 				DBG_ASSERT( m_xConverter.is(), "HangulHanjaConversion_Impl::OnFind: no converter!" );
1015 				TextConversionResult aToHanja = m_xConverter->getConversions(
1016 					sNewOriginal,
1017 					0, sNewOriginal.getLength(),
1018                     m_aSourceLocale,
1019 					TextConversionType::TO_HANJA,
1020 					TextConversionOption::NONE
1021 				);
1022 				TextConversionResult aToHangul = m_xConverter->getConversions(
1023 					sNewOriginal,
1024 					0, sNewOriginal.getLength(),
1025                     m_aSourceLocale,
1026 					TextConversionType::TO_HANGUL,
1027 					TextConversionOption::NONE
1028 				);
1029 
1030 				bool bHaveToHanja = ( aToHanja.Boundary.startPos < aToHanja.Boundary.endPos );
1031 				bool bHaveToHangul = ( aToHangul.Boundary.startPos < aToHangul.Boundary.endPos );
1032 
1033 				TextConversionResult* pResult = NULL;
1034 				if ( bHaveToHanja && bHaveToHangul )
1035 				{	// it found convertibles in both directions -> use the first
1036 					if ( aToHangul.Boundary.startPos < aToHanja.Boundary.startPos )
1037 						pResult = &aToHangul;
1038 					else
1039 						pResult = &aToHanja;
1040 				}
1041 				else if ( bHaveToHanja )
1042 				{	// only found toHanja
1043 					pResult = &aToHanja;
1044 				}
1045 				else
1046 				{	// only found toHangul
1047 					pResult = &aToHangul;
1048 				}
1049 				if ( pResult )
1050 					aSuggestions = pResult->Candidates;
1051 
1052 				m_pConversionDialog->SetCurrentString( sNewOriginal, aSuggestions, false );
1053 				m_pConversionDialog->FocusSuggestion();
1054 			}
1055 			catch( const Exception& )
1056 			{
1057 				DBG_ERROR( "HangulHanjaConversion_Impl::OnFind: caught an exception!" );
1058 			}
1059 		}
1060 		return 0L;
1061 	}
1062 
1063 	//=========================================================================
1064 	//= HangulHanjaConversion
1065 	//=========================================================================
1066 	//-------------------------------------------------------------------------
1067 
1068 	// static member initialization
1069 	sal_Bool	HangulHanjaConversion::m_bUseSavedValues		= sal_False;
1070 	sal_Bool	HangulHanjaConversion::m_bTryBothDirectionsSave	= sal_False;
1071     HHC::ConversionDirection HangulHanjaConversion::m_ePrimaryConversionDirectionSave	= HHC::eHangulToHanja;
1072 
1073 	//-------------------------------------------------------------------------
1074     HangulHanjaConversion::HangulHanjaConversion( Window* _pUIParent,
1075         const Reference< XMultiServiceFactory >& _rxORB,
1076         const Locale& _rSourceLocale, const Locale& _rTargetLocale,
1077         const Font* _pTargetFont,
1078         sal_Int32 _nOptions, sal_Bool _bIsInteractive)
1079         :m_pImpl( new HangulHanjaConversion_Impl( _pUIParent, _rxORB, _rSourceLocale, _rTargetLocale, _pTargetFont, _nOptions, _bIsInteractive, this ) )
1080 	{
1081 	}
1082 
1083 	//-------------------------------------------------------------------------
1084 	HangulHanjaConversion::~HangulHanjaConversion( )
1085 	{
1086 	}
1087 
1088 	//-------------------------------------------------------------------------
1089 	void HangulHanjaConversion::SetUseSavedConversionDirectionState( sal_Bool bVal )
1090 	{
1091 		m_bUseSavedValues = bVal;
1092 	}
1093 
1094 	//-------------------------------------------------------------------------
1095 	sal_Bool HangulHanjaConversion::IsUseSavedConversionDirectionState()
1096 	{
1097 		return m_bUseSavedValues;
1098 	}
1099 
1100     //-------------------------------------------------------------------------
1101     LanguageType HangulHanjaConversion::GetSourceLanguage( ) const
1102     {
1103         return m_pImpl->GetSourceLang();
1104     }
1105 
1106     //-------------------------------------------------------------------------
1107     LanguageType HangulHanjaConversion::GetTargetLanguage( ) const
1108     {
1109         return m_pImpl->GetTargetLang();
1110     }
1111 
1112     //-------------------------------------------------------------------------
1113     const Font * HangulHanjaConversion::GetTargetFont( ) const
1114     {
1115         return m_pImpl->GetTargetFont();
1116     }
1117 
1118     //-------------------------------------------------------------------------
1119     sal_Int32 HangulHanjaConversion::GetConversionOptions( ) const
1120     {
1121         return m_pImpl->GetConvOptions();
1122     }
1123 
1124     //-------------------------------------------------------------------------
1125     sal_Bool HangulHanjaConversion::IsInteractive( ) const
1126     {
1127         return m_pImpl->IsInteractive();
1128     }
1129 
1130     //-------------------------------------------------------------------------
1131 	void HangulHanjaConversion::HandleNewUnit( const sal_Int32, const sal_Int32 )
1132 	{
1133 		// nothing to do, only derived classes need this.
1134 	}
1135 
1136 	//-------------------------------------------------------------------------
1137     void HangulHanjaConversion::GetNextPortion( ::rtl::OUString&, LanguageType&, sal_Bool )
1138 	{
1139 		DBG_ERROR( "HangulHanjaConversion::GetNextPortion: to be overridden!" );
1140 	}
1141 
1142 	//-------------------------------------------------------------------------
1143     void HangulHanjaConversion::ReplaceUnit(
1144             const sal_Int32, const sal_Int32,
1145             const ::rtl::OUString&,
1146             const ::rtl::OUString&,
1147             const ::com::sun::star::uno::Sequence< sal_Int32 > &,
1148             ReplacementAction,
1149             LanguageType * )
1150 	{
1151 		DBG_ERROR( "HangulHanjaConversion::ReplaceUnit: to be overridden!" );
1152 	}
1153 
1154     //-------------------------------------------------------------------------
1155     sal_Bool HangulHanjaConversion::HasRubySupport() const
1156     {
1157         DBG_ERROR( "HangulHanjaConversion::HasRubySupport: to be overridden!" );
1158         return sal_False;
1159     }
1160 
1161 	//-------------------------------------------------------------------------
1162 	void HangulHanjaConversion::ConvertDocument()
1163 	{
1164 		if ( m_pImpl->IsValid() )
1165 			m_pImpl->DoDocumentConversion( );
1166 	}
1167 
1168 //.............................................................................
1169 }	// namespace svx
1170 //.............................................................................
1171 
1172