summaryrefslogtreecommitdiff
path: root/editeng/source/editeng/textconv.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'editeng/source/editeng/textconv.cxx')
-rw-r--r--editeng/source/editeng/textconv.cxx629
1 files changed, 629 insertions, 0 deletions
diff --git a/editeng/source/editeng/textconv.cxx b/editeng/source/editeng/textconv.cxx
new file mode 100644
index 000000000000..e46a40f09e02
--- /dev/null
+++ b/editeng/source/editeng/textconv.cxx
@@ -0,0 +1,629 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_editeng.hxx"
+
+#include <vcl/wrkwin.hxx>
+#include <vcl/dialog.hxx>
+#include <vcl/msgbox.hxx>
+#include <vcl/svapp.hxx>
+
+#include <impedit.hxx>
+#include <editeng/editview.hxx>
+#include <editeng/editeng.hxx>
+#include <editeng/unolingu.hxx>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/Locale.hpp>
+#include <editeng/langitem.hxx>
+#include <editeng/fontitem.hxx>
+#include <textconv.hxx>
+
+
+using ::rtl::OUString;
+using namespace com::sun::star;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::linguistic2;
+
+#define C2U(cChar) OUString::createFromAscii(cChar)
+
+//////////////////////////////////////////////////////////////////////
+
+TextConvWrapper::TextConvWrapper( Window* pWindow,
+ const Reference< XMultiServiceFactory >& rxMSF,
+ const Locale& rSourceLocale,
+ const Locale& rTargetLocale,
+ const Font* pTargetFont,
+ sal_Int32 nOptions,
+ sal_Bool bIsInteractive,
+ BOOL bIsStart,
+ EditView* pView ) :
+ HangulHanjaConversion( pWindow, rxMSF, rSourceLocale, rTargetLocale, pTargetFont, nOptions, bIsInteractive )
+{
+ DBG_ASSERT( pWindow, "TextConvWrapper: window missing" );
+
+ nConvTextLang = LANGUAGE_NONE;
+ nUnitOffset = 0;
+
+ bStartChk = sal_False;
+ bStartDone = bIsStart;
+ bEndDone = sal_False;
+ pWin = pWindow;
+ pEditView = pView;
+
+ aConvSel = pEditView->GetSelection();
+ aConvSel.Adjust(); // make Start <= End
+
+ bAllowChange = sal_False;
+}
+
+
+TextConvWrapper::~TextConvWrapper()
+{
+}
+
+
+sal_Bool TextConvWrapper::ConvNext_impl()
+{
+ // modified version of SvxSpellWrapper::SpellNext
+
+ if( bStartChk )
+ bStartDone = sal_True;
+ else
+ bEndDone = sal_True;
+
+ if ( bStartDone && bEndDone )
+ {
+ if ( ConvMore_impl() ) // ein weiteres Dokument pruefen?
+ {
+ bStartDone = sal_True;
+ bEndDone = sal_False;
+ ConvStart_impl( SVX_SPELL_BODY );
+ return sal_True;
+ }
+ return sal_False;
+
+ }
+
+ //ResMgr* pMgr = DIALOG_MGR();
+ sal_Bool bGoOn = sal_False;
+
+ if ( bStartDone && bEndDone )
+ {
+ if ( ConvMore_impl() ) // ein weiteres Dokument pruefen?
+ {
+ bStartDone = sal_True;
+ bEndDone = sal_False;
+ ConvStart_impl( SVX_SPELL_BODY );
+ return sal_True;
+ }
+ }
+ else
+ {
+ // Ein BODY_Bereich erledigt, Frage nach dem anderen BODY_Bereich
+/*
+ pWin->LeaveWait();
+
+ sal_uInt16 nResId = bReverse ? RID_SVXQB_BW_CONTINUE : RID_SVXQB_CONTINUE;
+ QueryBox aBox( pWin, ResId( nResId, pMgr ) );
+ if ( aBox.Execute() != RET_YES )
+ {
+ // Verzicht auf den anderen Bereich, ggf. Frage nach Sonderbereich
+ pWin->EnterWait();
+ bStartDone = bEndDone = sal_True;
+ return ConvNext_impl();
+ }
+ else
+ {
+*/
+ if (!aConvSel.HasRange())
+ {
+ bStartChk = !bStartDone;
+ ConvStart_impl( bStartChk ? SVX_SPELL_BODY_START : SVX_SPELL_BODY_END );
+ bGoOn = sal_True;
+ }
+/*
+ }
+ pWin->EnterWait();
+*/
+ }
+ return bGoOn;
+}
+
+
+sal_Bool TextConvWrapper::FindConvText_impl()
+{
+ // modified version of SvxSpellWrapper::FindSpellError
+
+ //ShowLanguageErrors();
+
+ sal_Bool bFound = sal_False;
+
+ pWin->EnterWait();
+ sal_Bool bConvert = sal_True;
+
+ while ( bConvert )
+ {
+ bFound = ConvContinue_impl();
+ if (bFound)
+ {
+ bConvert = sal_False;
+ }
+ else
+ {
+ ConvEnd_impl();
+ bConvert = ConvNext_impl();
+ }
+ }
+ pWin->LeaveWait();
+ return bFound;
+}
+
+
+sal_Bool TextConvWrapper::ConvMore_impl()
+{
+ // modified version of SvxSpellWrapper::SpellMore
+
+ sal_Bool bMore = sal_False;
+ ImpEditEngine* pImpEE = pEditView->GetImpEditEngine();
+ ConvInfo* pConvInfo = pImpEE->GetConvInfo();
+ if ( pConvInfo->bMultipleDoc )
+ {
+ bMore = pImpEE->GetEditEnginePtr()->ConvertNextDocument();
+ if ( bMore )
+ {
+ // Der Text wurde in diese Engine getreten...
+ pEditView->GetImpEditView()->SetEditSelection(
+ pImpEE->GetEditDoc().GetStartPaM() );
+ }
+ }
+ return bMore;
+}
+
+
+void TextConvWrapper::ConvStart_impl( SvxSpellArea eArea )
+{
+ // modified version of EditSpellWrapper::SpellStart
+
+ ImpEditEngine* pImpEE = pEditView->GetImpEditEngine();
+ ConvInfo* pConvInfo = pImpEE->GetConvInfo();
+
+ if ( eArea == SVX_SPELL_BODY_START )
+ {
+ // Wird gerufen, wenn Spell-Forwad am Ende angekomment ist
+ // und soll von vorne beginnen
+ if ( bEndDone )
+ {
+ pConvInfo->bConvToEnd = sal_False;
+ pConvInfo->aConvTo = pConvInfo->aConvStart;
+ pConvInfo->aConvContinue = EPaM( 0, 0 );
+ pEditView->GetImpEditView()->SetEditSelection(
+ pImpEE->GetEditDoc().GetStartPaM() );
+ }
+ else
+ {
+ pConvInfo->bConvToEnd = sal_True;
+ pConvInfo->aConvTo = pImpEE->CreateEPaM(
+ pImpEE->GetEditDoc().GetStartPaM() );
+ }
+ }
+ else if ( eArea == SVX_SPELL_BODY_END )
+ {
+ // Wird gerufen, wenn Spell-Forwad gestartet wird
+ pConvInfo->bConvToEnd = sal_True;
+ if (aConvSel.HasRange())
+ {
+ // user selection: convert to end of selection
+ pConvInfo->aConvTo.nPara = aConvSel.nEndPara;
+ pConvInfo->aConvTo.nIndex = aConvSel.nEndPos;
+ pConvInfo->bConvToEnd = sal_False;
+ }
+ else
+ {
+ // nothing selected: convert to end of document
+ pConvInfo->aConvTo = pImpEE->CreateEPaM(
+ pImpEE->GetEditDoc().GetEndPaM() );
+ }
+ }
+ else if ( eArea == SVX_SPELL_BODY )
+ {
+ // called by ConvNext_impl...
+ pConvInfo->aConvContinue = pConvInfo->aConvStart;
+ pConvInfo->aConvTo = pImpEE->CreateEPaM(
+ pImpEE->GetEditDoc().GetEndPaM() );
+ // pSpellInfo->bSpellToEnd = sal_True;
+ }
+ else
+ {
+ DBG_ERROR( "ConvStart_impl: Unknown Area!" );
+ }
+}
+
+
+void TextConvWrapper::ConvEnd_impl()
+{
+}
+
+
+sal_Bool TextConvWrapper::ConvContinue_impl()
+{
+ // modified version of EditSpellWrapper::SpellContinue
+
+ // get next convertible text portion and its language
+ aConvText = rtl::OUString();
+ nConvTextLang = LANGUAGE_NONE;
+ pEditView->GetImpEditEngine()->ImpConvert( aConvText, nConvTextLang,
+ pEditView, GetSourceLanguage(), aConvSel,
+ bAllowChange, GetTargetLanguage(), GetTargetFont() );
+ return aConvText.getLength() != 0;
+}
+
+
+void TextConvWrapper::SetLanguageAndFont( const ESelection &rESel,
+ LanguageType nLang, USHORT nLangWhichId,
+ const Font *pFont, USHORT nFontWhichId )
+{
+ ESelection aOldSel = pEditView->GetSelection();
+ pEditView->SetSelection( rESel );
+
+ // set new language attribute
+ SfxItemSet aNewSet( pEditView->GetEmptyItemSet() );
+ aNewSet.Put( SvxLanguageItem( nLang, nLangWhichId ) );
+
+ // new font to be set?
+ DBG_ASSERT( pFont, "target font missing?" );
+ if (pFont)
+ {
+ // set new font attribute
+ SvxFontItem aFontItem = (SvxFontItem&) aNewSet.Get( nFontWhichId );
+ aFontItem.GetFamilyName() = pFont->GetName();
+ aFontItem.GetFamily() = pFont->GetFamily();
+ aFontItem.GetStyleName() = pFont->GetStyleName();
+ aFontItem.GetPitch() = pFont->GetPitch();
+ aFontItem.GetCharSet() = pFont->GetCharSet();
+ aNewSet.Put( aFontItem );
+ }
+
+ // apply new attributes
+ pEditView->SetAttribs( aNewSet );
+
+ pEditView->SetSelection( aOldSel );
+}
+
+
+void TextConvWrapper::SelectNewUnit_impl(
+ const sal_Int32 nUnitStart,
+ const sal_Int32 nUnitEnd )
+{
+ BOOL bOK = 0 <= nUnitStart && 0 <= nUnitEnd && nUnitStart <= nUnitEnd;
+ DBG_ASSERT( bOK, "invalid arguments" );
+ if (!bOK)
+ return;
+
+ ESelection aSelection = pEditView->GetSelection();
+ DBG_ASSERT( aSelection.nStartPara == aSelection.nEndPara,
+ "paragraph mismatch in selection" );
+ aSelection.nStartPos = (USHORT) (nLastPos + nUnitOffset + nUnitStart);
+ aSelection.nEndPos = (USHORT) (nLastPos + nUnitOffset + nUnitEnd);
+ pEditView->SetSelection( aSelection );
+}
+
+
+void TextConvWrapper::GetNextPortion(
+ ::rtl::OUString& /* [out] */ rNextPortion,
+ LanguageType& /* [out] */ rLangOfPortion,
+ sal_Bool /* [in] */ _bAllowImplicitChangesForNotConvertibleText )
+{
+ bAllowChange = _bAllowImplicitChangesForNotConvertibleText;
+
+ FindConvText_impl();
+ rNextPortion = aConvText;
+ rLangOfPortion = nConvTextLang;
+ nUnitOffset = 0;
+
+ ESelection aSelection = pEditView->GetSelection();
+ DBG_ASSERT( aSelection.nStartPara == aSelection.nEndPara,
+ "paragraph mismatch in selection" );
+ DBG_ASSERT( aSelection.nStartPos <= aSelection.nEndPos,
+ "start pos > end pos" );
+ nLastPos = aSelection.nStartPos;
+}
+
+
+void TextConvWrapper::HandleNewUnit(
+ const sal_Int32 nUnitStart,
+ const sal_Int32 nUnitEnd )
+{
+ SelectNewUnit_impl( nUnitStart, nUnitEnd );
+}
+
+
+void TextConvWrapper::ReplaceUnit(
+ const sal_Int32 nUnitStart, const sal_Int32 nUnitEnd,
+ const ::rtl::OUString& rOrigText,
+ const ::rtl::OUString& rReplaceWith,
+ const ::com::sun::star::uno::Sequence< sal_Int32 > &rOffsets,
+ ReplacementAction eAction,
+ LanguageType *pNewUnitLanguage )
+{
+ BOOL bOK = 0 <= nUnitStart && 0 <= nUnitEnd && nUnitStart <= nUnitEnd;
+ DBG_ASSERT( bOK, "invalid arguments" );
+ if (!bOK)
+ return;
+
+ static OUString aBracketedStart( C2U( "(" ) );
+ static OUString aBracketedEnd( C2U( ")" ) );
+
+ // select current unit
+ SelectNewUnit_impl( nUnitStart, nUnitEnd );
+
+ OUString aOrigTxt( pEditView->GetSelected() );
+ OUString aNewTxt( rReplaceWith );
+ String aNewOrigText;
+ switch (eAction)
+ {
+ case eExchange :
+ break;
+ case eReplacementBracketed :
+ (((aNewTxt = aOrigTxt) += aBracketedStart) += rReplaceWith) += aBracketedEnd;
+ break;
+ case eOriginalBracketed :
+ (((aNewTxt = rReplaceWith) += aBracketedStart) += aOrigTxt) += aBracketedEnd;
+ break;
+ case eReplacementAbove :
+ case eOriginalAbove :
+ case eReplacementBelow :
+ case eOriginalBelow :
+ DBG_ERROR( "Rubies not supported" );
+ break;
+ default:
+ DBG_ERROR( "unexpected case" );
+ }
+ nUnitOffset = sal::static_int_cast< USHORT >(
+ nUnitOffset + nUnitStart + aNewTxt.getLength());
+
+ // remember current original language for kater use
+ ImpEditEngine *pImpEditEng = pEditView->GetImpEditEngine();
+ ESelection _aOldSel = pEditView->GetSelection();
+ //EditSelection aOldEditSel = pEditView->GetImpEditView()->GetEditSelection();
+
+#ifdef DBG_UTIL
+ LanguageType nOldLang = pImpEditEng->GetLanguage( pImpEditEng->CreateSel( _aOldSel ).Min() );
+#endif
+
+ pImpEditEng->UndoActionStart( EDITUNDO_INSERT );
+
+ // according to FT we should currently not bother about keeping
+ // attributes in Hangul/Hanja conversion and leave that untouched.
+ // Thus we do this only for Chinese translation...
+ sal_Bool bIsChineseConversion = IsChinese( GetSourceLanguage() );
+ if (bIsChineseConversion)
+ ChangeText( aNewTxt, rOrigText, &rOffsets, &_aOldSel );
+ else
+ ChangeText( aNewTxt, rOrigText, NULL, NULL );
+
+ // change language and font if necessary
+ if (bIsChineseConversion)
+ {
+ DBG_ASSERT( GetTargetLanguage() == LANGUAGE_CHINESE_SIMPLIFIED || GetTargetLanguage() == LANGUAGE_CHINESE_TRADITIONAL,
+ "TextConvWrapper::ReplaceUnit : unexpected target language" );
+
+ ESelection aOldSel = pEditView->GetSelection();
+ ESelection aNewSel( aOldSel );
+ aNewSel.nStartPos = sal::static_int_cast< xub_StrLen >(
+ aNewSel.nStartPos - aNewTxt.getLength());
+// DBG_ASSERT( aOldSel.nEndPos >= 0, "error while building selection" );
+
+ if (pNewUnitLanguage)
+ {
+ DBG_ASSERT(!IsSimilarChinese( *pNewUnitLanguage, nOldLang ),
+ "similar language should not be changed!");
+ SetLanguageAndFont( aNewSel, *pNewUnitLanguage, EE_CHAR_LANGUAGE_CJK,
+ GetTargetFont(), EE_CHAR_FONTINFO_CJK );
+ }
+ }
+
+ pImpEditEng->UndoActionEnd( EDITUNDO_INSERT );
+
+ // adjust ConvContinue / ConvTo if necessary
+ ImpEditEngine* pImpEE = pEditView->GetImpEditEngine();
+ ConvInfo* pConvInfo = pImpEE->GetConvInfo();
+ sal_Int32 nDelta = aNewTxt.getLength() - aOrigTxt.getLength();
+ if (nDelta != 0)
+ {
+ // Note: replacement is always done in the current paragraph
+ // which is the one ConvContinue points to
+ pConvInfo->aConvContinue.nIndex = sal::static_int_cast< USHORT >(
+ pConvInfo->aConvContinue.nIndex + nDelta);
+
+ // if that is the same as the one where the conversions ends
+ // the end needs to be updated also
+ if (pConvInfo->aConvTo.nPara == pConvInfo->aConvContinue.nPara)
+ pConvInfo->aConvTo.nIndex = sal::static_int_cast< USHORT >(
+ pConvInfo->aConvTo.nIndex + nDelta);
+ }
+}
+
+
+void TextConvWrapper::ChangeText( const String &rNewText,
+ const OUString& rOrigText,
+ const uno::Sequence< sal_Int32 > *pOffsets,
+ ESelection *pESelection )
+{
+ //!! code is a modifed copy of SwHHCWrapper::ChangeText from sw !!
+
+ DBG_ASSERT( rNewText.Len() != 0, "unexpected empty string" );
+ if (rNewText.Len() == 0)
+ return;
+
+ if (pOffsets && pESelection) // try to keep as much attributation as possible ?
+ {
+ pESelection->Adjust();
+
+ // remember cursor start position for later setting of the cursor
+ const xub_StrLen nStartIndex = pESelection->nStartPos;
+
+ const sal_Int32 nIndices = pOffsets->getLength();
+ const sal_Int32 *pIndices = pOffsets->getConstArray();
+ xub_StrLen nConvTextLen = rNewText.Len();
+ xub_StrLen nPos = 0;
+ xub_StrLen nChgPos = STRING_NOTFOUND;
+ xub_StrLen nChgLen = 0;
+ xub_StrLen nConvChgPos = STRING_NOTFOUND;
+ xub_StrLen nConvChgLen = 0;
+
+ // offset to calculate the position in the text taking into
+ // account that text may have been replaced with new text of
+ // different length. Negative values allowed!
+ long nCorrectionOffset = 0;
+
+ DBG_ASSERT(nIndices == 0 || nIndices == nConvTextLen,
+ "mismatch between string length and sequence length!" );
+
+ // find all substrings that need to be replaced (and only those)
+ while (sal_True)
+ {
+ // get index in original text that matches nPos in new text
+ xub_StrLen nIndex;
+ if (nPos < nConvTextLen)
+ nIndex = (sal_Int32) nPos < nIndices ? (xub_StrLen) pIndices[nPos] : nPos;
+ else
+ {
+ nPos = nConvTextLen;
+ nIndex = static_cast< xub_StrLen >( rOrigText.getLength() );
+ }
+
+ if (rOrigText.getStr()[nIndex] == rNewText.GetChar(nPos) ||
+ nPos == nConvTextLen /* end of string also terminates non-matching char sequence */)
+ {
+ // substring that needs to be replaced found?
+ if (nChgPos != STRING_NOTFOUND && nConvChgPos != STRING_NOTFOUND)
+ {
+ nChgLen = nIndex - nChgPos;
+ nConvChgLen = nPos - nConvChgPos;
+#ifdef DEBUG
+ String aInOrig( rOrigText.copy( nChgPos, nChgLen ) );
+#endif
+ String aInNew( rNewText.Copy( nConvChgPos, nConvChgLen ) );
+
+ // set selection to sub string to be replaced in original text
+ ESelection aSel( *pESelection );
+ xub_StrLen nChgInNodeStartIndex = static_cast< xub_StrLen >( nStartIndex + nCorrectionOffset + nChgPos );
+ aSel.nStartPos = nChgInNodeStartIndex;
+ aSel.nEndPos = nChgInNodeStartIndex + nChgLen;
+ pEditView->SetSelection( aSel );
+#ifdef DEBUG
+ String aSelTxt1( pEditView->GetSelected() );
+#endif
+
+ // replace selected sub string with the corresponding
+ // sub string from the new text while keeping as
+ // much from the attributes as possible
+ ChangeText_impl( aInNew, sal_True );
+
+ nCorrectionOffset += nConvChgLen - nChgLen;
+
+ nChgPos = STRING_NOTFOUND;
+ nConvChgPos = STRING_NOTFOUND;
+ }
+ }
+ else
+ {
+ // begin of non-matching char sequence found ?
+ if (nChgPos == STRING_NOTFOUND && nConvChgPos == STRING_NOTFOUND)
+ {
+ nChgPos = nIndex;
+ nConvChgPos = nPos;
+ }
+ }
+ if (nPos >= nConvTextLen)
+ break;
+ ++nPos;
+ }
+
+ // set cursor to the end of the inserted text
+ // (as it would happen after ChangeText_impl (Delete and Insert)
+ // of the whole text in the 'else' branch below)
+ pESelection->nStartPos = pESelection->nEndPos = nStartIndex + nConvTextLen;
+ }
+ else
+ {
+ ChangeText_impl( rNewText, sal_False );
+ }
+}
+
+
+void TextConvWrapper::ChangeText_impl( const String &rNewText, sal_Bool bKeepAttributes )
+{
+ if (bKeepAttributes)
+ {
+ // save attributes to be restored
+ SfxItemSet aSet( pEditView->GetAttribs() );
+
+#ifdef DEBUG
+ String aSelTxt1( pEditView->GetSelected() );
+#endif
+ // replace old text and select new text
+ pEditView->InsertText( rNewText, sal_True );
+#ifdef DEBUG
+ String aSelTxt2( pEditView->GetSelected() );
+#endif
+
+ // since 'SetAttribs' below function like merging with the attributes
+ // from the itemset with any existing ones we have to get rid of all
+ // all attributes now. (Those attributes that may take effect left
+ // to the position where the new text gets inserted after the old text
+ // was deleted)
+ pEditView->RemoveAttribs();
+ // apply saved attributes to new inserted text
+ pEditView->SetAttribs( aSet );
+ }
+ else
+ {
+ pEditView->InsertText( rNewText );
+ }
+}
+
+
+void TextConvWrapper::Convert()
+{
+ bStartChk = sal_False;
+ ConvStart_impl( SVX_SPELL_BODY_END );
+ ConvertDocument();
+ ConvEnd_impl();
+}
+
+
+sal_Bool TextConvWrapper::HasRubySupport() const
+{
+ return sal_False;
+}
+
+//////////////////////////////////////////////////////////////////////
+