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
52 using namespace ::com::sun::star
;
53 using namespace ::com::sun::star::uno
;
54 using namespace ::com::sun::star::i18n
;
55 using namespace ::com::sun::star::i18n::TextConversionOption
;
56 using namespace ::com::sun::star::i18n::TextConversionType
;
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 VclPtr
<vcl::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 lang::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 vcl::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(
122 vcl::Window
* _pUIParent
,
123 const Reference
< XComponentContext
>& rxContext
,
124 const lang::Locale
& _rSourceLocale
,
125 const lang::Locale
& _rTargetLocale
,
126 const vcl::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 vcl::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( vcl::Window
* _pUIParent
,
233 const Reference
< XComponentContext
>& rxContext
,
234 const lang::Locale
& _rSourceLocale
,
235 const lang::Locale
& _rTargetLocale
,
236 const vcl::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::convertToLanguageType( _rSourceLocale
) )
245 , m_nTargetLang( LanguageTag::convertToLanguageType( _rTargetLocale
) )
246 , m_pTargetFont( _pTargetFont
)
247 , m_nConvOptions(_nOptions
)
248 , m_bIsInteractive( _bIsInteractive
)
249 , m_pAntiImpl( _pAntiImpl
)
250 , m_bByCharacter((_nOptions
& CHARACTER_BY_CHARACTER
) != 0)
251 , m_eConversionFormat( HHC::eSimpleConversion
)
252 , m_ePrimaryConversionDirection( HHC::eHangulToHanja
) // used for eConvHangulHanja
253 , m_eCurrentConversionDirection( HHC::eHangulToHanja
) // used for eConvHangulHanja
254 , m_nCurrentPortionLang( LANGUAGE_NONE
)
255 , m_nCurrentStartIndex( 0 )
256 , m_nCurrentEndIndex( 0 )
257 , m_nReplacementBaseIndex( 0 )
258 , m_nCurrentConversionOption( TextConversionOption::NONE
)
259 , m_nCurrentConversionType( -1 ) // not yet known
260 , m_bTryBothDirections( true )
262 implReadOptionsFromConfiguration();
264 DBG_ASSERT( m_xContext
.is(), "HangulHanjaConversion_Impl::HangulHanjaConversion_Impl: no ORB!" );
266 // determine conversion type
267 if (m_nSourceLang
== LANGUAGE_KOREAN
&& m_nTargetLang
== LANGUAGE_KOREAN
)
268 m_eConvType
= HHC::eConvHangulHanja
;
269 else if ( (m_nSourceLang
== LANGUAGE_CHINESE_TRADITIONAL
&& m_nTargetLang
== LANGUAGE_CHINESE_SIMPLIFIED
) ||
270 (m_nSourceLang
== LANGUAGE_CHINESE_SIMPLIFIED
&& m_nTargetLang
== LANGUAGE_CHINESE_TRADITIONAL
) )
271 m_eConvType
= HHC::eConvSimplifiedTraditional
;
274 m_eConvType
= HHC::eConvHangulHanja
;
275 OSL_FAIL( "failed to determine conversion type from languages" );
278 m_xConverter
= TextConversion::create( m_xContext
);
281 void HangulHanjaConversion_Impl::createDialog()
283 DBG_ASSERT( m_bIsInteractive
, "createDialog when the conversion should not be interactive?" );
284 if ( m_bIsInteractive
&& !m_pConversionDialog
)
286 EditAbstractDialogFactory
* pFact
= EditAbstractDialogFactory::Create();
289 m_pConversionDialog
= pFact
->CreateHangulHanjaConversionDialog(m_pUIParent
, m_ePrimaryConversionDirection
);
290 DBG_ASSERT(m_pConversionDialog
, "Dialog creation failed!");
292 m_pConversionDialog
->EnableRubySupport( m_pAntiImpl
->HasRubySupport() );
294 m_pConversionDialog
->SetByCharacter( m_bByCharacter
);
295 m_pConversionDialog
->SetConversionFormat( m_eConversionFormat
);
296 m_pConversionDialog
->SetConversionDirectionState( m_bTryBothDirections
, m_ePrimaryConversionDirection
);
299 m_pConversionDialog
->SetOptionsChangedHdl( LINK( this, HangulHanjaConversion_Impl
, OnOptionsChanged
) );
300 m_pConversionDialog
->SetIgnoreHdl( LINK( this, HangulHanjaConversion_Impl
, OnIgnore
) );
301 m_pConversionDialog
->SetIgnoreAllHdl( LINK( this, HangulHanjaConversion_Impl
, OnIgnoreAll
) );
302 m_pConversionDialog
->SetChangeHdl( LINK( this, HangulHanjaConversion_Impl
, OnChange
) );
303 m_pConversionDialog
->SetChangeAllHdl( LINK( this, HangulHanjaConversion_Impl
, OnChangeAll
) );
304 m_pConversionDialog
->SetClickByCharacterHdl( LINK( this, HangulHanjaConversion_Impl
, OnByCharClicked
) );
305 m_pConversionDialog
->SetConversionFormatChangedHdl( LINK( this, HangulHanjaConversion_Impl
, OnConversionTypeChanged
) );
306 m_pConversionDialog
->SetFindHdl( LINK( this, HangulHanjaConversion_Impl
, OnFind
) );
311 sal_Int16
HangulHanjaConversion_Impl::implGetConversionType( bool bSwitchDirection
) const
313 sal_Int16 nConversionType
= -1;
314 if (m_eConvType
== HHC::eConvHangulHanja
)
315 nConversionType
= ( HHC::eHangulToHanja
== m_eCurrentConversionDirection
&& !bSwitchDirection
) ? TO_HANJA
: TO_HANGUL
;
316 else if (m_eConvType
== HHC::eConvSimplifiedTraditional
)
317 nConversionType
= LANGUAGE_CHINESE_SIMPLIFIED
== m_nTargetLang
? TO_SCHINESE
: TO_TCHINESE
;
318 DBG_ASSERT( nConversionType
!= -1, "unexpected conversion type" );
319 return nConversionType
;
322 bool HangulHanjaConversion_Impl::implUpdateSuggestions( bool _bAllowSearchNextConvertibleText
, const sal_Int32 _nStartAt
)
324 // parameters for the converter
325 sal_Int32 nStartSearch
= m_nCurrentStartIndex
;
326 if( _bAllowSearchNextConvertibleText
)
327 nStartSearch
= _nStartAt
;
329 sal_Int32 nLength
= m_sCurrentPortion
.getLength() - nStartSearch
;
330 m_nCurrentConversionType
= implGetConversionType();
331 m_nCurrentConversionOption
= IsByCharacter() ? CHARACTER_BY_CHARACTER
: css::i18n::TextConversionOption::NONE
;
332 if( m_bIgnorePostPositionalWord
)
333 m_nCurrentConversionOption
= m_nCurrentConversionOption
| IGNORE_POST_POSITIONAL_WORD
;
335 // no need to check both directions for chinese conversion (saves time)
336 if (m_eConvType
== HHC::eConvSimplifiedTraditional
)
337 m_bTryBothDirections
= false;
339 bool bFoundAny
= true;
342 TextConversionResult aResult
= m_xConverter
->getConversions(
347 m_nCurrentConversionType
,
348 m_nCurrentConversionOption
350 const bool bFoundPrimary
= aResult
.Boundary
.startPos
< aResult
.Boundary
.endPos
;
351 bFoundAny
= bFoundPrimary
;
353 if ( m_bTryBothDirections
)
354 { // see if we find another convertible when assuming the other direction
355 TextConversionResult aSecondResult
= m_xConverter
->getConversions(
360 implGetConversionType( true ), // switched!
361 m_nCurrentConversionOption
363 if ( aSecondResult
.Boundary
.startPos
< aSecondResult
.Boundary
.endPos
)
364 { // we indeed found such a convertible
366 // in case the first attempt (with the original conversion direction)
367 // didn't find anything
369 // or if the second location is _before_ the first one
370 || ( aSecondResult
.Boundary
.startPos
< aResult
.Boundary
.startPos
)
373 // then use the second finding
374 aResult
= aSecondResult
;
376 // our current conversion direction changed now
377 m_eCurrentConversionDirection
= ( HHC::eHangulToHanja
== m_eCurrentConversionDirection
)
378 ? HHC::eHanjaToHangul
: HHC::eHangulToHanja
;
384 if( _bAllowSearchNextConvertibleText
)
386 //this might change the current position
387 m_aCurrentSuggestions
= aResult
.Candidates
;
388 m_nCurrentStartIndex
= aResult
.Boundary
.startPos
;
389 m_nCurrentEndIndex
= aResult
.Boundary
.endPos
;
393 //the change of starting position is not allowed
394 if( m_nCurrentStartIndex
== aResult
.Boundary
.startPos
395 && aResult
.Boundary
.endPos
!= aResult
.Boundary
.startPos
)
397 m_aCurrentSuggestions
= aResult
.Candidates
;
398 m_nCurrentEndIndex
= aResult
.Boundary
.endPos
;
402 m_aCurrentSuggestions
.realloc( 0 );
403 if( m_sCurrentPortion
.getLength() >= m_nCurrentStartIndex
+1 )
404 m_nCurrentEndIndex
= m_nCurrentStartIndex
+1;
408 //put recently used string to front:
409 if( m_bShowRecentlyUsedFirst
&& m_aCurrentSuggestions
.getLength()>1 )
411 OUString
sCurrentUnit( GetCurrentUnit() );
412 StringMap::const_iterator aRecentlyUsed
= m_aRecentlyUsedList
.find( sCurrentUnit
);
413 bool bUsedBefore
= aRecentlyUsed
!= m_aRecentlyUsedList
.end();
414 if( bUsedBefore
&& m_aCurrentSuggestions
[0] != aRecentlyUsed
->second
)
416 sal_Int32 nCount
= m_aCurrentSuggestions
.getLength();
417 Sequence
< OUString
> aTmp(nCount
);
418 aTmp
[0]=aRecentlyUsed
->second
;
420 for( sal_Int32 n
=1; n
<nCount
; n
++)//we had 0 already
422 if( nDiff
&& m_aCurrentSuggestions
[n
-nDiff
]==aRecentlyUsed
->second
)
424 aTmp
[n
]=m_aCurrentSuggestions
[n
-nDiff
];
426 m_aCurrentSuggestions
= aTmp
;
430 catch( const Exception
& )
432 OSL_FAIL( "HangulHanjaConversion_Impl::implNextConvertibleUnit: caught an exception!" );
434 //!!! at least we want to move on in the text in order
435 //!!! to avoid an endless loop...
441 bool HangulHanjaConversion_Impl::implNextConvertibleUnit( const sal_Int32 _nStartAt
)
443 m_aCurrentSuggestions
.realloc( 0 );
445 // ask the TextConversion service for the next convertible piece of text
447 // get current values from dialog
448 if( m_eConvType
== HHC::eConvHangulHanja
&& m_pConversionDialog
)
450 m_bTryBothDirections
= m_pConversionDialog
->GetUseBothDirections();
451 HHC::ConversionDirection eDialogDirection
= HHC::eHangulToHanja
;
452 eDialogDirection
= m_pConversionDialog
->GetDirection( eDialogDirection
);
454 if( !m_bTryBothDirections
&& eDialogDirection
!= m_eCurrentConversionDirection
)
456 m_eCurrentConversionDirection
= eDialogDirection
;
459 // save currently used value for possible later use
460 m_pAntiImpl
->m_bTryBothDirectionsSave
= m_bTryBothDirections
;
461 m_pAntiImpl
->m_ePrimaryConversionDirectionSave
= m_eCurrentConversionDirection
;
464 bool bFoundAny
= implUpdateSuggestions( true, _nStartAt
);
467 (m_nCurrentStartIndex
< m_sCurrentPortion
.getLength());
470 bool HangulHanjaConversion_Impl::implRetrieveNextPortion( )
472 const bool bAllowImplicitChanges
= m_eConvType
== HHC::eConvSimplifiedTraditional
;
474 m_sCurrentPortion
.clear();
475 m_nCurrentPortionLang
= LANGUAGE_NONE
;
476 m_pAntiImpl
->GetNextPortion( m_sCurrentPortion
, m_nCurrentPortionLang
, bAllowImplicitChanges
);
477 m_nReplacementBaseIndex
= 0;
478 m_nCurrentStartIndex
= m_nCurrentEndIndex
= 0;
480 bool bRet
= !m_sCurrentPortion
.isEmpty();
482 if (m_eConvType
== HHC::eConvHangulHanja
&& m_bTryBothDirections
)
483 implGetConversionDirectionForCurrentPortion( m_eCurrentConversionDirection
);
488 bool HangulHanjaConversion_Impl::implNextConvertible( bool _bRepeatUnit
)
490 if ( _bRepeatUnit
|| ( m_nCurrentEndIndex
< m_sCurrentPortion
.getLength() ) )
492 if ( implNextConvertibleUnit(
494 ? m_nCurrentStartIndex
500 // no convertible text in the current portion anymore
501 // -> advance to the next portion
505 if ( implRetrieveNextPortion( ) )
506 { // there is a next portion
507 // -> find the next convertible unit in the current portion
508 if ( implNextConvertibleUnit( 0 ) )
512 while ( !m_sCurrentPortion
.isEmpty() );
518 OUString
HangulHanjaConversion_Impl::GetCurrentUnit() const
520 DBG_ASSERT( m_nCurrentStartIndex
< m_sCurrentPortion
.getLength(),
521 "HangulHanjaConversion_Impl::GetCurrentUnit: invalid index into current portion!" );
522 DBG_ASSERT( m_nCurrentEndIndex
<= m_sCurrentPortion
.getLength(),
523 "HangulHanjaConversion_Impl::GetCurrentUnit: invalid index into current portion!" );
524 DBG_ASSERT( m_nCurrentStartIndex
<= m_nCurrentEndIndex
,
525 "HangulHanjaConversion_Impl::GetCurrentUnit: invalid interval!" );
527 OUString sCurrentUnit
= m_sCurrentPortion
.copy( m_nCurrentStartIndex
, m_nCurrentEndIndex
- m_nCurrentStartIndex
);
531 bool HangulHanjaConversion_Impl::ContinueConversion( bool _bRepeatCurrentUnit
)
533 while ( implNextConvertible( _bRepeatCurrentUnit
) )
535 OUString
sCurrentUnit( GetCurrentUnit() );
537 // do we need to ignore it?
538 const bool bAlwaysIgnoreThis
= m_sIgnoreList
.end() != m_sIgnoreList
.find( sCurrentUnit
);
540 // do we need to change it?
541 StringMap::const_iterator aChangeListPos
= m_aChangeList
.find( sCurrentUnit
);
542 const bool bAlwaysChangeThis
= m_aChangeList
.end() != aChangeListPos
;
544 // do we automatically change this?
545 const bool bAutoChange
= m_bAutoReplaceUnique
&& m_aCurrentSuggestions
.getLength() == 1;
547 if (!m_bIsInteractive
)
549 // silent conversion (e.g. for simplified/traditional Chinese)...
550 if(m_aCurrentSuggestions
.getLength()>0)
551 implChange( m_aCurrentSuggestions
.getConstArray()[0] );
553 else if (bAutoChange
)
555 implChange( m_aCurrentSuggestions
.getConstArray()[0] );
557 else if ( bAlwaysChangeThis
)
559 implChange( aChangeListPos
->second
);
561 else if ( !bAlwaysIgnoreThis
)
563 // here we need to ask the user for what to do with the text
564 // for this, allow derivees to highlight the current text unit in a possible document view
565 m_pAntiImpl
->HandleNewUnit( m_nCurrentStartIndex
- m_nReplacementBaseIndex
, m_nCurrentEndIndex
- m_nReplacementBaseIndex
);
567 DBG_ASSERT( m_pConversionDialog
, "we should always have a dialog here!" );
568 if( m_pConversionDialog
)
569 m_pConversionDialog
->SetCurrentString( sCurrentUnit
, m_aCurrentSuggestions
);
571 // do not look for the next convertible: We have to wait for the user to interactivly
572 // decide what happens with the current convertible
580 bool HangulHanjaConversion_Impl::implGetConversionDirectionForCurrentPortion( HHC::ConversionDirection
& rDirection
)
582 // - For eConvHangulHanja the direction is determined by
583 // the first encountered Korean character.
584 // - For eConvSimplifiedTraditional the conversion direction
585 // is already specified by the source language.
587 bool bSuccess
= true;
589 if (m_eConvType
== HHC::eConvHangulHanja
)
594 // get the break iterator service
595 Reference
< XBreakIterator
> xBreakIter
= i18n::BreakIterator::create( m_xContext
);
596 sal_Int32 nNextAsianScript
= xBreakIter
->beginOfScript( m_sCurrentPortion
, m_nCurrentStartIndex
, com::sun::star::i18n::ScriptType::ASIAN
);
597 if ( -1 == nNextAsianScript
)
598 nNextAsianScript
= xBreakIter
->nextScript( m_sCurrentPortion
, m_nCurrentStartIndex
, com::sun::star::i18n::ScriptType::ASIAN
);
599 if ( ( nNextAsianScript
>= m_nCurrentStartIndex
) && ( nNextAsianScript
< m_sCurrentPortion
.getLength() ) )
600 { // found asian text
602 // determine if it's Hangul
603 CharClass
aCharClassificaton( m_xContext
, LanguageTag( m_aSourceLocale
) );
604 sal_Int16 nScript
= aCharClassificaton
.getScript( m_sCurrentPortion
, sal::static_int_cast
< sal_uInt16
>(nNextAsianScript
) );
605 if ( ( UnicodeScript_kHangulJamo
== nScript
)
606 || ( UnicodeScript_kHangulCompatibilityJamo
== nScript
)
607 || ( UnicodeScript_kHangulSyllable
== nScript
)
610 rDirection
= HHC::eHangulToHanja
;
614 rDirection
= HHC::eHanjaToHangul
;
620 catch( const Exception
& )
622 OSL_FAIL( "HangulHanjaConversion_Impl::implGetConversionDirectionForCurrentPortion: caught an exception!" );
629 void HangulHanjaConversion_Impl::DoDocumentConversion( )
631 // clear the change-all list - it's to be re-initialized for every single document
634 m_aChangeList
.swap( aEmpty
);
637 // first of all, we need to guess the direction of our conversion - it is determined by the first
638 // hangul or hanja character in the first text
639 if ( !implRetrieveNextPortion() )
641 DBG_WARNING( "HangulHanjaConversion_Impl::DoDocumentConversion: why did you call me if you do have nothing to convert?" );
645 if( m_eConvType
== HHC::eConvHangulHanja
)
647 //init conversion direction from saved value
648 HHC::ConversionDirection eDirection
= HHC::eHangulToHanja
;
649 if(!implGetConversionDirectionForCurrentPortion( eDirection
))
650 // something went wrong, has already been asserted
653 if (HangulHanjaConversion::IsUseSavedConversionDirectionState())
655 m_ePrimaryConversionDirection
= m_pAntiImpl
->m_ePrimaryConversionDirectionSave
;
656 m_bTryBothDirections
= m_pAntiImpl
->m_bTryBothDirectionsSave
;
657 if( m_bTryBothDirections
)
658 m_eCurrentConversionDirection
= eDirection
;
660 m_eCurrentConversionDirection
= m_ePrimaryConversionDirection
;
664 m_ePrimaryConversionDirection
= eDirection
;
665 m_eCurrentConversionDirection
= eDirection
;
669 if (m_bIsInteractive
&& m_eConvType
== HHC::eConvHangulHanja
)
671 //always open dialog if at least having a hangul or hanja text portion
673 if(HangulHanjaConversion::IsUseSavedConversionDirectionState())
674 ContinueConversion( false );
677 m_pConversionDialog
->Execute();
678 DELETEZ( m_pConversionDialog
);
683 const bool bCompletelyDone
=
685 ContinueConversion( false );
686 DBG_ASSERT( bCompletelyDone
, "HangulHanjaConversion_Impl::DoDocumentConversion: ContinueConversion should have returned true here!" );
690 void HangulHanjaConversion_Impl::implProceed( bool _bRepeatCurrentUnit
)
692 if ( ContinueConversion( _bRepeatCurrentUnit
) )
693 { // we're done with the whole document
694 DBG_ASSERT( !m_bIsInteractive
|| m_pConversionDialog
, "HangulHanjaConversion_Impl::implProceed: we should not reach this here without dialog!" );
695 if ( m_pConversionDialog
)
696 m_pConversionDialog
->EndDialog( RET_OK
);
700 void HangulHanjaConversion_Impl::implChange( const OUString
& _rChangeInto
)
702 if( _rChangeInto
.isEmpty() )
705 // translate the conversion format into a replacement action
706 // this translation depends on whether we have a Hangul original, or a Hanja original
708 HHC::ReplacementAction
eAction( HHC::eExchange
);
710 if (m_eConvType
== HHC::eConvHangulHanja
)
712 // is the original we're about to change in Hangul?
713 const bool bOriginalIsHangul
= HHC::eHangulToHanja
== m_eCurrentConversionDirection
;
715 switch ( m_eConversionFormat
)
717 case HHC::eSimpleConversion
: eAction
= HHC::eExchange
; break;
718 case HHC::eHangulBracketed
: eAction
= bOriginalIsHangul
? HHC::eOriginalBracketed
: HHC::eReplacementBracketed
; break;
719 case HHC::eHanjaBracketed
: eAction
= bOriginalIsHangul
? HHC::eReplacementBracketed
: HHC::eOriginalBracketed
; break;
720 case HHC::eRubyHanjaAbove
: eAction
= bOriginalIsHangul
? HHC::eReplacementAbove
: HHC::eOriginalAbove
; break;
721 case HHC::eRubyHanjaBelow
: eAction
= bOriginalIsHangul
? HHC::eReplacementBelow
: HHC::eOriginalBelow
; break;
722 case HHC::eRubyHangulAbove
: eAction
= bOriginalIsHangul
? HHC::eOriginalAbove
: HHC::eReplacementAbove
; break;
723 case HHC::eRubyHangulBelow
: eAction
= bOriginalIsHangul
? HHC::eOriginalBelow
: HHC::eReplacementBelow
; break;
725 OSL_FAIL( "HangulHanjaConversion_Impl::implChange: invalid/unexpected conversion format!" );
729 // the proper indices (the wrapper implementation needs indices relative to the
730 // previous replacement)
731 DBG_ASSERT( ( m_nReplacementBaseIndex
<= m_nCurrentStartIndex
) && ( m_nReplacementBaseIndex
<= m_nCurrentEndIndex
),
732 "HangulHanjaConversion_Impl::implChange: invalid replacement base!" );
734 sal_Int32 nStartIndex
= m_nCurrentStartIndex
- m_nReplacementBaseIndex
;
735 sal_Int32 nEndIndex
= m_nCurrentEndIndex
- m_nReplacementBaseIndex
;
737 //remind this decision
738 m_aRecentlyUsedList
[ GetCurrentUnit() ] = _rChangeInto
;
740 LanguageType
*pNewUnitLang
= 0;
741 LanguageType nNewUnitLang
= LANGUAGE_NONE
;
742 if (m_eConvType
== HHC::eConvSimplifiedTraditional
)
744 // check if language needs to be changed
745 if ( m_pAntiImpl
->GetTargetLanguage() == LANGUAGE_CHINESE_TRADITIONAL
&&
746 !HangulHanjaConversion::IsTraditional( m_nCurrentPortionLang
))
747 nNewUnitLang
= LANGUAGE_CHINESE_TRADITIONAL
;
748 else if ( m_pAntiImpl
->GetTargetLanguage() == LANGUAGE_CHINESE_SIMPLIFIED
&&
749 !HangulHanjaConversion::IsSimplified( m_nCurrentPortionLang
))
750 nNewUnitLang
= LANGUAGE_CHINESE_SIMPLIFIED
;
751 if (nNewUnitLang
!= LANGUAGE_NONE
)
752 pNewUnitLang
= &nNewUnitLang
;
755 // according to FT we should not (yet) bother about Hangul/Hanja conversion here
757 // aOffsets is needed in ReplaceUnit below in order to find out
758 // exactly which characters are really changed in order to keep as much
759 // from attributation for the text as possible.
760 Sequence
< sal_Int32
> aOffsets
;
761 Reference
< XExtendedTextConversion
> xExtConverter( m_xConverter
, UNO_QUERY
);
762 if (m_eConvType
== HHC::eConvSimplifiedTraditional
&& xExtConverter
.is())
766 xExtConverter
->getConversionWithOffset(
768 m_nCurrentStartIndex
,
769 m_nCurrentEndIndex
- m_nCurrentStartIndex
,
771 m_nCurrentConversionType
,
772 m_nCurrentConversionOption
,
776 catch( const Exception
& )
778 OSL_FAIL( "HangulHanjaConversion_Impl::implChange: caught unexpected exception!" );
783 // do the replacement
784 m_pAntiImpl
->ReplaceUnit( nStartIndex
, nEndIndex
, m_sCurrentPortion
,
785 _rChangeInto
, aOffsets
, eAction
, pNewUnitLang
);
788 // adjust the replacement base
789 m_nReplacementBaseIndex
= m_nCurrentEndIndex
;
792 void HangulHanjaConversion_Impl::implReadOptionsFromConfiguration()
794 SvtLinguConfig aLngCfg
;
795 aLngCfg
.GetProperty( UPH_IS_IGNORE_POST_POSITIONAL_WORD
) >>= m_bIgnorePostPositionalWord
;
796 aLngCfg
.GetProperty( UPH_IS_SHOW_ENTRIES_RECENTLY_USED_FIRST
) >>= m_bShowRecentlyUsedFirst
;
797 aLngCfg
.GetProperty( UPH_IS_AUTO_REPLACE_UNIQUE_ENTRIES
) >>= m_bAutoReplaceUnique
;
800 void HangulHanjaConversion_Impl::implUpdateData()
802 implReadOptionsFromConfiguration();
803 implUpdateSuggestions();
805 if(m_pConversionDialog
)
807 OUString
sCurrentUnit( GetCurrentUnit() );
809 m_pConversionDialog
->SetCurrentString( sCurrentUnit
, m_aCurrentSuggestions
);
810 m_pConversionDialog
->FocusSuggestion();
813 m_pAntiImpl
->HandleNewUnit( m_nCurrentStartIndex
- m_nReplacementBaseIndex
, m_nCurrentEndIndex
- m_nReplacementBaseIndex
);
816 IMPL_LINK_NOARG(HangulHanjaConversion_Impl
, OnOptionsChanged
)
818 //options and dictionaries might have been changed
819 //-> update our internal settings and the dialog
825 IMPL_LINK_NOARG(HangulHanjaConversion_Impl
, OnIgnore
)
827 // simply ignore, and proceed
828 implProceed( false );
832 IMPL_LINK_NOARG(HangulHanjaConversion_Impl
, OnIgnoreAll
)
834 DBG_ASSERT( m_pConversionDialog
, "HangulHanjaConversion_Impl::OnIgnoreAll: no dialog! How this?" );
836 if ( m_pConversionDialog
)
838 OUString sCurrentUnit
= m_pConversionDialog
->GetCurrentString();
839 DBG_ASSERT( m_sIgnoreList
.end() == m_sIgnoreList
.find( sCurrentUnit
),
840 "HangulHanjaConversion_Impl, OnIgnoreAll: shouldn't this have been ignored before" );
842 // put into the "ignore all" list
843 m_sIgnoreList
.insert( sCurrentUnit
);
846 implProceed( false );
852 IMPL_LINK_NOARG(HangulHanjaConversion_Impl
, OnChange
)
855 DBG_ASSERT( m_pConversionDialog
, "we should always have a dialog here!" );
856 if( m_pConversionDialog
)
857 implChange( m_pConversionDialog
->GetCurrentSuggestion( ) );
859 implProceed( false );
864 IMPL_LINK_NOARG(HangulHanjaConversion_Impl
, OnChangeAll
)
866 DBG_ASSERT( m_pConversionDialog
, "HangulHanjaConversion_Impl::OnChangeAll: no dialog! How this?" );
867 if ( m_pConversionDialog
)
869 OUString
sCurrentUnit( m_pConversionDialog
->GetCurrentString() );
870 OUString
sChangeInto( m_pConversionDialog
->GetCurrentSuggestion( ) );
872 if( !sChangeInto
.isEmpty() )
874 // change the current occurrence
875 implChange( sChangeInto
);
877 // put into the "change all" list
878 m_aChangeList
.insert( StringMap::value_type( sCurrentUnit
, sChangeInto
) );
882 implProceed( false );
888 IMPL_LINK( HangulHanjaConversion_Impl
, OnByCharClicked
, CheckBox
*, _pBox
)
890 m_bByCharacter
= _pBox
->IsChecked();
892 // continue conversion, without advancing to the next unit, but instead continuing with the current unit
897 IMPL_LINK_NOARG(HangulHanjaConversion_Impl
, OnConversionTypeChanged
)
899 DBG_ASSERT( m_pConversionDialog
, "we should always have a dialog here!" );
900 if( m_pConversionDialog
)
901 m_eConversionFormat
= m_pConversionDialog
->GetConversionFormat( );
905 IMPL_LINK_NOARG(HangulHanjaConversion_Impl
, OnFind
)
907 DBG_ASSERT( m_pConversionDialog
, "HangulHanjaConversion_Impl::OnFind: where did this come from?" );
908 if ( m_pConversionDialog
)
912 OUString
sNewOriginal( m_pConversionDialog
->GetCurrentSuggestion( ) );
913 Sequence
< OUString
> aSuggestions
;
915 DBG_ASSERT( m_xConverter
.is(), "HangulHanjaConversion_Impl::OnFind: no converter!" );
916 TextConversionResult aToHanja
= m_xConverter
->getConversions(
918 0, sNewOriginal
.getLength(),
920 TextConversionType::TO_HANJA
,
921 TextConversionOption::NONE
923 TextConversionResult aToHangul
= m_xConverter
->getConversions(
925 0, sNewOriginal
.getLength(),
927 TextConversionType::TO_HANGUL
,
928 TextConversionOption::NONE
931 bool bHaveToHanja
= ( aToHanja
.Boundary
.startPos
< aToHanja
.Boundary
.endPos
);
932 bool bHaveToHangul
= ( aToHangul
.Boundary
.startPos
< aToHangul
.Boundary
.endPos
);
934 TextConversionResult
* pResult
= NULL
;
935 if ( bHaveToHanja
&& bHaveToHangul
)
936 { // it found convertibles in both directions -> use the first
937 if ( aToHangul
.Boundary
.startPos
< aToHanja
.Boundary
.startPos
)
938 pResult
= &aToHangul
;
942 else if ( bHaveToHanja
)
943 { // only found toHanja
947 { // only found toHangul
948 pResult
= &aToHangul
;
951 aSuggestions
= pResult
->Candidates
;
953 m_pConversionDialog
->SetCurrentString( sNewOriginal
, aSuggestions
, false );
954 m_pConversionDialog
->FocusSuggestion();
956 catch( const Exception
& )
958 OSL_FAIL( "HangulHanjaConversion_Impl::OnFind: caught an exception!" );
964 bool HangulHanjaConversion::m_bUseSavedValues
= false;
965 bool HangulHanjaConversion::m_bTryBothDirectionsSave
= false;
966 HHC::ConversionDirection
HangulHanjaConversion::m_ePrimaryConversionDirectionSave
= HHC::eHangulToHanja
;
968 HangulHanjaConversion::HangulHanjaConversion( vcl::Window
* _pUIParent
,
969 const Reference
< XComponentContext
>& rxContext
,
970 const lang::Locale
& _rSourceLocale
, const lang::Locale
& _rTargetLocale
,
971 const vcl::Font
* _pTargetFont
,
972 sal_Int32 _nOptions
, bool _bIsInteractive
)
973 :m_pImpl( new HangulHanjaConversion_Impl( _pUIParent
, rxContext
, _rSourceLocale
, _rTargetLocale
, _pTargetFont
, _nOptions
, _bIsInteractive
, this ) )
977 HangulHanjaConversion::~HangulHanjaConversion( )
981 void HangulHanjaConversion::SetUseSavedConversionDirectionState( bool bVal
)
983 m_bUseSavedValues
= bVal
;
986 bool HangulHanjaConversion::IsUseSavedConversionDirectionState()
988 return m_bUseSavedValues
;
991 LanguageType
HangulHanjaConversion::GetSourceLanguage( ) const
993 return m_pImpl
->GetSourceLang();
996 LanguageType
HangulHanjaConversion::GetTargetLanguage( ) const
998 return m_pImpl
->GetTargetLang();
1001 const vcl::Font
* HangulHanjaConversion::GetTargetFont( ) const
1003 return m_pImpl
->GetTargetFont();
1006 sal_Int32
HangulHanjaConversion::GetConversionOptions( ) const
1008 return m_pImpl
->GetConvOptions();
1011 bool HangulHanjaConversion::IsInteractive( ) const
1013 return m_pImpl
->IsInteractive();
1016 void HangulHanjaConversion::ConvertDocument()
1018 if ( m_pImpl
->IsValid() )
1019 m_pImpl
->DoDocumentConversion( );
1024 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */