/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_editeng.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define HHC HangulHanjaConversion //............................................................................. namespace editeng { //............................................................................. using namespace ::com::sun::star::uno; using namespace ::com::sun::star::i18n; using namespace ::com::sun::star::i18n::TextConversionOption; using namespace ::com::sun::star::i18n::TextConversionType; using namespace ::com::sun::star::lang; /* using HangulHanjaConversion::ReplacementAction; using HangulHanjaConversion::eExchange; using HangulHanjaConversion::eReplacementBracketed; using HangulHanjaConversion::eOriginalBracketed; using HangulHanjaConversion::eReplacementAbove; using HangulHanjaConversion::eOriginalAbove; using HangulHanjaConversion::eReplacementBelow; using HangulHanjaConversion::eOriginalBelow; using HangulHanjaConversion::eHangulToHanja; using HangulHanjaConversion::eHanjaToHangul; using HangulHanjaConversion::eSimpleConversion; using HangulHanjaConversion::eHangulBracketed; using HangulHanjaConversion::eHanjaBracketed; using HangulHanjaConversion::eRubyHanjaAbove; using HangulHanjaConversion::eRubyHanjaBelow; using HangulHanjaConversion::eRubyHangulAbove; using HangulHanjaConversion::eRubyHangulBelow; using ::com::sun::star::i18n::TextConversionType::TO_HANJA; using ::com::sun::star::i18n::TextConversionType::TO_HANGUL; using ::com::sun::star::i18n::TextConversionOption::CHARACTER_BY_CHARACTER; using ::com::sun::star::i18n::TextConversionOption::NONE; */ //========================================================================= //= HangulHanjaConversion_Impl //========================================================================= //using HangulHanjaConversion::ConversionFormat; class HangulHanjaConversion_Impl { private: typedef ::std::set< ::rtl::OUString, ::std::less< ::rtl::OUString > > StringBag; typedef ::std::map< ::rtl::OUString, ::rtl::OUString, ::std::less< ::rtl::OUString > > StringMap; private: StringBag m_sIgnoreList; StringMap m_aChangeList; static StringMap m_aRecentlyUsedList; // general AbstractHangulHanjaConversionDialog* //CHINA001 HangulHanjaConversionDialog* m_pConversionDialog; // the dialog to display for user interaction Window* m_pUIParent; // the parent window for any UI we raise Reference< XMultiServiceFactory > m_xORB; // the service factory to use Reference< XTextConversion > m_xConverter; // the text conversion service Locale m_aSourceLocale; // the locale we're working with // additions for Chinese simplified / traditional conversion HHC::ConversionType m_eConvType; // conversion type (Hangul/Hanja, simplified/traditional Chinese,...) LanguageType m_nSourceLang; // just a 'copy' of m_aSourceLocale in order in order to // save the applications from always converting to this // type in their implementations LanguageType m_nTargetLang; // target language of new replacement text const Font* m_pTargetFont; // target font of new replacement text sal_Int32 m_nConvOptions; // text conversion options (as used by 'getConversions') sal_Bool m_bIsInteractive; // specifies if the conversion requires user interaction // (and likeley a specialised dialog) or if it is to run // automatically without any user interaction. // True for Hangul / Hanja conversion // False for Chinese simlified / traditional conversion HangulHanjaConversion* m_pAntiImpl; // our "anti-impl" instance // options sal_Bool m_bByCharacter; // are we in "by character" mode currently? HHC::ConversionFormat m_eConversionFormat; // the current format for the conversion HHC::ConversionDirection m_ePrimaryConversionDirection; // the primary conversion direction HHC::ConversionDirection m_eCurrentConversionDirection; // the primary conversion direction //options from Hangul/Hanja Options dialog (also saved to configuration) bool m_bIgnorePostPositionalWord; bool m_bShowRecentlyUsedFirst; bool m_bAutoReplaceUnique; // state ::rtl::OUString m_sCurrentPortion; // the text which we are currently working on LanguageType m_nCurrentPortionLang; // language of m_sCurrentPortion found sal_Int32 m_nCurrentStartIndex; // the start index within m_sCurrentPortion of the current convertible portion sal_Int32 m_nCurrentEndIndex; // the end index (excluding) within m_sCurrentPortion of the current convertible portion sal_Int32 m_nReplacementBaseIndex;// index which ReplaceUnit-calls need to be relative to sal_Int32 m_nCurrentConversionOption; sal_Int16 m_nCurrentConversionType; Sequence< ::rtl::OUString > m_aCurrentSuggestions; // the suggestions for the current unit // (means for the text [m_nCurrentStartIndex, m_nCurrentEndIndex) in m_sCurrentPortion) sal_Bool m_bTryBothDirections; // specifies if other conversion directions should be tried when looking for convertible characters public: HangulHanjaConversion_Impl( Window* _pUIParent, const Reference< XMultiServiceFactory >& _rxORB, const Locale& _rSourceLocale, const Locale& _rTargetLocale, const Font* _pTargetFont, sal_Int32 _nConvOptions, sal_Bool _bIsInteractive, HangulHanjaConversion* _pAntiImpl ); public: static void SetUseSavedConversionDirectionState( sal_Bool bVal ); void DoDocumentConversion( ); inline sal_Bool IsByCharacter( ) const { return m_bByCharacter; } inline sal_Bool IsValid() const { return m_xConverter.is(); } inline LanguageType GetSourceLang() const { return m_nSourceLang; } inline LanguageType GetTargetLang() const { return m_nTargetLang; } inline const Font * GetTargetFont() const { return m_pTargetFont; } inline sal_Int32 GetConvOptions() const { return m_nConvOptions; } inline sal_Bool IsInteractive() const { return m_bIsInteractive; } protected: void createDialog(); /** continue with the conversion, return if and only if the complete conversion is done @param _bRepeatCurrentUnit if , an implNextConvertible will be called initially to advance to the next convertible. if , the method will initially work with the current convertible unit */ sal_Bool ContinueConversion( bool _bRepeatCurrentUnit ); private: DECL_LINK( OnOptionsChanged, void* ); DECL_LINK( OnIgnore, void* ); DECL_LINK( OnIgnoreAll, void* ); DECL_LINK( OnChange, void* ); DECL_LINK( OnChangeAll, void* ); DECL_LINK( OnByCharClicked, CheckBox* ); DECL_LINK( OnConversionTypeChanged, void* ); DECL_LINK( OnFind, void* ); /** proceed, after the current convertible has been handled

Attention: When returning from this method, the dialog may have been deleted!

@param _bRepeatCurrentUnit will be passed to the ContinueConversion call */ void implProceed( bool _bRepeatCurrentUnit ); // change the current convertible, and do _not_ proceed void implChange( const ::rtl::OUString& _rChangeInto ); /** find the next convertible piece of text, with possibly advancing to the next portion @see HangulHanjaConversion::GetNextPortion */ sal_Bool implNextConvertible( bool _bRepeatUnit ); /** find the next convertible unit within the current portion @param _bRepeatUnit if , the search will start at the beginning of the current unit, if , it will start at the end of the current unit */ bool implNextConvertibleUnit( const sal_Int32 _nStartAt ); /** retrieves the next portion, with setting the index members properly @return if and only if there is a next portion */ bool implRetrieveNextPortion( ); /** determine the ConversionDirection for m_sCurrentPortion @return if and only if something went wrong */ bool implGetConversionDirectionForCurrentPortion( HHC::ConversionDirection& rDirection ); /** member m_aCurrentSuggestions and m_nCurrentEndIndex are updated according to the other settings and current dictionaries if _bAllowSearchNextConvertibleText is true _nStartAt is used as starting point to search the next convertible text portion. This may result in changing of the member m_nCurrentStartIndex additionally. @return if Suggestions were found */ bool implUpdateSuggestions( const bool _bAllowSearchNextConvertibleText=false, const sal_Int32 _nStartAt=-1 ); /** reads the options from Hangul/Hanja Options dialog that are saved to configuration */ void implReadOptionsFromConfiguration(); /** get the string currently considered to be replaced or ignored */ ::rtl::OUString GetCurrentUnit() const; /** read options from configuration, update suggestion list and dialog content */ void implUpdateData(); /** get the conversion direction dependent from m_eConvType and m_eCurrentConversionDirection in case of switching the direction is allowed this can be triggered with parameter bSwitchDirection */ sal_Int16 implGetConversionType( bool bSwitchDirection=false ) const; }; //========================================================================= //= HangulHanjaConversion_Impl //========================================================================= //------------------------------------------------------------------------- // static member initialization HangulHanjaConversion_Impl::StringMap HangulHanjaConversion_Impl::m_aRecentlyUsedList = HangulHanjaConversion_Impl::StringMap(); //------------------------------------------------------------------------- HangulHanjaConversion_Impl::HangulHanjaConversion_Impl( Window* _pUIParent, const Reference< XMultiServiceFactory >& _rxORB, const Locale& _rSourceLocale, const Locale& _rTargetLocale, const Font* _pTargetFont, sal_Int32 _nOptions, sal_Bool _bIsInteractive, HangulHanjaConversion* _pAntiImpl ) : m_pConversionDialog( NULL ) , m_pUIParent( _pUIParent ) , m_xORB( _rxORB ) , m_aSourceLocale( _rSourceLocale ) , m_nSourceLang( SvxLocaleToLanguage( _rSourceLocale ) ) , m_nTargetLang( SvxLocaleToLanguage( _rTargetLocale ) ) , m_pTargetFont( _pTargetFont ) , m_bIsInteractive( _bIsInteractive ) , m_pAntiImpl( _pAntiImpl ) , m_nCurrentPortionLang( LANGUAGE_NONE ) , m_nCurrentStartIndex( 0 ) , m_nCurrentEndIndex( 0 ) , m_nReplacementBaseIndex( 0 ) , m_nCurrentConversionOption( TextConversionOption::NONE ) , m_nCurrentConversionType( -1 ) // not yet known , m_bTryBothDirections( sal_True ) { implReadOptionsFromConfiguration(); DBG_ASSERT( m_xORB.is(), "HangulHanjaConversion_Impl::HangulHanjaConversion_Impl: no ORB!" ); // determine conversion type if (m_nSourceLang == LANGUAGE_KOREAN && m_nTargetLang == LANGUAGE_KOREAN) m_eConvType = HHC::eConvHangulHanja; else if ( (m_nSourceLang == LANGUAGE_CHINESE_TRADITIONAL && m_nTargetLang == LANGUAGE_CHINESE_SIMPLIFIED) || (m_nSourceLang == LANGUAGE_CHINESE_SIMPLIFIED && m_nTargetLang == LANGUAGE_CHINESE_TRADITIONAL) ) m_eConvType = HHC::eConvSimplifiedTraditional; else { DBG_ERROR( "failed to determine conversion type from languages" ); } // set remaining conversion parameters to their default values m_nConvOptions = _nOptions; m_bByCharacter = 0 != (_nOptions & CHARACTER_BY_CHARACTER); m_eConversionFormat = HHC::eSimpleConversion; m_ePrimaryConversionDirection = HHC::eHangulToHanja; // used for eConvHangulHanja m_eCurrentConversionDirection = HHC::eHangulToHanja; // used for eConvHangulHanja if ( m_xORB.is() ) { ::rtl::OUString sTextConversionService( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.i18n.TextConversion" ) ); m_xConverter = m_xConverter.query( m_xORB->createInstance( sTextConversionService ) ); if ( !m_xConverter.is() ) ShowServiceNotAvailableError( m_pUIParent, sTextConversionService, sal_True ); } } //------------------------------------------------------------------------- void HangulHanjaConversion_Impl::createDialog() { DBG_ASSERT( m_bIsInteractive, "createDialog when the conversion should not be interactive?" ); if ( m_bIsInteractive && !m_pConversionDialog ) { EditAbstractDialogFactory* pFact = EditAbstractDialogFactory::Create(); if(pFact) { m_pConversionDialog = pFact->CreateHangulHanjaConversionDialog(m_pUIParent, m_ePrimaryConversionDirection ); DBG_ASSERT(m_pConversionDialog, "Dialogdiet fail!");//CHINA001 m_pConversionDialog->EnableRubySupport( m_pAntiImpl->HasRubySupport() ); m_pConversionDialog->SetByCharacter( m_bByCharacter ); m_pConversionDialog->SetConversionFormat( m_eConversionFormat ); m_pConversionDialog->SetConversionDirectionState( m_bTryBothDirections, m_ePrimaryConversionDirection ); // the handlers m_pConversionDialog->SetOptionsChangedHdl( LINK( this, HangulHanjaConversion_Impl, OnOptionsChanged ) ); m_pConversionDialog->SetIgnoreHdl( LINK( this, HangulHanjaConversion_Impl, OnIgnore ) ); m_pConversionDialog->SetIgnoreAllHdl( LINK( this, HangulHanjaConversion_Impl, OnIgnoreAll ) ); m_pConversionDialog->SetChangeHdl( LINK( this, HangulHanjaConversion_Impl, OnChange ) ); m_pConversionDialog->SetChangeAllHdl( LINK( this, HangulHanjaConversion_Impl, OnChangeAll ) ); m_pConversionDialog->SetClickByCharacterHdl( LINK( this, HangulHanjaConversion_Impl, OnByCharClicked ) ); m_pConversionDialog->SetConversionFormatChangedHdl( LINK( this, HangulHanjaConversion_Impl, OnConversionTypeChanged ) ); m_pConversionDialog->SetFindHdl( LINK( this, HangulHanjaConversion_Impl, OnFind ) ); } } } //------------------------------------------------------------------------- sal_Int16 HangulHanjaConversion_Impl::implGetConversionType( bool bSwitchDirection ) const { sal_Int16 nConversionType = -1; if (m_eConvType == HHC::eConvHangulHanja) nConversionType = HHC::eHangulToHanja == ( m_eCurrentConversionDirection && !bSwitchDirection ) ? TO_HANJA : TO_HANGUL; else if (m_eConvType == HHC::eConvSimplifiedTraditional) nConversionType = LANGUAGE_CHINESE_SIMPLIFIED == m_nTargetLang ? TO_SCHINESE : TO_TCHINESE; DBG_ASSERT( nConversionType != -1, "unexpected conversion type" ); return nConversionType; } //------------------------------------------------------------------------- bool HangulHanjaConversion_Impl::implUpdateSuggestions( bool _bAllowSearchNextConvertibleText, const sal_Int32 _nStartAt ) { // parameters for the converter sal_Int32 nStartSearch = m_nCurrentStartIndex; if( _bAllowSearchNextConvertibleText ) nStartSearch = _nStartAt; sal_Int32 nLength = m_sCurrentPortion.getLength() - nStartSearch; m_nCurrentConversionType = implGetConversionType(); m_nCurrentConversionOption = IsByCharacter() ? CHARACTER_BY_CHARACTER : NONE; if( m_bIgnorePostPositionalWord ) m_nCurrentConversionOption = m_nCurrentConversionOption | IGNORE_POST_POSITIONAL_WORD; // no need to check both directions for chinese conversion (saves time) if (m_eConvType == HHC::eConvSimplifiedTraditional) m_bTryBothDirections = sal_False; sal_Bool bFoundAny = sal_True; try { TextConversionResult aResult = m_xConverter->getConversions( m_sCurrentPortion, nStartSearch, nLength, m_aSourceLocale, m_nCurrentConversionType, m_nCurrentConversionOption ); sal_Bool bFoundPrimary = aResult.Boundary.startPos < aResult.Boundary.endPos; bFoundAny = bFoundPrimary; if ( m_bTryBothDirections ) { // see if we find another convertible when assuming the other direction TextConversionResult aSecondResult = m_xConverter->getConversions( m_sCurrentPortion, nStartSearch, nLength, m_aSourceLocale, implGetConversionType( true ), // switched! m_nCurrentConversionOption ); if ( aSecondResult.Boundary.startPos < aSecondResult.Boundary.endPos ) { // we indeed found such a convertible // in case the first attempt (with the original conversion direction) // didn't find anything if ( !bFoundPrimary // or if the second location is _before_ the first one || ( aSecondResult.Boundary.startPos < aResult.Boundary.startPos ) ) { // then use the second finding aResult = aSecondResult; // our current conversion direction changed now m_eCurrentConversionDirection = ( HHC::eHangulToHanja == m_eCurrentConversionDirection ) ? HHC::eHanjaToHangul : HHC::eHangulToHanja; bFoundAny = sal_True; } } } if( _bAllowSearchNextConvertibleText ) { //this might change the current position m_aCurrentSuggestions = aResult.Candidates; m_nCurrentStartIndex = aResult.Boundary.startPos; m_nCurrentEndIndex = aResult.Boundary.endPos; } else { //the change of starting position is not allowed if( m_nCurrentStartIndex == aResult.Boundary.startPos && aResult.Boundary.endPos != aResult.Boundary.startPos ) { m_aCurrentSuggestions = aResult.Candidates; m_nCurrentEndIndex = aResult.Boundary.endPos; } else { m_aCurrentSuggestions.realloc( 0 ); if( m_sCurrentPortion.getLength() >= m_nCurrentStartIndex+1 ) m_nCurrentEndIndex = m_nCurrentStartIndex+1; } } //put recently used string to front: if( m_bShowRecentlyUsedFirst && m_aCurrentSuggestions.getLength()>1 ) { ::rtl::OUString sCurrentUnit( GetCurrentUnit() ); StringMap::const_iterator aRecentlyUsed = m_aRecentlyUsedList.find( sCurrentUnit ); bool bUsedBefore = aRecentlyUsed != m_aRecentlyUsedList.end(); if( bUsedBefore && m_aCurrentSuggestions[0] != aRecentlyUsed->second ) { sal_Int32 nCount = m_aCurrentSuggestions.getLength(); Sequence< ::rtl::OUString > aTmp(nCount); aTmp[0]=aRecentlyUsed->second; sal_Int32 nDiff = 1; for( sal_Int32 n=1; nsecond ) nDiff=0; aTmp[n]=m_aCurrentSuggestions[n-nDiff]; } m_aCurrentSuggestions = aTmp; } } } catch( const Exception& ) { DBG_ERROR( "HangulHanjaConversion_Impl::implNextConvertibleUnit: caught an exception!" ); //!!! at least we want to move on in the text in order //!!! to avoid an endless loop... return false; } return bFoundAny; } //------------------------------------------------------------------------- bool HangulHanjaConversion_Impl::implNextConvertibleUnit( const sal_Int32 _nStartAt ) { m_aCurrentSuggestions.realloc( 0 ); // ask the TextConversion service for the next convertible piece of text // get current values from dialog if( m_eConvType == HHC::eConvHangulHanja && m_pConversionDialog ) { m_bTryBothDirections = m_pConversionDialog->GetUseBothDirections(); HHC::ConversionDirection eDialogDirection = HHC::eHangulToHanja; eDialogDirection = m_pConversionDialog->GetDirection( eDialogDirection ); if( !m_bTryBothDirections && eDialogDirection != m_eCurrentConversionDirection ) { m_eCurrentConversionDirection = eDialogDirection; } // save currently used value for possible later use m_pAntiImpl->m_bTryBothDirectionsSave = m_bTryBothDirections; m_pAntiImpl->m_ePrimaryConversionDirectionSave = m_eCurrentConversionDirection; } bool bFoundAny = implUpdateSuggestions( true, _nStartAt ); return bFoundAny && (m_nCurrentStartIndex < m_sCurrentPortion.getLength()); } //------------------------------------------------------------------------- bool HangulHanjaConversion_Impl::implRetrieveNextPortion( ) { sal_Bool bAllowImplicitChanges = m_eConvType == HHC::eConvSimplifiedTraditional; m_sCurrentPortion = ::rtl::OUString(); m_nCurrentPortionLang = LANGUAGE_NONE; m_pAntiImpl->GetNextPortion( m_sCurrentPortion, m_nCurrentPortionLang, bAllowImplicitChanges ); m_nReplacementBaseIndex = 0; m_nCurrentStartIndex = m_nCurrentEndIndex = 0; bool bRet = 0 != m_sCurrentPortion.getLength(); if (m_eConvType == HHC::eConvHangulHanja && m_bTryBothDirections) implGetConversionDirectionForCurrentPortion( m_eCurrentConversionDirection ); return bRet; } //------------------------------------------------------------------------- sal_Bool HangulHanjaConversion_Impl::implNextConvertible( bool _bRepeatUnit ) { if ( _bRepeatUnit || ( m_nCurrentEndIndex < m_sCurrentPortion.getLength() ) ) { if ( implNextConvertibleUnit( _bRepeatUnit ? ( IsByCharacter() ? m_nCurrentStartIndex : m_nCurrentStartIndex ) : m_nCurrentEndIndex ) ) return sal_True; } // no convertible text in the current portion anymore // -> advance to the next portion do { // next portion if ( implRetrieveNextPortion( ) ) { // there is a next portion // -> find the next convertible unit in the current portion if ( implNextConvertibleUnit( 0 ) ) return sal_True; } } while ( m_sCurrentPortion.getLength() ); // no more portions return sal_False; } //------------------------------------------------------------------------- ::rtl::OUString HangulHanjaConversion_Impl::GetCurrentUnit() const { DBG_ASSERT( m_nCurrentStartIndex < m_sCurrentPortion.getLength(), "HangulHanjaConversion_Impl::GetCurrentUnit: invalid index into current portion!" ); DBG_ASSERT( m_nCurrentEndIndex <= m_sCurrentPortion.getLength(), "HangulHanjaConversion_Impl::GetCurrentUnit: invalid index into current portion!" ); DBG_ASSERT( m_nCurrentStartIndex <= m_nCurrentEndIndex, "HangulHanjaConversion_Impl::GetCurrentUnit: invalid interval!" ); ::rtl::OUString sCurrentUnit = m_sCurrentPortion.copy( m_nCurrentStartIndex, m_nCurrentEndIndex - m_nCurrentStartIndex ); return sCurrentUnit; } //------------------------------------------------------------------------- sal_Bool HangulHanjaConversion_Impl::ContinueConversion( bool _bRepeatCurrentUnit ) { sal_Bool bNeedUserInteraction = sal_False; // when we leave here, do we need user interaction? sal_Bool bDocumentDone = sal_False; // did we already check the whole document? while ( !bDocumentDone && !bNeedUserInteraction && implNextConvertible( _bRepeatCurrentUnit ) ) { ::rtl::OUString sCurrentUnit( GetCurrentUnit() ); // do we need to ignore it? sal_Bool bAlwaysIgnoreThis = m_sIgnoreList.end() != m_sIgnoreList.find( sCurrentUnit ); // do we need to change it? StringMap::const_iterator aChangeListPos = m_aChangeList.find( sCurrentUnit ); sal_Bool bAlwaysChangeThis = m_aChangeList.end() != aChangeListPos; // do we automatically change this? sal_Bool bAutoChange = m_bAutoReplaceUnique && m_aCurrentSuggestions.getLength() == 1; if (!m_bIsInteractive) { // silent conversion (e.g. for simplified/traditional Chinese)... if(m_aCurrentSuggestions.getLength()>0) implChange( m_aCurrentSuggestions.getConstArray()[0] ); } else if (bAutoChange) { implChange( m_aCurrentSuggestions.getConstArray()[0] ); } else if ( bAlwaysChangeThis ) { implChange( aChangeListPos->second ); } else if ( !bAlwaysIgnoreThis ) { // here we need to ask the user for what to do with the text // for this, allow derivees to highlight the current text unit in a possible document view m_pAntiImpl->HandleNewUnit( m_nCurrentStartIndex - m_nReplacementBaseIndex, m_nCurrentEndIndex - m_nReplacementBaseIndex ); DBG_ASSERT( m_pConversionDialog, "we should always have a dialog here!" ); if( m_pConversionDialog ) m_pConversionDialog->SetCurrentString( sCurrentUnit, m_aCurrentSuggestions ); // do not look for the next convertible: We have to wait for the user to interactivly // decide what happens with the current convertible bNeedUserInteraction = sal_True; } } /* if ( bDocumentDone ) return sal_True; // we explicitly know that the complete document is done else if ( bNeedUserInteraction ) return sal_False; // the doc is not done, we found a convertible, but need the user to decide else return sal_True; // we did not find a next convertible, so the document is implicitly done */ return bDocumentDone || !bNeedUserInteraction; } //------------------------------------------------------------------------- bool HangulHanjaConversion_Impl::implGetConversionDirectionForCurrentPortion( HHC::ConversionDirection& rDirection ) { // - For eConvHangulHanja the direction is determined by // the first encountered Korean character. // - For eConvSimplifiedTraditional the conversion direction // is already specified by the source language. bool bSuccess = true; if (m_eConvType == HHC::eConvHangulHanja) { bSuccess = false; try { // get the break iterator service ::rtl::OUString sBreakIteratorService( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.i18n.BreakIterator" ) ); Reference< XInterface > xBI( m_xORB->createInstance( ::rtl::OUString( sBreakIteratorService ) ) ); Reference< XBreakIterator > xBreakIter( xBI, UNO_QUERY ); if ( !xBreakIter.is() ) { ShowServiceNotAvailableError( m_pUIParent, sBreakIteratorService, sal_True ); } else { sal_Int32 nNextAsianScript = xBreakIter->beginOfScript( m_sCurrentPortion, m_nCurrentStartIndex, com::sun::star::i18n::ScriptType::ASIAN ); if ( -1 == nNextAsianScript ) nNextAsianScript = xBreakIter->nextScript( m_sCurrentPortion, m_nCurrentStartIndex, com::sun::star::i18n::ScriptType::ASIAN ); if ( ( nNextAsianScript >= m_nCurrentStartIndex ) && ( nNextAsianScript < m_sCurrentPortion.getLength() ) ) { // found asian text // determine if it's Hangul CharClass aCharClassificaton( m_xORB, m_aSourceLocale ); sal_Int16 nScript = aCharClassificaton.getScript( m_sCurrentPortion, sal::static_int_cast< sal_uInt16 >(nNextAsianScript) ); if ( ( UnicodeScript_kHangulJamo == nScript ) || ( UnicodeScript_kHangulCompatibilityJamo == nScript ) || ( UnicodeScript_kHangulSyllable == nScript ) ) { rDirection = HHC::eHangulToHanja; } else { rDirection = HHC::eHanjaToHangul; } bSuccess = true; } } } catch( const Exception& ) { DBG_ERROR( "HangulHanjaConversion_Impl::implGetConversionDirectionForCurrentPortion: caught an exception!" ); } } return bSuccess; } //------------------------------------------------------------------------- void HangulHanjaConversion_Impl::DoDocumentConversion( ) { // clear the change-all list - it's to be re-initialized for every single document { StringMap aEmpty; m_aChangeList.swap( aEmpty ); } // first of all, we need to guess the direction of our conversion - it is determined by the first // hangul or hanja character in the first text if ( !implRetrieveNextPortion() ) { DBG_WARNING( "HangulHanjaConversion_Impl::DoDocumentConversion: why did you call me if you do have nothing to convert?" ); // nothing to do return; } if( m_eConvType == HHC::eConvHangulHanja ) { //init conversion direction from saved value HHC::ConversionDirection eDirection = HHC::eHangulToHanja; if(!implGetConversionDirectionForCurrentPortion( eDirection )) // something went wrong, has already been asserted return; if (m_pAntiImpl->IsUseSavedConversionDirectionState()) { m_ePrimaryConversionDirection = m_pAntiImpl->m_ePrimaryConversionDirectionSave; m_bTryBothDirections = m_pAntiImpl->m_bTryBothDirectionsSave; if( m_bTryBothDirections ) m_eCurrentConversionDirection = eDirection; else m_eCurrentConversionDirection = m_ePrimaryConversionDirection; } else { m_ePrimaryConversionDirection = eDirection; m_eCurrentConversionDirection = eDirection; } } if (m_bIsInteractive && m_eConvType == HHC::eConvHangulHanja) { //always open dialog if at least having a hangul or hanja text portion createDialog(); if(m_pAntiImpl->IsUseSavedConversionDirectionState()) ContinueConversion( sal_False ); else implUpdateData(); m_pConversionDialog->Execute(); DELETEZ( m_pConversionDialog ); } else { #ifdef DBG_UTIL sal_Bool bCompletelyDone = #endif ContinueConversion( sal_False ); DBG_ASSERT( bCompletelyDone, "HangulHanjaConversion_Impl::DoDocumentConversion: ContinueConversion should have returned true here!" ); } } //------------------------------------------------------------------------- void HangulHanjaConversion_Impl::implProceed( bool _bRepeatCurrentUnit ) { if ( ContinueConversion( _bRepeatCurrentUnit ) ) { // we're done with the whole document DBG_ASSERT( !m_bIsInteractive || m_pConversionDialog, "HangulHanjaConversion_Impl::implProceed: we should not reach this here without dialog!" ); if ( m_pConversionDialog ) m_pConversionDialog->EndDialog( RET_OK ); } } //------------------------------------------------------------------------- void HangulHanjaConversion_Impl::implChange( const ::rtl::OUString& _rChangeInto ) { if( !_rChangeInto.getLength() ) return; // translate the conversion format into a replacement action // this translation depends on whether we have a Hangul original, or a Hanja original HHC::ReplacementAction eAction( HHC::eExchange ); if (m_eConvType == HHC::eConvHangulHanja) { // is the original we're about to change in Hangul? sal_Bool bOriginalIsHangul = HHC::eHangulToHanja == m_eCurrentConversionDirection; switch ( m_eConversionFormat ) { case HHC::eSimpleConversion: eAction = HHC::eExchange; break; case HHC::eHangulBracketed: eAction = bOriginalIsHangul ? HHC::eOriginalBracketed : HHC::eReplacementBracketed; break; case HHC::eHanjaBracketed: eAction = bOriginalIsHangul ? HHC::eReplacementBracketed : HHC::eOriginalBracketed; break; case HHC::eRubyHanjaAbove: eAction = bOriginalIsHangul ? HHC::eReplacementAbove : HHC::eOriginalAbove; break; case HHC::eRubyHanjaBelow: eAction = bOriginalIsHangul ? HHC::eReplacementBelow : HHC::eOriginalBelow; break; case HHC::eRubyHangulAbove: eAction = bOriginalIsHangul ? HHC::eOriginalAbove : HHC::eReplacementAbove; break; case HHC::eRubyHangulBelow: eAction = bOriginalIsHangul ? HHC::eOriginalBelow : HHC::eReplacementBelow; break; default: DBG_ERROR( "HangulHanjaConversion_Impl::implChange: invalid/unexpected conversion format!" ); } } // the proper indices (the wrapper implementation needs indices relative to the // previous replacement) DBG_ASSERT( ( m_nReplacementBaseIndex <= m_nCurrentStartIndex ) && ( m_nReplacementBaseIndex <= m_nCurrentEndIndex ), "HangulHanjaConversion_Impl::implChange: invalid replacement base!" ); sal_Int32 nStartIndex = m_nCurrentStartIndex - m_nReplacementBaseIndex; sal_Int32 nEndIndex = m_nCurrentEndIndex - m_nReplacementBaseIndex; //remind this decision m_aRecentlyUsedList[ GetCurrentUnit() ] = _rChangeInto; LanguageType *pNewUnitLang = 0; LanguageType nNewUnitLang = LANGUAGE_NONE; if (m_eConvType == HHC::eConvSimplifiedTraditional) { // check if language needs to be changed if ( m_pAntiImpl->GetTargetLanguage() == LANGUAGE_CHINESE_TRADITIONAL && !m_pAntiImpl->IsTraditional( m_nCurrentPortionLang )) nNewUnitLang = LANGUAGE_CHINESE_TRADITIONAL; else if ( m_pAntiImpl->GetTargetLanguage() == LANGUAGE_CHINESE_SIMPLIFIED && !m_pAntiImpl->IsSimplified( m_nCurrentPortionLang )) nNewUnitLang = LANGUAGE_CHINESE_SIMPLIFIED; if (nNewUnitLang != LANGUAGE_NONE) pNewUnitLang = &nNewUnitLang; } // according to FT we should not (yet) bother about Hangul/Hanja conversion here // // aOffsets is needed in ReplaceUnit below in order to to find out // exactly which characters are really changed in order to keep as much // from attributation for the text as possible. Sequence< sal_Int32 > aOffsets; Reference< XExtendedTextConversion > xExtConverter( m_xConverter, UNO_QUERY ); if (m_eConvType == HHC::eConvSimplifiedTraditional && xExtConverter.is()) { try { ::rtl::OUString aConvText = xExtConverter->getConversionWithOffset( m_sCurrentPortion, m_nCurrentStartIndex, m_nCurrentEndIndex - m_nCurrentStartIndex, m_aSourceLocale, m_nCurrentConversionType, m_nCurrentConversionOption, aOffsets ); } catch( const Exception& ) { DBG_ERROR( "HangulHanjaConversion_Impl::implChange: caught unexpected exception!" ); aOffsets.realloc(0); } } // do the replacement m_pAntiImpl->ReplaceUnit( nStartIndex, nEndIndex, m_sCurrentPortion, _rChangeInto, aOffsets, eAction, pNewUnitLang ); // adjust the replacement base m_nReplacementBaseIndex = m_nCurrentEndIndex; } //------------------------------------------------------------------------- void HangulHanjaConversion_Impl::implReadOptionsFromConfiguration() { SvtLinguConfig aLngCfg; aLngCfg.GetProperty( UPH_IS_IGNORE_POST_POSITIONAL_WORD ) >>= m_bIgnorePostPositionalWord; aLngCfg.GetProperty( UPH_IS_SHOW_ENTRIES_RECENTLY_USED_FIRST ) >>= m_bShowRecentlyUsedFirst; aLngCfg.GetProperty( UPH_IS_AUTO_REPLACE_UNIQUE_ENTRIES ) >>= m_bAutoReplaceUnique; } //------------------------------------------------------------------------- void HangulHanjaConversion_Impl::implUpdateData() { implReadOptionsFromConfiguration(); implUpdateSuggestions(); if(m_pConversionDialog) { ::rtl::OUString sCurrentUnit( GetCurrentUnit() ); m_pConversionDialog->SetCurrentString( sCurrentUnit, m_aCurrentSuggestions ); m_pConversionDialog->FocusSuggestion(); } m_pAntiImpl->HandleNewUnit( m_nCurrentStartIndex - m_nReplacementBaseIndex, m_nCurrentEndIndex - m_nReplacementBaseIndex ); } //------------------------------------------------------------------------- IMPL_LINK( HangulHanjaConversion_Impl, OnOptionsChanged, void*, EMPTYARG ) { //options and dictionaries might have been changed //-> update our internal settings and the dialog implUpdateData(); return 0L; } //------------------------------------------------------------------------- IMPL_LINK( HangulHanjaConversion_Impl, OnIgnore, void*, EMPTYARG ) { // simply ignore, and proceed implProceed( sal_False ); return 0L; } //------------------------------------------------------------------------- IMPL_LINK( HangulHanjaConversion_Impl, OnIgnoreAll, void*, EMPTYARG ) { DBG_ASSERT( m_pConversionDialog, "HangulHanjaConversion_Impl::OnIgnoreAll: no dialog! How this?" ); if ( m_pConversionDialog ) { String sCurrentUnit = m_pConversionDialog->GetCurrentString(); DBG_ASSERT( m_sIgnoreList.end() == m_sIgnoreList.find( sCurrentUnit ), "HangulHanjaConversion_Impl, OnIgnoreAll: shouldn't this have been ignored before" ); // put into the "ignore all" list m_sIgnoreList.insert( sCurrentUnit ); // and proceed implProceed( sal_False ); } return 0L; } //------------------------------------------------------------------------- IMPL_LINK( HangulHanjaConversion_Impl, OnChange, void*, EMPTYARG ) { // change DBG_ASSERT( m_pConversionDialog, "we should always have a dialog here!" ); if( m_pConversionDialog ) implChange( m_pConversionDialog->GetCurrentSuggestion( ) ); // and proceed implProceed( sal_False ); return 0L; } //------------------------------------------------------------------------- IMPL_LINK( HangulHanjaConversion_Impl, OnChangeAll, void*, EMPTYARG ) { DBG_ASSERT( m_pConversionDialog, "HangulHanjaConversion_Impl::OnChangeAll: no dialog! How this?" ); if ( m_pConversionDialog ) { ::rtl::OUString sCurrentUnit( m_pConversionDialog->GetCurrentString() ); ::rtl::OUString sChangeInto( m_pConversionDialog->GetCurrentSuggestion( ) ); if( sChangeInto.getLength() ) { // change the current occurrence implChange( sChangeInto ); // put into the "change all" list m_aChangeList.insert( StringMap::value_type( sCurrentUnit, sChangeInto ) ); } // and proceed implProceed( sal_False ); } return 0L; } //------------------------------------------------------------------------- IMPL_LINK( HangulHanjaConversion_Impl, OnByCharClicked, CheckBox*, _pBox ) { m_bByCharacter = _pBox->IsChecked(); // continue conversion, without advancing to the next unit, but instead continuing with the current unit implProceed( sal_True ); return 0L; } //------------------------------------------------------------------------- IMPL_LINK( HangulHanjaConversion_Impl, OnConversionTypeChanged, void*, EMPTYARG ) { DBG_ASSERT( m_pConversionDialog, "we should always have a dialog here!" ); if( m_pConversionDialog ) m_eConversionFormat = m_pConversionDialog->GetConversionFormat( ); return 0L; } //------------------------------------------------------------------------- IMPL_LINK( HangulHanjaConversion_Impl, OnFind, void*, EMPTYARG ) { DBG_ASSERT( m_pConversionDialog, "HangulHanjaConversion_Impl::OnFind: where did this come from?" ); if ( m_pConversionDialog ) { try { ::rtl::OUString sNewOriginal( m_pConversionDialog->GetCurrentSuggestion( ) ); Sequence< ::rtl::OUString > aSuggestions; DBG_ASSERT( m_xConverter.is(), "HangulHanjaConversion_Impl::OnFind: no converter!" ); TextConversionResult aToHanja = m_xConverter->getConversions( sNewOriginal, 0, sNewOriginal.getLength(), m_aSourceLocale, TextConversionType::TO_HANJA, TextConversionOption::NONE ); TextConversionResult aToHangul = m_xConverter->getConversions( sNewOriginal, 0, sNewOriginal.getLength(), m_aSourceLocale, TextConversionType::TO_HANGUL, TextConversionOption::NONE ); bool bHaveToHanja = ( aToHanja.Boundary.startPos < aToHanja.Boundary.endPos ); bool bHaveToHangul = ( aToHangul.Boundary.startPos < aToHangul.Boundary.endPos ); TextConversionResult* pResult = NULL; if ( bHaveToHanja && bHaveToHangul ) { // it found convertibles in both directions -> use the first if ( aToHangul.Boundary.startPos < aToHanja.Boundary.startPos ) pResult = &aToHangul; else pResult = &aToHanja; } else if ( bHaveToHanja ) { // only found toHanja pResult = &aToHanja; } else { // only found toHangul pResult = &aToHangul; } if ( pResult ) aSuggestions = pResult->Candidates; m_pConversionDialog->SetCurrentString( sNewOriginal, aSuggestions, false ); m_pConversionDialog->FocusSuggestion(); } catch( const Exception& ) { DBG_ERROR( "HangulHanjaConversion_Impl::OnFind: caught an exception!" ); } } return 0L; } //========================================================================= //= HangulHanjaConversion //========================================================================= //------------------------------------------------------------------------- // static member initialization sal_Bool HangulHanjaConversion::m_bUseSavedValues = sal_False; sal_Bool HangulHanjaConversion::m_bTryBothDirectionsSave = sal_False; HHC::ConversionDirection HangulHanjaConversion::m_ePrimaryConversionDirectionSave = HHC::eHangulToHanja; //------------------------------------------------------------------------- HangulHanjaConversion::HangulHanjaConversion( Window* _pUIParent, const Reference< XMultiServiceFactory >& _rxORB, const Locale& _rSourceLocale, const Locale& _rTargetLocale, const Font* _pTargetFont, sal_Int32 _nOptions, sal_Bool _bIsInteractive) :m_pImpl( new HangulHanjaConversion_Impl( _pUIParent, _rxORB, _rSourceLocale, _rTargetLocale, _pTargetFont, _nOptions, _bIsInteractive, this ) ) { } //------------------------------------------------------------------------- HangulHanjaConversion::~HangulHanjaConversion( ) { } //------------------------------------------------------------------------- void HangulHanjaConversion::SetUseSavedConversionDirectionState( sal_Bool bVal ) { m_bUseSavedValues = bVal; } //------------------------------------------------------------------------- sal_Bool HangulHanjaConversion::IsUseSavedConversionDirectionState() { return m_bUseSavedValues; } //------------------------------------------------------------------------- LanguageType HangulHanjaConversion::GetSourceLanguage( ) const { return m_pImpl->GetSourceLang(); } //------------------------------------------------------------------------- LanguageType HangulHanjaConversion::GetTargetLanguage( ) const { return m_pImpl->GetTargetLang(); } //------------------------------------------------------------------------- const Font * HangulHanjaConversion::GetTargetFont( ) const { return m_pImpl->GetTargetFont(); } //------------------------------------------------------------------------- sal_Int32 HangulHanjaConversion::GetConversionOptions( ) const { return m_pImpl->GetConvOptions(); } //------------------------------------------------------------------------- sal_Bool HangulHanjaConversion::IsInteractive( ) const { return m_pImpl->IsInteractive(); } //------------------------------------------------------------------------- void HangulHanjaConversion::HandleNewUnit( const sal_Int32, const sal_Int32 ) { // nothing to do, only derived classes need this. } //------------------------------------------------------------------------- void HangulHanjaConversion::GetNextPortion( ::rtl::OUString&, LanguageType&, sal_Bool ) { DBG_ERROR( "HangulHanjaConversion::GetNextPortion: to be overridden!" ); } //------------------------------------------------------------------------- void HangulHanjaConversion::ReplaceUnit( const sal_Int32, const sal_Int32, const ::rtl::OUString&, const ::rtl::OUString&, const ::com::sun::star::uno::Sequence< sal_Int32 > &, ReplacementAction, LanguageType * ) { DBG_ERROR( "HangulHanjaConversion::ReplaceUnit: to be overridden!" ); } //------------------------------------------------------------------------- sal_Bool HangulHanjaConversion::HasRubySupport() const { DBG_ERROR( "HangulHanjaConversion::HasRubySupport: to be overridden!" ); return sal_False; } //------------------------------------------------------------------------- void HangulHanjaConversion::ConvertDocument() { if ( m_pImpl->IsValid() ) m_pImpl->DoDocumentConversion( ); } //............................................................................. } // namespace svx //.............................................................................