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