/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * 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 .
*/
// general
VclPtr<AbstractHangulHanjaConversionDialog>
m_pConversionDialog; // the dialog to display for user interaction
weld::Widget* m_pUIParent; // the parent window for any UI we raise
Reference< XComponentContext >
m_xContext; // the service factory to use
Reference< XExtendedTextConversion >
m_xConverter; // the text conversion service
lang::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 to // save the applications from always converting to this // type in their implementations
LanguageType m_nTargetLang; // target language of new replacement text const vcl::Font* m_pTargetFont; // target font of new replacement text
sal_Int32 m_nConvOptions; // text conversion options (as used by 'getConversions') bool m_bIsInteractive; // specifies if the conversion requires user interaction // (and likely a specialised dialog) or if it is to run // automatically without any user interaction. // True for Hangul / Hanja conversion // False for Chinese simplified / traditional conversion
// options 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
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< OUString >
m_aCurrentSuggestions; // the suggestions for the current unit // (means for the text [m_nCurrentStartIndex, m_nCurrentEndIndex) in m_sCurrentPortion) bool m_bTryBothDirections; // specifies if other conversion directions should be tried when looking for convertible characters
/** continue with the conversion, return <TRUE/> if and only if the complete conversion is done @param _bRepeatCurrentUnit if <TRUE/>, an implNextConvertible will be called initially to advance to the next convertible. if <FALSE/>, the method will initially work with the current convertible unit
*/ bool ContinueConversion( bool _bRepeatCurrentUnit );
/** find the next convertible unit within the current portion @param _bRepeatUnit if <TRUE/>, the search will start at the beginning of the current unit, if <FALSE/>, 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 <TRUE/> if and only if there is a next portion
*/ bool implRetrieveNextPortion( );
/** determine the ConversionDirection for m_sCurrentPortion @return <FALSE/> 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 <TRUE/> if Suggestions were found
*/ bool implUpdateSuggestions( constbool _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
*/
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;
};
void HangulHanjaConversion_Impl::createDialog()
{
DBG_ASSERT( m_bIsInteractive, "createDialog when the conversion should not be interactive?" ); if ( !m_bIsInteractive || m_pConversionDialog ) return;
// no need to check both directions for chinese conversion (saves time) if (m_eConvType == HHC::eConvSimplifiedTraditional)
m_bTryBothDirections = false;
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 = std::move(aSecondResult);
// our current conversion direction changed now
m_eCurrentConversionDirection = ( HHC::eHangulToHanja == m_eCurrentConversionDirection )
? HHC::eHanjaToHangul : HHC::eHangulToHanja;
bFoundAny = 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;
}
}
// save currently used value for possible later use
HangulHanjaConversion::m_bTryBothDirectionsSave = m_bTryBothDirections;
HangulHanjaConversion::m_ePrimaryConversionDirectionSave = m_eCurrentConversionDirection;
}
// 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 ) ) returntrue;
}
} while ( !m_sCurrentPortion.isEmpty() );
// no more portions returnfalse;
}
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!" );
// do we need to ignore it? constbool bAlwaysIgnoreThis = m_sIgnoreList.end() != m_sIgnoreList.find( sCurrentUnit );
// do we need to change it?
StringMap::const_iterator aChangeListPos = m_aChangeList.find( sCurrentUnit ); constbool bAlwaysChangeThis = m_aChangeList.end() != aChangeListPos;
// do we automatically change this? constbool bAutoChange = m_bAutoReplaceUnique && m_aCurrentSuggestions.getLength() == 1;
if (!m_bIsInteractive)
{ // silent conversion (e.g. for simplified/traditional Chinese)... if(m_aCurrentSuggestions.hasElements())
implChange( m_aCurrentSuggestions.getConstArray()[0] );
} elseif (bAutoChange)
{
implChange( m_aCurrentSuggestions.getConstArray()[0] );
} elseif ( bAlwaysChangeThis )
{
implChange( aChangeListPos->second );
} elseif ( !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 interactively // decide what happens with the current convertible returnfalse;
}
}
returntrue;
}
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
Reference< XBreakIterator > xBreakIter = i18n::BreakIterator::create( m_xContext );
sal_Int32 nNextAsianScript = xBreakIter->beginOfScript( m_sCurrentPortion, m_nCurrentStartIndex, css::i18n::ScriptType::ASIAN ); if ( -1 == nNextAsianScript )
nNextAsianScript = xBreakIter->nextScript( m_sCurrentPortion, m_nCurrentStartIndex, css::i18n::ScriptType::ASIAN ); if ( ( nNextAsianScript >= m_nCurrentStartIndex ) && ( nNextAsianScript < m_sCurrentPortion.getLength() ) )
{ // found asian text
void HangulHanjaConversion_Impl::DoDocumentConversion( )
{ // clear the change-all list - it's to be re-initialized for every single document
StringMap().swap(m_aChangeList);
// 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() )
{
SAL_INFO( "editeng", "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_bIsInteractive && m_eConvType == HHC::eConvHangulHanja)
{ //always open dialog if at least having a hangul or hanja text portion
createDialog(); if(HangulHanjaConversion::IsUseSavedConversionDirectionState())
ContinueConversion( false ); else
implUpdateData();
m_pConversionDialog->Execute();
m_pConversionDialog.disposeAndClear();
} else
{ constbool bCompletelyDone = ContinueConversion( 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 );
}
}
// 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? constbool bOriginalIsHangul = HHC::eHangulToHanja == m_eCurrentConversionDirection;
//remind this decision
m_aRecentlyUsedList[ GetCurrentUnit() ] = _rChangeInto;
LanguageType *pNewUnitLang = nullptr;
LanguageType nNewUnitLang = LANGUAGE_NONE; if (m_eConvType == HHC::eConvSimplifiedTraditional)
{ // check if language needs to be changed if ( m_pAntiImpl->GetTargetLanguage() == LANGUAGE_CHINESE_TRADITIONAL &&
!HangulHanjaConversion::IsTraditional( m_nCurrentPortionLang ))
nNewUnitLang = LANGUAGE_CHINESE_TRADITIONAL; elseif ( m_pAntiImpl->GetTargetLanguage() == LANGUAGE_CHINESE_SIMPLIFIED &&
!HangulHanjaConversion::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 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; if (m_eConvType == HHC::eConvSimplifiedTraditional && m_xConverter.is())
{ try
{
m_xConverter->getConversionWithOffset(
m_sCurrentPortion,
m_nCurrentStartIndex,
m_nCurrentEndIndex - m_nCurrentStartIndex,
m_aSourceLocale,
m_nCurrentConversionType,
m_nCurrentConversionOption,
aOffsets
);
} catch( const Exception& )
{
TOOLS_WARN_EXCEPTION( "editeng", "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;
}
IMPL_LINK_NOARG(HangulHanjaConversion_Impl, OnOptionsChanged, LinkParamNone*, void)
{ //options and dictionaries might have been changed //-> update our internal settings and the dialog
implUpdateData();
}
// continue conversion, without advancing to the next unit, but instead continuing with the current unit
implProceed( true );
}
IMPL_LINK_NOARG(HangulHanjaConversion_Impl, OnConversionTypeChanged, weld::Toggleable&, void)
{
DBG_ASSERT( m_pConversionDialog, "we should always have a dialog here!" ); if( m_pConversionDialog )
m_eConversionFormat = m_pConversionDialog->GetConversionFormat( );
}
IMPL_LINK_NOARG(HangulHanjaConversion_Impl, OnFind, weld::Button&, void)
{
DBG_ASSERT( m_pConversionDialog, "HangulHanjaConversion_Impl::OnFind: where did this come from?" ); if ( !m_pConversionDialog ) return;
TextConversionResult* pResult = nullptr; if ( bHaveToHanja && bHaveToHangul )
{ // it found convertibles in both directions -> use the first if ( aToHangul.Boundary.startPos < aToHanja.Boundary.startPos )
pResult = &aToHangul; else
pResult = &aToHanja;
} elseif ( bHaveToHanja )
{ // only found toHanja
pResult = &aToHanja;
} else
{ // only found toHangul
pResult = &aToHangul;
} if ( pResult )
aSuggestions = pResult->Candidates;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.