1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <editeng/hangulhanja.hxx>
21 #include <vcl/msgbox.hxx>
22 #include <vcl/button.hxx>
23 #include <unotools/lingucfg.hxx>
24 #include <unotools/linguprops.hxx>
28 #include <comphelper/processfactory.hxx>
29 #include <com/sun/star/uno/Sequence.hxx>
30 #include <com/sun/star/i18n/BreakIterator.hpp>
31 #include <com/sun/star/i18n/ScriptType.hpp>
32 #include <com/sun/star/i18n/UnicodeScript.hpp>
33 #include <com/sun/star/i18n/TextConversion.hpp>
34 #include <com/sun/star/i18n/XExtendedTextConversion.hpp>
35 #include <com/sun/star/i18n/TextConversionType.hpp>
36 #include <com/sun/star/i18n/TextConversionOption.hpp>
37 #include <com/sun/star/i18n/WordType.hpp>
38 #include <vcl/stdtext.hxx>
39 #include <unotools/charclass.hxx>
41 #include <editeng/edtdlg.hxx>
42 #include <editeng/editrids.hrc>
43 #include <editeng/unolingu.hxx>
45 #define HHC HangulHanjaConversion
47 //.............................................................................
50 //.............................................................................
52 using namespace ::com::sun::star::uno
;
53 using namespace ::com::sun::star::i18n
;
54 using namespace ::com::sun::star::i18n::TextConversionOption
;
55 using namespace ::com::sun::star::i18n::TextConversionType
;
56 using namespace ::com::sun::star::lang
;
58 class HangulHanjaConversion_Impl
61 typedef ::std::set
< OUString
, ::std::less
< OUString
> > StringBag
;
62 typedef ::std::map
< OUString
, OUString
, ::std::less
< OUString
> > StringMap
;
65 StringBag m_sIgnoreList
;
66 StringMap m_aChangeList
;
67 static StringMap m_aRecentlyUsedList
;
70 AbstractHangulHanjaConversionDialog
*
71 m_pConversionDialog
; // the dialog to display for user interaction
72 Window
* m_pUIParent
; // the parent window for any UI we raise
73 Reference
< XComponentContext
>
74 m_xContext
; // the service factory to use
75 Reference
< XExtendedTextConversion
>
76 m_xConverter
; // the text conversion service
77 Locale m_aSourceLocale
; // the locale we're working with
79 // additions for Chinese simplified / traditional conversion
80 HHC::ConversionType m_eConvType
; // conversion type (Hangul/Hanja, simplified/traditional Chinese,...)
81 LanguageType m_nSourceLang
; // just a 'copy' of m_aSourceLocale in order in order to
82 // save the applications from always converting to this
83 // type in their implementations
84 LanguageType m_nTargetLang
; // target language of new replacement text
85 const Font
* m_pTargetFont
; // target font of new replacement text
86 sal_Int32 m_nConvOptions
; // text conversion options (as used by 'getConversions')
87 bool m_bIsInteractive
; // specifies if the conversion requires user interaction
88 // (and likeley a specialised dialog) or if it is to run
89 // automatically without any user interaction.
90 // True for Hangul / Hanja conversion
91 // False for Chinese simlified / traditional conversion
93 HangulHanjaConversion
* m_pAntiImpl
; // our "anti-impl" instance
96 bool m_bByCharacter
; // are we in "by character" mode currently?
97 HHC::ConversionFormat m_eConversionFormat
; // the current format for the conversion
98 HHC::ConversionDirection m_ePrimaryConversionDirection
; // the primary conversion direction
99 HHC::ConversionDirection m_eCurrentConversionDirection
; // the primary conversion direction
101 //options from Hangul/Hanja Options dialog (also saved to configuration)
102 bool m_bIgnorePostPositionalWord
;
103 bool m_bShowRecentlyUsedFirst
;
104 bool m_bAutoReplaceUnique
;
107 OUString m_sCurrentPortion
; // the text which we are currently working on
108 LanguageType m_nCurrentPortionLang
; // language of m_sCurrentPortion found
109 sal_Int32 m_nCurrentStartIndex
; // the start index within m_sCurrentPortion of the current convertible portion
110 sal_Int32 m_nCurrentEndIndex
; // the end index (excluding) within m_sCurrentPortion of the current convertible portion
111 sal_Int32 m_nReplacementBaseIndex
;// index which ReplaceUnit-calls need to be relative to
112 sal_Int32 m_nCurrentConversionOption
;
113 sal_Int16 m_nCurrentConversionType
;
115 m_aCurrentSuggestions
; // the suggestions for the current unit
116 // (means for the text [m_nCurrentStartIndex, m_nCurrentEndIndex) in m_sCurrentPortion)
117 bool m_bTryBothDirections
; // specifies if other conversion directions should be tried when looking for convertible characters
121 HangulHanjaConversion_Impl(
123 const Reference
< XComponentContext
>& rxContext
,
124 const Locale
& _rSourceLocale
,
125 const Locale
& _rTargetLocale
,
126 const Font
* _pTargetFont
,
127 sal_Int32 _nConvOptions
,
128 bool _bIsInteractive
,
129 HangulHanjaConversion
* _pAntiImpl
);
132 void DoDocumentConversion( );
134 inline bool IsByCharacter( ) const { return m_bByCharacter
; }
136 inline bool IsValid() const { return m_xConverter
.is(); }
138 inline LanguageType
GetSourceLang() const { return m_nSourceLang
; }
139 inline LanguageType
GetTargetLang() const { return m_nTargetLang
; }
140 inline const Font
* GetTargetFont() const { return m_pTargetFont
; }
141 inline sal_Int32
GetConvOptions() const { return m_nConvOptions
; }
142 inline bool IsInteractive() const { return m_bIsInteractive
; }
147 /** continue with the conversion, return <TRUE/> if and only if the complete conversion is done
148 @param _bRepeatCurrentUnit
149 if <TRUE/>, an implNextConvertible will be called initially to advance to the next convertible.
150 if <FALSE/>, the method will initially work with the current convertible unit
152 bool ContinueConversion( bool _bRepeatCurrentUnit
);
155 DECL_LINK( OnOptionsChanged
, void* );
156 DECL_LINK( OnIgnore
, void* );
157 DECL_LINK( OnIgnoreAll
, void* );
158 DECL_LINK( OnChange
, void* );
159 DECL_LINK( OnChangeAll
, void* );
160 DECL_LINK( OnByCharClicked
, CheckBox
* );
161 DECL_LINK( OnConversionTypeChanged
, void* );
162 DECL_LINK( OnFind
, void* );
164 /** proceed, after the current convertible has been handled
167 When returning from this method, the dialog may have been deleted!</p>
169 @param _bRepeatCurrentUnit
170 will be passed to the <member>ContinueConversion</member> call
172 void implProceed( bool _bRepeatCurrentUnit
);
174 // change the current convertible, and do _not_ proceed
175 void implChange( const OUString
& _rChangeInto
);
177 /** find the next convertible piece of text, with possibly advancing to the next portion
179 @see HangulHanjaConversion::GetNextPortion
181 bool implNextConvertible( bool _bRepeatUnit
);
183 /** find the next convertible unit within the current portion
185 if <TRUE/>, the search will start at the beginning of the current unit,
186 if <FALSE/>, it will start at the end of the current unit
188 bool implNextConvertibleUnit( const sal_Int32 _nStartAt
);
190 /** retrieves the next portion, with setting the index members properly
192 <TRUE/> if and only if there is a next portion
194 bool implRetrieveNextPortion( );
196 /** determine the ConversionDirection for m_sCurrentPortion
198 <FALSE/> if and only if something went wrong
200 bool implGetConversionDirectionForCurrentPortion( HHC::ConversionDirection
& rDirection
);
202 /** member m_aCurrentSuggestions and m_nCurrentEndIndex are updated according to the other settings and current dictionaries
204 if _bAllowSearchNextConvertibleText is true _nStartAt is used as starting point to search the next
205 convertible text portion. This may result in changing of the member m_nCurrentStartIndex additionally.
208 <TRUE/> if Suggestions were found
210 bool implUpdateSuggestions( const bool _bAllowSearchNextConvertibleText
=false, const sal_Int32 _nStartAt
=-1 );
212 /** reads the options from Hangul/Hanja Options dialog that are saved to configuration
214 void implReadOptionsFromConfiguration();
216 /** get the string currently considered to be replaced or ignored
218 OUString
GetCurrentUnit() const;
220 /** read options from configuration, update suggestion list and dialog content
222 void implUpdateData();
224 /** get the conversion direction dependent from m_eConvType and m_eCurrentConversionDirection
225 in case of switching the direction is allowed this can be triggered with parameter bSwitchDirection
227 sal_Int16
implGetConversionType( bool bSwitchDirection
=false ) const;
230 HangulHanjaConversion_Impl::StringMap
HangulHanjaConversion_Impl::m_aRecentlyUsedList
= HangulHanjaConversion_Impl::StringMap();
232 HangulHanjaConversion_Impl::HangulHanjaConversion_Impl( Window
* _pUIParent
,
233 const Reference
< XComponentContext
>& rxContext
,
234 const Locale
& _rSourceLocale
,
235 const Locale
& _rTargetLocale
,
236 const Font
* _pTargetFont
,
238 bool _bIsInteractive
,
239 HangulHanjaConversion
* _pAntiImpl
)
240 : m_pConversionDialog( NULL
)
241 , m_pUIParent( _pUIParent
)
242 , m_xContext( rxContext
)
243 , m_aSourceLocale( _rSourceLocale
)
244 , m_nSourceLang( LanguageTag( _rSourceLocale
).getLanguageType() )
245 , m_nTargetLang( LanguageTag( _rTargetLocale
).getLanguageType() )
246 , m_pTargetFont( _pTargetFont
)
247 , m_bIsInteractive( _bIsInteractive
)
248 , m_pAntiImpl( _pAntiImpl
)
249 , m_nCurrentPortionLang( LANGUAGE_NONE
)
250 , m_nCurrentStartIndex( 0 )
251 , m_nCurrentEndIndex( 0 )
252 , m_nReplacementBaseIndex( 0 )
253 , m_nCurrentConversionOption( TextConversionOption::NONE
)
254 , m_nCurrentConversionType( -1 ) // not yet known
255 , m_bTryBothDirections( true )
257 implReadOptionsFromConfiguration();
259 DBG_ASSERT( m_xContext
.is(), "HangulHanjaConversion_Impl::HangulHanjaConversion_Impl: no ORB!" );
261 // determine conversion type
262 if (m_nSourceLang
== LANGUAGE_KOREAN
&& m_nTargetLang
== LANGUAGE_KOREAN
)
263 m_eConvType
= HHC::eConvHangulHanja
;
264 else if ( (m_nSourceLang
== LANGUAGE_CHINESE_TRADITIONAL
&& m_nTargetLang
== LANGUAGE_CHINESE_SIMPLIFIED
) ||
265 (m_nSourceLang
== LANGUAGE_CHINESE_SIMPLIFIED
&& m_nTargetLang
== LANGUAGE_CHINESE_TRADITIONAL
) )
266 m_eConvType
= HHC::eConvSimplifiedTraditional
;
269 OSL_FAIL( "failed to determine conversion type from languages" );
272 // set remaining conversion parameters to their default values
273 m_nConvOptions
= _nOptions
;
274 m_bByCharacter
= 0 != (_nOptions
& CHARACTER_BY_CHARACTER
);
275 m_eConversionFormat
= HHC::eSimpleConversion
;
276 m_ePrimaryConversionDirection
= HHC::eHangulToHanja
; // used for eConvHangulHanja
277 m_eCurrentConversionDirection
= HHC::eHangulToHanja
; // used for eConvHangulHanja
279 m_xConverter
= TextConversion::create( m_xContext
);
282 void HangulHanjaConversion_Impl::createDialog()
284 DBG_ASSERT( m_bIsInteractive
, "createDialog when the conversion should not be interactive?" );
285 if ( m_bIsInteractive
&& !m_pConversionDialog
)
287 EditAbstractDialogFactory
* pFact
= EditAbstractDialogFactory::Create();
290 m_pConversionDialog
= pFact
->CreateHangulHanjaConversionDialog(m_pUIParent
, m_ePrimaryConversionDirection
);
291 DBG_ASSERT(m_pConversionDialog
, "Dialogdiet fail!");
293 m_pConversionDialog
->EnableRubySupport( m_pAntiImpl
->HasRubySupport() );
295 m_pConversionDialog
->SetByCharacter( m_bByCharacter
);
296 m_pConversionDialog
->SetConversionFormat( m_eConversionFormat
);
297 m_pConversionDialog
->SetConversionDirectionState( m_bTryBothDirections
, m_ePrimaryConversionDirection
);
300 m_pConversionDialog
->SetOptionsChangedHdl( LINK( this, HangulHanjaConversion_Impl
, OnOptionsChanged
) );
301 m_pConversionDialog
->SetIgnoreHdl( LINK( this, HangulHanjaConversion_Impl
, OnIgnore
) );
302 m_pConversionDialog
->SetIgnoreAllHdl( LINK( this, HangulHanjaConversion_Impl
, OnIgnoreAll
) );
303 m_pConversionDialog
->SetChangeHdl( LINK( this, HangulHanjaConversion_Impl
, OnChange
) );
304 m_pConversionDialog
->SetChangeAllHdl( LINK( this, HangulHanjaConversion_Impl
, OnChangeAll
) );
305 m_pConversionDialog
->SetClickByCharacterHdl( LINK( this, HangulHanjaConversion_Impl
, OnByCharClicked
) );
306 m_pConversionDialog
->SetConversionFormatChangedHdl( LINK( this, HangulHanjaConversion_Impl
, OnConversionTypeChanged
) );
307 m_pConversionDialog
->SetFindHdl( LINK( this, HangulHanjaConversion_Impl
, OnFind
) );
312 sal_Int16
HangulHanjaConversion_Impl::implGetConversionType( bool bSwitchDirection
) const
314 sal_Int16 nConversionType
= -1;
315 if (m_eConvType
== HHC::eConvHangulHanja
)
316 nConversionType
= HHC::eHangulToHanja
== ( m_eCurrentConversionDirection
&& !bSwitchDirection
) ? TO_HANJA
: TO_HANGUL
;
317 else if (m_eConvType
== HHC::eConvSimplifiedTraditional
)
318 nConversionType
= LANGUAGE_CHINESE_SIMPLIFIED
== m_nTargetLang
? TO_SCHINESE
: TO_TCHINESE
;
319 DBG_ASSERT( nConversionType
!= -1, "unexpected conversion type" );
320 return nConversionType
;
323 bool HangulHanjaConversion_Impl::implUpdateSuggestions( bool _bAllowSearchNextConvertibleText
, const sal_Int32 _nStartAt
)
325 // parameters for the converter
326 sal_Int32 nStartSearch
= m_nCurrentStartIndex
;
327 if( _bAllowSearchNextConvertibleText
)
328 nStartSearch
= _nStartAt
;
330 sal_Int32 nLength
= m_sCurrentPortion
.getLength() - nStartSearch
;
331 m_nCurrentConversionType
= implGetConversionType();
332 m_nCurrentConversionOption
= IsByCharacter() ? CHARACTER_BY_CHARACTER
: NONE
;
333 if( m_bIgnorePostPositionalWord
)
334 m_nCurrentConversionOption
= m_nCurrentConversionOption
| IGNORE_POST_POSITIONAL_WORD
;
336 // no need to check both directions for chinese conversion (saves time)
337 if (m_eConvType
== HHC::eConvSimplifiedTraditional
)
338 m_bTryBothDirections
= false;
340 bool bFoundAny
= true;
343 TextConversionResult aResult
= m_xConverter
->getConversions(
348 m_nCurrentConversionType
,
349 m_nCurrentConversionOption
351 const bool bFoundPrimary
= aResult
.Boundary
.startPos
< aResult
.Boundary
.endPos
;
352 bFoundAny
= bFoundPrimary
;
354 if ( m_bTryBothDirections
)
355 { // see if we find another convertible when assuming the other direction
356 TextConversionResult aSecondResult
= m_xConverter
->getConversions(
361 implGetConversionType( true ), // switched!
362 m_nCurrentConversionOption
364 if ( aSecondResult
.Boundary
.startPos
< aSecondResult
.Boundary
.endPos
)
365 { // we indeed found such a convertible
367 // in case the first attempt (with the original conversion direction)
368 // didn't find anything
370 // or if the second location is _before_ the first one
371 || ( aSecondResult
.Boundary
.startPos
< aResult
.Boundary
.startPos
)
374 // then use the second finding
375 aResult
= aSecondResult
;
377 // our current conversion direction changed now
378 m_eCurrentConversionDirection
= ( HHC::eHangulToHanja
== m_eCurrentConversionDirection
)
379 ? HHC::eHanjaToHangul
: HHC::eHangulToHanja
;
385 if( _bAllowSearchNextConvertibleText
)
387 //this might change the current position
388 m_aCurrentSuggestions
= aResult
.Candidates
;
389 m_nCurrentStartIndex
= aResult
.Boundary
.startPos
;
390 m_nCurrentEndIndex
= aResult
.Boundary
.endPos
;
394 //the change of starting position is not allowed
395 if( m_nCurrentStartIndex
== aResult
.Boundary
.startPos
396 && aResult
.Boundary
.endPos
!= aResult
.Boundary
.startPos
)
398 m_aCurrentSuggestions
= aResult
.Candidates
;
399 m_nCurrentEndIndex
= aResult
.Boundary
.endPos
;
403 m_aCurrentSuggestions
.realloc( 0 );
404 if( m_sCurrentPortion
.getLength() >= m_nCurrentStartIndex
+1 )
405 m_nCurrentEndIndex
= m_nCurrentStartIndex
+1;
409 //put recently used string to front:
410 if( m_bShowRecentlyUsedFirst
&& m_aCurrentSuggestions
.getLength()>1 )
412 OUString
sCurrentUnit( GetCurrentUnit() );
413 StringMap::const_iterator aRecentlyUsed
= m_aRecentlyUsedList
.find( sCurrentUnit
);
414 bool bUsedBefore
= aRecentlyUsed
!= m_aRecentlyUsedList
.end();
415 if( bUsedBefore
&& m_aCurrentSuggestions
[0] != aRecentlyUsed
->second
)
417 sal_Int32 nCount
= m_aCurrentSuggestions
.getLength();
418 Sequence
< OUString
> aTmp(nCount
);
419 aTmp
[0]=aRecentlyUsed
->second
;
421 for( sal_Int32 n
=1; n
<nCount
; n
++)//we had 0 already
423 if( nDiff
&& m_aCurrentSuggestions
[n
-nDiff
]==aRecentlyUsed
->second
)
425 aTmp
[n
]=m_aCurrentSuggestions
[n
-nDiff
];
427 m_aCurrentSuggestions
= aTmp
;
431 catch( const Exception
& )
433 OSL_FAIL( "HangulHanjaConversion_Impl::implNextConvertibleUnit: caught an exception!" );
435 //!!! at least we want to move on in the text in order
436 //!!! to avoid an endless loop...
442 bool HangulHanjaConversion_Impl::implNextConvertibleUnit( const sal_Int32 _nStartAt
)
444 m_aCurrentSuggestions
.realloc( 0 );
446 // ask the TextConversion service for the next convertible piece of text
448 // get current values from dialog
449 if( m_eConvType
== HHC::eConvHangulHanja
&& m_pConversionDialog
)
451 m_bTryBothDirections
= m_pConversionDialog
->GetUseBothDirections();
452 HHC::ConversionDirection eDialogDirection
= HHC::eHangulToHanja
;
453 eDialogDirection
= m_pConversionDialog
->GetDirection( eDialogDirection
);
455 if( !m_bTryBothDirections
&& eDialogDirection
!= m_eCurrentConversionDirection
)
457 m_eCurrentConversionDirection
= eDialogDirection
;
460 // save curently used value for possible later use
461 m_pAntiImpl
->m_bTryBothDirectionsSave
= m_bTryBothDirections
;
462 m_pAntiImpl
->m_ePrimaryConversionDirectionSave
= m_eCurrentConversionDirection
;
465 bool bFoundAny
= implUpdateSuggestions( true, _nStartAt
);
468 (m_nCurrentStartIndex
< m_sCurrentPortion
.getLength());
471 bool HangulHanjaConversion_Impl::implRetrieveNextPortion( )
473 const bool bAllowImplicitChanges
= m_eConvType
== HHC::eConvSimplifiedTraditional
;
475 m_sCurrentPortion
= OUString();
476 m_nCurrentPortionLang
= LANGUAGE_NONE
;
477 m_pAntiImpl
->GetNextPortion( m_sCurrentPortion
, m_nCurrentPortionLang
, bAllowImplicitChanges
);
478 m_nReplacementBaseIndex
= 0;
479 m_nCurrentStartIndex
= m_nCurrentEndIndex
= 0;
481 bool bRet
= !m_sCurrentPortion
.isEmpty();
483 if (m_eConvType
== HHC::eConvHangulHanja
&& m_bTryBothDirections
)
484 implGetConversionDirectionForCurrentPortion( m_eCurrentConversionDirection
);
489 bool HangulHanjaConversion_Impl::implNextConvertible( bool _bRepeatUnit
)
491 if ( _bRepeatUnit
|| ( m_nCurrentEndIndex
< m_sCurrentPortion
.getLength() ) )
493 if ( implNextConvertibleUnit(
495 ? ( IsByCharacter() ? m_nCurrentStartIndex
: m_nCurrentStartIndex
)
501 // no convertible text in the current portion anymore
502 // -> advance to the next portion
506 if ( implRetrieveNextPortion( ) )
507 { // there is a next portion
508 // -> find the next convertible unit in the current portion
509 if ( implNextConvertibleUnit( 0 ) )
513 while ( !m_sCurrentPortion
.isEmpty() );
519 OUString
HangulHanjaConversion_Impl::GetCurrentUnit() const
521 DBG_ASSERT( m_nCurrentStartIndex
< m_sCurrentPortion
.getLength(),
522 "HangulHanjaConversion_Impl::GetCurrentUnit: invalid index into current portion!" );
523 DBG_ASSERT( m_nCurrentEndIndex
<= m_sCurrentPortion
.getLength(),
524 "HangulHanjaConversion_Impl::GetCurrentUnit: invalid index into current portion!" );
525 DBG_ASSERT( m_nCurrentStartIndex
<= m_nCurrentEndIndex
,
526 "HangulHanjaConversion_Impl::GetCurrentUnit: invalid interval!" );
528 OUString sCurrentUnit
= m_sCurrentPortion
.copy( m_nCurrentStartIndex
, m_nCurrentEndIndex
- m_nCurrentStartIndex
);
532 bool HangulHanjaConversion_Impl::ContinueConversion( bool _bRepeatCurrentUnit
)
534 while ( implNextConvertible( _bRepeatCurrentUnit
) )
536 OUString
sCurrentUnit( GetCurrentUnit() );
538 // do we need to ignore it?
539 const bool bAlwaysIgnoreThis
= m_sIgnoreList
.end() != m_sIgnoreList
.find( sCurrentUnit
);
541 // do we need to change it?
542 StringMap::const_iterator aChangeListPos
= m_aChangeList
.find( sCurrentUnit
);
543 const bool bAlwaysChangeThis
= m_aChangeList
.end() != aChangeListPos
;
545 // do we automatically change this?
546 const bool bAutoChange
= m_bAutoReplaceUnique
&& m_aCurrentSuggestions
.getLength() == 1;
548 if (!m_bIsInteractive
)
550 // silent conversion (e.g. for simplified/traditional Chinese)...
551 if(m_aCurrentSuggestions
.getLength()>0)
552 implChange( m_aCurrentSuggestions
.getConstArray()[0] );
554 else if (bAutoChange
)
556 implChange( m_aCurrentSuggestions
.getConstArray()[0] );
558 else if ( bAlwaysChangeThis
)
560 implChange( aChangeListPos
->second
);
562 else if ( !bAlwaysIgnoreThis
)
564 // here we need to ask the user for what to do with the text
565 // for this, allow derivees to highlight the current text unit in a possible document view
566 m_pAntiImpl
->HandleNewUnit( m_nCurrentStartIndex
- m_nReplacementBaseIndex
, m_nCurrentEndIndex
- m_nReplacementBaseIndex
);
568 DBG_ASSERT( m_pConversionDialog
, "we should always have a dialog here!" );
569 if( m_pConversionDialog
)
570 m_pConversionDialog
->SetCurrentString( sCurrentUnit
, m_aCurrentSuggestions
);
572 // do not look for the next convertible: We have to wait for the user to interactivly
573 // decide what happens with the current convertible
581 bool HangulHanjaConversion_Impl::implGetConversionDirectionForCurrentPortion( HHC::ConversionDirection
& rDirection
)
583 // - For eConvHangulHanja the direction is determined by
584 // the first encountered Korean character.
585 // - For eConvSimplifiedTraditional the conversion direction
586 // is already specified by the source language.
588 bool bSuccess
= true;
590 if (m_eConvType
== HHC::eConvHangulHanja
)
595 // get the break iterator service
596 Reference
< XBreakIterator
> xBreakIter
= BreakIterator::create( m_xContext
);
597 sal_Int32 nNextAsianScript
= xBreakIter
->beginOfScript( m_sCurrentPortion
, m_nCurrentStartIndex
, com::sun::star::i18n::ScriptType::ASIAN
);
598 if ( -1 == nNextAsianScript
)
599 nNextAsianScript
= xBreakIter
->nextScript( m_sCurrentPortion
, m_nCurrentStartIndex
, com::sun::star::i18n::ScriptType::ASIAN
);
600 if ( ( nNextAsianScript
>= m_nCurrentStartIndex
) && ( nNextAsianScript
< m_sCurrentPortion
.getLength() ) )
601 { // found asian text
603 // determine if it's Hangul
604 CharClass
aCharClassificaton( m_xContext
, LanguageTag( m_aSourceLocale
) );
605 sal_Int16 nScript
= aCharClassificaton
.getScript( m_sCurrentPortion
, sal::static_int_cast
< sal_uInt16
>(nNextAsianScript
) );
606 if ( ( UnicodeScript_kHangulJamo
== nScript
)
607 || ( UnicodeScript_kHangulCompatibilityJamo
== nScript
)
608 || ( UnicodeScript_kHangulSyllable
== nScript
)
611 rDirection
= HHC::eHangulToHanja
;
615 rDirection
= HHC::eHanjaToHangul
;
621 catch( const Exception
& )
623 OSL_FAIL( "HangulHanjaConversion_Impl::implGetConversionDirectionForCurrentPortion: caught an exception!" );
630 void HangulHanjaConversion_Impl::DoDocumentConversion( )
632 // clear the change-all list - it's to be re-initialized for every single document
635 m_aChangeList
.swap( aEmpty
);
638 // first of all, we need to guess the direction of our conversion - it is determined by the first
639 // hangul or hanja character in the first text
640 if ( !implRetrieveNextPortion() )
642 DBG_WARNING( "HangulHanjaConversion_Impl::DoDocumentConversion: why did you call me if you do have nothing to convert?" );
646 if( m_eConvType
== HHC::eConvHangulHanja
)
648 //init conversion direction from saved value
649 HHC::ConversionDirection eDirection
= HHC::eHangulToHanja
;
650 if(!implGetConversionDirectionForCurrentPortion( eDirection
))
651 // something went wrong, has already been asserted
654 if (m_pAntiImpl
->IsUseSavedConversionDirectionState())
656 m_ePrimaryConversionDirection
= m_pAntiImpl
->m_ePrimaryConversionDirectionSave
;
657 m_bTryBothDirections
= m_pAntiImpl
->m_bTryBothDirectionsSave
;
658 if( m_bTryBothDirections
)
659 m_eCurrentConversionDirection
= eDirection
;
661 m_eCurrentConversionDirection
= m_ePrimaryConversionDirection
;
665 m_ePrimaryConversionDirection
= eDirection
;
666 m_eCurrentConversionDirection
= eDirection
;
670 if (m_bIsInteractive
&& m_eConvType
== HHC::eConvHangulHanja
)
672 //always open dialog if at least having a hangul or hanja text portion
674 if(m_pAntiImpl
->IsUseSavedConversionDirectionState())
675 ContinueConversion( false );
678 m_pConversionDialog
->Execute();
679 DELETEZ( m_pConversionDialog
);
684 const bool bCompletelyDone
=
686 ContinueConversion( false );
687 DBG_ASSERT( bCompletelyDone
, "HangulHanjaConversion_Impl::DoDocumentConversion: ContinueConversion should have returned true here!" );
691 void HangulHanjaConversion_Impl::implProceed( bool _bRepeatCurrentUnit
)
693 if ( ContinueConversion( _bRepeatCurrentUnit
) )
694 { // we're done with the whole document
695 DBG_ASSERT( !m_bIsInteractive
|| m_pConversionDialog
, "HangulHanjaConversion_Impl::implProceed: we should not reach this here without dialog!" );
696 if ( m_pConversionDialog
)
697 m_pConversionDialog
->EndDialog( RET_OK
);
701 void HangulHanjaConversion_Impl::implChange( const OUString
& _rChangeInto
)
703 if( _rChangeInto
.isEmpty() )
706 // translate the conversion format into a replacement action
707 // this translation depends on whether we have a Hangul original, or a Hanja original
709 HHC::ReplacementAction
eAction( HHC::eExchange
);
711 if (m_eConvType
== HHC::eConvHangulHanja
)
713 // is the original we're about to change in Hangul?
714 const bool bOriginalIsHangul
= HHC::eHangulToHanja
== m_eCurrentConversionDirection
;
716 switch ( m_eConversionFormat
)
718 case HHC::eSimpleConversion
: eAction
= HHC::eExchange
; break;
719 case HHC::eHangulBracketed
: eAction
= bOriginalIsHangul
? HHC::eOriginalBracketed
: HHC::eReplacementBracketed
; break;
720 case HHC::eHanjaBracketed
: eAction
= bOriginalIsHangul
? HHC::eReplacementBracketed
: HHC::eOriginalBracketed
; break;
721 case HHC::eRubyHanjaAbove
: eAction
= bOriginalIsHangul
? HHC::eReplacementAbove
: HHC::eOriginalAbove
; break;
722 case HHC::eRubyHanjaBelow
: eAction
= bOriginalIsHangul
? HHC::eReplacementBelow
: HHC::eOriginalBelow
; break;
723 case HHC::eRubyHangulAbove
: eAction
= bOriginalIsHangul
? HHC::eOriginalAbove
: HHC::eReplacementAbove
; break;
724 case HHC::eRubyHangulBelow
: eAction
= bOriginalIsHangul
? HHC::eOriginalBelow
: HHC::eReplacementBelow
; break;
726 OSL_FAIL( "HangulHanjaConversion_Impl::implChange: invalid/unexpected conversion format!" );
730 // the proper indicies (the wrapper implementation needs indicies relative to the
731 // previous replacement)
732 DBG_ASSERT( ( m_nReplacementBaseIndex
<= m_nCurrentStartIndex
) && ( m_nReplacementBaseIndex
<= m_nCurrentEndIndex
),
733 "HangulHanjaConversion_Impl::implChange: invalid replacement base!" );
735 sal_Int32 nStartIndex
= m_nCurrentStartIndex
- m_nReplacementBaseIndex
;
736 sal_Int32 nEndIndex
= m_nCurrentEndIndex
- m_nReplacementBaseIndex
;
738 //remind this decision
739 m_aRecentlyUsedList
[ GetCurrentUnit() ] = _rChangeInto
;
741 LanguageType
*pNewUnitLang
= 0;
742 LanguageType nNewUnitLang
= LANGUAGE_NONE
;
743 if (m_eConvType
== HHC::eConvSimplifiedTraditional
)
745 // check if language needs to be changed
746 if ( m_pAntiImpl
->GetTargetLanguage() == LANGUAGE_CHINESE_TRADITIONAL
&&
747 !m_pAntiImpl
->IsTraditional( m_nCurrentPortionLang
))
748 nNewUnitLang
= LANGUAGE_CHINESE_TRADITIONAL
;
749 else if ( m_pAntiImpl
->GetTargetLanguage() == LANGUAGE_CHINESE_SIMPLIFIED
&&
750 !m_pAntiImpl
->IsSimplified( m_nCurrentPortionLang
))
751 nNewUnitLang
= LANGUAGE_CHINESE_SIMPLIFIED
;
752 if (nNewUnitLang
!= LANGUAGE_NONE
)
753 pNewUnitLang
= &nNewUnitLang
;
756 // according to FT we should not (yet) bother about Hangul/Hanja conversion here
758 // aOffsets is needed in ReplaceUnit below in order to to find out
759 // exactly which characters are really changed in order to keep as much
760 // from attributation for the text as possible.
761 Sequence
< sal_Int32
> aOffsets
;
762 Reference
< XExtendedTextConversion
> xExtConverter( m_xConverter
, UNO_QUERY
);
763 if (m_eConvType
== HHC::eConvSimplifiedTraditional
&& xExtConverter
.is())
767 xExtConverter
->getConversionWithOffset(
769 m_nCurrentStartIndex
,
770 m_nCurrentEndIndex
- m_nCurrentStartIndex
,
772 m_nCurrentConversionType
,
773 m_nCurrentConversionOption
,
777 catch( const Exception
& )
779 OSL_FAIL( "HangulHanjaConversion_Impl::implChange: caught unexpected exception!" );
784 // do the replacement
785 m_pAntiImpl
->ReplaceUnit( nStartIndex
, nEndIndex
, m_sCurrentPortion
,
786 _rChangeInto
, aOffsets
, eAction
, pNewUnitLang
);
789 // adjust the replacement base
790 m_nReplacementBaseIndex
= m_nCurrentEndIndex
;
793 void HangulHanjaConversion_Impl::implReadOptionsFromConfiguration()
795 SvtLinguConfig aLngCfg
;
796 aLngCfg
.GetProperty( UPH_IS_IGNORE_POST_POSITIONAL_WORD
) >>= m_bIgnorePostPositionalWord
;
797 aLngCfg
.GetProperty( UPH_IS_SHOW_ENTRIES_RECENTLY_USED_FIRST
) >>= m_bShowRecentlyUsedFirst
;
798 aLngCfg
.GetProperty( UPH_IS_AUTO_REPLACE_UNIQUE_ENTRIES
) >>= m_bAutoReplaceUnique
;
801 void HangulHanjaConversion_Impl::implUpdateData()
803 implReadOptionsFromConfiguration();
804 implUpdateSuggestions();
806 if(m_pConversionDialog
)
808 OUString
sCurrentUnit( GetCurrentUnit() );
810 m_pConversionDialog
->SetCurrentString( sCurrentUnit
, m_aCurrentSuggestions
);
811 m_pConversionDialog
->FocusSuggestion();
814 m_pAntiImpl
->HandleNewUnit( m_nCurrentStartIndex
- m_nReplacementBaseIndex
, m_nCurrentEndIndex
- m_nReplacementBaseIndex
);
817 IMPL_LINK_NOARG(HangulHanjaConversion_Impl
, OnOptionsChanged
)
819 //options and dictionaries might have been changed
820 //-> update our internal settings and the dialog
826 IMPL_LINK_NOARG(HangulHanjaConversion_Impl
, OnIgnore
)
828 // simply ignore, and proceed
829 implProceed( false );
833 IMPL_LINK_NOARG(HangulHanjaConversion_Impl
, OnIgnoreAll
)
835 DBG_ASSERT( m_pConversionDialog
, "HangulHanjaConversion_Impl::OnIgnoreAll: no dialog! How this?" );
837 if ( m_pConversionDialog
)
839 String sCurrentUnit
= m_pConversionDialog
->GetCurrentString();
840 DBG_ASSERT( m_sIgnoreList
.end() == m_sIgnoreList
.find( sCurrentUnit
),
841 "HangulHanjaConversion_Impl, OnIgnoreAll: shouldn't this have been ignored before" );
843 // put into the "ignore all" list
844 m_sIgnoreList
.insert( sCurrentUnit
);
847 implProceed( false );
853 IMPL_LINK_NOARG(HangulHanjaConversion_Impl
, OnChange
)
856 DBG_ASSERT( m_pConversionDialog
, "we should always have a dialog here!" );
857 if( m_pConversionDialog
)
858 implChange( m_pConversionDialog
->GetCurrentSuggestion( ) );
860 implProceed( false );
865 IMPL_LINK_NOARG(HangulHanjaConversion_Impl
, OnChangeAll
)
867 DBG_ASSERT( m_pConversionDialog
, "HangulHanjaConversion_Impl::OnChangeAll: no dialog! How this?" );
868 if ( m_pConversionDialog
)
870 OUString
sCurrentUnit( m_pConversionDialog
->GetCurrentString() );
871 OUString
sChangeInto( m_pConversionDialog
->GetCurrentSuggestion( ) );
873 if( !sChangeInto
.isEmpty() )
875 // change the current occurrence
876 implChange( sChangeInto
);
878 // put into the "change all" list
879 m_aChangeList
.insert( StringMap::value_type( sCurrentUnit
, sChangeInto
) );
883 implProceed( false );
889 IMPL_LINK( HangulHanjaConversion_Impl
, OnByCharClicked
, CheckBox
*, _pBox
)
891 m_bByCharacter
= _pBox
->IsChecked();
893 // continue conversion, without advancing to the next unit, but instead continuing with the current unit
898 IMPL_LINK_NOARG(HangulHanjaConversion_Impl
, OnConversionTypeChanged
)
900 DBG_ASSERT( m_pConversionDialog
, "we should always have a dialog here!" );
901 if( m_pConversionDialog
)
902 m_eConversionFormat
= m_pConversionDialog
->GetConversionFormat( );
906 IMPL_LINK_NOARG(HangulHanjaConversion_Impl
, OnFind
)
908 DBG_ASSERT( m_pConversionDialog
, "HangulHanjaConversion_Impl::OnFind: where did this come from?" );
909 if ( m_pConversionDialog
)
913 OUString
sNewOriginal( m_pConversionDialog
->GetCurrentSuggestion( ) );
914 Sequence
< OUString
> aSuggestions
;
916 DBG_ASSERT( m_xConverter
.is(), "HangulHanjaConversion_Impl::OnFind: no converter!" );
917 TextConversionResult aToHanja
= m_xConverter
->getConversions(
919 0, sNewOriginal
.getLength(),
921 TextConversionType::TO_HANJA
,
922 TextConversionOption::NONE
924 TextConversionResult aToHangul
= m_xConverter
->getConversions(
926 0, sNewOriginal
.getLength(),
928 TextConversionType::TO_HANGUL
,
929 TextConversionOption::NONE
932 bool bHaveToHanja
= ( aToHanja
.Boundary
.startPos
< aToHanja
.Boundary
.endPos
);
933 bool bHaveToHangul
= ( aToHangul
.Boundary
.startPos
< aToHangul
.Boundary
.endPos
);
935 TextConversionResult
* pResult
= NULL
;
936 if ( bHaveToHanja
&& bHaveToHangul
)
937 { // it found convertibles in both directions -> use the first
938 if ( aToHangul
.Boundary
.startPos
< aToHanja
.Boundary
.startPos
)
939 pResult
= &aToHangul
;
943 else if ( bHaveToHanja
)
944 { // only found toHanja
948 { // only found toHangul
949 pResult
= &aToHangul
;
952 aSuggestions
= pResult
->Candidates
;
954 m_pConversionDialog
->SetCurrentString( sNewOriginal
, aSuggestions
, false );
955 m_pConversionDialog
->FocusSuggestion();
957 catch( const Exception
& )
959 OSL_FAIL( "HangulHanjaConversion_Impl::OnFind: caught an exception!" );
965 bool HangulHanjaConversion::m_bUseSavedValues
= false;
966 bool HangulHanjaConversion::m_bTryBothDirectionsSave
= false;
967 HHC::ConversionDirection
HangulHanjaConversion::m_ePrimaryConversionDirectionSave
= HHC::eHangulToHanja
;
969 HangulHanjaConversion::HangulHanjaConversion( Window
* _pUIParent
,
970 const Reference
< XComponentContext
>& rxContext
,
971 const Locale
& _rSourceLocale
, const Locale
& _rTargetLocale
,
972 const Font
* _pTargetFont
,
973 sal_Int32 _nOptions
, bool _bIsInteractive
)
974 :m_pImpl( new HangulHanjaConversion_Impl( _pUIParent
, rxContext
, _rSourceLocale
, _rTargetLocale
, _pTargetFont
, _nOptions
, _bIsInteractive
, this ) )
978 HangulHanjaConversion::~HangulHanjaConversion( )
982 void HangulHanjaConversion::SetUseSavedConversionDirectionState( bool bVal
)
984 m_bUseSavedValues
= bVal
;
987 bool HangulHanjaConversion::IsUseSavedConversionDirectionState()
989 return m_bUseSavedValues
;
992 LanguageType
HangulHanjaConversion::GetSourceLanguage( ) const
994 return m_pImpl
->GetSourceLang();
997 LanguageType
HangulHanjaConversion::GetTargetLanguage( ) const
999 return m_pImpl
->GetTargetLang();
1002 const Font
* HangulHanjaConversion::GetTargetFont( ) const
1004 return m_pImpl
->GetTargetFont();
1007 sal_Int32
HangulHanjaConversion::GetConversionOptions( ) const
1009 return m_pImpl
->GetConvOptions();
1012 bool HangulHanjaConversion::IsInteractive( ) const
1014 return m_pImpl
->IsInteractive();
1017 void HangulHanjaConversion::ConvertDocument()
1019 if ( m_pImpl
->IsValid() )
1020 m_pImpl
->DoDocumentConversion( );
1025 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */