Update ooo320-m1
[ooovba.git] / svx / source / editeng / textconv.cxx
blob4975b0cf7fab3975a6da3e7bbc465fe07c193100
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: textconv.cxx,v $
10 * $Revision: 1.14 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svx.hxx"
33 #include <eeng_pch.hxx>
35 #include <impedit.hxx>
36 #include <svx/editview.hxx>
37 #include <svx/editeng.hxx>
38 #include <unolingu.hxx>
39 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
40 #include <com/sun/star/lang/Locale.hpp>
41 #include <svx/langitem.hxx>
42 #include <fontitem.hxx>
43 #include "textconv.hxx"
46 using ::rtl::OUString;
47 using namespace com::sun::star;
48 using namespace com::sun::star::uno;
49 using namespace com::sun::star::beans;
50 using namespace com::sun::star::lang;
51 using namespace com::sun::star::linguistic2;
53 #define C2U(cChar) OUString::createFromAscii(cChar)
55 //////////////////////////////////////////////////////////////////////
57 TextConvWrapper::TextConvWrapper( Window* pWindow,
58 const Reference< XMultiServiceFactory >& rxMSF,
59 const Locale& rSourceLocale,
60 const Locale& rTargetLocale,
61 const Font* pTargetFont,
62 sal_Int32 nOptions,
63 sal_Bool bIsInteractive,
64 BOOL bIsStart,
65 EditView* pView ) :
66 HangulHanjaConversion( pWindow, rxMSF, rSourceLocale, rTargetLocale, pTargetFont, nOptions, bIsInteractive )
68 DBG_ASSERT( pWindow, "TextConvWrapper: window missing" );
70 nConvTextLang = LANGUAGE_NONE;
71 nUnitOffset = 0;
73 bStartChk = sal_False;
74 bStartDone = bIsStart;
75 bEndDone = sal_False;
76 pWin = pWindow;
77 pEditView = pView;
79 aConvSel = pEditView->GetSelection();
80 aConvSel.Adjust(); // make Start <= End
82 bAllowChange = sal_False;
86 TextConvWrapper::~TextConvWrapper()
91 sal_Bool TextConvWrapper::ConvNext_impl()
93 // modified version of SvxSpellWrapper::SpellNext
95 if( bStartChk )
96 bStartDone = sal_True;
97 else
98 bEndDone = sal_True;
100 if ( bStartDone && bEndDone )
102 if ( ConvMore_impl() ) // ein weiteres Dokument pruefen?
104 bStartDone = sal_True;
105 bEndDone = sal_False;
106 ConvStart_impl( SVX_SPELL_BODY );
107 return sal_True;
109 return sal_False;
113 //ResMgr* pMgr = DIALOG_MGR();
114 sal_Bool bGoOn = sal_False;
116 if ( bStartDone && bEndDone )
118 if ( ConvMore_impl() ) // ein weiteres Dokument pruefen?
120 bStartDone = sal_True;
121 bEndDone = sal_False;
122 ConvStart_impl( SVX_SPELL_BODY );
123 return sal_True;
126 else
128 // Ein BODY_Bereich erledigt, Frage nach dem anderen BODY_Bereich
130 pWin->LeaveWait();
132 sal_uInt16 nResId = bReverse ? RID_SVXQB_BW_CONTINUE : RID_SVXQB_CONTINUE;
133 QueryBox aBox( pWin, ResId( nResId, pMgr ) );
134 if ( aBox.Execute() != RET_YES )
136 // Verzicht auf den anderen Bereich, ggf. Frage nach Sonderbereich
137 pWin->EnterWait();
138 bStartDone = bEndDone = sal_True;
139 return ConvNext_impl();
141 else
144 if (!aConvSel.HasRange())
146 bStartChk = !bStartDone;
147 ConvStart_impl( bStartChk ? SVX_SPELL_BODY_START : SVX_SPELL_BODY_END );
148 bGoOn = sal_True;
152 pWin->EnterWait();
155 return bGoOn;
159 sal_Bool TextConvWrapper::FindConvText_impl()
161 // modified version of SvxSpellWrapper::FindSpellError
163 //ShowLanguageErrors();
165 sal_Bool bFound = sal_False;
167 pWin->EnterWait();
168 sal_Bool bConvert = sal_True;
170 while ( bConvert )
172 bFound = ConvContinue_impl();
173 if (bFound)
175 bConvert = sal_False;
177 else
179 ConvEnd_impl();
180 bConvert = ConvNext_impl();
183 pWin->LeaveWait();
184 return bFound;
188 sal_Bool TextConvWrapper::ConvMore_impl()
190 // modified version of SvxSpellWrapper::SpellMore
192 sal_Bool bMore = sal_False;
193 ImpEditEngine* pImpEE = pEditView->GetImpEditEngine();
194 ConvInfo* pConvInfo = pImpEE->GetConvInfo();
195 if ( pConvInfo->bMultipleDoc )
197 bMore = pImpEE->GetEditEnginePtr()->ConvertNextDocument();
198 if ( bMore )
200 // Der Text wurde in diese Engine getreten...
201 pEditView->GetImpEditView()->SetEditSelection(
202 pImpEE->GetEditDoc().GetStartPaM() );
205 return bMore;
209 void TextConvWrapper::ConvStart_impl( SvxSpellArea eArea )
211 // modified version of EditSpellWrapper::SpellStart
213 ImpEditEngine* pImpEE = pEditView->GetImpEditEngine();
214 ConvInfo* pConvInfo = pImpEE->GetConvInfo();
216 if ( eArea == SVX_SPELL_BODY_START )
218 // Wird gerufen, wenn Spell-Forwad am Ende angekomment ist
219 // und soll von vorne beginnen
220 if ( bEndDone )
222 pConvInfo->bConvToEnd = sal_False;
223 pConvInfo->aConvTo = pConvInfo->aConvStart;
224 pConvInfo->aConvContinue = EPaM( 0, 0 );
225 pEditView->GetImpEditView()->SetEditSelection(
226 pImpEE->GetEditDoc().GetStartPaM() );
228 else
230 pConvInfo->bConvToEnd = sal_True;
231 pConvInfo->aConvTo = pImpEE->CreateEPaM(
232 pImpEE->GetEditDoc().GetStartPaM() );
235 else if ( eArea == SVX_SPELL_BODY_END )
237 // Wird gerufen, wenn Spell-Forwad gestartet wird
238 pConvInfo->bConvToEnd = sal_True;
239 if (aConvSel.HasRange())
241 // user selection: convert to end of selection
242 pConvInfo->aConvTo.nPara = aConvSel.nEndPara;
243 pConvInfo->aConvTo.nIndex = aConvSel.nEndPos;
244 pConvInfo->bConvToEnd = sal_False;
246 else
248 // nothing selected: convert to end of document
249 pConvInfo->aConvTo = pImpEE->CreateEPaM(
250 pImpEE->GetEditDoc().GetEndPaM() );
253 else if ( eArea == SVX_SPELL_BODY )
255 // called by ConvNext_impl...
256 pConvInfo->aConvContinue = pConvInfo->aConvStart;
257 pConvInfo->aConvTo = pImpEE->CreateEPaM(
258 pImpEE->GetEditDoc().GetEndPaM() );
259 // pSpellInfo->bSpellToEnd = sal_True;
261 else
263 DBG_ERROR( "ConvStart_impl: Unknown Area!" );
268 void TextConvWrapper::ConvEnd_impl()
273 sal_Bool TextConvWrapper::ConvContinue_impl()
275 // modified version of EditSpellWrapper::SpellContinue
277 // get next convertible text portion and its language
278 aConvText = rtl::OUString();
279 nConvTextLang = LANGUAGE_NONE;
280 pEditView->GetImpEditEngine()->ImpConvert( aConvText, nConvTextLang,
281 pEditView, GetSourceLanguage(), aConvSel,
282 bAllowChange, GetTargetLanguage(), GetTargetFont() );
283 return aConvText.getLength() != 0;
287 void TextConvWrapper::SetLanguageAndFont( const ESelection &rESel,
288 LanguageType nLang, USHORT nLangWhichId,
289 const Font *pFont, USHORT nFontWhichId )
291 ESelection aOldSel = pEditView->GetSelection();
292 pEditView->SetSelection( rESel );
294 // set new language attribute
295 SfxItemSet aNewSet( pEditView->GetEmptyItemSet() );
296 aNewSet.Put( SvxLanguageItem( nLang, nLangWhichId ) );
298 // new font to be set?
299 DBG_ASSERT( pFont, "target font missing?" );
300 if (pFont)
302 // set new font attribute
303 SvxFontItem aFontItem = (SvxFontItem&) aNewSet.Get( nFontWhichId );
304 aFontItem.GetFamilyName() = pFont->GetName();
305 aFontItem.GetFamily() = pFont->GetFamily();
306 aFontItem.GetStyleName() = pFont->GetStyleName();
307 aFontItem.GetPitch() = pFont->GetPitch();
308 aFontItem.GetCharSet() = pFont->GetCharSet();
309 aNewSet.Put( aFontItem );
312 // apply new attributes
313 pEditView->SetAttribs( aNewSet );
315 pEditView->SetSelection( aOldSel );
319 void TextConvWrapper::SelectNewUnit_impl(
320 const sal_Int32 nUnitStart,
321 const sal_Int32 nUnitEnd )
323 BOOL bOK = 0 <= nUnitStart && 0 <= nUnitEnd && nUnitStart <= nUnitEnd;
324 DBG_ASSERT( bOK, "invalid arguments" );
325 if (!bOK)
326 return;
328 ESelection aSelection = pEditView->GetSelection();
329 DBG_ASSERT( aSelection.nStartPara == aSelection.nEndPara,
330 "paragraph mismatch in selection" );
331 aSelection.nStartPos = (USHORT) (nLastPos + nUnitOffset + nUnitStart);
332 aSelection.nEndPos = (USHORT) (nLastPos + nUnitOffset + nUnitEnd);
333 pEditView->SetSelection( aSelection );
337 void TextConvWrapper::GetNextPortion(
338 ::rtl::OUString& /* [out] */ rNextPortion,
339 LanguageType& /* [out] */ rLangOfPortion,
340 sal_Bool /* [in] */ _bAllowImplicitChangesForNotConvertibleText )
342 bAllowChange = _bAllowImplicitChangesForNotConvertibleText;
344 FindConvText_impl();
345 rNextPortion = aConvText;
346 rLangOfPortion = nConvTextLang;
347 nUnitOffset = 0;
349 ESelection aSelection = pEditView->GetSelection();
350 DBG_ASSERT( aSelection.nStartPara == aSelection.nEndPara,
351 "paragraph mismatch in selection" );
352 DBG_ASSERT( aSelection.nStartPos <= aSelection.nEndPos,
353 "start pos > end pos" );
354 nLastPos = aSelection.nStartPos;
358 void TextConvWrapper::HandleNewUnit(
359 const sal_Int32 nUnitStart,
360 const sal_Int32 nUnitEnd )
362 SelectNewUnit_impl( nUnitStart, nUnitEnd );
366 void TextConvWrapper::ReplaceUnit(
367 const sal_Int32 nUnitStart, const sal_Int32 nUnitEnd,
368 const ::rtl::OUString& rOrigText,
369 const ::rtl::OUString& rReplaceWith,
370 const ::com::sun::star::uno::Sequence< sal_Int32 > &rOffsets,
371 ReplacementAction eAction,
372 LanguageType *pNewUnitLanguage )
374 BOOL bOK = 0 <= nUnitStart && 0 <= nUnitEnd && nUnitStart <= nUnitEnd;
375 DBG_ASSERT( bOK, "invalid arguments" );
376 if (!bOK)
377 return;
379 static OUString aBracketedStart( C2U( "(" ) );
380 static OUString aBracketedEnd( C2U( ")" ) );
382 // select current unit
383 SelectNewUnit_impl( nUnitStart, nUnitEnd );
385 OUString aOrigTxt( pEditView->GetSelected() );
386 OUString aNewTxt( rReplaceWith );
387 String aNewOrigText;
388 switch (eAction)
390 case eExchange :
391 break;
392 case eReplacementBracketed :
393 (((aNewTxt = aOrigTxt) += aBracketedStart) += rReplaceWith) += aBracketedEnd;
394 break;
395 case eOriginalBracketed :
396 (((aNewTxt = rReplaceWith) += aBracketedStart) += aOrigTxt) += aBracketedEnd;
397 break;
398 case eReplacementAbove :
399 case eOriginalAbove :
400 case eReplacementBelow :
401 case eOriginalBelow :
402 DBG_ERROR( "Rubies not supported" );
403 break;
404 default:
405 DBG_ERROR( "unexpected case" );
407 nUnitOffset = sal::static_int_cast< USHORT >(
408 nUnitOffset + nUnitStart + aNewTxt.getLength());
410 // remember current original language for kater use
411 ImpEditEngine *pImpEditEng = pEditView->GetImpEditEngine();
412 ESelection _aOldSel = pEditView->GetSelection();
413 //EditSelection aOldEditSel = pEditView->GetImpEditView()->GetEditSelection();
415 #ifdef DBG_UTIL
416 LanguageType nOldLang = pImpEditEng->GetLanguage( pImpEditEng->CreateSel( _aOldSel ).Min() );
417 #endif
419 pImpEditEng->UndoActionStart( EDITUNDO_INSERT );
421 // according to FT we should currently not bother about keeping
422 // attributes in Hangul/Hanja conversion and leave that untouched.
423 // Thus we do this only for Chinese translation...
424 sal_Bool bIsChineseConversion = IsChinese( GetSourceLanguage() );
425 if (bIsChineseConversion)
426 ChangeText( aNewTxt, rOrigText, &rOffsets, &_aOldSel );
427 else
428 ChangeText( aNewTxt, rOrigText, NULL, NULL );
430 // change language and font if necessary
431 if (bIsChineseConversion)
433 DBG_ASSERT( GetTargetLanguage() == LANGUAGE_CHINESE_SIMPLIFIED || GetTargetLanguage() == LANGUAGE_CHINESE_TRADITIONAL,
434 "TextConvWrapper::ReplaceUnit : unexpected target language" );
436 ESelection aOldSel = pEditView->GetSelection();
437 ESelection aNewSel( aOldSel );
438 aNewSel.nStartPos = sal::static_int_cast< xub_StrLen >(
439 aNewSel.nStartPos - aNewTxt.getLength());
440 // DBG_ASSERT( aOldSel.nEndPos >= 0, "error while building selection" );
442 if (pNewUnitLanguage)
444 DBG_ASSERT(!IsSimilarChinese( *pNewUnitLanguage, nOldLang ),
445 "similar language should not be changed!");
446 SetLanguageAndFont( aNewSel, *pNewUnitLanguage, EE_CHAR_LANGUAGE_CJK,
447 GetTargetFont(), EE_CHAR_FONTINFO_CJK );
451 pImpEditEng->UndoActionEnd( EDITUNDO_INSERT );
453 // adjust ConvContinue / ConvTo if necessary
454 ImpEditEngine* pImpEE = pEditView->GetImpEditEngine();
455 ConvInfo* pConvInfo = pImpEE->GetConvInfo();
456 sal_Int32 nDelta = aNewTxt.getLength() - aOrigTxt.getLength();
457 if (nDelta != 0)
459 // Note: replacement is always done in the current paragraph
460 // which is the one ConvContinue points to
461 pConvInfo->aConvContinue.nIndex = sal::static_int_cast< USHORT >(
462 pConvInfo->aConvContinue.nIndex + nDelta);
464 // if that is the same as the one where the conversions ends
465 // the end needs to be updated also
466 if (pConvInfo->aConvTo.nPara == pConvInfo->aConvContinue.nPara)
467 pConvInfo->aConvTo.nIndex = sal::static_int_cast< USHORT >(
468 pConvInfo->aConvTo.nIndex + nDelta);
473 void TextConvWrapper::ChangeText( const String &rNewText,
474 const OUString& rOrigText,
475 const uno::Sequence< sal_Int32 > *pOffsets,
476 ESelection *pESelection )
478 //!! code is a modifed copy of SwHHCWrapper::ChangeText from sw !!
480 DBG_ASSERT( rNewText.Len() != 0, "unexpected empty string" );
481 if (rNewText.Len() == 0)
482 return;
484 if (pOffsets && pESelection) // try to keep as much attributation as possible ?
486 pESelection->Adjust();
488 // remember cursor start position for later setting of the cursor
489 const xub_StrLen nStartIndex = pESelection->nStartPos;
491 const sal_Int32 nIndices = pOffsets->getLength();
492 const sal_Int32 *pIndices = pOffsets->getConstArray();
493 xub_StrLen nConvTextLen = rNewText.Len();
494 xub_StrLen nPos = 0;
495 xub_StrLen nChgPos = STRING_NOTFOUND;
496 xub_StrLen nChgLen = 0;
497 xub_StrLen nConvChgPos = STRING_NOTFOUND;
498 xub_StrLen nConvChgLen = 0;
500 // offset to calculate the position in the text taking into
501 // account that text may have been replaced with new text of
502 // different length. Negative values allowed!
503 long nCorrectionOffset = 0;
505 DBG_ASSERT(nIndices == 0 || nIndices == nConvTextLen,
506 "mismatch between string length and sequence length!" );
508 // find all substrings that need to be replaced (and only those)
509 while (sal_True)
511 // get index in original text that matches nPos in new text
512 xub_StrLen nIndex;
513 if (nPos < nConvTextLen)
514 nIndex = (sal_Int32) nPos < nIndices ? (xub_StrLen) pIndices[nPos] : nPos;
515 else
517 nPos = nConvTextLen;
518 nIndex = static_cast< xub_StrLen >( rOrigText.getLength() );
521 if (rOrigText.getStr()[nIndex] == rNewText.GetChar(nPos) ||
522 nPos == nConvTextLen /* end of string also terminates non-matching char sequence */)
524 // substring that needs to be replaced found?
525 if (nChgPos != STRING_NOTFOUND && nConvChgPos != STRING_NOTFOUND)
527 nChgLen = nIndex - nChgPos;
528 nConvChgLen = nPos - nConvChgPos;
529 #ifdef DEBUG
530 String aInOrig( rOrigText.copy( nChgPos, nChgLen ) );
531 #endif
532 String aInNew( rNewText.Copy( nConvChgPos, nConvChgLen ) );
534 // set selection to sub string to be replaced in original text
535 ESelection aSel( *pESelection );
536 xub_StrLen nChgInNodeStartIndex = static_cast< xub_StrLen >( nStartIndex + nCorrectionOffset + nChgPos );
537 aSel.nStartPos = nChgInNodeStartIndex;
538 aSel.nEndPos = nChgInNodeStartIndex + nChgLen;
539 pEditView->SetSelection( aSel );
540 #ifdef DEBUG
541 String aSelTxt1( pEditView->GetSelected() );
542 #endif
544 // replace selected sub string with the corresponding
545 // sub string from the new text while keeping as
546 // much from the attributes as possible
547 ChangeText_impl( aInNew, sal_True );
549 nCorrectionOffset += nConvChgLen - nChgLen;
551 nChgPos = STRING_NOTFOUND;
552 nConvChgPos = STRING_NOTFOUND;
555 else
557 // begin of non-matching char sequence found ?
558 if (nChgPos == STRING_NOTFOUND && nConvChgPos == STRING_NOTFOUND)
560 nChgPos = nIndex;
561 nConvChgPos = nPos;
564 if (nPos >= nConvTextLen)
565 break;
566 ++nPos;
569 // set cursor to the end of the inserted text
570 // (as it would happen after ChangeText_impl (Delete and Insert)
571 // of the whole text in the 'else' branch below)
572 pESelection->nStartPos = pESelection->nEndPos = nStartIndex + nConvTextLen;
574 else
576 ChangeText_impl( rNewText, sal_False );
581 void TextConvWrapper::ChangeText_impl( const String &rNewText, sal_Bool bKeepAttributes )
583 if (bKeepAttributes)
585 // save attributes to be restored
586 SfxItemSet aSet( pEditView->GetAttribs() );
588 #ifdef DEBUG
589 String aSelTxt1( pEditView->GetSelected() );
590 #endif
591 // replace old text and select new text
592 pEditView->InsertText( rNewText, sal_True );
593 #ifdef DEBUG
594 String aSelTxt2( pEditView->GetSelected() );
595 #endif
597 // since 'SetAttribs' below function like merging with the attributes
598 // from the itemset with any existing ones we have to get rid of all
599 // all attributes now. (Those attributes that may take effect left
600 // to the position where the new text gets inserted after the old text
601 // was deleted)
602 pEditView->RemoveAttribs();
603 // apply saved attributes to new inserted text
604 pEditView->SetAttribs( aSet );
606 else
608 pEditView->InsertText( rNewText );
613 void TextConvWrapper::Convert()
615 bStartChk = sal_False;
616 ConvStart_impl( SVX_SPELL_BODY_END );
617 ConvertDocument();
618 ConvEnd_impl();
622 sal_Bool TextConvWrapper::HasRubySupport() const
624 return sal_False;
627 //////////////////////////////////////////////////////////////////////