LibreOffice Module editeng (master) 1
hangulhanja.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
21#include <unotools/lingucfg.hxx>
23
24#include <set>
25#include <map>
26#include <com/sun/star/uno/Sequence.hxx>
27#include <com/sun/star/i18n/BreakIterator.hpp>
28#include <com/sun/star/i18n/ScriptType.hpp>
29#include <com/sun/star/i18n/UnicodeScript.hpp>
30#include <com/sun/star/i18n/TextConversion.hpp>
31#include <com/sun/star/i18n/XExtendedTextConversion.hpp>
32#include <com/sun/star/i18n/TextConversionType.hpp>
33#include <com/sun/star/i18n/TextConversionOption.hpp>
34#include <vcl/weld.hxx>
36#include <sal/log.hxx>
37#include <osl/diagnose.h>
38#include <tools/debug.hxx>
40
41#include <editeng/edtdlg.hxx>
42
43#define HHC HangulHanjaConversion
44
45
46namespace editeng
47{
48
49
50 using namespace ::com::sun::star;
51 using namespace ::com::sun::star::uno;
52 using namespace ::com::sun::star::i18n;
53 using namespace ::com::sun::star::i18n::TextConversionOption;
54 using namespace ::com::sun::star::i18n::TextConversionType;
55
57 {
58 private:
59 typedef std::set<OUString> StringBag;
60 typedef std::map<OUString, OUString> StringMap;
61
62 private:
66
67 // general
69 m_pConversionDialog; // the dialog to display for user interaction
70 weld::Widget* m_pUIParent; // the parent window for any UI we raise
71 Reference< XComponentContext >
72 m_xContext; // the service factory to use
73 Reference< XExtendedTextConversion >
74 m_xConverter; // the text conversion service
75 lang::Locale m_aSourceLocale; // the locale we're working with
76
77 // additions for Chinese simplified / traditional conversion
78 HHC::ConversionType m_eConvType; // conversion type (Hangul/Hanja, simplified/traditional Chinese,...)
79 LanguageType m_nSourceLang; // just a 'copy' of m_aSourceLocale in order to
80 // save the applications from always converting to this
81 // type in their implementations
82 LanguageType m_nTargetLang; // target language of new replacement text
83 const vcl::Font* m_pTargetFont; // target font of new replacement text
84 sal_Int32 m_nConvOptions; // text conversion options (as used by 'getConversions')
85 bool m_bIsInteractive; // specifies if the conversion requires user interaction
86 // (and likely a specialised dialog) or if it is to run
87 // automatically without any user interaction.
88 // True for Hangul / Hanja conversion
89 // False for Chinese simplified / traditional conversion
90
91 HangulHanjaConversion* m_pAntiImpl; // our "anti-impl" instance
92
93 // options
94 bool m_bByCharacter; // are we in "by character" mode currently?
95 HHC::ConversionFormat m_eConversionFormat; // the current format for the conversion
96 HHC::ConversionDirection m_ePrimaryConversionDirection; // the primary conversion direction
97 HHC::ConversionDirection m_eCurrentConversionDirection; // the primary conversion direction
98
99 //options from Hangul/Hanja Options dialog (also saved to configuration)
103
104 // state
105 OUString m_sCurrentPortion; // the text which we are currently working on
106 LanguageType m_nCurrentPortionLang; // language of m_sCurrentPortion found
107 sal_Int32 m_nCurrentStartIndex; // the start index within m_sCurrentPortion of the current convertible portion
108 sal_Int32 m_nCurrentEndIndex; // the end index (excluding) within m_sCurrentPortion of the current convertible portion
109 sal_Int32 m_nReplacementBaseIndex;// index which ReplaceUnit-calls need to be relative to
112 Sequence< OUString >
113 m_aCurrentSuggestions; // the suggestions for the current unit
114 // (means for the text [m_nCurrentStartIndex, m_nCurrentEndIndex) in m_sCurrentPortion)
115 bool m_bTryBothDirections; // specifies if other conversion directions should be tried when looking for convertible characters
116
117
118 public:
120 weld::Widget* pUIParent,
121 const Reference< XComponentContext >& rxContext,
122 const lang::Locale& _rSourceLocale,
123 const lang::Locale& _rTargetLocale,
124 const vcl::Font* _pTargetFont,
125 sal_Int32 _nConvOptions,
126 bool _bIsInteractive,
127 HangulHanjaConversion* _pAntiImpl );
128
129 public:
130 void DoDocumentConversion( );
131
132 bool IsValid() const { return m_xConverter.is(); }
133
137 const vcl::Font * GetTargetFont() const { return m_pTargetFont; }
138 sal_Int32 GetConvOptions() const { return m_nConvOptions; }
139 bool IsInteractive() const { return m_bIsInteractive; }
140
141 protected:
142 void createDialog();
143
149 bool ContinueConversion( bool _bRepeatCurrentUnit );
150
151 private:
152 DECL_LINK( OnOptionsChanged, LinkParamNone*, void );
153 DECL_LINK( OnIgnore, weld::Button&, void );
154 DECL_LINK( OnIgnoreAll, weld::Button&, void );
155 DECL_LINK( OnChange, weld::Button&, void );
156 DECL_LINK( OnChangeAll, weld::Button&, void );
157 DECL_LINK( OnByCharClicked, weld::Toggleable&, void );
158 DECL_LINK( OnConversionTypeChanged, weld::Toggleable&, void );
159 DECL_LINK( OnFind, weld::Button&, void );
160
169 void implProceed( bool _bRepeatCurrentUnit );
170
171 // change the current convertible, and do _not_ proceed
172 void implChange( const OUString& _rChangeInto );
173
178 bool implNextConvertible( bool _bRepeatUnit );
179
185 bool implNextConvertibleUnit( const sal_Int32 _nStartAt );
186
192
197 bool implGetConversionDirectionForCurrentPortion( HHC::ConversionDirection& rDirection );
198
207 bool implUpdateSuggestions( const bool _bAllowSearchNextConvertibleText=false, const sal_Int32 _nStartAt=-1 );
208
212
215 OUString GetCurrentUnit() const;
216
219 void implUpdateData();
220
224 sal_Int16 implGetConversionType( bool bSwitchDirection=false ) const;
225 };
226
228
230 const Reference< XComponentContext >& rxContext,
231 const lang::Locale& _rSourceLocale,
232 const lang::Locale& _rTargetLocale,
233 const vcl::Font* _pTargetFont,
234 sal_Int32 _nOptions,
235 bool _bIsInteractive,
236 HangulHanjaConversion* _pAntiImpl )
237 : m_pUIParent( pUIParent )
238 , m_xContext( rxContext )
239 , m_aSourceLocale( _rSourceLocale )
240 , m_nSourceLang( LanguageTag::convertToLanguageType( _rSourceLocale ) )
241 , m_nTargetLang( LanguageTag::convertToLanguageType( _rTargetLocale ) )
242 , m_pTargetFont( _pTargetFont )
243 , m_nConvOptions(_nOptions)
244 , m_bIsInteractive( _bIsInteractive )
245 , m_pAntiImpl( _pAntiImpl )
246 , m_bByCharacter((_nOptions & CHARACTER_BY_CHARACTER) != 0)
247 , m_eConversionFormat( HHC::eSimpleConversion)
248 , m_ePrimaryConversionDirection( HHC::eHangulToHanja) // used for eConvHangulHanja
249 , m_eCurrentConversionDirection( HHC::eHangulToHanja) // used for eConvHangulHanja
250 , m_nCurrentPortionLang( LANGUAGE_NONE )
251 , m_nCurrentStartIndex( 0 )
252 , m_nCurrentEndIndex( 0 )
253 , m_nReplacementBaseIndex( 0 )
254 , m_nCurrentConversionOption( TextConversionOption::NONE )
255 , m_nCurrentConversionType( -1 ) // not yet known
256 , m_bTryBothDirections( true )
257 {
259
260 DBG_ASSERT( m_xContext.is(), "HangulHanjaConversion_Impl::HangulHanjaConversion_Impl: no ORB!" );
261
262 // determine conversion type
264 m_eConvType = HHC::eConvHangulHanja;
267 m_eConvType = HHC::eConvSimplifiedTraditional;
268 else
269 {
270 m_eConvType = HHC::eConvHangulHanja;
271 OSL_FAIL( "failed to determine conversion type from languages" );
272 }
273
274 m_xConverter = TextConversion::create( m_xContext );
275 }
276
278 {
279 DBG_ASSERT( m_bIsInteractive, "createDialog when the conversion should not be interactive?" );
281 return;
282
285
286 m_pConversionDialog->EnableRubySupport( m_pAntiImpl->HasRubySupport() );
287
288 m_pConversionDialog->SetByCharacter( m_bByCharacter );
289 m_pConversionDialog->SetConversionFormat( m_eConversionFormat );
291
292 // the handlers
293 m_pConversionDialog->SetOptionsChangedHdl( LINK( this, HangulHanjaConversion_Impl, OnOptionsChanged ) );
294 m_pConversionDialog->SetIgnoreHdl( LINK( this, HangulHanjaConversion_Impl, OnIgnore ) );
295 m_pConversionDialog->SetIgnoreAllHdl( LINK( this, HangulHanjaConversion_Impl, OnIgnoreAll ) );
297 m_pConversionDialog->SetChangeAllHdl( LINK( this, HangulHanjaConversion_Impl, OnChangeAll ) );
298 m_pConversionDialog->SetClickByCharacterHdl( LINK( this, HangulHanjaConversion_Impl, OnByCharClicked ) );
299 m_pConversionDialog->SetConversionFormatChangedHdl( LINK( this, HangulHanjaConversion_Impl, OnConversionTypeChanged ) );
300 m_pConversionDialog->SetFindHdl( LINK( this, HangulHanjaConversion_Impl, OnFind ) );
301 }
302
303 sal_Int16 HangulHanjaConversion_Impl::implGetConversionType( bool bSwitchDirection ) const
304 {
305 sal_Int16 nConversionType = -1;
306 if (m_eConvType == HHC::eConvHangulHanja)
307 nConversionType = ( HHC::eHangulToHanja == m_eCurrentConversionDirection && !bSwitchDirection ) ? TO_HANJA : TO_HANGUL;
308 else if (m_eConvType == HHC::eConvSimplifiedTraditional)
309 nConversionType = LANGUAGE_CHINESE_SIMPLIFIED == m_nTargetLang ? TO_SCHINESE : TO_TCHINESE;
310 DBG_ASSERT( nConversionType != -1, "unexpected conversion type" );
311 return nConversionType;
312 }
313
314 bool HangulHanjaConversion_Impl::implUpdateSuggestions( bool _bAllowSearchNextConvertibleText, const sal_Int32 _nStartAt )
315 {
316 // parameters for the converter
317 sal_Int32 nStartSearch = m_nCurrentStartIndex;
318 if( _bAllowSearchNextConvertibleText )
319 nStartSearch = _nStartAt;
320
321 sal_Int32 nLength = m_sCurrentPortion.getLength() - nStartSearch;
323 m_nCurrentConversionOption = m_bByCharacter ? CHARACTER_BY_CHARACTER : css::i18n::TextConversionOption::NONE;
325 m_nCurrentConversionOption = m_nCurrentConversionOption | IGNORE_POST_POSITIONAL_WORD;
326
327 // no need to check both directions for chinese conversion (saves time)
328 if (m_eConvType == HHC::eConvSimplifiedTraditional)
329 m_bTryBothDirections = false;
330
331 bool bFoundAny = true;
332 try
333 {
334 TextConversionResult aResult = m_xConverter->getConversions(
336 nStartSearch,
337 nLength,
341 );
342 const bool bFoundPrimary = aResult.Boundary.startPos < aResult.Boundary.endPos;
343 bFoundAny = bFoundPrimary;
344
346 { // see if we find another convertible when assuming the other direction
347 TextConversionResult aSecondResult = m_xConverter->getConversions(
349 nStartSearch,
350 nLength,
352 implGetConversionType( true ), // switched!
354 );
355 if ( aSecondResult.Boundary.startPos < aSecondResult.Boundary.endPos )
356 { // we indeed found such a convertible
357
358 // in case the first attempt (with the original conversion direction)
359 // didn't find anything
360 if ( !bFoundPrimary
361 // or if the second location is _before_ the first one
362 || ( aSecondResult.Boundary.startPos < aResult.Boundary.startPos )
363 )
364 {
365 // then use the second finding
366 aResult = aSecondResult;
367
368 // our current conversion direction changed now
370 ? HHC::eHanjaToHangul : HHC::eHangulToHanja;
371 bFoundAny = true;
372 }
373 }
374 }
375
376 if( _bAllowSearchNextConvertibleText )
377 {
378 //this might change the current position
379 m_aCurrentSuggestions = aResult.Candidates;
380 m_nCurrentStartIndex = aResult.Boundary.startPos;
381 m_nCurrentEndIndex = aResult.Boundary.endPos;
382 }
383 else
384 {
385 //the change of starting position is not allowed
386 if( m_nCurrentStartIndex == aResult.Boundary.startPos
387 && aResult.Boundary.endPos != aResult.Boundary.startPos )
388 {
389 m_aCurrentSuggestions = aResult.Candidates;
390 m_nCurrentEndIndex = aResult.Boundary.endPos;
391 }
392 else
393 {
394 m_aCurrentSuggestions.realloc( 0 );
395 if( m_sCurrentPortion.getLength() >= m_nCurrentStartIndex+1 )
397 }
398 }
399
400 //put recently used string to front:
402 {
403 OUString sCurrentUnit( GetCurrentUnit() );
404 StringMap::const_iterator aRecentlyUsed = m_aRecentlyUsedList.find( sCurrentUnit );
405 bool bUsedBefore = aRecentlyUsed != m_aRecentlyUsedList.end();
406 if( bUsedBefore && m_aCurrentSuggestions[0] != aRecentlyUsed->second )
407 {
408 sal_Int32 nCount = m_aCurrentSuggestions.getLength();
409 Sequence< OUString > aTmp(nCount);
410 auto pTmp = aTmp.getArray();
411 pTmp[0]=aRecentlyUsed->second;
412 sal_Int32 nDiff = 1;
413 for( sal_Int32 n=1; n<nCount; n++)//we had 0 already
414 {
415 if( nDiff && m_aCurrentSuggestions[n-nDiff]==aRecentlyUsed->second )
416 nDiff=0;
417 pTmp[n]=m_aCurrentSuggestions[n-nDiff];
418 }
420 }
421 }
422 }
423 catch( const Exception& )
424 {
425 TOOLS_WARN_EXCEPTION( "editeng", "HangulHanjaConversion_Impl::implNextConvertibleUnit" );
426
429 return false;
430 }
431 return bFoundAny;
432 }
433
435 {
436 m_aCurrentSuggestions.realloc( 0 );
437
438 // ask the TextConversion service for the next convertible piece of text
439
440 // get current values from dialog
441 if( m_eConvType == HHC::eConvHangulHanja && m_pConversionDialog )
442 {
443 m_bTryBothDirections = m_pConversionDialog->GetUseBothDirections();
444 HHC::ConversionDirection eDialogDirection = m_pConversionDialog->GetDirection( HHC::eHangulToHanja );
445
446 if( !m_bTryBothDirections && eDialogDirection != m_eCurrentConversionDirection )
447 {
448 m_eCurrentConversionDirection = eDialogDirection;
449 }
450
451 // save currently used value for possible later use
454 }
455
456 bool bFoundAny = implUpdateSuggestions( true, _nStartAt );
457
458 return bFoundAny &&
460 }
461
463 {
464 const bool bAllowImplicitChanges = m_eConvType == HHC::eConvSimplifiedTraditional;
465
466 m_sCurrentPortion.clear();
471
472 bool bRet = !m_sCurrentPortion.isEmpty();
473
474 if (m_eConvType == HHC::eConvHangulHanja && m_bTryBothDirections)
476
477 return bRet;
478 }
479
481 {
482 if ( _bRepeatUnit || ( m_nCurrentEndIndex < m_sCurrentPortion.getLength() ) )
483 {
485 _bRepeatUnit
488 ) )
489 return true;
490 }
491
492 // no convertible text in the current portion anymore
493 // -> advance to the next portion
494 do
495 {
496 // next portion
498 { // there is a next portion
499 // -> find the next convertible unit in the current portion
500 if ( implNextConvertibleUnit( 0 ) )
501 return true;
502 }
503 }
504 while ( !m_sCurrentPortion.isEmpty() );
505
506 // no more portions
507 return false;
508 }
509
511 {
513 "HangulHanjaConversion_Impl::GetCurrentUnit: invalid index into current portion!" );
515 "HangulHanjaConversion_Impl::GetCurrentUnit: invalid index into current portion!" );
517 "HangulHanjaConversion_Impl::GetCurrentUnit: invalid interval!" );
518
520 return sCurrentUnit;
521 }
522
523 bool HangulHanjaConversion_Impl::ContinueConversion( bool _bRepeatCurrentUnit )
524 {
525 while ( implNextConvertible( _bRepeatCurrentUnit ) )
526 {
527 OUString sCurrentUnit( GetCurrentUnit() );
528
529 // do we need to ignore it?
530 const bool bAlwaysIgnoreThis = m_sIgnoreList.end() != m_sIgnoreList.find( sCurrentUnit );
531
532 // do we need to change it?
533 StringMap::const_iterator aChangeListPos = m_aChangeList.find( sCurrentUnit );
534 const bool bAlwaysChangeThis = m_aChangeList.end() != aChangeListPos;
535
536 // do we automatically change this?
537 const bool bAutoChange = m_bAutoReplaceUnique && m_aCurrentSuggestions.getLength() == 1;
538
539 if (!m_bIsInteractive)
540 {
541 // silent conversion (e.g. for simplified/traditional Chinese)...
542 if(m_aCurrentSuggestions.hasElements())
543 implChange( m_aCurrentSuggestions.getConstArray()[0] );
544 }
545 else if (bAutoChange)
546 {
547 implChange( m_aCurrentSuggestions.getConstArray()[0] );
548 }
549 else if ( bAlwaysChangeThis )
550 {
551 implChange( aChangeListPos->second );
552 }
553 else if ( !bAlwaysIgnoreThis )
554 {
555 // here we need to ask the user for what to do with the text
556 // for this, allow derivees to highlight the current text unit in a possible document view
558
559 DBG_ASSERT( m_pConversionDialog, "we should always have a dialog here!" );
561 m_pConversionDialog->SetCurrentString( sCurrentUnit, m_aCurrentSuggestions );
562
563 // do not look for the next convertible: We have to wait for the user to interactively
564 // decide what happens with the current convertible
565 return false;
566 }
567 }
568
569 return true;
570 }
571
573 {
574 // - For eConvHangulHanja the direction is determined by
575 // the first encountered Korean character.
576 // - For eConvSimplifiedTraditional the conversion direction
577 // is already specified by the source language.
578
579 bool bSuccess = true;
580
581 if (m_eConvType == HHC::eConvHangulHanja)
582 {
583 bSuccess = false;
584 try
585 {
586 // get the break iterator service
587 Reference< XBreakIterator > xBreakIter = i18n::BreakIterator::create( m_xContext );
588 sal_Int32 nNextAsianScript = xBreakIter->beginOfScript( m_sCurrentPortion, m_nCurrentStartIndex, css::i18n::ScriptType::ASIAN );
589 if ( -1 == nNextAsianScript )
590 nNextAsianScript = xBreakIter->nextScript( m_sCurrentPortion, m_nCurrentStartIndex, css::i18n::ScriptType::ASIAN );
591 if ( ( nNextAsianScript >= m_nCurrentStartIndex ) && ( nNextAsianScript < m_sCurrentPortion.getLength() ) )
592 { // found asian text
593
594 // determine if it's Hangul
595 CharClass aCharClassificaton( m_xContext, LanguageTag( m_aSourceLocale) );
596 css::i18n::UnicodeScript nScript = aCharClassificaton.getScript( m_sCurrentPortion, sal::static_int_cast< sal_uInt16 >(nNextAsianScript) );
597 if ( ( UnicodeScript_kHangulJamo == nScript )
598 || ( UnicodeScript_kHangulCompatibilityJamo == nScript )
599 || ( UnicodeScript_kHangulSyllable == nScript )
600 )
601 {
602 rDirection = HHC::eHangulToHanja;
603 }
604 else
605 {
606 rDirection = HHC::eHanjaToHangul;
607 }
608
609 bSuccess = true;
610 }
611 }
612 catch( const Exception& )
613 {
614 TOOLS_WARN_EXCEPTION( "editeng", "HangulHanjaConversion_Impl::implGetConversionDirectionForCurrentPortion" );
615 }
616 }
617
618 return bSuccess;
619 }
620
622 {
623 // clear the change-all list - it's to be re-initialized for every single document
624 StringMap().swap(m_aChangeList);
625
626 // first of all, we need to guess the direction of our conversion - it is determined by the first
627 // hangul or hanja character in the first text
629 {
630 SAL_INFO( "editeng", "HangulHanjaConversion_Impl::DoDocumentConversion: why did you call me if you do have nothing to convert?" );
631 // nothing to do
632 return;
633 }
634 if( m_eConvType == HHC::eConvHangulHanja )
635 {
636 //init conversion direction from saved value
637 HHC::ConversionDirection eDirection = HHC::eHangulToHanja;
639 // something went wrong, has already been asserted
640 return;
641
643 {
648 else
650 }
651 else
652 {
655 }
656 }
657
658 if (m_bIsInteractive && m_eConvType == HHC::eConvHangulHanja)
659 {
660 //always open dialog if at least having a hangul or hanja text portion
661 createDialog();
663 ContinueConversion( false );
664 else
666 m_pConversionDialog->Execute();
668 }
669 else
670 {
671 const bool bCompletelyDone = ContinueConversion( false );
672 DBG_ASSERT( bCompletelyDone, "HangulHanjaConversion_Impl::DoDocumentConversion: ContinueConversion should have returned true here!" );
673 }
674 }
675
676 void HangulHanjaConversion_Impl::implProceed( bool _bRepeatCurrentUnit )
677 {
678 if ( ContinueConversion( _bRepeatCurrentUnit ) )
679 { // we're done with the whole document
680 DBG_ASSERT( !m_bIsInteractive || m_pConversionDialog, "HangulHanjaConversion_Impl::implProceed: we should not reach this here without dialog!" );
682 m_pConversionDialog->EndDialog( RET_OK );
683 }
684 }
685
686 void HangulHanjaConversion_Impl::implChange( const OUString& _rChangeInto )
687 {
688 if( _rChangeInto.isEmpty() )
689 return;
690
691 // translate the conversion format into a replacement action
692 // this translation depends on whether we have a Hangul original, or a Hanja original
693
694 HHC::ReplacementAction eAction( HHC::eExchange );
695
696 if (m_eConvType == HHC::eConvHangulHanja)
697 {
698 // is the original we're about to change in Hangul?
699 const bool bOriginalIsHangul = HHC::eHangulToHanja == m_eCurrentConversionDirection;
700
701 switch ( m_eConversionFormat )
702 {
703 case HHC::eSimpleConversion: eAction = HHC::eExchange; break;
704 case HHC::eHangulBracketed: eAction = bOriginalIsHangul ? HHC::eOriginalBracketed : HHC::eReplacementBracketed; break;
705 case HHC::eHanjaBracketed: eAction = bOriginalIsHangul ? HHC::eReplacementBracketed : HHC::eOriginalBracketed; break;
706 case HHC::eRubyHanjaAbove: eAction = bOriginalIsHangul ? HHC::eReplacementAbove : HHC::eOriginalAbove; break;
707 case HHC::eRubyHanjaBelow: eAction = bOriginalIsHangul ? HHC::eReplacementBelow : HHC::eOriginalBelow; break;
708 case HHC::eRubyHangulAbove: eAction = bOriginalIsHangul ? HHC::eOriginalAbove : HHC::eReplacementAbove; break;
709 case HHC::eRubyHangulBelow: eAction = bOriginalIsHangul ? HHC::eOriginalBelow : HHC::eReplacementBelow; break;
710 default:
711 OSL_FAIL( "HangulHanjaConversion_Impl::implChange: invalid/unexpected conversion format!" );
712 }
713 }
714
715 // the proper indices (the wrapper implementation needs indices relative to the
716 // previous replacement)
718 "HangulHanjaConversion_Impl::implChange: invalid replacement base!" );
719
720 sal_Int32 nStartIndex = m_nCurrentStartIndex - m_nReplacementBaseIndex;
721 sal_Int32 nEndIndex = m_nCurrentEndIndex - m_nReplacementBaseIndex;
722
723 //remind this decision
724 m_aRecentlyUsedList[ GetCurrentUnit() ] = _rChangeInto;
725
726 LanguageType *pNewUnitLang = nullptr;
727 LanguageType nNewUnitLang = LANGUAGE_NONE;
728 if (m_eConvType == HHC::eConvSimplifiedTraditional)
729 {
730 // check if language needs to be changed
733 nNewUnitLang = LANGUAGE_CHINESE_TRADITIONAL;
736 nNewUnitLang = LANGUAGE_CHINESE_SIMPLIFIED;
737 if (nNewUnitLang != LANGUAGE_NONE)
738 pNewUnitLang = &nNewUnitLang;
739 }
740
741 // according to FT we should not (yet) bother about Hangul/Hanja conversion here
742 //
743 // aOffsets is needed in ReplaceUnit below in order to find out
744 // exactly which characters are really changed in order to keep as much
745 // from attributation for the text as possible.
746 Sequence< sal_Int32 > aOffsets;
747 if (m_eConvType == HHC::eConvSimplifiedTraditional && m_xConverter.is())
748 {
749 try
750 {
751 m_xConverter->getConversionWithOffset(
758 aOffsets
759 );
760 }
761 catch( const Exception& )
762 {
763 TOOLS_WARN_EXCEPTION( "editeng", "HangulHanjaConversion_Impl::implChange: caught unexpected exception!" );
764 aOffsets.realloc(0);
765 }
766 }
767
768 // do the replacement
769 m_pAntiImpl->ReplaceUnit( nStartIndex, nEndIndex, m_sCurrentPortion,
770 _rChangeInto, aOffsets, eAction, pNewUnitLang );
771
772
773 // adjust the replacement base
775 }
776
778 {
779 SvtLinguConfig aLngCfg;
783 }
784
786 {
789
791 {
792 OUString sCurrentUnit( GetCurrentUnit() );
793
794 m_pConversionDialog->SetCurrentString( sCurrentUnit, m_aCurrentSuggestions );
795 m_pConversionDialog->FocusSuggestion();
796 }
797
799 }
800
802 {
803 //options and dictionaries might have been changed
804 //-> update our internal settings and the dialog
805 implUpdateData();
806 }
807
809 {
810 // simply ignore, and proceed
811 implProceed( false );
812 }
813
815 {
816 DBG_ASSERT( m_pConversionDialog, "HangulHanjaConversion_Impl::OnIgnoreAll: no dialog! How this?" );
817
818 if ( m_pConversionDialog )
819 {
820 OUString sCurrentUnit = m_pConversionDialog->GetCurrentString();
821 DBG_ASSERT( m_sIgnoreList.end() == m_sIgnoreList.find( sCurrentUnit ),
822 "HangulHanjaConversion_Impl, OnIgnoreAll: shouldn't this have been ignored before" );
823
824 // put into the "ignore all" list
825 m_sIgnoreList.insert( sCurrentUnit );
826
827 // and proceed
828 implProceed( false );
829 }
830 }
831
833 {
834 // change
835 DBG_ASSERT( m_pConversionDialog, "we should always have a dialog here!" );
836 if( m_pConversionDialog )
837 implChange( m_pConversionDialog->GetCurrentSuggestion( ) );
838 // and proceed
839 implProceed( false );
840 }
841
843 {
844 DBG_ASSERT( m_pConversionDialog, "HangulHanjaConversion_Impl::OnChangeAll: no dialog! How this?" );
845 if ( !m_pConversionDialog )
846 return;
847
848 OUString sCurrentUnit( m_pConversionDialog->GetCurrentString() );
849 OUString sChangeInto( m_pConversionDialog->GetCurrentSuggestion( ) );
850
851 if( !sChangeInto.isEmpty() )
852 {
853 // change the current occurrence
854 implChange( sChangeInto );
855
856 // put into the "change all" list
857 m_aChangeList.emplace( sCurrentUnit, sChangeInto );
858 }
859
860 // and proceed
861 implProceed( false );
862 }
863
865 {
866 m_bByCharacter = rBox.get_active();
867
868 // continue conversion, without advancing to the next unit, but instead continuing with the current unit
869 implProceed( true );
870 }
871
873 {
874 DBG_ASSERT( m_pConversionDialog, "we should always have a dialog here!" );
875 if( m_pConversionDialog )
876 m_eConversionFormat = m_pConversionDialog->GetConversionFormat( );
877 }
878
880 {
881 DBG_ASSERT( m_pConversionDialog, "HangulHanjaConversion_Impl::OnFind: where did this come from?" );
882 if ( !m_pConversionDialog )
883 return;
884
885 try
886 {
887 OUString sNewOriginal( m_pConversionDialog->GetCurrentSuggestion( ) );
888 Sequence< OUString > aSuggestions;
889
890 DBG_ASSERT( m_xConverter.is(), "HangulHanjaConversion_Impl::OnFind: no converter!" );
891 TextConversionResult aToHanja = m_xConverter->getConversions(
892 sNewOriginal,
893 0, sNewOriginal.getLength(),
894 m_aSourceLocale,
895 TextConversionType::TO_HANJA,
896 TextConversionOption::NONE
897 );
898 TextConversionResult aToHangul = m_xConverter->getConversions(
899 sNewOriginal,
900 0, sNewOriginal.getLength(),
901 m_aSourceLocale,
902 TextConversionType::TO_HANGUL,
903 TextConversionOption::NONE
904 );
905
906 bool bHaveToHanja = ( aToHanja.Boundary.startPos < aToHanja.Boundary.endPos );
907 bool bHaveToHangul = ( aToHangul.Boundary.startPos < aToHangul.Boundary.endPos );
908
909 TextConversionResult* pResult = nullptr;
910 if ( bHaveToHanja && bHaveToHangul )
911 { // it found convertibles in both directions -> use the first
912 if ( aToHangul.Boundary.startPos < aToHanja.Boundary.startPos )
913 pResult = &aToHangul;
914 else
915 pResult = &aToHanja;
916 }
917 else if ( bHaveToHanja )
918 { // only found toHanja
919 pResult = &aToHanja;
920 }
921 else
922 { // only found toHangul
923 pResult = &aToHangul;
924 }
925 if ( pResult )
926 aSuggestions = pResult->Candidates;
927
928 m_pConversionDialog->SetCurrentString( sNewOriginal, aSuggestions, false );
929 m_pConversionDialog->FocusSuggestion();
930 }
931 catch( const Exception& )
932 {
933 TOOLS_WARN_EXCEPTION( "editeng", "HangulHanjaConversion_Impl::OnFind" );
934 }
935 }
936
939 HHC::ConversionDirection HangulHanjaConversion::m_ePrimaryConversionDirectionSave = HHC::eHangulToHanja;
940
942 const Reference< XComponentContext >& rxContext,
943 const lang::Locale& _rSourceLocale, const lang::Locale& _rTargetLocale,
944 const vcl::Font* _pTargetFont,
945 sal_Int32 _nOptions, bool _bIsInteractive)
946 :m_pImpl( new HangulHanjaConversion_Impl( pUIParent, rxContext, _rSourceLocale, _rTargetLocale, _pTargetFont, _nOptions, _bIsInteractive, this ) )
947 {
948 }
949
950 HangulHanjaConversion::~HangulHanjaConversion() COVERITY_NOEXCEPT_FALSE
951 {
952 }
953
954 void HangulHanjaConversion::SetUseSavedConversionDirectionState( bool bVal )
955 {
956 m_bUseSavedValues = bVal;
957 }
958
959 bool HangulHanjaConversion::IsUseSavedConversionDirectionState()
960 {
961 return m_bUseSavedValues;
962 }
963
964 weld::Widget* HangulHanjaConversion::GetUIParent() const
965 {
966 return m_pImpl->GetUIParent();
967 }
968
969 LanguageType HangulHanjaConversion::GetSourceLanguage( ) const
970 {
971 return m_pImpl->GetSourceLang();
972 }
973
974 LanguageType HangulHanjaConversion::GetTargetLanguage( ) const
975 {
976 return m_pImpl->GetTargetLang();
977 }
978
979 const vcl::Font * HangulHanjaConversion::GetTargetFont( ) const
980 {
981 return m_pImpl->GetTargetFont();
982 }
983
984 sal_Int32 HangulHanjaConversion::GetConversionOptions( ) const
985 {
986 return m_pImpl->GetConvOptions();
987 }
988
989 bool HangulHanjaConversion::IsInteractive( ) const
990 {
991 return m_pImpl->IsInteractive();
992 }
993
994 void HangulHanjaConversion::ConvertDocument()
995 {
996 if ( m_pImpl->IsValid() )
997 m_pImpl->DoDocumentConversion( );
998 }
999
1000}
1001
1002/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
::std::unique_ptr< XmlIdRegistry_Impl > m_pImpl
Reference< XComponentContext > m_xContext
css::i18n::UnicodeScript getScript(const OUString &rStr, sal_Int32 nPos) const
virtual VclPtr< AbstractHangulHanjaConversionDialog > CreateHangulHanjaConversionDialog(weld::Widget *pParent)=0
static EditAbstractDialogFactory * Create()
Definition: edtdlg.cxx:22
css::uno::Any GetProperty(std::u16string_view rPropertyName) const
void disposeAndClear()
DECL_LINK(OnChange, weld::Button &, void)
void implChange(const OUString &_rChangeInto)
LanguageType GetTargetLang() const
HHC::ConversionFormat m_eConversionFormat
Definition: hangulhanja.cxx:95
DECL_LINK(OnConversionTypeChanged, weld::Toggleable &, void)
VclPtr< AbstractHangulHanjaConversionDialog > m_pConversionDialog
Definition: hangulhanja.cxx:69
bool implRetrieveNextPortion()
retrieves the next portion, with setting the index members properly
HHC::ConversionDirection m_eCurrentConversionDirection
Definition: hangulhanja.cxx:97
bool implNextConvertibleUnit(const sal_Int32 _nStartAt)
find the next convertible unit within the current portion
OUString GetCurrentUnit() const
get the string currently considered to be replaced or ignored
void implUpdateData()
read options from configuration, update suggestion list and dialog content
bool implNextConvertible(bool _bRepeatUnit)
find the next convertible piece of text, with possibly advancing to the next portion
HangulHanjaConversion_Impl(weld::Widget *pUIParent, const Reference< XComponentContext > &rxContext, const lang::Locale &_rSourceLocale, const lang::Locale &_rTargetLocale, const vcl::Font *_pTargetFont, sal_Int32 _nConvOptions, bool _bIsInteractive, HangulHanjaConversion *_pAntiImpl)
Sequence< OUString > m_aCurrentSuggestions
Reference< XComponentContext > m_xContext
Definition: hangulhanja.cxx:72
std::map< OUString, OUString > StringMap
Definition: hangulhanja.cxx:60
sal_Int16 implGetConversionType(bool bSwitchDirection=false) const
get the conversion direction dependent from m_eConvType and m_eCurrentConversionDirection in case of ...
DECL_LINK(OnFind, weld::Button &, void)
bool ContinueConversion(bool _bRepeatCurrentUnit)
continue with the conversion, return <TRUE> if and only if the complete conversion is done
void implProceed(bool _bRepeatCurrentUnit)
proceed, after the current convertible has been handled
HangulHanjaConversion * m_pAntiImpl
Definition: hangulhanja.cxx:91
const vcl::Font * GetTargetFont() const
weld::Widget * GetUIParent() const
DECL_LINK(OnOptionsChanged, LinkParamNone *, void)
DECL_LINK(OnChangeAll, weld::Button &, void)
bool implGetConversionDirectionForCurrentPortion(HHC::ConversionDirection &rDirection)
determine the ConversionDirection for m_sCurrentPortion
DECL_LINK(OnByCharClicked, weld::Toggleable &, void)
DECL_LINK(OnIgnore, weld::Button &, void)
Reference< XExtendedTextConversion > m_xConverter
Definition: hangulhanja.cxx:74
DECL_LINK(OnIgnoreAll, weld::Button &, void)
LanguageType GetSourceLang() const
HHC::ConversionDirection m_ePrimaryConversionDirection
Definition: hangulhanja.cxx:96
bool implUpdateSuggestions(const bool _bAllowSearchNextConvertibleText=false, const sal_Int32 _nStartAt=-1)
member m_aCurrentSuggestions and m_nCurrentEndIndex are updated according to the other settings and c...
void implReadOptionsFromConfiguration()
reads the options from Hangul/Hanja Options dialog that are saved to configuration
encapsulates Hangul-Hanja conversion functionality
Definition: hangulhanja.hxx:56
static ConversionDirection m_ePrimaryConversionDirectionSave
HangulHanjaConversion(const HangulHanjaConversion &)=delete
virtual void GetNextPortion(OUString &_rNextPortion, LanguageType &_rLangOfPortion, bool _bAllowImplicitChangesForNotConvertibleText)=0
retrieves the next text portion which is to be analyzed
static bool IsSimplified(LanguageType nLang)
virtual void ReplaceUnit(const sal_Int32 _nUnitStart, const sal_Int32 _nUnitEnd, const OUString &_rOrigText, const OUString &_rReplaceWith, const css::uno::Sequence< sal_Int32 > &_rOffsets, ReplacementAction _eAction, LanguageType *pNewUnitLanguage)=0
replaces a text unit within a text portion with a new text
static bool IsTraditional(LanguageType nLang)
virtual void HandleNewUnit(const sal_Int32 _nUnitStart, const sal_Int32 _nUnitEnd)=0
announces a new "current unit"
virtual bool HasRubySupport() const =0
specifies if rubies are supported by the document implementing this class.
static bool IsUseSavedConversionDirectionState()
LanguageType GetTargetLanguage() const
int nCount
#define DBG_ASSERT(sCon, aError)
#define TOOLS_WARN_EXCEPTION(area, stream)
Reference< XTypeConverter > m_xConverter
#define HHC
Definition: hangulhanja.cxx:43
sal_Int64 n
#define LANGUAGE_CHINESE_TRADITIONAL
#define LANGUAGE_NONE
#define LANGUAGE_CHINESE_SIMPLIFIED
#define LANGUAGE_KOREAN
#define UPH_IS_SHOW_ENTRIES_RECENTLY_USED_FIRST
#define UPH_IS_IGNORE_POST_POSITIONAL_WORD
#define UPH_IS_AUTO_REPLACE_UNIQUE_ENTRIES
#define SAL_INFO(area, stream)
NONE
@ Exception
IMPL_LINK_NOARG(HangulHanjaConversion_Impl, OnOptionsChanged, LinkParamNone *, void)
IMPL_LINK(HangulHanjaConversion_Impl, OnByCharClicked, weld::Toggleable &, rBox, void)
RET_OK
sal_Int32 nLength