Line data Source code
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 :
20 : #include <editeng/hangulhanja.hxx>
21 : #include <vcl/msgbox.hxx>
22 : #include <vcl/button.hxx>
23 : #include <unotools/lingucfg.hxx>
24 : #include <unotools/linguprops.hxx>
25 :
26 : #include <set>
27 : #include <map>
28 : #include <comphelper/processfactory.hxx>
29 : #include <com/sun/star/uno/Sequence.hxx>
30 : #include <com/sun/star/i18n/BreakIterator.hpp>
31 : #include <com/sun/star/i18n/ScriptType.hpp>
32 : #include <com/sun/star/i18n/UnicodeScript.hpp>
33 : #include <com/sun/star/i18n/TextConversion.hpp>
34 : #include <com/sun/star/i18n/XExtendedTextConversion.hpp>
35 : #include <com/sun/star/i18n/TextConversionType.hpp>
36 : #include <com/sun/star/i18n/TextConversionOption.hpp>
37 : #include <com/sun/star/i18n/WordType.hpp>
38 : #include <vcl/stdtext.hxx>
39 : #include <unotools/charclass.hxx>
40 :
41 : #include <editeng/edtdlg.hxx>
42 : #include <editeng/editrids.hrc>
43 : #include <editeng/unolingu.hxx>
44 :
45 : #define HHC HangulHanjaConversion
46 :
47 : //.............................................................................
48 : namespace editeng
49 : {
50 : //.............................................................................
51 :
52 : using namespace ::com::sun::star::uno;
53 : using namespace ::com::sun::star::i18n;
54 : using namespace ::com::sun::star::i18n::TextConversionOption;
55 : using namespace ::com::sun::star::i18n::TextConversionType;
56 : using namespace ::com::sun::star::lang;
57 :
58 0 : class HangulHanjaConversion_Impl
59 : {
60 : private:
61 : typedef ::std::set< OUString, ::std::less< OUString > > StringBag;
62 : typedef ::std::map< OUString, OUString, ::std::less< OUString > > StringMap;
63 :
64 : private:
65 : StringBag m_sIgnoreList;
66 : StringMap m_aChangeList;
67 : static StringMap m_aRecentlyUsedList;
68 :
69 : // general
70 : AbstractHangulHanjaConversionDialog*
71 : m_pConversionDialog; // the dialog to display for user interaction
72 : Window* m_pUIParent; // the parent window for any UI we raise
73 : Reference< XComponentContext >
74 : m_xContext; // the service factory to use
75 : Reference< XExtendedTextConversion >
76 : m_xConverter; // the text conversion service
77 : Locale m_aSourceLocale; // the locale we're working with
78 :
79 : // additions for Chinese simplified / traditional conversion
80 : HHC::ConversionType m_eConvType; // conversion type (Hangul/Hanja, simplified/traditional Chinese,...)
81 : LanguageType m_nSourceLang; // just a 'copy' of m_aSourceLocale in order in order to
82 : // save the applications from always converting to this
83 : // type in their implementations
84 : LanguageType m_nTargetLang; // target language of new replacement text
85 : const Font* m_pTargetFont; // target font of new replacement text
86 : sal_Int32 m_nConvOptions; // text conversion options (as used by 'getConversions')
87 : bool m_bIsInteractive; // specifies if the conversion requires user interaction
88 : // (and likeley a specialised dialog) or if it is to run
89 : // automatically without any user interaction.
90 : // True for Hangul / Hanja conversion
91 : // False for Chinese simlified / traditional conversion
92 :
93 : HangulHanjaConversion* m_pAntiImpl; // our "anti-impl" instance
94 :
95 : // options
96 : bool m_bByCharacter; // are we in "by character" mode currently?
97 : HHC::ConversionFormat m_eConversionFormat; // the current format for the conversion
98 : HHC::ConversionDirection m_ePrimaryConversionDirection; // the primary conversion direction
99 : HHC::ConversionDirection m_eCurrentConversionDirection; // the primary conversion direction
100 :
101 : //options from Hangul/Hanja Options dialog (also saved to configuration)
102 : bool m_bIgnorePostPositionalWord;
103 : bool m_bShowRecentlyUsedFirst;
104 : bool m_bAutoReplaceUnique;
105 :
106 : // state
107 : OUString m_sCurrentPortion; // the text which we are currently working on
108 : LanguageType m_nCurrentPortionLang; // language of m_sCurrentPortion found
109 : sal_Int32 m_nCurrentStartIndex; // the start index within m_sCurrentPortion of the current convertible portion
110 : sal_Int32 m_nCurrentEndIndex; // the end index (excluding) within m_sCurrentPortion of the current convertible portion
111 : sal_Int32 m_nReplacementBaseIndex;// index which ReplaceUnit-calls need to be relative to
112 : sal_Int32 m_nCurrentConversionOption;
113 : sal_Int16 m_nCurrentConversionType;
114 : Sequence< OUString >
115 : m_aCurrentSuggestions; // the suggestions for the current unit
116 : // (means for the text [m_nCurrentStartIndex, m_nCurrentEndIndex) in m_sCurrentPortion)
117 : bool m_bTryBothDirections; // specifies if other conversion directions should be tried when looking for convertible characters
118 :
119 :
120 : public:
121 : HangulHanjaConversion_Impl(
122 : Window* _pUIParent,
123 : const Reference< XComponentContext >& rxContext,
124 : const Locale& _rSourceLocale,
125 : const Locale& _rTargetLocale,
126 : const Font* _pTargetFont,
127 : sal_Int32 _nConvOptions,
128 : bool _bIsInteractive,
129 : HangulHanjaConversion* _pAntiImpl );
130 :
131 : public:
132 : void DoDocumentConversion( );
133 :
134 0 : inline bool IsByCharacter( ) const { return m_bByCharacter; }
135 :
136 0 : inline bool IsValid() const { return m_xConverter.is(); }
137 :
138 0 : inline LanguageType GetSourceLang() const { return m_nSourceLang; }
139 0 : inline LanguageType GetTargetLang() const { return m_nTargetLang; }
140 0 : inline const Font * GetTargetFont() const { return m_pTargetFont; }
141 0 : inline sal_Int32 GetConvOptions() const { return m_nConvOptions; }
142 0 : inline bool IsInteractive() const { return m_bIsInteractive; }
143 :
144 : protected:
145 : void createDialog();
146 :
147 : /** continue with the conversion, return <TRUE/> if and only if the complete conversion is done
148 : @param _bRepeatCurrentUnit
149 : if <TRUE/>, an implNextConvertible will be called initially to advance to the next convertible.
150 : if <FALSE/>, the method will initially work with the current convertible unit
151 : */
152 : bool ContinueConversion( bool _bRepeatCurrentUnit );
153 :
154 : private:
155 : DECL_LINK( OnOptionsChanged, void* );
156 : DECL_LINK( OnIgnore, void* );
157 : DECL_LINK( OnIgnoreAll, void* );
158 : DECL_LINK( OnChange, void* );
159 : DECL_LINK( OnChangeAll, void* );
160 : DECL_LINK( OnByCharClicked, CheckBox* );
161 : DECL_LINK( OnConversionTypeChanged, void* );
162 : DECL_LINK( OnFind, void* );
163 :
164 : /** proceed, after the current convertible has been handled
165 :
166 : <p><b>Attention:</b>
167 : When returning from this method, the dialog may have been deleted!</p>
168 :
169 : @param _bRepeatCurrentUnit
170 : will be passed to the <member>ContinueConversion</member> call
171 : */
172 : void implProceed( bool _bRepeatCurrentUnit );
173 :
174 : // change the current convertible, and do _not_ proceed
175 : void implChange( const OUString& _rChangeInto );
176 :
177 : /** find the next convertible piece of text, with possibly advancing to the next portion
178 :
179 : @see HangulHanjaConversion::GetNextPortion
180 : */
181 : bool implNextConvertible( bool _bRepeatUnit );
182 :
183 : /** find the next convertible unit within the current portion
184 : @param _bRepeatUnit
185 : if <TRUE/>, the search will start at the beginning of the current unit,
186 : if <FALSE/>, it will start at the end of the current unit
187 : */
188 : bool implNextConvertibleUnit( const sal_Int32 _nStartAt );
189 :
190 : /** retrieves the next portion, with setting the index members properly
191 : @return
192 : <TRUE/> if and only if there is a next portion
193 : */
194 : bool implRetrieveNextPortion( );
195 :
196 : /** determine the ConversionDirection for m_sCurrentPortion
197 : @return
198 : <FALSE/> if and only if something went wrong
199 : */
200 : bool implGetConversionDirectionForCurrentPortion( HHC::ConversionDirection& rDirection );
201 :
202 : /** member m_aCurrentSuggestions and m_nCurrentEndIndex are updated according to the other settings and current dictionaries
203 :
204 : if _bAllowSearchNextConvertibleText is true _nStartAt is used as starting point to search the next
205 : convertible text portion. This may result in changing of the member m_nCurrentStartIndex additionally.
206 :
207 : @return
208 : <TRUE/> if Suggestions were found
209 : */
210 : bool implUpdateSuggestions( const bool _bAllowSearchNextConvertibleText=false, const sal_Int32 _nStartAt=-1 );
211 :
212 : /** reads the options from Hangul/Hanja Options dialog that are saved to configuration
213 : */
214 : void implReadOptionsFromConfiguration();
215 :
216 : /** get the string currently considered to be replaced or ignored
217 : */
218 : OUString GetCurrentUnit() const;
219 :
220 : /** read options from configuration, update suggestion list and dialog content
221 : */
222 : void implUpdateData();
223 :
224 : /** get the conversion direction dependent from m_eConvType and m_eCurrentConversionDirection
225 : in case of switching the direction is allowed this can be triggered with parameter bSwitchDirection
226 : */
227 : sal_Int16 implGetConversionType( bool bSwitchDirection=false ) const;
228 : };
229 :
230 89 : HangulHanjaConversion_Impl::StringMap HangulHanjaConversion_Impl::m_aRecentlyUsedList = HangulHanjaConversion_Impl::StringMap();
231 :
232 0 : HangulHanjaConversion_Impl::HangulHanjaConversion_Impl( Window* _pUIParent,
233 : const Reference< XComponentContext >& rxContext,
234 : const Locale& _rSourceLocale,
235 : const Locale& _rTargetLocale,
236 : const Font* _pTargetFont,
237 : sal_Int32 _nOptions,
238 : bool _bIsInteractive,
239 : HangulHanjaConversion* _pAntiImpl )
240 : : m_pConversionDialog( NULL )
241 : , m_pUIParent( _pUIParent )
242 : , m_xContext( rxContext )
243 : , m_aSourceLocale( _rSourceLocale )
244 0 : , m_nSourceLang( LanguageTag( _rSourceLocale ).getLanguageType() )
245 0 : , m_nTargetLang( LanguageTag( _rTargetLocale ).getLanguageType() )
246 : , m_pTargetFont( _pTargetFont )
247 : , m_bIsInteractive( _bIsInteractive )
248 : , m_pAntiImpl( _pAntiImpl )
249 : , m_nCurrentPortionLang( LANGUAGE_NONE )
250 : , m_nCurrentStartIndex( 0 )
251 : , m_nCurrentEndIndex( 0 )
252 : , m_nReplacementBaseIndex( 0 )
253 : , m_nCurrentConversionOption( TextConversionOption::NONE )
254 : , m_nCurrentConversionType( -1 ) // not yet known
255 0 : , m_bTryBothDirections( true )
256 : {
257 0 : implReadOptionsFromConfiguration();
258 :
259 : DBG_ASSERT( m_xContext.is(), "HangulHanjaConversion_Impl::HangulHanjaConversion_Impl: no ORB!" );
260 :
261 : // determine conversion type
262 0 : if (m_nSourceLang == LANGUAGE_KOREAN && m_nTargetLang == LANGUAGE_KOREAN)
263 0 : m_eConvType = HHC::eConvHangulHanja;
264 0 : else if ( (m_nSourceLang == LANGUAGE_CHINESE_TRADITIONAL && m_nTargetLang == LANGUAGE_CHINESE_SIMPLIFIED) ||
265 0 : (m_nSourceLang == LANGUAGE_CHINESE_SIMPLIFIED && m_nTargetLang == LANGUAGE_CHINESE_TRADITIONAL) )
266 0 : m_eConvType = HHC::eConvSimplifiedTraditional;
267 : else
268 : {
269 : OSL_FAIL( "failed to determine conversion type from languages" );
270 : }
271 :
272 : // set remaining conversion parameters to their default values
273 0 : m_nConvOptions = _nOptions;
274 0 : m_bByCharacter = 0 != (_nOptions & CHARACTER_BY_CHARACTER);
275 0 : m_eConversionFormat = HHC::eSimpleConversion;
276 0 : m_ePrimaryConversionDirection = HHC::eHangulToHanja; // used for eConvHangulHanja
277 0 : m_eCurrentConversionDirection = HHC::eHangulToHanja; // used for eConvHangulHanja
278 :
279 0 : m_xConverter = TextConversion::create( m_xContext );
280 0 : }
281 :
282 0 : void HangulHanjaConversion_Impl::createDialog()
283 : {
284 : DBG_ASSERT( m_bIsInteractive, "createDialog when the conversion should not be interactive?" );
285 0 : if ( m_bIsInteractive && !m_pConversionDialog )
286 : {
287 0 : EditAbstractDialogFactory* pFact = EditAbstractDialogFactory::Create();
288 0 : if(pFact)
289 : {
290 0 : m_pConversionDialog = pFact->CreateHangulHanjaConversionDialog(m_pUIParent, m_ePrimaryConversionDirection );
291 : DBG_ASSERT(m_pConversionDialog, "Dialogdiet fail!");
292 :
293 0 : m_pConversionDialog->EnableRubySupport( m_pAntiImpl->HasRubySupport() );
294 :
295 0 : m_pConversionDialog->SetByCharacter( m_bByCharacter );
296 0 : m_pConversionDialog->SetConversionFormat( m_eConversionFormat );
297 0 : m_pConversionDialog->SetConversionDirectionState( m_bTryBothDirections, m_ePrimaryConversionDirection );
298 :
299 : // the handlers
300 0 : m_pConversionDialog->SetOptionsChangedHdl( LINK( this, HangulHanjaConversion_Impl, OnOptionsChanged ) );
301 0 : m_pConversionDialog->SetIgnoreHdl( LINK( this, HangulHanjaConversion_Impl, OnIgnore ) );
302 0 : m_pConversionDialog->SetIgnoreAllHdl( LINK( this, HangulHanjaConversion_Impl, OnIgnoreAll ) );
303 0 : m_pConversionDialog->SetChangeHdl( LINK( this, HangulHanjaConversion_Impl, OnChange ) );
304 0 : m_pConversionDialog->SetChangeAllHdl( LINK( this, HangulHanjaConversion_Impl, OnChangeAll ) );
305 0 : m_pConversionDialog->SetClickByCharacterHdl( LINK( this, HangulHanjaConversion_Impl, OnByCharClicked ) );
306 0 : m_pConversionDialog->SetConversionFormatChangedHdl( LINK( this, HangulHanjaConversion_Impl, OnConversionTypeChanged ) );
307 0 : m_pConversionDialog->SetFindHdl( LINK( this, HangulHanjaConversion_Impl, OnFind ) );
308 : }
309 : }
310 0 : }
311 :
312 0 : sal_Int16 HangulHanjaConversion_Impl::implGetConversionType( bool bSwitchDirection ) const
313 : {
314 0 : sal_Int16 nConversionType = -1;
315 0 : if (m_eConvType == HHC::eConvHangulHanja)
316 0 : nConversionType = HHC::eHangulToHanja == ( m_eCurrentConversionDirection && !bSwitchDirection ) ? TO_HANJA : TO_HANGUL;
317 0 : else if (m_eConvType == HHC::eConvSimplifiedTraditional)
318 0 : nConversionType = LANGUAGE_CHINESE_SIMPLIFIED == m_nTargetLang ? TO_SCHINESE : TO_TCHINESE;
319 : DBG_ASSERT( nConversionType != -1, "unexpected conversion type" );
320 0 : return nConversionType;
321 : }
322 :
323 0 : bool HangulHanjaConversion_Impl::implUpdateSuggestions( bool _bAllowSearchNextConvertibleText, const sal_Int32 _nStartAt )
324 : {
325 : // parameters for the converter
326 0 : sal_Int32 nStartSearch = m_nCurrentStartIndex;
327 0 : if( _bAllowSearchNextConvertibleText )
328 0 : nStartSearch = _nStartAt;
329 :
330 0 : sal_Int32 nLength = m_sCurrentPortion.getLength() - nStartSearch;
331 0 : m_nCurrentConversionType = implGetConversionType();
332 0 : m_nCurrentConversionOption = IsByCharacter() ? CHARACTER_BY_CHARACTER : NONE;
333 0 : if( m_bIgnorePostPositionalWord )
334 0 : m_nCurrentConversionOption = m_nCurrentConversionOption | IGNORE_POST_POSITIONAL_WORD;
335 :
336 : // no need to check both directions for chinese conversion (saves time)
337 0 : if (m_eConvType == HHC::eConvSimplifiedTraditional)
338 0 : m_bTryBothDirections = false;
339 :
340 0 : bool bFoundAny = true;
341 : try
342 : {
343 0 : TextConversionResult aResult = m_xConverter->getConversions(
344 : m_sCurrentPortion,
345 : nStartSearch,
346 : nLength,
347 : m_aSourceLocale,
348 : m_nCurrentConversionType,
349 : m_nCurrentConversionOption
350 0 : );
351 0 : const bool bFoundPrimary = aResult.Boundary.startPos < aResult.Boundary.endPos;
352 0 : bFoundAny = bFoundPrimary;
353 :
354 0 : if ( m_bTryBothDirections )
355 : { // see if we find another convertible when assuming the other direction
356 0 : TextConversionResult aSecondResult = m_xConverter->getConversions(
357 : m_sCurrentPortion,
358 : nStartSearch,
359 : nLength,
360 : m_aSourceLocale,
361 0 : implGetConversionType( true ), // switched!
362 : m_nCurrentConversionOption
363 0 : );
364 0 : if ( aSecondResult.Boundary.startPos < aSecondResult.Boundary.endPos )
365 : { // we indeed found such a convertible
366 :
367 : // in case the first attempt (with the original conversion direction)
368 : // didn't find anything
369 0 : if ( !bFoundPrimary
370 : // or if the second location is _before_ the first one
371 0 : || ( aSecondResult.Boundary.startPos < aResult.Boundary.startPos )
372 : )
373 : {
374 : // then use the second finding
375 0 : aResult = aSecondResult;
376 :
377 : // our current conversion direction changed now
378 0 : m_eCurrentConversionDirection = ( HHC::eHangulToHanja == m_eCurrentConversionDirection )
379 0 : ? HHC::eHanjaToHangul : HHC::eHangulToHanja;
380 0 : bFoundAny = true;
381 : }
382 0 : }
383 : }
384 :
385 0 : if( _bAllowSearchNextConvertibleText )
386 : {
387 : //this might change the current position
388 0 : m_aCurrentSuggestions = aResult.Candidates;
389 0 : m_nCurrentStartIndex = aResult.Boundary.startPos;
390 0 : m_nCurrentEndIndex = aResult.Boundary.endPos;
391 : }
392 : else
393 : {
394 : //the change of starting position is not allowed
395 0 : if( m_nCurrentStartIndex == aResult.Boundary.startPos
396 0 : && aResult.Boundary.endPos != aResult.Boundary.startPos )
397 : {
398 0 : m_aCurrentSuggestions = aResult.Candidates;
399 0 : m_nCurrentEndIndex = aResult.Boundary.endPos;
400 : }
401 : else
402 : {
403 0 : m_aCurrentSuggestions.realloc( 0 );
404 0 : if( m_sCurrentPortion.getLength() >= m_nCurrentStartIndex+1 )
405 0 : m_nCurrentEndIndex = m_nCurrentStartIndex+1;
406 : }
407 : }
408 :
409 : //put recently used string to front:
410 0 : if( m_bShowRecentlyUsedFirst && m_aCurrentSuggestions.getLength()>1 )
411 : {
412 0 : OUString sCurrentUnit( GetCurrentUnit() );
413 0 : StringMap::const_iterator aRecentlyUsed = m_aRecentlyUsedList.find( sCurrentUnit );
414 0 : bool bUsedBefore = aRecentlyUsed != m_aRecentlyUsedList.end();
415 0 : if( bUsedBefore && m_aCurrentSuggestions[0] != aRecentlyUsed->second )
416 : {
417 0 : sal_Int32 nCount = m_aCurrentSuggestions.getLength();
418 0 : Sequence< OUString > aTmp(nCount);
419 0 : aTmp[0]=aRecentlyUsed->second;
420 0 : sal_Int32 nDiff = 1;
421 0 : for( sal_Int32 n=1; n<nCount; n++)//we had 0 already
422 : {
423 0 : if( nDiff && m_aCurrentSuggestions[n-nDiff]==aRecentlyUsed->second )
424 0 : nDiff=0;
425 0 : aTmp[n]=m_aCurrentSuggestions[n-nDiff];
426 : }
427 0 : m_aCurrentSuggestions = aTmp;
428 0 : }
429 0 : }
430 : }
431 0 : catch( const Exception& )
432 : {
433 : OSL_FAIL( "HangulHanjaConversion_Impl::implNextConvertibleUnit: caught an exception!" );
434 :
435 : //!!! at least we want to move on in the text in order
436 : //!!! to avoid an endless loop...
437 0 : return false;
438 : }
439 0 : return bFoundAny;
440 : }
441 :
442 0 : bool HangulHanjaConversion_Impl::implNextConvertibleUnit( const sal_Int32 _nStartAt )
443 : {
444 0 : m_aCurrentSuggestions.realloc( 0 );
445 :
446 : // ask the TextConversion service for the next convertible piece of text
447 :
448 : // get current values from dialog
449 0 : if( m_eConvType == HHC::eConvHangulHanja && m_pConversionDialog )
450 : {
451 0 : m_bTryBothDirections = m_pConversionDialog->GetUseBothDirections();
452 0 : HHC::ConversionDirection eDialogDirection = HHC::eHangulToHanja;
453 0 : eDialogDirection = m_pConversionDialog->GetDirection( eDialogDirection );
454 :
455 0 : if( !m_bTryBothDirections && eDialogDirection != m_eCurrentConversionDirection )
456 : {
457 0 : m_eCurrentConversionDirection = eDialogDirection;
458 : }
459 :
460 : // save curently used value for possible later use
461 0 : m_pAntiImpl->m_bTryBothDirectionsSave = m_bTryBothDirections;
462 0 : m_pAntiImpl->m_ePrimaryConversionDirectionSave = m_eCurrentConversionDirection;
463 : }
464 :
465 0 : bool bFoundAny = implUpdateSuggestions( true, _nStartAt );
466 :
467 0 : return bFoundAny &&
468 0 : (m_nCurrentStartIndex < m_sCurrentPortion.getLength());
469 : }
470 :
471 0 : bool HangulHanjaConversion_Impl::implRetrieveNextPortion( )
472 : {
473 0 : const bool bAllowImplicitChanges = m_eConvType == HHC::eConvSimplifiedTraditional;
474 :
475 0 : m_sCurrentPortion = OUString();
476 0 : m_nCurrentPortionLang = LANGUAGE_NONE;
477 0 : m_pAntiImpl->GetNextPortion( m_sCurrentPortion, m_nCurrentPortionLang, bAllowImplicitChanges );
478 0 : m_nReplacementBaseIndex = 0;
479 0 : m_nCurrentStartIndex = m_nCurrentEndIndex = 0;
480 :
481 0 : bool bRet = !m_sCurrentPortion.isEmpty();
482 :
483 0 : if (m_eConvType == HHC::eConvHangulHanja && m_bTryBothDirections)
484 0 : implGetConversionDirectionForCurrentPortion( m_eCurrentConversionDirection );
485 :
486 0 : return bRet;
487 : }
488 :
489 0 : bool HangulHanjaConversion_Impl::implNextConvertible( bool _bRepeatUnit )
490 : {
491 0 : if ( _bRepeatUnit || ( m_nCurrentEndIndex < m_sCurrentPortion.getLength() ) )
492 : {
493 0 : if ( implNextConvertibleUnit(
494 : _bRepeatUnit
495 0 : ? ( IsByCharacter() ? m_nCurrentStartIndex : m_nCurrentStartIndex )
496 : : m_nCurrentEndIndex
497 0 : ) )
498 0 : return true;
499 : }
500 :
501 : // no convertible text in the current portion anymore
502 : // -> advance to the next portion
503 0 : do
504 : {
505 : // next portion
506 0 : if ( implRetrieveNextPortion( ) )
507 : { // there is a next portion
508 : // -> find the next convertible unit in the current portion
509 0 : if ( implNextConvertibleUnit( 0 ) )
510 0 : return true;
511 : }
512 : }
513 0 : while ( !m_sCurrentPortion.isEmpty() );
514 :
515 : // no more portions
516 0 : return false;
517 : }
518 :
519 0 : OUString HangulHanjaConversion_Impl::GetCurrentUnit() const
520 : {
521 : DBG_ASSERT( m_nCurrentStartIndex < m_sCurrentPortion.getLength(),
522 : "HangulHanjaConversion_Impl::GetCurrentUnit: invalid index into current portion!" );
523 : DBG_ASSERT( m_nCurrentEndIndex <= m_sCurrentPortion.getLength(),
524 : "HangulHanjaConversion_Impl::GetCurrentUnit: invalid index into current portion!" );
525 : DBG_ASSERT( m_nCurrentStartIndex <= m_nCurrentEndIndex,
526 : "HangulHanjaConversion_Impl::GetCurrentUnit: invalid interval!" );
527 :
528 0 : OUString sCurrentUnit = m_sCurrentPortion.copy( m_nCurrentStartIndex, m_nCurrentEndIndex - m_nCurrentStartIndex );
529 0 : return sCurrentUnit;
530 : }
531 :
532 0 : bool HangulHanjaConversion_Impl::ContinueConversion( bool _bRepeatCurrentUnit )
533 : {
534 0 : while ( implNextConvertible( _bRepeatCurrentUnit ) )
535 : {
536 0 : OUString sCurrentUnit( GetCurrentUnit() );
537 :
538 : // do we need to ignore it?
539 0 : const bool bAlwaysIgnoreThis = m_sIgnoreList.end() != m_sIgnoreList.find( sCurrentUnit );
540 :
541 : // do we need to change it?
542 0 : StringMap::const_iterator aChangeListPos = m_aChangeList.find( sCurrentUnit );
543 0 : const bool bAlwaysChangeThis = m_aChangeList.end() != aChangeListPos;
544 :
545 : // do we automatically change this?
546 0 : const bool bAutoChange = m_bAutoReplaceUnique && m_aCurrentSuggestions.getLength() == 1;
547 :
548 0 : if (!m_bIsInteractive)
549 : {
550 : // silent conversion (e.g. for simplified/traditional Chinese)...
551 0 : if(m_aCurrentSuggestions.getLength()>0)
552 0 : implChange( m_aCurrentSuggestions.getConstArray()[0] );
553 : }
554 0 : else if (bAutoChange)
555 : {
556 0 : implChange( m_aCurrentSuggestions.getConstArray()[0] );
557 : }
558 0 : else if ( bAlwaysChangeThis )
559 : {
560 0 : implChange( aChangeListPos->second );
561 : }
562 0 : else if ( !bAlwaysIgnoreThis )
563 : {
564 : // here we need to ask the user for what to do with the text
565 : // for this, allow derivees to highlight the current text unit in a possible document view
566 0 : m_pAntiImpl->HandleNewUnit( m_nCurrentStartIndex - m_nReplacementBaseIndex, m_nCurrentEndIndex - m_nReplacementBaseIndex );
567 :
568 : DBG_ASSERT( m_pConversionDialog, "we should always have a dialog here!" );
569 0 : if( m_pConversionDialog )
570 0 : m_pConversionDialog->SetCurrentString( sCurrentUnit, m_aCurrentSuggestions );
571 :
572 : // do not look for the next convertible: We have to wait for the user to interactivly
573 : // decide what happens with the current convertible
574 0 : return false;
575 : }
576 0 : }
577 :
578 0 : return true;
579 : }
580 :
581 0 : bool HangulHanjaConversion_Impl::implGetConversionDirectionForCurrentPortion( HHC::ConversionDirection& rDirection )
582 : {
583 : // - For eConvHangulHanja the direction is determined by
584 : // the first encountered Korean character.
585 : // - For eConvSimplifiedTraditional the conversion direction
586 : // is already specified by the source language.
587 :
588 0 : bool bSuccess = true;
589 :
590 0 : if (m_eConvType == HHC::eConvHangulHanja)
591 : {
592 0 : bSuccess = false;
593 : try
594 : {
595 : // get the break iterator service
596 0 : Reference< XBreakIterator > xBreakIter = BreakIterator::create( m_xContext );
597 0 : sal_Int32 nNextAsianScript = xBreakIter->beginOfScript( m_sCurrentPortion, m_nCurrentStartIndex, com::sun::star::i18n::ScriptType::ASIAN );
598 0 : if ( -1 == nNextAsianScript )
599 0 : nNextAsianScript = xBreakIter->nextScript( m_sCurrentPortion, m_nCurrentStartIndex, com::sun::star::i18n::ScriptType::ASIAN );
600 0 : if ( ( nNextAsianScript >= m_nCurrentStartIndex ) && ( nNextAsianScript < m_sCurrentPortion.getLength() ) )
601 : { // found asian text
602 :
603 : // determine if it's Hangul
604 0 : CharClass aCharClassificaton( m_xContext, LanguageTag( m_aSourceLocale) );
605 0 : sal_Int16 nScript = aCharClassificaton.getScript( m_sCurrentPortion, sal::static_int_cast< sal_uInt16 >(nNextAsianScript) );
606 0 : if ( ( UnicodeScript_kHangulJamo == nScript )
607 0 : || ( UnicodeScript_kHangulCompatibilityJamo == nScript )
608 0 : || ( UnicodeScript_kHangulSyllable == nScript )
609 : )
610 : {
611 0 : rDirection = HHC::eHangulToHanja;
612 : }
613 : else
614 : {
615 0 : rDirection = HHC::eHanjaToHangul;
616 : }
617 :
618 0 : bSuccess = true;
619 0 : }
620 : }
621 0 : catch( const Exception& )
622 : {
623 : OSL_FAIL( "HangulHanjaConversion_Impl::implGetConversionDirectionForCurrentPortion: caught an exception!" );
624 : }
625 : }
626 :
627 0 : return bSuccess;
628 : }
629 :
630 0 : void HangulHanjaConversion_Impl::DoDocumentConversion( )
631 : {
632 : // clear the change-all list - it's to be re-initialized for every single document
633 : {
634 0 : StringMap aEmpty;
635 0 : m_aChangeList.swap( aEmpty );
636 : }
637 :
638 : // first of all, we need to guess the direction of our conversion - it is determined by the first
639 : // hangul or hanja character in the first text
640 0 : if ( !implRetrieveNextPortion() )
641 : {
642 : DBG_WARNING( "HangulHanjaConversion_Impl::DoDocumentConversion: why did you call me if you do have nothing to convert?" );
643 : // nothing to do
644 0 : return;
645 : }
646 0 : if( m_eConvType == HHC::eConvHangulHanja )
647 : {
648 : //init conversion direction from saved value
649 0 : HHC::ConversionDirection eDirection = HHC::eHangulToHanja;
650 0 : if(!implGetConversionDirectionForCurrentPortion( eDirection ))
651 : // something went wrong, has already been asserted
652 0 : return;
653 :
654 0 : if (m_pAntiImpl->IsUseSavedConversionDirectionState())
655 : {
656 0 : m_ePrimaryConversionDirection = m_pAntiImpl->m_ePrimaryConversionDirectionSave;
657 0 : m_bTryBothDirections = m_pAntiImpl->m_bTryBothDirectionsSave;
658 0 : if( m_bTryBothDirections )
659 0 : m_eCurrentConversionDirection = eDirection;
660 : else
661 0 : m_eCurrentConversionDirection = m_ePrimaryConversionDirection;
662 : }
663 : else
664 : {
665 0 : m_ePrimaryConversionDirection = eDirection;
666 0 : m_eCurrentConversionDirection = eDirection;
667 : }
668 : }
669 :
670 0 : if (m_bIsInteractive && m_eConvType == HHC::eConvHangulHanja)
671 : {
672 : //always open dialog if at least having a hangul or hanja text portion
673 0 : createDialog();
674 0 : if(m_pAntiImpl->IsUseSavedConversionDirectionState())
675 0 : ContinueConversion( false );
676 : else
677 0 : implUpdateData();
678 0 : m_pConversionDialog->Execute();
679 0 : DELETEZ( m_pConversionDialog );
680 : }
681 : else
682 : {
683 : #ifdef DBG_UTIL
684 : const bool bCompletelyDone =
685 : #endif
686 0 : ContinueConversion( false );
687 : DBG_ASSERT( bCompletelyDone, "HangulHanjaConversion_Impl::DoDocumentConversion: ContinueConversion should have returned true here!" );
688 : }
689 : }
690 :
691 0 : void HangulHanjaConversion_Impl::implProceed( bool _bRepeatCurrentUnit )
692 : {
693 0 : if ( ContinueConversion( _bRepeatCurrentUnit ) )
694 : { // we're done with the whole document
695 : DBG_ASSERT( !m_bIsInteractive || m_pConversionDialog, "HangulHanjaConversion_Impl::implProceed: we should not reach this here without dialog!" );
696 0 : if ( m_pConversionDialog )
697 0 : m_pConversionDialog->EndDialog( RET_OK );
698 : }
699 0 : }
700 :
701 0 : void HangulHanjaConversion_Impl::implChange( const OUString& _rChangeInto )
702 : {
703 0 : if( _rChangeInto.isEmpty() )
704 0 : return;
705 :
706 : // translate the conversion format into a replacement action
707 : // this translation depends on whether we have a Hangul original, or a Hanja original
708 :
709 0 : HHC::ReplacementAction eAction( HHC::eExchange );
710 :
711 0 : if (m_eConvType == HHC::eConvHangulHanja)
712 : {
713 : // is the original we're about to change in Hangul?
714 0 : const bool bOriginalIsHangul = HHC::eHangulToHanja == m_eCurrentConversionDirection;
715 :
716 0 : switch ( m_eConversionFormat )
717 : {
718 0 : case HHC::eSimpleConversion: eAction = HHC::eExchange; break;
719 0 : case HHC::eHangulBracketed: eAction = bOriginalIsHangul ? HHC::eOriginalBracketed : HHC::eReplacementBracketed; break;
720 0 : case HHC::eHanjaBracketed: eAction = bOriginalIsHangul ? HHC::eReplacementBracketed : HHC::eOriginalBracketed; break;
721 0 : case HHC::eRubyHanjaAbove: eAction = bOriginalIsHangul ? HHC::eReplacementAbove : HHC::eOriginalAbove; break;
722 0 : case HHC::eRubyHanjaBelow: eAction = bOriginalIsHangul ? HHC::eReplacementBelow : HHC::eOriginalBelow; break;
723 0 : case HHC::eRubyHangulAbove: eAction = bOriginalIsHangul ? HHC::eOriginalAbove : HHC::eReplacementAbove; break;
724 0 : case HHC::eRubyHangulBelow: eAction = bOriginalIsHangul ? HHC::eOriginalBelow : HHC::eReplacementBelow; break;
725 : default:
726 : OSL_FAIL( "HangulHanjaConversion_Impl::implChange: invalid/unexpected conversion format!" );
727 : }
728 : }
729 :
730 : // the proper indicies (the wrapper implementation needs indicies relative to the
731 : // previous replacement)
732 : DBG_ASSERT( ( m_nReplacementBaseIndex <= m_nCurrentStartIndex ) && ( m_nReplacementBaseIndex <= m_nCurrentEndIndex ),
733 : "HangulHanjaConversion_Impl::implChange: invalid replacement base!" );
734 :
735 0 : sal_Int32 nStartIndex = m_nCurrentStartIndex - m_nReplacementBaseIndex;
736 0 : sal_Int32 nEndIndex = m_nCurrentEndIndex - m_nReplacementBaseIndex;
737 :
738 : //remind this decision
739 0 : m_aRecentlyUsedList[ GetCurrentUnit() ] = _rChangeInto;
740 :
741 0 : LanguageType *pNewUnitLang = 0;
742 0 : LanguageType nNewUnitLang = LANGUAGE_NONE;
743 0 : if (m_eConvType == HHC::eConvSimplifiedTraditional)
744 : {
745 : // check if language needs to be changed
746 0 : if ( m_pAntiImpl->GetTargetLanguage() == LANGUAGE_CHINESE_TRADITIONAL &&
747 0 : !m_pAntiImpl->IsTraditional( m_nCurrentPortionLang ))
748 0 : nNewUnitLang = LANGUAGE_CHINESE_TRADITIONAL;
749 0 : else if ( m_pAntiImpl->GetTargetLanguage() == LANGUAGE_CHINESE_SIMPLIFIED &&
750 0 : !m_pAntiImpl->IsSimplified( m_nCurrentPortionLang ))
751 0 : nNewUnitLang = LANGUAGE_CHINESE_SIMPLIFIED;
752 0 : if (nNewUnitLang != LANGUAGE_NONE)
753 0 : pNewUnitLang = &nNewUnitLang;
754 : }
755 :
756 : // according to FT we should not (yet) bother about Hangul/Hanja conversion here
757 : //
758 : // aOffsets is needed in ReplaceUnit below in order to to find out
759 : // exactly which characters are really changed in order to keep as much
760 : // from attributation for the text as possible.
761 0 : Sequence< sal_Int32 > aOffsets;
762 0 : Reference< XExtendedTextConversion > xExtConverter( m_xConverter, UNO_QUERY );
763 0 : if (m_eConvType == HHC::eConvSimplifiedTraditional && xExtConverter.is())
764 : {
765 : try
766 : {
767 0 : xExtConverter->getConversionWithOffset(
768 : m_sCurrentPortion,
769 : m_nCurrentStartIndex,
770 : m_nCurrentEndIndex - m_nCurrentStartIndex,
771 : m_aSourceLocale,
772 : m_nCurrentConversionType,
773 : m_nCurrentConversionOption,
774 : aOffsets
775 0 : );
776 : }
777 0 : catch( const Exception& )
778 : {
779 : OSL_FAIL( "HangulHanjaConversion_Impl::implChange: caught unexpected exception!" );
780 0 : aOffsets.realloc(0);
781 : }
782 : }
783 :
784 : // do the replacement
785 : m_pAntiImpl->ReplaceUnit( nStartIndex, nEndIndex, m_sCurrentPortion,
786 0 : _rChangeInto, aOffsets, eAction, pNewUnitLang );
787 :
788 :
789 : // adjust the replacement base
790 0 : m_nReplacementBaseIndex = m_nCurrentEndIndex;
791 : }
792 :
793 0 : void HangulHanjaConversion_Impl::implReadOptionsFromConfiguration()
794 : {
795 0 : SvtLinguConfig aLngCfg;
796 0 : aLngCfg.GetProperty( UPH_IS_IGNORE_POST_POSITIONAL_WORD ) >>= m_bIgnorePostPositionalWord;
797 0 : aLngCfg.GetProperty( UPH_IS_SHOW_ENTRIES_RECENTLY_USED_FIRST ) >>= m_bShowRecentlyUsedFirst;
798 0 : aLngCfg.GetProperty( UPH_IS_AUTO_REPLACE_UNIQUE_ENTRIES ) >>= m_bAutoReplaceUnique;
799 0 : }
800 :
801 0 : void HangulHanjaConversion_Impl::implUpdateData()
802 : {
803 0 : implReadOptionsFromConfiguration();
804 0 : implUpdateSuggestions();
805 :
806 0 : if(m_pConversionDialog)
807 : {
808 0 : OUString sCurrentUnit( GetCurrentUnit() );
809 :
810 0 : m_pConversionDialog->SetCurrentString( sCurrentUnit, m_aCurrentSuggestions );
811 0 : m_pConversionDialog->FocusSuggestion();
812 : }
813 :
814 0 : m_pAntiImpl->HandleNewUnit( m_nCurrentStartIndex - m_nReplacementBaseIndex, m_nCurrentEndIndex - m_nReplacementBaseIndex );
815 0 : }
816 :
817 0 : IMPL_LINK_NOARG(HangulHanjaConversion_Impl, OnOptionsChanged)
818 : {
819 : //options and dictionaries might have been changed
820 : //-> update our internal settings and the dialog
821 0 : implUpdateData();
822 :
823 0 : return 0L;
824 : }
825 :
826 0 : IMPL_LINK_NOARG(HangulHanjaConversion_Impl, OnIgnore)
827 : {
828 : // simply ignore, and proceed
829 0 : implProceed( false );
830 0 : return 0L;
831 : }
832 :
833 0 : IMPL_LINK_NOARG(HangulHanjaConversion_Impl, OnIgnoreAll)
834 : {
835 : DBG_ASSERT( m_pConversionDialog, "HangulHanjaConversion_Impl::OnIgnoreAll: no dialog! How this?" );
836 :
837 0 : if ( m_pConversionDialog )
838 : {
839 0 : String sCurrentUnit = m_pConversionDialog->GetCurrentString();
840 : DBG_ASSERT( m_sIgnoreList.end() == m_sIgnoreList.find( sCurrentUnit ),
841 : "HangulHanjaConversion_Impl, OnIgnoreAll: shouldn't this have been ignored before" );
842 :
843 : // put into the "ignore all" list
844 0 : m_sIgnoreList.insert( sCurrentUnit );
845 :
846 : // and proceed
847 0 : implProceed( false );
848 : }
849 :
850 0 : return 0L;
851 : }
852 :
853 0 : IMPL_LINK_NOARG(HangulHanjaConversion_Impl, OnChange)
854 : {
855 : // change
856 : DBG_ASSERT( m_pConversionDialog, "we should always have a dialog here!" );
857 0 : if( m_pConversionDialog )
858 0 : implChange( m_pConversionDialog->GetCurrentSuggestion( ) );
859 : // and proceed
860 0 : implProceed( false );
861 :
862 0 : return 0L;
863 : }
864 :
865 0 : IMPL_LINK_NOARG(HangulHanjaConversion_Impl, OnChangeAll)
866 : {
867 : DBG_ASSERT( m_pConversionDialog, "HangulHanjaConversion_Impl::OnChangeAll: no dialog! How this?" );
868 0 : if ( m_pConversionDialog )
869 : {
870 0 : OUString sCurrentUnit( m_pConversionDialog->GetCurrentString() );
871 0 : OUString sChangeInto( m_pConversionDialog->GetCurrentSuggestion( ) );
872 :
873 0 : if( !sChangeInto.isEmpty() )
874 : {
875 : // change the current occurrence
876 0 : implChange( sChangeInto );
877 :
878 : // put into the "change all" list
879 0 : m_aChangeList.insert( StringMap::value_type( sCurrentUnit, sChangeInto ) );
880 : }
881 :
882 : // and proceed
883 0 : implProceed( false );
884 : }
885 :
886 0 : return 0L;
887 : }
888 :
889 0 : IMPL_LINK( HangulHanjaConversion_Impl, OnByCharClicked, CheckBox*, _pBox )
890 : {
891 0 : m_bByCharacter = _pBox->IsChecked();
892 :
893 : // continue conversion, without advancing to the next unit, but instead continuing with the current unit
894 0 : implProceed( true );
895 0 : return 0L;
896 : }
897 :
898 0 : IMPL_LINK_NOARG(HangulHanjaConversion_Impl, OnConversionTypeChanged)
899 : {
900 : DBG_ASSERT( m_pConversionDialog, "we should always have a dialog here!" );
901 0 : if( m_pConversionDialog )
902 0 : m_eConversionFormat = m_pConversionDialog->GetConversionFormat( );
903 0 : return 0L;
904 : }
905 :
906 0 : IMPL_LINK_NOARG(HangulHanjaConversion_Impl, OnFind)
907 : {
908 : DBG_ASSERT( m_pConversionDialog, "HangulHanjaConversion_Impl::OnFind: where did this come from?" );
909 0 : if ( m_pConversionDialog )
910 : {
911 : try
912 : {
913 0 : OUString sNewOriginal( m_pConversionDialog->GetCurrentSuggestion( ) );
914 0 : Sequence< OUString > aSuggestions;
915 :
916 : DBG_ASSERT( m_xConverter.is(), "HangulHanjaConversion_Impl::OnFind: no converter!" );
917 0 : TextConversionResult aToHanja = m_xConverter->getConversions(
918 : sNewOriginal,
919 : 0, sNewOriginal.getLength(),
920 : m_aSourceLocale,
921 : TextConversionType::TO_HANJA,
922 : TextConversionOption::NONE
923 0 : );
924 0 : TextConversionResult aToHangul = m_xConverter->getConversions(
925 : sNewOriginal,
926 : 0, sNewOriginal.getLength(),
927 : m_aSourceLocale,
928 : TextConversionType::TO_HANGUL,
929 : TextConversionOption::NONE
930 0 : );
931 :
932 0 : bool bHaveToHanja = ( aToHanja.Boundary.startPos < aToHanja.Boundary.endPos );
933 0 : bool bHaveToHangul = ( aToHangul.Boundary.startPos < aToHangul.Boundary.endPos );
934 :
935 0 : TextConversionResult* pResult = NULL;
936 0 : if ( bHaveToHanja && bHaveToHangul )
937 : { // it found convertibles in both directions -> use the first
938 0 : if ( aToHangul.Boundary.startPos < aToHanja.Boundary.startPos )
939 0 : pResult = &aToHangul;
940 : else
941 0 : pResult = &aToHanja;
942 : }
943 0 : else if ( bHaveToHanja )
944 : { // only found toHanja
945 0 : pResult = &aToHanja;
946 : }
947 : else
948 : { // only found toHangul
949 0 : pResult = &aToHangul;
950 : }
951 0 : if ( pResult )
952 0 : aSuggestions = pResult->Candidates;
953 :
954 0 : m_pConversionDialog->SetCurrentString( sNewOriginal, aSuggestions, false );
955 0 : m_pConversionDialog->FocusSuggestion();
956 : }
957 0 : catch( const Exception& )
958 : {
959 : OSL_FAIL( "HangulHanjaConversion_Impl::OnFind: caught an exception!" );
960 : }
961 : }
962 0 : return 0L;
963 : }
964 :
965 : bool HangulHanjaConversion::m_bUseSavedValues = false;
966 : bool HangulHanjaConversion::m_bTryBothDirectionsSave = false;
967 : HHC::ConversionDirection HangulHanjaConversion::m_ePrimaryConversionDirectionSave = HHC::eHangulToHanja;
968 :
969 0 : HangulHanjaConversion::HangulHanjaConversion( Window* _pUIParent,
970 : const Reference< XComponentContext >& rxContext,
971 : const Locale& _rSourceLocale, const Locale& _rTargetLocale,
972 : const Font* _pTargetFont,
973 : sal_Int32 _nOptions, bool _bIsInteractive)
974 0 : :m_pImpl( new HangulHanjaConversion_Impl( _pUIParent, rxContext, _rSourceLocale, _rTargetLocale, _pTargetFont, _nOptions, _bIsInteractive, this ) )
975 : {
976 0 : }
977 :
978 0 : HangulHanjaConversion::~HangulHanjaConversion( )
979 : {
980 0 : }
981 :
982 0 : void HangulHanjaConversion::SetUseSavedConversionDirectionState( bool bVal )
983 : {
984 0 : m_bUseSavedValues = bVal;
985 0 : }
986 :
987 0 : bool HangulHanjaConversion::IsUseSavedConversionDirectionState()
988 : {
989 0 : return m_bUseSavedValues;
990 : }
991 :
992 0 : LanguageType HangulHanjaConversion::GetSourceLanguage( ) const
993 : {
994 0 : return m_pImpl->GetSourceLang();
995 : }
996 :
997 0 : LanguageType HangulHanjaConversion::GetTargetLanguage( ) const
998 : {
999 0 : return m_pImpl->GetTargetLang();
1000 : }
1001 :
1002 0 : const Font * HangulHanjaConversion::GetTargetFont( ) const
1003 : {
1004 0 : return m_pImpl->GetTargetFont();
1005 : }
1006 :
1007 0 : sal_Int32 HangulHanjaConversion::GetConversionOptions( ) const
1008 : {
1009 0 : return m_pImpl->GetConvOptions();
1010 : }
1011 :
1012 0 : bool HangulHanjaConversion::IsInteractive( ) const
1013 : {
1014 0 : return m_pImpl->IsInteractive();
1015 : }
1016 :
1017 0 : void HangulHanjaConversion::ConvertDocument()
1018 : {
1019 0 : if ( m_pImpl->IsValid() )
1020 0 : m_pImpl->DoDocumentConversion( );
1021 0 : }
1022 :
1023 267 : } // namespace svx
1024 :
1025 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|