1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
29 #include <editeng/hangulhanja.hxx>
30 #include <vcl/msgbox.hxx>
31 #include <vcl/button.hxx>
32 #include <unotools/lingucfg.hxx>
33 #include <unotools/linguprops.hxx>
37 #include <com/sun/star/uno/Sequence.hxx>
38 #include <com/sun/star/i18n/XBreakIterator.hpp>
39 #include <com/sun/star/i18n/ScriptType.hpp>
40 #include <com/sun/star/i18n/UnicodeScript.hpp>
41 #include <com/sun/star/i18n/XTextConversion.hpp>
42 #include <com/sun/star/i18n/XExtendedTextConversion.hpp>
43 #include <com/sun/star/i18n/TextConversionType.hpp>
44 #include <com/sun/star/i18n/TextConversionOption.hpp>
45 #include <com/sun/star/i18n/WordType.hpp>
46 #include <vcl/stdtext.hxx>
47 #include <unotools/charclass.hxx>
49 #include <editeng/edtdlg.hxx>
50 #include <editeng/editrids.hrc>
51 #include <editeng/unolingu.hxx>
53 #define HHC HangulHanjaConversion
55 //.............................................................................
58 //.............................................................................
60 using namespace ::com::sun::star::uno
;
61 using namespace ::com::sun::star::i18n
;
62 using namespace ::com::sun::star::i18n::TextConversionOption
;
63 using namespace ::com::sun::star::i18n::TextConversionType
;
64 using namespace ::com::sun::star::lang
;
66 class HangulHanjaConversion_Impl
69 typedef ::std::set
< ::rtl::OUString
, ::std::less
< ::rtl::OUString
> > StringBag
;
70 typedef ::std::map
< ::rtl::OUString
, ::rtl::OUString
, ::std::less
< ::rtl::OUString
> > StringMap
;
73 StringBag m_sIgnoreList
;
74 StringMap m_aChangeList
;
75 static StringMap m_aRecentlyUsedList
;
78 AbstractHangulHanjaConversionDialog
*
79 m_pConversionDialog
; // the dialog to display for user interaction
80 Window
* m_pUIParent
; // the parent window for any UI we raise
81 Reference
< XMultiServiceFactory
>
82 m_xORB
; // the service factory to use
83 Reference
< XTextConversion
>
84 m_xConverter
; // the text conversion service
85 Locale m_aSourceLocale
; // the locale we're working with
87 // additions for Chinese simplified / traditional conversion
88 HHC::ConversionType m_eConvType
; // conversion type (Hangul/Hanja, simplified/traditional Chinese,...)
89 LanguageType m_nSourceLang
; // just a 'copy' of m_aSourceLocale in order in order to
90 // save the applications from always converting to this
91 // type in their implementations
92 LanguageType m_nTargetLang
; // target language of new replacement text
93 const Font
* m_pTargetFont
; // target font of new replacement text
94 sal_Int32 m_nConvOptions
; // text conversion options (as used by 'getConversions')
95 sal_Bool m_bIsInteractive
; // specifies if the conversion requires user interaction
96 // (and likeley a specialised dialog) or if it is to run
97 // automatically without any user interaction.
98 // True for Hangul / Hanja conversion
99 // False for Chinese simlified / traditional conversion
101 HangulHanjaConversion
* m_pAntiImpl
; // our "anti-impl" instance
104 sal_Bool m_bByCharacter
; // are we in "by character" mode currently?
105 HHC::ConversionFormat m_eConversionFormat
; // the current format for the conversion
106 HHC::ConversionDirection m_ePrimaryConversionDirection
; // the primary conversion direction
107 HHC::ConversionDirection m_eCurrentConversionDirection
; // the primary conversion direction
109 //options from Hangul/Hanja Options dialog (also saved to configuration)
110 bool m_bIgnorePostPositionalWord
;
111 bool m_bShowRecentlyUsedFirst
;
112 bool m_bAutoReplaceUnique
;
115 ::rtl::OUString m_sCurrentPortion
; // the text which we are currently working on
116 LanguageType m_nCurrentPortionLang
; // language of m_sCurrentPortion found
117 sal_Int32 m_nCurrentStartIndex
; // the start index within m_sCurrentPortion of the current convertible portion
118 sal_Int32 m_nCurrentEndIndex
; // the end index (excluding) within m_sCurrentPortion of the current convertible portion
119 sal_Int32 m_nReplacementBaseIndex
;// index which ReplaceUnit-calls need to be relative to
120 sal_Int32 m_nCurrentConversionOption
;
121 sal_Int16 m_nCurrentConversionType
;
122 Sequence
< ::rtl::OUString
>
123 m_aCurrentSuggestions
; // the suggestions for the current unit
124 // (means for the text [m_nCurrentStartIndex, m_nCurrentEndIndex) in m_sCurrentPortion)
125 sal_Bool m_bTryBothDirections
; // specifies if other conversion directions should be tried when looking for convertible characters
129 HangulHanjaConversion_Impl(
131 const Reference
< XMultiServiceFactory
>& _rxORB
,
132 const Locale
& _rSourceLocale
,
133 const Locale
& _rTargetLocale
,
134 const Font
* _pTargetFont
,
135 sal_Int32 _nConvOptions
,
136 sal_Bool _bIsInteractive
,
137 HangulHanjaConversion
* _pAntiImpl
);
141 static void SetUseSavedConversionDirectionState( sal_Bool bVal
);
143 void DoDocumentConversion( );
145 inline sal_Bool
IsByCharacter( ) const { return m_bByCharacter
; }
147 inline sal_Bool
IsValid() const { return m_xConverter
.is(); }
149 inline LanguageType
GetSourceLang() const { return m_nSourceLang
; }
150 inline LanguageType
GetTargetLang() const { return m_nTargetLang
; }
151 inline const Font
* GetTargetFont() const { return m_pTargetFont
; }
152 inline sal_Int32
GetConvOptions() const { return m_nConvOptions
; }
153 inline sal_Bool
IsInteractive() const { return m_bIsInteractive
; }
158 /** continue with the conversion, return <TRUE/> if and only if the complete conversion is done
159 @param _bRepeatCurrentUnit
160 if <TRUE/>, an implNextConvertible will be called initially to advance to the next convertible.
161 if <FALSE/>, the method will initially work with the current convertible unit
163 sal_Bool
ContinueConversion( bool _bRepeatCurrentUnit
);
166 DECL_LINK( OnOptionsChanged
, void* );
167 DECL_LINK( OnIgnore
, void* );
168 DECL_LINK( OnIgnoreAll
, void* );
169 DECL_LINK( OnChange
, void* );
170 DECL_LINK( OnChangeAll
, void* );
171 DECL_LINK( OnByCharClicked
, CheckBox
* );
172 DECL_LINK( OnConversionTypeChanged
, void* );
173 DECL_LINK( OnFind
, void* );
175 /** proceed, after the current convertible has been handled
178 When returning from this method, the dialog may have been deleted!</p>
180 @param _bRepeatCurrentUnit
181 will be passed to the <member>ContinueConversion</member> call
183 void implProceed( bool _bRepeatCurrentUnit
);
185 // change the current convertible, and do _not_ proceed
186 void implChange( const ::rtl::OUString
& _rChangeInto
);
188 /** find the next convertible piece of text, with possibly advancing to the next portion
190 @see HangulHanjaConversion::GetNextPortion
192 sal_Bool
implNextConvertible( bool _bRepeatUnit
);
194 /** find the next convertible unit within the current portion
196 if <TRUE/>, the search will start at the beginning of the current unit,
197 if <FALSE/>, it will start at the end of the current unit
199 bool implNextConvertibleUnit( const sal_Int32 _nStartAt
);
201 /** retrieves the next portion, with setting the index members properly
203 <TRUE/> if and only if there is a next portion
205 bool implRetrieveNextPortion( );
207 /** determine the ConversionDirection for m_sCurrentPortion
209 <FALSE/> if and only if something went wrong
211 bool implGetConversionDirectionForCurrentPortion( HHC::ConversionDirection
& rDirection
);
213 /** member m_aCurrentSuggestions and m_nCurrentEndIndex are updated according to the other settings and current dictionaries
215 if _bAllowSearchNextConvertibleText is true _nStartAt is used as starting point to search the next
216 convertible text portion. This may result in changing of the member m_nCurrentStartIndex additionally.
219 <TRUE/> if Suggestions were found
221 bool implUpdateSuggestions( const bool _bAllowSearchNextConvertibleText
=false, const sal_Int32 _nStartAt
=-1 );
223 /** reads the options from Hangul/Hanja Options dialog that are saved to configuration
225 void implReadOptionsFromConfiguration();
227 /** get the string currently considered to be replaced or ignored
229 ::rtl::OUString
GetCurrentUnit() const;
231 /** read options from configuration, update suggestion list and dialog content
233 void implUpdateData();
235 /** get the conversion direction dependent from m_eConvType and m_eCurrentConversionDirection
236 in case of switching the direction is allowed this can be triggered with parameter bSwitchDirection
238 sal_Int16
implGetConversionType( bool bSwitchDirection
=false ) const;
241 HangulHanjaConversion_Impl::StringMap
HangulHanjaConversion_Impl::m_aRecentlyUsedList
= HangulHanjaConversion_Impl::StringMap();
243 HangulHanjaConversion_Impl::HangulHanjaConversion_Impl( Window
* _pUIParent
,
244 const Reference
< XMultiServiceFactory
>& _rxORB
,
245 const Locale
& _rSourceLocale
,
246 const Locale
& _rTargetLocale
,
247 const Font
* _pTargetFont
,
249 sal_Bool _bIsInteractive
,
250 HangulHanjaConversion
* _pAntiImpl
)
251 : m_pConversionDialog( NULL
)
252 , m_pUIParent( _pUIParent
)
254 , m_aSourceLocale( _rSourceLocale
)
255 , m_nSourceLang( SvxLocaleToLanguage( _rSourceLocale
) )
256 , m_nTargetLang( SvxLocaleToLanguage( _rTargetLocale
) )
257 , m_pTargetFont( _pTargetFont
)
258 , m_bIsInteractive( _bIsInteractive
)
259 , m_pAntiImpl( _pAntiImpl
)
260 , m_nCurrentPortionLang( LANGUAGE_NONE
)
261 , m_nCurrentStartIndex( 0 )
262 , m_nCurrentEndIndex( 0 )
263 , m_nReplacementBaseIndex( 0 )
264 , m_nCurrentConversionOption( TextConversionOption::NONE
)
265 , m_nCurrentConversionType( -1 ) // not yet known
266 , m_bTryBothDirections( sal_True
)
268 implReadOptionsFromConfiguration();
270 DBG_ASSERT( m_xORB
.is(), "HangulHanjaConversion_Impl::HangulHanjaConversion_Impl: no ORB!" );
272 // determine conversion type
273 if (m_nSourceLang
== LANGUAGE_KOREAN
&& m_nTargetLang
== LANGUAGE_KOREAN
)
274 m_eConvType
= HHC::eConvHangulHanja
;
275 else if ( (m_nSourceLang
== LANGUAGE_CHINESE_TRADITIONAL
&& m_nTargetLang
== LANGUAGE_CHINESE_SIMPLIFIED
) ||
276 (m_nSourceLang
== LANGUAGE_CHINESE_SIMPLIFIED
&& m_nTargetLang
== LANGUAGE_CHINESE_TRADITIONAL
) )
277 m_eConvType
= HHC::eConvSimplifiedTraditional
;
280 OSL_FAIL( "failed to determine conversion type from languages" );
283 // set remaining conversion parameters to their default values
284 m_nConvOptions
= _nOptions
;
285 m_bByCharacter
= 0 != (_nOptions
& CHARACTER_BY_CHARACTER
);
286 m_eConversionFormat
= HHC::eSimpleConversion
;
287 m_ePrimaryConversionDirection
= HHC::eHangulToHanja
; // used for eConvHangulHanja
288 m_eCurrentConversionDirection
= HHC::eHangulToHanja
; // used for eConvHangulHanja
292 ::rtl::OUString
sTextConversionService( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.i18n.TextConversion" ) );
293 m_xConverter
= m_xConverter
.query( m_xORB
->createInstance( sTextConversionService
) );
294 if ( !m_xConverter
.is() )
295 ShowServiceNotAvailableError( m_pUIParent
, sTextConversionService
, sal_True
);
300 void HangulHanjaConversion_Impl::createDialog()
302 DBG_ASSERT( m_bIsInteractive
, "createDialog when the conversion should not be interactive?" );
303 if ( m_bIsInteractive
&& !m_pConversionDialog
)
305 EditAbstractDialogFactory
* pFact
= EditAbstractDialogFactory::Create();
308 m_pConversionDialog
= pFact
->CreateHangulHanjaConversionDialog(m_pUIParent
, m_ePrimaryConversionDirection
);
309 DBG_ASSERT(m_pConversionDialog
, "Dialogdiet fail!");
311 m_pConversionDialog
->EnableRubySupport( m_pAntiImpl
->HasRubySupport() );
313 m_pConversionDialog
->SetByCharacter( m_bByCharacter
);
314 m_pConversionDialog
->SetConversionFormat( m_eConversionFormat
);
315 m_pConversionDialog
->SetConversionDirectionState( m_bTryBothDirections
, m_ePrimaryConversionDirection
);
318 m_pConversionDialog
->SetOptionsChangedHdl( LINK( this, HangulHanjaConversion_Impl
, OnOptionsChanged
) );
319 m_pConversionDialog
->SetIgnoreHdl( LINK( this, HangulHanjaConversion_Impl
, OnIgnore
) );
320 m_pConversionDialog
->SetIgnoreAllHdl( LINK( this, HangulHanjaConversion_Impl
, OnIgnoreAll
) );
321 m_pConversionDialog
->SetChangeHdl( LINK( this, HangulHanjaConversion_Impl
, OnChange
) );
322 m_pConversionDialog
->SetChangeAllHdl( LINK( this, HangulHanjaConversion_Impl
, OnChangeAll
) );
323 m_pConversionDialog
->SetClickByCharacterHdl( LINK( this, HangulHanjaConversion_Impl
, OnByCharClicked
) );
324 m_pConversionDialog
->SetConversionFormatChangedHdl( LINK( this, HangulHanjaConversion_Impl
, OnConversionTypeChanged
) );
325 m_pConversionDialog
->SetFindHdl( LINK( this, HangulHanjaConversion_Impl
, OnFind
) );
330 sal_Int16
HangulHanjaConversion_Impl::implGetConversionType( bool bSwitchDirection
) const
332 sal_Int16 nConversionType
= -1;
333 if (m_eConvType
== HHC::eConvHangulHanja
)
334 nConversionType
= HHC::eHangulToHanja
== ( m_eCurrentConversionDirection
&& !bSwitchDirection
) ? TO_HANJA
: TO_HANGUL
;
335 else if (m_eConvType
== HHC::eConvSimplifiedTraditional
)
336 nConversionType
= LANGUAGE_CHINESE_SIMPLIFIED
== m_nTargetLang
? TO_SCHINESE
: TO_TCHINESE
;
337 DBG_ASSERT( nConversionType
!= -1, "unexpected conversion type" );
338 return nConversionType
;
341 bool HangulHanjaConversion_Impl::implUpdateSuggestions( bool _bAllowSearchNextConvertibleText
, const sal_Int32 _nStartAt
)
343 // parameters for the converter
344 sal_Int32 nStartSearch
= m_nCurrentStartIndex
;
345 if( _bAllowSearchNextConvertibleText
)
346 nStartSearch
= _nStartAt
;
348 sal_Int32 nLength
= m_sCurrentPortion
.getLength() - nStartSearch
;
349 m_nCurrentConversionType
= implGetConversionType();
350 m_nCurrentConversionOption
= IsByCharacter() ? CHARACTER_BY_CHARACTER
: NONE
;
351 if( m_bIgnorePostPositionalWord
)
352 m_nCurrentConversionOption
= m_nCurrentConversionOption
| IGNORE_POST_POSITIONAL_WORD
;
354 // no need to check both directions for chinese conversion (saves time)
355 if (m_eConvType
== HHC::eConvSimplifiedTraditional
)
356 m_bTryBothDirections
= sal_False
;
358 sal_Bool bFoundAny
= sal_True
;
361 TextConversionResult aResult
= m_xConverter
->getConversions(
366 m_nCurrentConversionType
,
367 m_nCurrentConversionOption
369 sal_Bool bFoundPrimary
= aResult
.Boundary
.startPos
< aResult
.Boundary
.endPos
;
370 bFoundAny
= bFoundPrimary
;
372 if ( m_bTryBothDirections
)
373 { // see if we find another convertible when assuming the other direction
374 TextConversionResult aSecondResult
= m_xConverter
->getConversions(
379 implGetConversionType( true ), // switched!
380 m_nCurrentConversionOption
382 if ( aSecondResult
.Boundary
.startPos
< aSecondResult
.Boundary
.endPos
)
383 { // we indeed found such a convertible
385 // in case the first attempt (with the original conversion direction)
386 // didn't find anything
388 // or if the second location is _before_ the first one
389 || ( aSecondResult
.Boundary
.startPos
< aResult
.Boundary
.startPos
)
392 // then use the second finding
393 aResult
= aSecondResult
;
395 // our current conversion direction changed now
396 m_eCurrentConversionDirection
= ( HHC::eHangulToHanja
== m_eCurrentConversionDirection
)
397 ? HHC::eHanjaToHangul
: HHC::eHangulToHanja
;
398 bFoundAny
= sal_True
;
403 if( _bAllowSearchNextConvertibleText
)
405 //this might change the current position
406 m_aCurrentSuggestions
= aResult
.Candidates
;
407 m_nCurrentStartIndex
= aResult
.Boundary
.startPos
;
408 m_nCurrentEndIndex
= aResult
.Boundary
.endPos
;
412 //the change of starting position is not allowed
413 if( m_nCurrentStartIndex
== aResult
.Boundary
.startPos
414 && aResult
.Boundary
.endPos
!= aResult
.Boundary
.startPos
)
416 m_aCurrentSuggestions
= aResult
.Candidates
;
417 m_nCurrentEndIndex
= aResult
.Boundary
.endPos
;
421 m_aCurrentSuggestions
.realloc( 0 );
422 if( m_sCurrentPortion
.getLength() >= m_nCurrentStartIndex
+1 )
423 m_nCurrentEndIndex
= m_nCurrentStartIndex
+1;
427 //put recently used string to front:
428 if( m_bShowRecentlyUsedFirst
&& m_aCurrentSuggestions
.getLength()>1 )
430 ::rtl::OUString
sCurrentUnit( GetCurrentUnit() );
431 StringMap::const_iterator aRecentlyUsed
= m_aRecentlyUsedList
.find( sCurrentUnit
);
432 bool bUsedBefore
= aRecentlyUsed
!= m_aRecentlyUsedList
.end();
433 if( bUsedBefore
&& m_aCurrentSuggestions
[0] != aRecentlyUsed
->second
)
435 sal_Int32 nCount
= m_aCurrentSuggestions
.getLength();
436 Sequence
< ::rtl::OUString
> aTmp(nCount
);
437 aTmp
[0]=aRecentlyUsed
->second
;
439 for( sal_Int32 n
=1; n
<nCount
; n
++)//we had 0 already
441 if( nDiff
&& m_aCurrentSuggestions
[n
-nDiff
]==aRecentlyUsed
->second
)
443 aTmp
[n
]=m_aCurrentSuggestions
[n
-nDiff
];
445 m_aCurrentSuggestions
= aTmp
;
449 catch( const Exception
& )
451 OSL_FAIL( "HangulHanjaConversion_Impl::implNextConvertibleUnit: caught an exception!" );
453 //!!! at least we want to move on in the text in order
454 //!!! to avoid an endless loop...
460 bool HangulHanjaConversion_Impl::implNextConvertibleUnit( const sal_Int32 _nStartAt
)
462 m_aCurrentSuggestions
.realloc( 0 );
464 // ask the TextConversion service for the next convertible piece of text
466 // get current values from dialog
467 if( m_eConvType
== HHC::eConvHangulHanja
&& m_pConversionDialog
)
469 m_bTryBothDirections
= m_pConversionDialog
->GetUseBothDirections();
470 HHC::ConversionDirection eDialogDirection
= HHC::eHangulToHanja
;
471 eDialogDirection
= m_pConversionDialog
->GetDirection( eDialogDirection
);
473 if( !m_bTryBothDirections
&& eDialogDirection
!= m_eCurrentConversionDirection
)
475 m_eCurrentConversionDirection
= eDialogDirection
;
478 // save curently used value for possible later use
479 m_pAntiImpl
->m_bTryBothDirectionsSave
= m_bTryBothDirections
;
480 m_pAntiImpl
->m_ePrimaryConversionDirectionSave
= m_eCurrentConversionDirection
;
483 bool bFoundAny
= implUpdateSuggestions( true, _nStartAt
);
486 (m_nCurrentStartIndex
< m_sCurrentPortion
.getLength());
489 bool HangulHanjaConversion_Impl::implRetrieveNextPortion( )
491 sal_Bool bAllowImplicitChanges
= m_eConvType
== HHC::eConvSimplifiedTraditional
;
493 m_sCurrentPortion
= ::rtl::OUString();
494 m_nCurrentPortionLang
= LANGUAGE_NONE
;
495 m_pAntiImpl
->GetNextPortion( m_sCurrentPortion
, m_nCurrentPortionLang
, bAllowImplicitChanges
);
496 m_nReplacementBaseIndex
= 0;
497 m_nCurrentStartIndex
= m_nCurrentEndIndex
= 0;
499 bool bRet
= !m_sCurrentPortion
.isEmpty();
501 if (m_eConvType
== HHC::eConvHangulHanja
&& m_bTryBothDirections
)
502 implGetConversionDirectionForCurrentPortion( m_eCurrentConversionDirection
);
507 sal_Bool
HangulHanjaConversion_Impl::implNextConvertible( bool _bRepeatUnit
)
509 if ( _bRepeatUnit
|| ( m_nCurrentEndIndex
< m_sCurrentPortion
.getLength() ) )
511 if ( implNextConvertibleUnit(
513 ? ( IsByCharacter() ? m_nCurrentStartIndex
: m_nCurrentStartIndex
)
519 // no convertible text in the current portion anymore
520 // -> advance to the next portion
524 if ( implRetrieveNextPortion( ) )
525 { // there is a next portion
526 // -> find the next convertible unit in the current portion
527 if ( implNextConvertibleUnit( 0 ) )
531 while ( !m_sCurrentPortion
.isEmpty() );
537 ::rtl::OUString
HangulHanjaConversion_Impl::GetCurrentUnit() const
539 DBG_ASSERT( m_nCurrentStartIndex
< m_sCurrentPortion
.getLength(),
540 "HangulHanjaConversion_Impl::GetCurrentUnit: invalid index into current portion!" );
541 DBG_ASSERT( m_nCurrentEndIndex
<= m_sCurrentPortion
.getLength(),
542 "HangulHanjaConversion_Impl::GetCurrentUnit: invalid index into current portion!" );
543 DBG_ASSERT( m_nCurrentStartIndex
<= m_nCurrentEndIndex
,
544 "HangulHanjaConversion_Impl::GetCurrentUnit: invalid interval!" );
546 ::rtl::OUString sCurrentUnit
= m_sCurrentPortion
.copy( m_nCurrentStartIndex
, m_nCurrentEndIndex
- m_nCurrentStartIndex
);
550 sal_Bool
HangulHanjaConversion_Impl::ContinueConversion( bool _bRepeatCurrentUnit
)
552 sal_Bool bNeedUserInteraction
= sal_False
; // when we leave here, do we need user interaction?
553 sal_Bool bDocumentDone
= sal_False
; // did we already check the whole document?
555 while ( !bDocumentDone
&& !bNeedUserInteraction
&& implNextConvertible( _bRepeatCurrentUnit
) )
557 ::rtl::OUString
sCurrentUnit( GetCurrentUnit() );
559 // do we need to ignore it?
560 sal_Bool bAlwaysIgnoreThis
= m_sIgnoreList
.end() != m_sIgnoreList
.find( sCurrentUnit
);
562 // do we need to change it?
563 StringMap::const_iterator aChangeListPos
= m_aChangeList
.find( sCurrentUnit
);
564 sal_Bool bAlwaysChangeThis
= m_aChangeList
.end() != aChangeListPos
;
566 // do we automatically change this?
567 sal_Bool bAutoChange
= m_bAutoReplaceUnique
&& m_aCurrentSuggestions
.getLength() == 1;
569 if (!m_bIsInteractive
)
571 // silent conversion (e.g. for simplified/traditional Chinese)...
572 if(m_aCurrentSuggestions
.getLength()>0)
573 implChange( m_aCurrentSuggestions
.getConstArray()[0] );
575 else if (bAutoChange
)
577 implChange( m_aCurrentSuggestions
.getConstArray()[0] );
579 else if ( bAlwaysChangeThis
)
581 implChange( aChangeListPos
->second
);
583 else if ( !bAlwaysIgnoreThis
)
585 // here we need to ask the user for what to do with the text
586 // for this, allow derivees to highlight the current text unit in a possible document view
587 m_pAntiImpl
->HandleNewUnit( m_nCurrentStartIndex
- m_nReplacementBaseIndex
, m_nCurrentEndIndex
- m_nReplacementBaseIndex
);
589 DBG_ASSERT( m_pConversionDialog
, "we should always have a dialog here!" );
590 if( m_pConversionDialog
)
591 m_pConversionDialog
->SetCurrentString( sCurrentUnit
, m_aCurrentSuggestions
);
593 // do not look for the next convertible: We have to wait for the user to interactivly
594 // decide what happens with the current convertible
595 bNeedUserInteraction
= sal_True
;
599 return bDocumentDone
|| !bNeedUserInteraction
;
602 bool HangulHanjaConversion_Impl::implGetConversionDirectionForCurrentPortion( HHC::ConversionDirection
& rDirection
)
604 // - For eConvHangulHanja the direction is determined by
605 // the first encountered Korean character.
606 // - For eConvSimplifiedTraditional the conversion direction
607 // is already specified by the source language.
609 bool bSuccess
= true;
611 if (m_eConvType
== HHC::eConvHangulHanja
)
616 // get the break iterator service
617 ::rtl::OUString
sBreakIteratorService( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.i18n.BreakIterator" ) );
618 Reference
< XInterface
> xBI( m_xORB
->createInstance( ::rtl::OUString( sBreakIteratorService
) ) );
619 Reference
< XBreakIterator
> xBreakIter( xBI
, UNO_QUERY
);
620 if ( !xBreakIter
.is() )
622 ShowServiceNotAvailableError( m_pUIParent
, sBreakIteratorService
, sal_True
);
626 sal_Int32 nNextAsianScript
= xBreakIter
->beginOfScript( m_sCurrentPortion
, m_nCurrentStartIndex
, com::sun::star::i18n::ScriptType::ASIAN
);
627 if ( -1 == nNextAsianScript
)
628 nNextAsianScript
= xBreakIter
->nextScript( m_sCurrentPortion
, m_nCurrentStartIndex
, com::sun::star::i18n::ScriptType::ASIAN
);
629 if ( ( nNextAsianScript
>= m_nCurrentStartIndex
) && ( nNextAsianScript
< m_sCurrentPortion
.getLength() ) )
630 { // found asian text
632 // determine if it's Hangul
633 CharClass
aCharClassificaton( m_xORB
, m_aSourceLocale
);
634 sal_Int16 nScript
= aCharClassificaton
.getScript( m_sCurrentPortion
, sal::static_int_cast
< sal_uInt16
>(nNextAsianScript
) );
635 if ( ( UnicodeScript_kHangulJamo
== nScript
)
636 || ( UnicodeScript_kHangulCompatibilityJamo
== nScript
)
637 || ( UnicodeScript_kHangulSyllable
== nScript
)
640 rDirection
= HHC::eHangulToHanja
;
644 rDirection
= HHC::eHanjaToHangul
;
651 catch( const Exception
& )
653 OSL_FAIL( "HangulHanjaConversion_Impl::implGetConversionDirectionForCurrentPortion: caught an exception!" );
660 void HangulHanjaConversion_Impl::DoDocumentConversion( )
662 // clear the change-all list - it's to be re-initialized for every single document
665 m_aChangeList
.swap( aEmpty
);
668 // first of all, we need to guess the direction of our conversion - it is determined by the first
669 // hangul or hanja character in the first text
670 if ( !implRetrieveNextPortion() )
672 DBG_WARNING( "HangulHanjaConversion_Impl::DoDocumentConversion: why did you call me if you do have nothing to convert?" );
676 if( m_eConvType
== HHC::eConvHangulHanja
)
678 //init conversion direction from saved value
679 HHC::ConversionDirection eDirection
= HHC::eHangulToHanja
;
680 if(!implGetConversionDirectionForCurrentPortion( eDirection
))
681 // something went wrong, has already been asserted
684 if (m_pAntiImpl
->IsUseSavedConversionDirectionState())
686 m_ePrimaryConversionDirection
= m_pAntiImpl
->m_ePrimaryConversionDirectionSave
;
687 m_bTryBothDirections
= m_pAntiImpl
->m_bTryBothDirectionsSave
;
688 if( m_bTryBothDirections
)
689 m_eCurrentConversionDirection
= eDirection
;
691 m_eCurrentConversionDirection
= m_ePrimaryConversionDirection
;
695 m_ePrimaryConversionDirection
= eDirection
;
696 m_eCurrentConversionDirection
= eDirection
;
700 if (m_bIsInteractive
&& m_eConvType
== HHC::eConvHangulHanja
)
702 //always open dialog if at least having a hangul or hanja text portion
704 if(m_pAntiImpl
->IsUseSavedConversionDirectionState())
705 ContinueConversion( sal_False
);
708 m_pConversionDialog
->Execute();
709 DELETEZ( m_pConversionDialog
);
714 sal_Bool bCompletelyDone
=
716 ContinueConversion( sal_False
);
717 DBG_ASSERT( bCompletelyDone
, "HangulHanjaConversion_Impl::DoDocumentConversion: ContinueConversion should have returned true here!" );
721 void HangulHanjaConversion_Impl::implProceed( bool _bRepeatCurrentUnit
)
723 if ( ContinueConversion( _bRepeatCurrentUnit
) )
724 { // we're done with the whole document
725 DBG_ASSERT( !m_bIsInteractive
|| m_pConversionDialog
, "HangulHanjaConversion_Impl::implProceed: we should not reach this here without dialog!" );
726 if ( m_pConversionDialog
)
727 m_pConversionDialog
->EndDialog( RET_OK
);
731 void HangulHanjaConversion_Impl::implChange( const ::rtl::OUString
& _rChangeInto
)
733 if( _rChangeInto
.isEmpty() )
736 // translate the conversion format into a replacement action
737 // this translation depends on whether we have a Hangul original, or a Hanja original
739 HHC::ReplacementAction
eAction( HHC::eExchange
);
741 if (m_eConvType
== HHC::eConvHangulHanja
)
743 // is the original we're about to change in Hangul?
744 sal_Bool bOriginalIsHangul
= HHC::eHangulToHanja
== m_eCurrentConversionDirection
;
746 switch ( m_eConversionFormat
)
748 case HHC::eSimpleConversion
: eAction
= HHC::eExchange
; break;
749 case HHC::eHangulBracketed
: eAction
= bOriginalIsHangul
? HHC::eOriginalBracketed
: HHC::eReplacementBracketed
; break;
750 case HHC::eHanjaBracketed
: eAction
= bOriginalIsHangul
? HHC::eReplacementBracketed
: HHC::eOriginalBracketed
; break;
751 case HHC::eRubyHanjaAbove
: eAction
= bOriginalIsHangul
? HHC::eReplacementAbove
: HHC::eOriginalAbove
; break;
752 case HHC::eRubyHanjaBelow
: eAction
= bOriginalIsHangul
? HHC::eReplacementBelow
: HHC::eOriginalBelow
; break;
753 case HHC::eRubyHangulAbove
: eAction
= bOriginalIsHangul
? HHC::eOriginalAbove
: HHC::eReplacementAbove
; break;
754 case HHC::eRubyHangulBelow
: eAction
= bOriginalIsHangul
? HHC::eOriginalBelow
: HHC::eReplacementBelow
; break;
756 OSL_FAIL( "HangulHanjaConversion_Impl::implChange: invalid/unexpected conversion format!" );
760 // the proper indicies (the wrapper implementation needs indicies relative to the
761 // previous replacement)
762 DBG_ASSERT( ( m_nReplacementBaseIndex
<= m_nCurrentStartIndex
) && ( m_nReplacementBaseIndex
<= m_nCurrentEndIndex
),
763 "HangulHanjaConversion_Impl::implChange: invalid replacement base!" );
765 sal_Int32 nStartIndex
= m_nCurrentStartIndex
- m_nReplacementBaseIndex
;
766 sal_Int32 nEndIndex
= m_nCurrentEndIndex
- m_nReplacementBaseIndex
;
768 //remind this decision
769 m_aRecentlyUsedList
[ GetCurrentUnit() ] = _rChangeInto
;
771 LanguageType
*pNewUnitLang
= 0;
772 LanguageType nNewUnitLang
= LANGUAGE_NONE
;
773 if (m_eConvType
== HHC::eConvSimplifiedTraditional
)
775 // check if language needs to be changed
776 if ( m_pAntiImpl
->GetTargetLanguage() == LANGUAGE_CHINESE_TRADITIONAL
&&
777 !m_pAntiImpl
->IsTraditional( m_nCurrentPortionLang
))
778 nNewUnitLang
= LANGUAGE_CHINESE_TRADITIONAL
;
779 else if ( m_pAntiImpl
->GetTargetLanguage() == LANGUAGE_CHINESE_SIMPLIFIED
&&
780 !m_pAntiImpl
->IsSimplified( m_nCurrentPortionLang
))
781 nNewUnitLang
= LANGUAGE_CHINESE_SIMPLIFIED
;
782 if (nNewUnitLang
!= LANGUAGE_NONE
)
783 pNewUnitLang
= &nNewUnitLang
;
786 // according to FT we should not (yet) bother about Hangul/Hanja conversion here
788 // aOffsets is needed in ReplaceUnit below in order to to find out
789 // exactly which characters are really changed in order to keep as much
790 // from attributation for the text as possible.
791 Sequence
< sal_Int32
> aOffsets
;
792 Reference
< XExtendedTextConversion
> xExtConverter( m_xConverter
, UNO_QUERY
);
793 if (m_eConvType
== HHC::eConvSimplifiedTraditional
&& xExtConverter
.is())
797 ::rtl::OUString aConvText
= xExtConverter
->getConversionWithOffset(
799 m_nCurrentStartIndex
,
800 m_nCurrentEndIndex
- m_nCurrentStartIndex
,
802 m_nCurrentConversionType
,
803 m_nCurrentConversionOption
,
807 catch( const Exception
& )
809 OSL_FAIL( "HangulHanjaConversion_Impl::implChange: caught unexpected exception!" );
814 // do the replacement
815 m_pAntiImpl
->ReplaceUnit( nStartIndex
, nEndIndex
, m_sCurrentPortion
,
816 _rChangeInto
, aOffsets
, eAction
, pNewUnitLang
);
819 // adjust the replacement base
820 m_nReplacementBaseIndex
= m_nCurrentEndIndex
;
823 void HangulHanjaConversion_Impl::implReadOptionsFromConfiguration()
825 SvtLinguConfig aLngCfg
;
826 aLngCfg
.GetProperty( UPH_IS_IGNORE_POST_POSITIONAL_WORD
) >>= m_bIgnorePostPositionalWord
;
827 aLngCfg
.GetProperty( UPH_IS_SHOW_ENTRIES_RECENTLY_USED_FIRST
) >>= m_bShowRecentlyUsedFirst
;
828 aLngCfg
.GetProperty( UPH_IS_AUTO_REPLACE_UNIQUE_ENTRIES
) >>= m_bAutoReplaceUnique
;
831 void HangulHanjaConversion_Impl::implUpdateData()
833 implReadOptionsFromConfiguration();
834 implUpdateSuggestions();
836 if(m_pConversionDialog
)
838 ::rtl::OUString
sCurrentUnit( GetCurrentUnit() );
840 m_pConversionDialog
->SetCurrentString( sCurrentUnit
, m_aCurrentSuggestions
);
841 m_pConversionDialog
->FocusSuggestion();
844 m_pAntiImpl
->HandleNewUnit( m_nCurrentStartIndex
- m_nReplacementBaseIndex
, m_nCurrentEndIndex
- m_nReplacementBaseIndex
);
847 IMPL_LINK_NOARG(HangulHanjaConversion_Impl
, OnOptionsChanged
)
849 //options and dictionaries might have been changed
850 //-> update our internal settings and the dialog
856 IMPL_LINK_NOARG(HangulHanjaConversion_Impl
, OnIgnore
)
858 // simply ignore, and proceed
859 implProceed( sal_False
);
863 IMPL_LINK_NOARG(HangulHanjaConversion_Impl
, OnIgnoreAll
)
865 DBG_ASSERT( m_pConversionDialog
, "HangulHanjaConversion_Impl::OnIgnoreAll: no dialog! How this?" );
867 if ( m_pConversionDialog
)
869 String sCurrentUnit
= m_pConversionDialog
->GetCurrentString();
870 DBG_ASSERT( m_sIgnoreList
.end() == m_sIgnoreList
.find( sCurrentUnit
),
871 "HangulHanjaConversion_Impl, OnIgnoreAll: shouldn't this have been ignored before" );
873 // put into the "ignore all" list
874 m_sIgnoreList
.insert( sCurrentUnit
);
877 implProceed( sal_False
);
883 IMPL_LINK_NOARG(HangulHanjaConversion_Impl
, OnChange
)
886 DBG_ASSERT( m_pConversionDialog
, "we should always have a dialog here!" );
887 if( m_pConversionDialog
)
888 implChange( m_pConversionDialog
->GetCurrentSuggestion( ) );
890 implProceed( sal_False
);
895 IMPL_LINK_NOARG(HangulHanjaConversion_Impl
, OnChangeAll
)
897 DBG_ASSERT( m_pConversionDialog
, "HangulHanjaConversion_Impl::OnChangeAll: no dialog! How this?" );
898 if ( m_pConversionDialog
)
900 ::rtl::OUString
sCurrentUnit( m_pConversionDialog
->GetCurrentString() );
901 ::rtl::OUString
sChangeInto( m_pConversionDialog
->GetCurrentSuggestion( ) );
903 if( !sChangeInto
.isEmpty() )
905 // change the current occurrence
906 implChange( sChangeInto
);
908 // put into the "change all" list
909 m_aChangeList
.insert( StringMap::value_type( sCurrentUnit
, sChangeInto
) );
913 implProceed( sal_False
);
919 IMPL_LINK( HangulHanjaConversion_Impl
, OnByCharClicked
, CheckBox
*, _pBox
)
921 m_bByCharacter
= _pBox
->IsChecked();
923 // continue conversion, without advancing to the next unit, but instead continuing with the current unit
924 implProceed( sal_True
);
928 IMPL_LINK_NOARG(HangulHanjaConversion_Impl
, OnConversionTypeChanged
)
930 DBG_ASSERT( m_pConversionDialog
, "we should always have a dialog here!" );
931 if( m_pConversionDialog
)
932 m_eConversionFormat
= m_pConversionDialog
->GetConversionFormat( );
936 IMPL_LINK_NOARG(HangulHanjaConversion_Impl
, OnFind
)
938 DBG_ASSERT( m_pConversionDialog
, "HangulHanjaConversion_Impl::OnFind: where did this come from?" );
939 if ( m_pConversionDialog
)
943 ::rtl::OUString
sNewOriginal( m_pConversionDialog
->GetCurrentSuggestion( ) );
944 Sequence
< ::rtl::OUString
> aSuggestions
;
946 DBG_ASSERT( m_xConverter
.is(), "HangulHanjaConversion_Impl::OnFind: no converter!" );
947 TextConversionResult aToHanja
= m_xConverter
->getConversions(
949 0, sNewOriginal
.getLength(),
951 TextConversionType::TO_HANJA
,
952 TextConversionOption::NONE
954 TextConversionResult aToHangul
= m_xConverter
->getConversions(
956 0, sNewOriginal
.getLength(),
958 TextConversionType::TO_HANGUL
,
959 TextConversionOption::NONE
962 bool bHaveToHanja
= ( aToHanja
.Boundary
.startPos
< aToHanja
.Boundary
.endPos
);
963 bool bHaveToHangul
= ( aToHangul
.Boundary
.startPos
< aToHangul
.Boundary
.endPos
);
965 TextConversionResult
* pResult
= NULL
;
966 if ( bHaveToHanja
&& bHaveToHangul
)
967 { // it found convertibles in both directions -> use the first
968 if ( aToHangul
.Boundary
.startPos
< aToHanja
.Boundary
.startPos
)
969 pResult
= &aToHangul
;
973 else if ( bHaveToHanja
)
974 { // only found toHanja
978 { // only found toHangul
979 pResult
= &aToHangul
;
982 aSuggestions
= pResult
->Candidates
;
984 m_pConversionDialog
->SetCurrentString( sNewOriginal
, aSuggestions
, false );
985 m_pConversionDialog
->FocusSuggestion();
987 catch( const Exception
& )
989 OSL_FAIL( "HangulHanjaConversion_Impl::OnFind: caught an exception!" );
995 sal_Bool
HangulHanjaConversion::m_bUseSavedValues
= sal_False
;
996 sal_Bool
HangulHanjaConversion::m_bTryBothDirectionsSave
= sal_False
;
997 HHC::ConversionDirection
HangulHanjaConversion::m_ePrimaryConversionDirectionSave
= HHC::eHangulToHanja
;
999 HangulHanjaConversion::HangulHanjaConversion( Window
* _pUIParent
,
1000 const Reference
< XMultiServiceFactory
>& _rxORB
,
1001 const Locale
& _rSourceLocale
, const Locale
& _rTargetLocale
,
1002 const Font
* _pTargetFont
,
1003 sal_Int32 _nOptions
, sal_Bool _bIsInteractive
)
1004 :m_pImpl( new HangulHanjaConversion_Impl( _pUIParent
, _rxORB
, _rSourceLocale
, _rTargetLocale
, _pTargetFont
, _nOptions
, _bIsInteractive
, this ) )
1008 HangulHanjaConversion::~HangulHanjaConversion( )
1012 void HangulHanjaConversion::SetUseSavedConversionDirectionState( sal_Bool bVal
)
1014 m_bUseSavedValues
= bVal
;
1017 sal_Bool
HangulHanjaConversion::IsUseSavedConversionDirectionState()
1019 return m_bUseSavedValues
;
1022 LanguageType
HangulHanjaConversion::GetSourceLanguage( ) const
1024 return m_pImpl
->GetSourceLang();
1027 LanguageType
HangulHanjaConversion::GetTargetLanguage( ) const
1029 return m_pImpl
->GetTargetLang();
1032 const Font
* HangulHanjaConversion::GetTargetFont( ) const
1034 return m_pImpl
->GetTargetFont();
1037 sal_Int32
HangulHanjaConversion::GetConversionOptions( ) const
1039 return m_pImpl
->GetConvOptions();
1042 sal_Bool
HangulHanjaConversion::IsInteractive( ) const
1044 return m_pImpl
->IsInteractive();
1047 void HangulHanjaConversion::HandleNewUnit( const sal_Int32
, const sal_Int32
)
1049 // nothing to do, only derived classes need this.
1052 void HangulHanjaConversion::GetNextPortion( ::rtl::OUString
&, LanguageType
&, sal_Bool
)
1054 OSL_FAIL( "HangulHanjaConversion::GetNextPortion: to be overridden!" );
1057 void HangulHanjaConversion::ReplaceUnit(
1058 const sal_Int32
, const sal_Int32
,
1059 const ::rtl::OUString
&,
1060 const ::rtl::OUString
&,
1061 const ::com::sun::star::uno::Sequence
< sal_Int32
> &,
1065 OSL_FAIL( "HangulHanjaConversion::ReplaceUnit: to be overridden!" );
1068 sal_Bool
HangulHanjaConversion::HasRubySupport() const
1070 OSL_FAIL( "HangulHanjaConversion::HasRubySupport: to be overridden!" );
1074 void HangulHanjaConversion::ConvertDocument()
1076 if ( m_pImpl
->IsValid() )
1077 m_pImpl
->DoDocumentConversion( );
1082 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */