2003/04/10 14:22:23 tl 1.1.2.12: #105688# implNextConvertibleUnit fixed 2003/04/09 14:05:15 tl 1.1.2.11: #105688# Linux compiler specific issue fixed 2003/04/03 12:01:27 tl 1.1.2.10: #105688# Hangul/Hanja conversion 2003/04/03 11:59:38 tl 1.1.2.9: #105688# Hangul/Hanja conversion 2003/04/03 07:18:59 tl 1.1.2.8: #105688# minor fixes 2003/04/02 16:14:23 fs 1.1.2.7: #108038# when switching from 'by-character' to 'by-word', don't repeat the current unit 2003/04/01 11:13:30 fs 1.1.2.6: #108038# implNextConvertible: corrected offset 2003/03/28 09:42:48 fs 1.1.2.5: #108038# implementation of the 'Find' behaviour 2003/03/27 16:31:56 fs 1.1.2.4: #108038# indexes in HandleNewUnit are also relative to replacement action 2003/03/27 15:54:14 fs 1.1.2.3: #108038# ongoing implementations 2003/03/19 08:51:43 fs 1.1.2.2: #108038# further implementations - should be in a usable shape now 2003/03/14 16:56:51 fs 1.1.2.1: initial checkin: wrapper for Hangul/Hanja-conversion (not yet finished)
909 lines
39 KiB
C++
909 lines
39 KiB
C++
/*************************************************************************
|
|
*
|
|
* $RCSfile: hangulhanja.cxx,v $
|
|
*
|
|
* $Revision: 1.2 $
|
|
*
|
|
* last change: $Author: vg $ $Date: 2003-04-17 17:41:42 $
|
|
*
|
|
* The Contents of this file are made available subject to the terms of
|
|
* either of the following licenses
|
|
*
|
|
* - GNU Lesser General Public License Version 2.1
|
|
* - Sun Industry Standards Source License Version 1.1
|
|
*
|
|
* Sun Microsystems Inc., October, 2000
|
|
*
|
|
* GNU Lesser General Public License Version 2.1
|
|
* =============================================
|
|
* Copyright 2000 by Sun Microsystems, Inc.
|
|
* 901 San Antonio Road, Palo Alto, CA 94303, USA
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License version 2.1, as published by the Free Software Foundation.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
|
* MA 02111-1307 USA
|
|
*
|
|
*
|
|
* Sun Industry Standards Source License Version 1.1
|
|
* =================================================
|
|
* The contents of this file are subject to the Sun Industry Standards
|
|
* Source License Version 1.1 (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.openoffice.org/license.html.
|
|
*
|
|
* Software provided under this License is provided on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
|
|
* WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
|
|
* MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
|
|
* See the License for the specific provisions governing your rights and
|
|
* obligations concerning the Software.
|
|
*
|
|
* The Initial Developer of the Original Code is: Sun Microsystems, Inc.
|
|
*
|
|
* Copyright: 2000 by Sun Microsystems, Inc.
|
|
*
|
|
* All Rights Reserved.
|
|
*
|
|
* Contributor(s): _______________________________________
|
|
*
|
|
*
|
|
************************************************************************/
|
|
|
|
#ifndef SVX_HANGUL_HANJA_CONVERSION_HXX
|
|
#include "hangulhanja.hxx"
|
|
#endif
|
|
#ifndef SVX_HANGUL_HANJA_DLG_HXX
|
|
#include "hangulhanjadlg.hxx"
|
|
#endif
|
|
|
|
#ifndef _SV_MSGBOX_HXX
|
|
#include <vcl/msgbox.hxx>
|
|
#endif
|
|
|
|
#include <set>
|
|
#include <map>
|
|
|
|
#ifndef _COM_SUN_STAR_UNO_SEQUENCE_HXX_
|
|
#include <com/sun/star/uno/Sequence.hxx>
|
|
#endif
|
|
#ifndef _COM_SUN_STAR_I18N_XBREAKITERATOR_HPP_
|
|
#include <com/sun/star/i18n/XBreakIterator.hpp>
|
|
#endif
|
|
#ifndef _COM_SUN_STAR_I18N_SCRIPTTYPE_HPP_
|
|
#include <com/sun/star/i18n/ScriptType.hpp>
|
|
#endif
|
|
#ifndef _COM_SUN_STAR_I18N_UNICODESCRIPT_HPP_
|
|
#include <com/sun/star/i18n/UnicodeScript.hpp>
|
|
#endif
|
|
#ifndef _COM_SUN_STAR_I18N_XTEXTCONVERSION_HPP_
|
|
#include <com/sun/star/i18n/XTextConversion.hpp>
|
|
#endif
|
|
#ifndef _COM_SUN_STAR_I18N_TEXTCONVERSIONTYPE_HPP_
|
|
#include <com/sun/star/i18n/TextConversionType.hpp>
|
|
#endif
|
|
#ifndef _COM_SUN_STAR_I18N_TEXTCONVERSIONOPTION_HPP_
|
|
#include <com/sun/star/i18n/TextConversionOption.hpp>
|
|
#endif
|
|
#ifndef _COM_SUN_STAR_I18N_WORDTYPE_HPP_
|
|
#include <com/sun/star/i18n/WordType.hpp>
|
|
#endif
|
|
|
|
#ifndef _VCL_STDTEXT_HXX
|
|
#include <vcl/stdtext.hxx>
|
|
#endif
|
|
#ifndef _UNOTOOLS_CHARCLASS_HXX
|
|
#include <unotools/charclass.hxx>
|
|
#endif
|
|
|
|
#define HHC HangulHanjaConversion
|
|
|
|
//.............................................................................
|
|
namespace svx
|
|
{
|
|
//.............................................................................
|
|
|
|
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:
|
|
static StringBag m_sIgnoreList;
|
|
StringMap m_aChangeList;
|
|
|
|
// general
|
|
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_aLocale; // the locale we're working with
|
|
|
|
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
|
|
|
|
// state
|
|
::rtl::OUString m_sCurrentPortion; // the text which we are currently working on
|
|
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
|
|
Sequence< ::rtl::OUString >
|
|
m_aCurrentSuggestions; // the suggestions for the current unit
|
|
// (means for the text [m_nCurrentStartIndex, m_nCurrentEndIndex) in m_sCurrentPortion)
|
|
|
|
#ifdef FS_HANGUL_HANJA
|
|
public:
|
|
::rtl::OUString m_sRememberPos;
|
|
#endif
|
|
|
|
public:
|
|
HangulHanjaConversion_Impl(
|
|
Window* _pUIParent,
|
|
const Reference< XMultiServiceFactory >& _rxORB,
|
|
const Locale& _rLocale,
|
|
HangulHanjaConversion* _pAntiImpl );
|
|
|
|
public:
|
|
void DoDocumentConversion( );
|
|
|
|
inline sal_Bool IsByCharacter( ) const { return m_bByCharacter; }
|
|
|
|
inline sal_Bool IsValid() const { return m_xConverter.is(); }
|
|
|
|
protected:
|
|
void createDialog();
|
|
|
|
/** 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
|
|
*/
|
|
sal_Bool ContinueConversion( bool _bRepeatCurrentUnit );
|
|
|
|
private:
|
|
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
|
|
|
|
<p><b>Attention:</b>
|
|
When returning from this method, the dialog may have been deleted!</p>
|
|
|
|
@param _bRepeatCurrentUnit
|
|
will be passed to the <member>ContinueConversion</member> 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 <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( );
|
|
|
|
/** fill in m_ePrimaryConversionDirection from m_sCurrentPortion
|
|
@return
|
|
<FALSE/> if and only if something went wrong
|
|
*/
|
|
bool implDeterminePrimaryDirection( );
|
|
};
|
|
|
|
//=========================================================================
|
|
//= HangulHanjaConversion_Impl
|
|
//=========================================================================
|
|
HangulHanjaConversion_Impl::StringBag HangulHanjaConversion_Impl::m_sIgnoreList;
|
|
//-------------------------------------------------------------------------
|
|
HangulHanjaConversion_Impl::HangulHanjaConversion_Impl( Window* _pUIParent,
|
|
const Reference< XMultiServiceFactory >& _rxORB, const Locale& _rLocale, HangulHanjaConversion* _pAntiImpl )
|
|
:m_pUIParent( _pUIParent )
|
|
,m_pAntiImpl( _pAntiImpl )
|
|
,m_bByCharacter( sal_False )
|
|
,m_pConversionDialog( NULL )
|
|
,m_eConversionFormat( HHC::eSimpleConversion )
|
|
,m_ePrimaryConversionDirection( HHC::eHangulToHanja )
|
|
,m_eCurrentConversionDirection( HHC::eHangulToHanja )
|
|
,m_nCurrentStartIndex( 0 )
|
|
,m_nCurrentEndIndex( 0 )
|
|
,m_nReplacementBaseIndex( 0 )
|
|
,m_xORB( _rxORB )
|
|
,m_aLocale( _rLocale )
|
|
{
|
|
DBG_ASSERT( m_xORB.is(), "HangulHanjaConversion_Impl::HangulHanjaConversion_Impl: no ORB!" );
|
|
// TODO: initialize m_bByCharacter and m_eConversionFormat from the configuration?
|
|
|
|
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()
|
|
{
|
|
if ( !m_pConversionDialog )
|
|
{
|
|
m_pConversionDialog = new HangulHanjaConversionDialog( m_pUIParent, m_ePrimaryConversionDirection );
|
|
|
|
m_pConversionDialog->SetByCharacter( m_bByCharacter );
|
|
m_pConversionDialog->SetConversionFormat( m_eConversionFormat );
|
|
|
|
// the handlers
|
|
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 ) );
|
|
}
|
|
}
|
|
|
|
#ifdef FS_HANGUL_HANJA
|
|
static bool lcl_isConvertible( const sal_Unicode _c )
|
|
{
|
|
return ( ( ( _c >= 'a' )
|
|
&& ( _c <= 'z' )
|
|
)
|
|
|| ( ( _c >= 'A' )
|
|
&& ( _c <= 'Z' )
|
|
)
|
|
);
|
|
}
|
|
#endif
|
|
|
|
//-------------------------------------------------------------------------
|
|
bool HangulHanjaConversion_Impl::implNextConvertibleUnit( const sal_Int32 _nStartAt )
|
|
{
|
|
m_aCurrentSuggestions.realloc( 0 );
|
|
|
|
#ifdef FS_HANGUL_HANJA
|
|
// until we have a text conversion service, do some dummy implementations here
|
|
// use the break iterator to iterate over all words
|
|
::rtl::OUString sBreakIteratorService( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.i18n.BreakIterator" ) );
|
|
Reference< XBreakIterator > xBreakIter( m_xORB->createInstance( ::rtl::OUString( sBreakIteratorService ) ), UNO_QUERY );
|
|
|
|
sal_Int32 nStartAt( _nStartAt );
|
|
Boundary aWordBoundary = xBreakIter->getWordBoundary( m_sCurrentPortion, nStartAt, m_aLocale, WordType::ANYWORD_IGNOREWHITESPACES, sal_True );
|
|
if ( m_sCurrentPortion.getStr()[ aWordBoundary.startPos ] == ' ' )
|
|
{ // HACK
|
|
aWordBoundary = xBreakIter->nextWord( m_sCurrentPortion, aWordBoundary.startPos, m_aLocale, WordType::ANYWORD_IGNOREWHITESPACES );
|
|
nStartAt = aWordBoundary.startPos;
|
|
}
|
|
if ( IsByCharacter() )
|
|
{
|
|
if ( nStartAt < aWordBoundary.endPos )
|
|
aWordBoundary.startPos = nStartAt;
|
|
else
|
|
aWordBoundary = xBreakIter->nextWord( m_sCurrentPortion, aWordBoundary.endPos, m_aLocale, WordType::ANYWORD_IGNOREWHITESPACES );
|
|
|
|
aWordBoundary.endPos = aWordBoundary.startPos + 1;
|
|
}
|
|
else
|
|
{
|
|
while ( ( aWordBoundary.startPos == aWordBoundary.endPos ) // empty word
|
|
&& ( aWordBoundary.endPos < m_sCurrentPortion.getLength() ) // still characters left
|
|
)
|
|
aWordBoundary = xBreakIter->nextWord( m_sCurrentPortion, aWordBoundary.endPos, m_aLocale, WordType::ANYWORD_IGNOREWHITESPACES );
|
|
}
|
|
m_nCurrentStartIndex = aWordBoundary.startPos;
|
|
m_nCurrentEndIndex = aWordBoundary.endPos;
|
|
|
|
// for testing reasons, we add all rotations of the original word as suggestions
|
|
m_aCurrentSuggestions.realloc( 0 );
|
|
if ( m_nCurrentStartIndex < m_sCurrentPortion.getLength() )
|
|
{
|
|
::rtl::OUString sCurrentUnit = m_sCurrentPortion.copy( m_nCurrentStartIndex, m_nCurrentEndIndex - m_nCurrentStartIndex );
|
|
m_aCurrentSuggestions.realloc( sCurrentUnit.getLength() );
|
|
::rtl::OUString* pSuggestion = m_aCurrentSuggestions.getArray();
|
|
String sSuggestion( sCurrentUnit );
|
|
for ( sal_Int32 i = 0; i < sCurrentUnit.getLength(); ++i, ++pSuggestion )
|
|
{
|
|
*pSuggestion = sSuggestion = sSuggestion.Copy( 1 ).Append( sSuggestion.GetBuffer()[0] );
|
|
}
|
|
}
|
|
#else
|
|
// ask the TextConversion service for the next convertible piece of text
|
|
sal_Int32 nStartLookupAt = _nStartAt;
|
|
|
|
// parameters for the converter
|
|
sal_Int32 nLength = m_sCurrentPortion.getLength() - _nStartAt;
|
|
|
|
sal_Int16 nConversionType = HHC::eHangulToHanja == m_ePrimaryConversionDirection ? TO_HANJA : TO_HANGUL;
|
|
sal_Int32 nConversionOption = IsByCharacter() ? CHARACTER_BY_CHARACTER : NONE;
|
|
|
|
sal_Bool bTryBothDirections = m_pConversionDialog ? m_pConversionDialog->GetUseBothDirections() : sal_True;
|
|
|
|
// until we know better, assume that this very conversion attempt will end up with
|
|
// the conversion direction which is our primary direction
|
|
m_eCurrentConversionDirection = m_ePrimaryConversionDirection;
|
|
|
|
sal_Bool bFoundAny = sal_True;
|
|
try
|
|
{
|
|
TextConversionResult aResult = m_xConverter->getConversions(
|
|
m_sCurrentPortion,
|
|
_nStartAt,
|
|
nLength,
|
|
m_aLocale,
|
|
nConversionType,
|
|
nConversionOption
|
|
);
|
|
sal_Bool bFoundPrimary = aResult.Boundary.startPos < aResult.Boundary.endPos;
|
|
bFoundAny = bFoundPrimary;
|
|
|
|
if ( bTryBothDirections )
|
|
{ // see if we find another convertible when assuming the other direction
|
|
TextConversionResult aSecondResult = m_xConverter->getConversions(
|
|
m_sCurrentPortion,
|
|
_nStartAt,
|
|
nLength,
|
|
m_aLocale,
|
|
HHC::eHangulToHanja == m_ePrimaryConversionDirection ? TO_HANGUL : TO_HANJA, // switched!
|
|
nConversionOption
|
|
);
|
|
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_ePrimaryConversionDirection )
|
|
? HHC::eHanjaToHangul : HHC::eHangulToHanja;
|
|
bFoundAny = sal_True;
|
|
}
|
|
}
|
|
}
|
|
|
|
m_aCurrentSuggestions = aResult.Candidates;
|
|
m_nCurrentStartIndex = aResult.Boundary.startPos;
|
|
m_nCurrentEndIndex = aResult.Boundary.endPos;
|
|
}
|
|
catch( const Exception& e )
|
|
{
|
|
e; // make compiler happy
|
|
DBG_ERROR( "HangulHanjaConversion_Impl::implNextConvertibleUnit: caught an exception!" );
|
|
}
|
|
#endif
|
|
|
|
return bFoundAny &&
|
|
(m_nCurrentStartIndex < m_sCurrentPortion.getLength());
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
bool HangulHanjaConversion_Impl::implRetrieveNextPortion( )
|
|
{
|
|
m_sCurrentPortion = ::rtl::OUString();
|
|
m_pAntiImpl->GetNextPortion( m_sCurrentPortion );
|
|
m_nReplacementBaseIndex = 0;
|
|
m_nCurrentStartIndex = m_nCurrentEndIndex = 0;
|
|
|
|
return 0 != m_sCurrentPortion.getLength();
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
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;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
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 ) )
|
|
{
|
|
DBG_ASSERT( m_nCurrentStartIndex < m_sCurrentPortion.getLength(),
|
|
"HangulHanjaConversion_Impl::ContinueConversion: invalid index into current portion!" );
|
|
DBG_ASSERT( m_nCurrentStartIndex <= m_nCurrentEndIndex,
|
|
"HangulHanjaConversion_Impl::ContinueConversion: invalid interval!" );
|
|
|
|
::rtl::OUString sCurrentUnit = m_sCurrentPortion.copy( m_nCurrentStartIndex, m_nCurrentEndIndex - m_nCurrentStartIndex );
|
|
|
|
// 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;
|
|
|
|
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 );
|
|
|
|
if ( !m_pConversionDialog )
|
|
{
|
|
// the dialog does not yet exists (it's our first encounter)
|
|
createDialog();
|
|
// initially fill the dialog
|
|
m_pConversionDialog->SetCurrentString( sCurrentUnit, m_aCurrentSuggestions );
|
|
// execute it. It will automatically advance
|
|
m_pConversionDialog->Execute();
|
|
// we're done
|
|
DELETEZ( m_pConversionDialog );
|
|
|
|
bDocumentDone = sal_True;
|
|
}
|
|
else
|
|
{
|
|
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::implDeterminePrimaryDirection( )
|
|
{
|
|
m_ePrimaryConversionDirection = HHC::eHangulToHanja; // default
|
|
|
|
bool 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, ScriptType::ASIAN );
|
|
if ( -1 == nNextAsianScript )
|
|
nNextAsianScript = xBreakIter->nextScript( m_sCurrentPortion, m_nCurrentStartIndex, ScriptType::ASIAN );
|
|
if ( ( nNextAsianScript >= m_nCurrentStartIndex ) && ( nNextAsianScript < m_sCurrentPortion.getLength() ) )
|
|
{ // found asian text
|
|
|
|
// determine if it's Hangul
|
|
CharClass aCharClassificaton( m_xORB, m_aLocale );
|
|
sal_Int16 nScript = aCharClassificaton.getScript( m_sCurrentPortion, nNextAsianScript );
|
|
if ( ( UnicodeScript_kHangulJamo == nScript )
|
|
|| ( UnicodeScript_kHangulCompatibilityJamo == nScript )
|
|
|| ( UnicodeScript_kHangulSyllable == nScript )
|
|
)
|
|
{
|
|
m_ePrimaryConversionDirection = HHC::eHangulToHanja;
|
|
}
|
|
else
|
|
{
|
|
m_ePrimaryConversionDirection = HHC::eHanjaToHangul;
|
|
}
|
|
|
|
bSuccess = true;
|
|
}
|
|
}
|
|
}
|
|
catch( const Exception& e )
|
|
{
|
|
e; // make compiler happy
|
|
DBG_ERROR( "HangulHanjaConversion_Impl::implDeterminePrimaryDirection: 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_ERROR( "HangulHanjaConversion_Impl::DoDocumentConversion: why did you call me if you do have nothing to convert?" );
|
|
// nothing to do
|
|
return;
|
|
}
|
|
if ( !implDeterminePrimaryDirection( ) )
|
|
// something went wrong, has already been asserted
|
|
return;
|
|
|
|
#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_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 )
|
|
{
|
|
// translate the conversion format into a replacement action
|
|
// this translation depends on whether we have a Hangul original, or a Hanja original
|
|
|
|
// is the original we're about to change in Hangul?
|
|
sal_Bool bOriginalIsHangul = HHC::eHangulToHanja == m_eCurrentConversionDirection;
|
|
|
|
HHC::ReplacementAction eAction( HHC::eExchange );
|
|
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 indicies (the wrapper implementation needs indicies 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;
|
|
|
|
// do the replacement
|
|
m_pAntiImpl->ReplaceUnit( nStartIndex, nEndIndex, _rChangeInto, eAction );
|
|
|
|
// adjust the replacement base
|
|
m_nReplacementBaseIndex = m_nCurrentEndIndex;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
IMPL_LINK( HangulHanjaConversion_Impl, OnIgnore, void*, NOTINTERESTEDIN )
|
|
{
|
|
// simply ignore, and proceed
|
|
implProceed( sal_False );
|
|
return 0L;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
IMPL_LINK( HangulHanjaConversion_Impl, OnIgnoreAll, void*, NOTINTERESTEDIN )
|
|
{
|
|
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*, NOTINTERESTEDIN )
|
|
{
|
|
// change
|
|
implChange( m_pConversionDialog->GetCurrentSuggestion( ) );
|
|
// and proceed
|
|
implProceed( sal_False );
|
|
|
|
return 0L;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
IMPL_LINK( HangulHanjaConversion_Impl, OnChangeAll, void*, NOTINTERESTEDIN )
|
|
{
|
|
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( ) );
|
|
|
|
// change the current occurence
|
|
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( m_bByCharacter ? sal_True : sal_False );
|
|
// if we just switched to "by character", then we want to start over with the current word
|
|
// if we just switched to "by word", then we don't want to start over with word which contains the current
|
|
// character, because this may be potentially dagerous in case a character within this word
|
|
// has already been replaced
|
|
return 0L;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
IMPL_LINK( HangulHanjaConversion_Impl, OnConversionTypeChanged, void*, NOTINTERESTEDIN )
|
|
{
|
|
m_eConversionFormat = m_pConversionDialog->GetConversionFormat( );
|
|
return 0L;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
IMPL_LINK( HangulHanjaConversion_Impl, OnFind, void*, NOTINTERESTEDIN )
|
|
{
|
|
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;
|
|
#ifdef FS_HANGUL_HANJA
|
|
// for testing reasons, we add all rotations of the original word as suggestions
|
|
aSuggestions.realloc( sNewOriginal.getLength() );
|
|
::rtl::OUString* pSuggestion = aSuggestions.getArray();
|
|
String sSuggestion( sNewOriginal );
|
|
for ( sal_Int32 i = 0; i < sNewOriginal.getLength(); ++i, ++pSuggestion )
|
|
{
|
|
*pSuggestion = sSuggestion = sSuggestion.Copy( 1 ).Append( sSuggestion.GetBuffer()[0] );
|
|
}
|
|
#else
|
|
DBG_ASSERT( m_xConverter.is(), "HangulHanjaConversion_Impl::OnFind: no converter!" );
|
|
TextConversionResult aToHanja = m_xConverter->getConversions(
|
|
sNewOriginal,
|
|
0, sNewOriginal.getLength(),
|
|
m_aLocale,
|
|
TextConversionType::TO_HANJA,
|
|
TextConversionOption::NONE
|
|
);
|
|
TextConversionResult aToHangul = m_xConverter->getConversions(
|
|
sNewOriginal,
|
|
0, sNewOriginal.getLength(),
|
|
m_aLocale,
|
|
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;
|
|
#endif
|
|
|
|
m_pConversionDialog->SetCurrentString( sNewOriginal, aSuggestions, false );
|
|
m_pConversionDialog->FocusSuggestion();
|
|
}
|
|
catch( const Exception& e )
|
|
{
|
|
e; // make compiler happy
|
|
DBG_ERROR( "HangulHanjaConversion_Impl::OnFind: caught an exception!" );
|
|
}
|
|
}
|
|
return 0L;
|
|
}
|
|
|
|
//=========================================================================
|
|
//= HangulHanjaConversion
|
|
//=========================================================================
|
|
//-------------------------------------------------------------------------
|
|
HangulHanjaConversion::HangulHanjaConversion( Window* _pUIParent, const Reference< XMultiServiceFactory >& _rxORB, const Locale& _rLocale )
|
|
:m_pImpl( new HangulHanjaConversion_Impl( _pUIParent, _rxORB, _rLocale, this ) )
|
|
{
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
HangulHanjaConversion::~HangulHanjaConversion( )
|
|
{
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
void HangulHanjaConversion::HandleNewUnit( const sal_Int32 _nStartIndex, const sal_Int32 _nEndIndex )
|
|
{
|
|
// nothing to do, only derived classes need this.
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
void HangulHanjaConversion::GetNextPortion( ::rtl::OUString& /* [out] */ _rNextPortion )
|
|
{
|
|
#ifdef FS_HANGUL_HANJA
|
|
#define TEST_TEXT "깔끔한 외형, 아름답게 디자인된 각 부분과 기능의 집약성으로, 디지털 카메라 1300은 쉽게 명함의 이미지를 촬영하여 PDA나 컴퓨터의 주소록으로 데이터를 변환할수 있다."
|
|
static ::rtl::OUString sPortion(
|
|
TEST_TEXT, sizeof( TEST_TEXT ) - 1,
|
|
RTL_TEXTENCODING_UTF8
|
|
);
|
|
|
|
if ( m_pImpl->m_sRememberPos == sPortion )
|
|
_rNextPortion = ::rtl::OUString();
|
|
else
|
|
m_pImpl->m_sRememberPos = _rNextPortion = sPortion;
|
|
#else
|
|
DBG_ERROR( "HangulHanjaConversion::GetNextPortion: to be overridden!" );
|
|
#endif
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
void HangulHanjaConversion::ReplaceUnit( const sal_Int32 _nUnitStart, const sal_Int32 _nUnitEnd,
|
|
const ::rtl::OUString& _rReplaceWith, ReplacementAction _eAction )
|
|
{
|
|
#ifndef FS_HANGUL_HANJA
|
|
DBG_ERROR( "HangulHanjaConversion::ReplaceUnit: to be overridden!" );
|
|
#endif
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
void HangulHanjaConversion::ConvertDocument()
|
|
{
|
|
#ifndef FS_HANGUL_HANJA
|
|
if ( m_pImpl->IsValid() )
|
|
#endif
|
|
m_pImpl->DoDocumentConversion( );
|
|
}
|
|
|
|
//.............................................................................
|
|
} // namespace svx
|
|
//.............................................................................
|