Files
libreoffice/editeng/source/misc/splwrap.cxx

618 lines
18 KiB
C++
Raw Normal View History

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2000-09-18 16:07:07 +00:00
/*************************************************************************
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
2000-09-18 16:07:07 +00:00
*
* Copyright 2000, 2010 Oracle and/or its affiliates.
2000-09-18 16:07:07 +00:00
*
* OpenOffice.org - a multi-platform office productivity suite
2000-09-18 16:07:07 +00:00
*
* This file is part of OpenOffice.org.
2000-09-18 16:07:07 +00:00
*
* 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.
2000-09-18 16:07:07 +00:00
*
* 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).
2000-09-18 16:07:07 +00:00
*
* 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.
2000-09-18 16:07:07 +00:00
*
************************************************************************/
#include<rtl/ustring.hxx>
#include <tools/shl.hxx>
#include <vcl/wrkwin.hxx>
#include <vcl/svapp.hxx>
#include <vcl/msgbox.hxx>
#include <svtools/langtab.hxx>
2000-09-18 16:07:07 +00:00
#ifndef __RSC
#include <tools/errinf.hxx>
#endif
#include <editeng/unolingu.hxx>
2000-11-19 10:41:10 +00:00
#include <linguistic/lngprops.hxx>
2000-09-18 16:07:07 +00:00
#include <com/sun/star/frame/XStorable.hpp>
#include <map>
2000-09-18 16:07:07 +00:00
#include <editeng/svxenum.hxx>
#include <editeng/splwrap.hxx>
#include <editeng/edtdlg.hxx>
#include <editeng/eerdll.hxx>
#include <editeng/editrids.hrc>
#include <editeng/editids.hrc>
#include <editeng/editerr.hxx>
#define WAIT_ON() if(pWin != NULL) { pWin->EnterWait(); }
#define WAIT_OFF() if(pWin != NULL) { pWin->LeaveWait(); }
2000-09-18 16:07:07 +00:00
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::beans;
2000-10-27 09:25:31 +00:00
using namespace ::com::sun::star::linguistic2;
// misc functions ---------------------------------------------
void SvxPrepareAutoCorrect( String &rOldText, String &rNewText )
{
// This function should be used to strip (or add) trailing '.' from
// the strings before passing them on to the autocorrect function in
// order that the autocorrect function will hopefully
// works properly with normal words and abbreviations (with trailing '.')
// independ of if they are at the end of the sentence or not.
//
// rOldText: text to be replaced
// rNewText: replacement text
xub_StrLen nOldLen = rOldText.Len(),
nNewLen = rNewText.Len();
if (nOldLen && nNewLen)
{
sal_Bool bOldHasDot = sal_Unicode( '.' ) == rOldText.GetChar( nOldLen - 1 ),
bNewHasDot = sal_Unicode( '.' ) == rNewText.GetChar( nNewLen - 1 );
if (bOldHasDot && !bNewHasDot
/*this is: !(bOldHasDot && bNewHasDot) && bOldHasDot*/)
rOldText.Erase( nOldLen - 1 );
}
}
#define SVX_LANG_NEED_CHECK 0
#define SVX_LANG_OK 1
#define SVX_LANG_MISSING 2
#define SVX_LANG_MISSING_DO_WARN 3
struct lt_LanguageType
{
bool operator()( LanguageType n1, LanguageType n2 ) const
{
return n1 < n2;
}
};
typedef std::map< LanguageType, sal_uInt16, lt_LanguageType > LangCheckState_map_t;
static LangCheckState_map_t & GetLangCheckState()
{
static LangCheckState_map_t aLangCheckState;
return aLangCheckState;
}
void SvxSpellWrapper::ShowLanguageErrors()
{
// display message boxes for languages not available for
// spellchecking or hyphenation
LangCheckState_map_t &rLCS = GetLangCheckState();
LangCheckState_map_t::iterator aIt( rLCS.begin() );
while (aIt != rLCS.end())
{
LanguageType nLang = aIt->first;
sal_uInt16 nVal = aIt->second;
sal_uInt16 nTmpSpell = nVal & 0x00FF;
sal_uInt16 nTmpHyph = (nVal >> 8) & 0x00FF;
if (SVX_LANG_MISSING_DO_WARN == nTmpSpell)
{
String aErr( SvtLanguageTable::GetLanguageString( nLang ) );
ErrorHandler::HandleError(
*new StringErrorInfo( ERRCODE_SVX_LINGU_LANGUAGENOTEXISTS, aErr ) );
nTmpSpell = SVX_LANG_MISSING;
}
if (SVX_LANG_MISSING_DO_WARN == nTmpHyph)
{
String aErr( SvtLanguageTable::GetLanguageString( nLang ) );
ErrorHandler::HandleError(
*new StringErrorInfo( ERRCODE_SVX_LINGU_LANGUAGENOTEXISTS, aErr ) );
nTmpHyph = SVX_LANG_MISSING;
}
rLCS[ nLang ] = (nTmpHyph << 8) | nTmpSpell;
++aIt;
}
}
SvxSpellWrapper::~SvxSpellWrapper()
{
}
2000-09-18 16:07:07 +00:00
/*--------------------------------------------------------------------
2011-02-16 16:34:02 -05:00
* Description: Constructor, the test sequence is determined
2000-09-18 16:07:07 +00:00
*
* !bStart && !bOtherCntnt: BODY_END, BODY_START, OTHER
* !bStart && bOtherCntnt: OTHER, BODY
* bStart && !bOtherCntnt: BODY_END, OTHER
* bStart && bOtherCntnt: OTHER
*
--------------------------------------------------------------------*/
SvxSpellWrapper::SvxSpellWrapper( Window* pWn,
Reference< XSpellChecker1 > &xSpellChecker,
const sal_Bool bStart, const sal_Bool bIsAllRight,
const sal_Bool bOther, const sal_Bool bRevAllow ) :
pWin ( pWn ),
xSpell ( xSpellChecker ),
bOtherCntnt ( bOther ),
bDialog ( sal_False ),
bHyphen ( sal_False ),
bAuto ( sal_False ),
bStartChk ( bOther ),
bRevAllowed ( bRevAllow ),
bAllRight ( bIsAllRight )
2000-09-18 16:07:07 +00:00
{
Reference< beans::XPropertySet > xProp( SvxGetLinguPropertySet() );
sal_Bool bWrapReverse = xProp.is() ?
*(sal_Bool*)xProp->getPropertyValue(
::rtl::OUString(UPN_IS_WRAP_REVERSE) ).getValue()
2000-09-18 16:07:07 +00:00
: sal_False;
bReverse = bRevAllow && bWrapReverse;
bStartDone = bOther || ( !bReverse && bStart );
bEndDone = bReverse && bStart && !bOther;
}
// -----------------------------------------------------------------------
SvxSpellWrapper::SvxSpellWrapper( Window* pWn,
Reference< XHyphenator > &xHyphenator,
const sal_Bool bStart, const sal_Bool bOther ) :
pWin ( pWn ),
xHyph ( xHyphenator ),
bOtherCntnt ( bOther ),
bDialog ( sal_False ),
bHyphen ( sal_False ),
bAuto ( sal_False ),
bReverse ( sal_False ),
2000-09-18 16:07:07 +00:00
bStartDone ( bOther || ( !bReverse && bStart ) ),
bEndDone ( bReverse && bStart && !bOther ),
bStartChk ( bOther ),
bRevAllowed ( sal_False ),
bAllRight ( sal_True )
2000-09-18 16:07:07 +00:00
{
}
// -----------------------------------------------------------------------
sal_Int16 SvxSpellWrapper::CheckSpellLang(
Reference< XSpellChecker1 > xSpell, sal_Int16 nLang)
{
LangCheckState_map_t &rLCS = GetLangCheckState();
2000-09-18 16:07:07 +00:00
LangCheckState_map_t::iterator aIt( rLCS.find( nLang ) );
sal_uInt16 nVal = aIt == rLCS.end() ? SVX_LANG_NEED_CHECK : aIt->second;
2000-09-18 16:07:07 +00:00
if (aIt == rLCS.end())
rLCS[ nLang ] = nVal;
2000-09-18 16:07:07 +00:00
if (SVX_LANG_NEED_CHECK == (nVal & 0x00FF))
{
sal_uInt16 nTmpVal = SVX_LANG_MISSING_DO_WARN;
if (xSpell.is() && xSpell->hasLanguage( nLang ))
nTmpVal = SVX_LANG_OK;
nVal &= 0xFF00;
nVal |= nTmpVal;
rLCS[ nLang ] = nVal;
2000-09-18 16:07:07 +00:00
}
return (sal_Int16) nVal;
2000-09-18 16:07:07 +00:00
}
sal_Int16 SvxSpellWrapper::CheckHyphLang(
Reference< XHyphenator > xHyph, sal_Int16 nLang)
{
LangCheckState_map_t &rLCS = GetLangCheckState();
2000-09-18 16:07:07 +00:00
LangCheckState_map_t::iterator aIt( rLCS.find( nLang ) );
sal_uInt16 nVal = aIt == rLCS.end() ? 0 : aIt->second;
2000-09-18 16:07:07 +00:00
if (aIt == rLCS.end())
rLCS[ nLang ] = nVal;
2000-09-18 16:07:07 +00:00
if (SVX_LANG_NEED_CHECK == ((nVal >> 8) & 0x00FF))
{
sal_uInt16 nTmpVal = SVX_LANG_MISSING_DO_WARN;
if (xHyph.is() && xHyph->hasLocale( SvxCreateLocale( nLang ) ))
nTmpVal = SVX_LANG_OK;
nVal &= 0x00FF;
nVal |= nTmpVal << 8;
rLCS[ nLang ] = nVal;
2000-09-18 16:07:07 +00:00
}
return (sal_Int16) nVal;
2000-09-18 16:07:07 +00:00
}
// -----------------------------------------------------------------------
void SvxSpellWrapper::SpellStart( SvxSpellArea /*eSpell*/ )
2011-02-16 16:34:02 -05:00
{ // Here, the necessary preparations be made for SpellContinue in the
} // given area.
2000-09-18 16:07:07 +00:00
// -----------------------------------------------------------------------
sal_Bool SvxSpellWrapper::HasOtherCnt()
{
2011-02-16 16:34:02 -05:00
return sal_False; // Is there a special area?
2000-09-18 16:07:07 +00:00
}
// -----------------------------------------------------------------------
sal_Bool SvxSpellWrapper::SpellMore()
{
2011-02-16 16:34:02 -05:00
return sal_False; // Should additional documents be examined?
2000-09-18 16:07:07 +00:00
}
// -----------------------------------------------------------------------
void SvxSpellWrapper::SpellEnd()
2011-02-16 16:34:02 -05:00
{ // Area is complete, tidy up if necessary
// display error for last language not found
ShowLanguageErrors();
2000-09-18 16:07:07 +00:00
}
// -----------------------------------------------------------------------
sal_Bool SvxSpellWrapper::SpellContinue()
{
return sal_False;
}
// -----------------------------------------------------------------------
void SvxSpellWrapper::AutoCorrect( const String&, const String& )
2000-09-18 16:07:07 +00:00
{
}
// -----------------------------------------------------------------------
void SvxSpellWrapper::ScrollArea()
2011-02-16 16:34:02 -05:00
{ // Set Scroll area
2000-09-18 16:07:07 +00:00
}
// -----------------------------------------------------------------------
void SvxSpellWrapper::ChangeWord( const String&, const sal_uInt16 )
2011-02-16 16:34:02 -05:00
{ // Insert Word
2000-09-18 16:07:07 +00:00
}
// -----------------------------------------------------------------------
String SvxSpellWrapper::GetThesWord()
{
2011-02-16 16:34:02 -05:00
// What word should be looked up?
2000-09-18 16:07:07 +00:00
return String();
}
// -----------------------------------------------------------------------
void SvxSpellWrapper::ChangeThesWord( const String& )
{
2011-02-16 16:34:02 -05:00
// replace word due to Thesaurus.
2000-09-18 16:07:07 +00:00
}
// -----------------------------------------------------------------------
void SvxSpellWrapper::StartThesaurus( const String &rWord, sal_uInt16 nLanguage )
{
Reference< XThesaurus > xThes( SvxGetThesaurus() );
if (!xThes.is())
{
InfoBox( pWin, EE_RESSTR( RID_SVXSTR_HMERR_THESAURUS ) ).Execute();
2000-09-18 16:07:07 +00:00
return;
}
WAIT_ON(); // while looking up for initial word
EditAbstractDialogFactory* pFact = EditAbstractDialogFactory::Create();
AbstractThesaurusDialog* pDlg = pFact->CreateThesaurusDialog( pWin, xThes, rWord, nLanguage );
2000-09-18 16:07:07 +00:00
WAIT_OFF();
if ( pDlg->Execute()== RET_OK )
2000-09-18 16:07:07 +00:00
{
ChangeThesWord( pDlg->GetWord() );
2000-09-18 16:07:07 +00:00
}
delete pDlg;
2000-09-18 16:07:07 +00:00
}
// -----------------------------------------------------------------------
void SvxSpellWrapper::ReplaceAll( const String &, sal_Int16 )
2011-02-16 16:34:02 -05:00
{ // Replace Word from the the Replace list
2000-09-18 16:07:07 +00:00
}
// -----------------------------------------------------------------------
void SvxSpellWrapper::SetLanguage( const sal_uInt16 )
2011-02-16 16:34:02 -05:00
{ // Set Language
2000-09-18 16:07:07 +00:00
}
// -----------------------------------------------------------------------
void SvxSpellWrapper::InsertHyphen( const sal_uInt16 )
2011-02-16 16:34:02 -05:00
{ // inserting and deleting Hyphae
2000-09-18 16:07:07 +00:00
}
// -----------------------------------------------------------------------
2011-02-16 16:34:02 -05:00
// Testing of the document areas in the order specified by the flags
2000-09-18 16:07:07 +00:00
void SvxSpellWrapper::SpellDocument( )
{
if ( bOtherCntnt )
{
bReverse = sal_False;
SpellStart( SVX_SPELL_OTHER );
}
else
{
bStartChk = bReverse;
SpellStart( bReverse ? SVX_SPELL_BODY_START : SVX_SPELL_BODY_END );
}
if ( FindSpellError() )
{
Reference< XSpellAlternatives > xAlt( GetLast(), UNO_QUERY );
Reference< XHyphenatedWord > xHyphWord( GetLast(), UNO_QUERY );
Window *pOld = pWin;
bDialog = sal_True;
if (xHyphWord.is())
{
EditAbstractDialogFactory* pFact = EditAbstractDialogFactory::Create();
AbstractHyphenWordDialog* pDlg = pFact->CreateHyphenWordDialog( pWin,
xHyphWord->getWord(),
2000-09-18 16:07:07 +00:00
SvxLocaleToLanguage( xHyphWord->getLocale() ),
xHyph, this );
pWin = pDlg->GetWindow();
2000-09-18 16:07:07 +00:00
pDlg->Execute();
delete pDlg;
}
bDialog = sal_False;
pWin = pOld;
};
}
// -----------------------------------------------------------------------
2011-02-16 16:34:02 -05:00
// Select the next area
2000-09-18 16:07:07 +00:00
sal_Bool SvxSpellWrapper::SpellNext( )
{
Reference< beans::XPropertySet > xProp( SvxGetLinguPropertySet() );
sal_Bool bWrapReverse = xProp.is() ?
*(sal_Bool*)xProp->getPropertyValue(
::rtl::OUString(UPN_IS_WRAP_REVERSE) ).getValue()
2000-09-18 16:07:07 +00:00
: sal_False;
sal_Bool bActRev = bRevAllowed && bWrapReverse;
2011-02-16 16:34:02 -05:00
// bActRev is the direction after Spell checking, bReverse is the one
// at the beginning.
2000-09-18 16:07:07 +00:00
if( bActRev == bReverse )
2011-02-16 16:34:02 -05:00
{ // No change of direction, thus is the
if( bStartChk ) // desired area ( bStartChk )
bStartDone = sal_True; // completely processed.
2000-09-18 16:07:07 +00:00
else
bEndDone = sal_True;
}
2011-02-16 16:34:02 -05:00
else if( bReverse == bStartChk ) //For a change of direction, an area can
{ // be processed during certain circumstances
if( bStartChk ) // If the firdt part is spell checked in backwards
bEndDone = sal_True; // and this is reversed in the process, then
else // then the end part is processed (and vice-versa).
2000-09-18 16:07:07 +00:00
bStartDone = sal_True;
}
bReverse = bActRev;
2011-02-16 16:34:02 -05:00
if( bOtherCntnt && bStartDone && bEndDone ) // Document has been fully checked?
2000-09-18 16:07:07 +00:00
{
2011-02-16 16:34:02 -05:00
if ( SpellMore() ) // spell check another document?
2000-09-18 16:07:07 +00:00
{
bOtherCntnt = sal_False;
bStartDone = !bReverse;
bEndDone = bReverse;
SpellStart( SVX_SPELL_BODY );
return sal_True;
}
return sal_False;
}
sal_Bool bGoOn = sal_False;
if ( bOtherCntnt )
{
bStartChk = sal_False;
SpellStart( SVX_SPELL_BODY );
bGoOn = sal_True;
}
else if ( bStartDone && bEndDone )
{
sal_Bool bIsSpellSpecial = xProp.is() ?
*(sal_Bool*)xProp->getPropertyValue(
::rtl::OUString(UPN_IS_SPELL_SPECIAL) ).getValue()
2000-09-18 16:07:07 +00:00
: sal_False;
2011-02-16 16:34:02 -05:00
// Body area done, ask for special area
2000-09-18 16:07:07 +00:00
if( !IsHyphen() && bIsSpellSpecial && HasOtherCnt() )
{
SpellStart( SVX_SPELL_OTHER );
bOtherCntnt = bGoOn = sal_True;
}
2011-02-16 16:34:02 -05:00
else if ( SpellMore() ) // check another document?
2000-09-18 16:07:07 +00:00
{
bOtherCntnt = sal_False;
bStartDone = !bReverse;
bEndDone = bReverse;
SpellStart( SVX_SPELL_BODY );
return sal_True;
}
}
else
{
2011-02-16 16:34:02 -05:00
// a BODY_area done, ask for the other BODY_area
2000-09-18 16:07:07 +00:00
WAIT_OFF();
sal_uInt16 nResId = bReverse ? RID_SVXQB_BW_CONTINUE : RID_SVXQB_CONTINUE;
QueryBox aBox( pWin, EditResId( nResId ) );
2000-09-18 16:07:07 +00:00
if ( aBox.Execute() != RET_YES )
{
2011-02-16 16:34:02 -05:00
// sacrifice the other area if necessary ask for special area
2000-09-18 16:07:07 +00:00
WAIT_ON();
bStartDone = bEndDone = sal_True;
return SpellNext();
}
else
{
bStartChk = !bStartDone;
SpellStart( bStartChk ? SVX_SPELL_BODY_START : SVX_SPELL_BODY_END );
bGoOn = sal_True;
}
WAIT_ON();
}
return bGoOn;
}
// -----------------------------------------------------------------------
2008-12-15 12:01:46 +00:00
Reference< XDictionary > SvxSpellWrapper::GetAllRightDic() const
2000-09-18 16:07:07 +00:00
{
2008-12-15 12:01:46 +00:00
Reference< XDictionary > xDic;
2000-09-18 16:07:07 +00:00
Reference< XDictionaryList > xDicList( SvxGetDictionaryList() );
if (xDicList.is())
{
Sequence< Reference< XDictionary > > aDics( xDicList->getDictionaries() );
const Reference< XDictionary > *pDic = aDics.getConstArray();
sal_Int32 nCount = aDics.getLength();
sal_Int32 i = 0;
while (!xDic.is() && i < nCount)
{
2008-12-15 12:01:46 +00:00
Reference< XDictionary > xTmp( pDic[i], UNO_QUERY );
2000-09-18 16:07:07 +00:00
if (xTmp.is())
{
if ( xTmp->isActive() &&
xTmp->getDictionaryType() != DictionaryType_NEGATIVE &&
2008-12-15 12:01:46 +00:00
SvxLocaleToLanguage( xTmp->getLocale() ) == LANGUAGE_NONE )
2000-09-18 16:07:07 +00:00
{
Reference< frame::XStorable > xStor( xTmp, UNO_QUERY );
if (xStor.is() && xStor->hasLocation() && !xStor->isReadonly())
{
xDic = xTmp;
}
}
}
++i;
}
if (!xDic.is())
{
xDic = SvxGetOrCreatePosDic( xDicList );
if (xDic.is())
xDic->setActive( sal_True );
}
}
return xDic;
}
// -----------------------------------------------------------------------
sal_Bool SvxSpellWrapper::FindSpellError()
{
ShowLanguageErrors();
2000-09-18 16:07:07 +00:00
Reference< XInterface > xRef;
WAIT_ON();
sal_Bool bSpell = sal_True;
2008-12-15 12:01:46 +00:00
Reference< XDictionary > xAllRightDic;
2000-09-18 16:07:07 +00:00
if (IsAllRight())
xAllRightDic = GetAllRightDic();
while ( bSpell )
{
SpellContinue();
Reference< XSpellAlternatives > xAlt( GetLast(), UNO_QUERY );
Reference< XHyphenatedWord > xHyphWord( GetLast(), UNO_QUERY );
if (xAlt.is())
{
if (IsAllRight() && xAllRightDic.is())
{
2000-10-27 09:25:31 +00:00
xAllRightDic->add( xAlt->getWord(), sal_False, ::rtl::OUString() );
2000-09-18 16:07:07 +00:00
}
else
{
// look up in ChangeAllList for misspelled word
2008-12-15 12:01:46 +00:00
Reference< XDictionary > xChangeAllList(
2000-09-18 16:07:07 +00:00
SvxGetChangeAllList(), UNO_QUERY );
Reference< XDictionaryEntry > xEntry;
if (xChangeAllList.is())
xEntry = xChangeAllList->getEntry( xAlt->getWord() );
if (xEntry.is())
{
// replace word without asking
2000-10-27 09:25:31 +00:00
ReplaceAll( xEntry->getReplacementText(),
SvxLocaleToLanguage( xAlt->getLocale() ) );
2000-09-18 16:07:07 +00:00
}
else
bSpell = sal_False;
}
}
else if (xHyphWord.is())
bSpell = sal_False;
else
{
SpellEnd();
bSpell = SpellNext();
}
}
WAIT_OFF();
return GetLast().is();
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */