731 lines
23 KiB
C++
731 lines
23 KiB
C++
/*************************************************************************
|
|
*
|
|
* OpenOffice.org - a multi-platform office productivity suite
|
|
*
|
|
* $RCSfile: edtspell.cxx,v $
|
|
*
|
|
* $Revision: 1.10 $
|
|
*
|
|
* last change: $Author: hr $ $Date: 2006-06-19 15:40:18 $
|
|
*
|
|
* The Contents of this file are made available subject to
|
|
* the terms of GNU Lesser General Public License Version 2.1.
|
|
*
|
|
*
|
|
* GNU Lesser General Public License Version 2.1
|
|
* =============================================
|
|
* Copyright 2005 by Sun Microsystems, Inc.
|
|
* 901 San Antonio Road, Palo Alto, CA 94303, USA
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License version 2.1, as published by the Free Software Foundation.
|
|
*
|
|
* This library 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 for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
|
* MA 02111-1307 USA
|
|
*
|
|
************************************************************************/
|
|
|
|
#include <eeng_pch.hxx>
|
|
|
|
#include <impedit.hxx>
|
|
#include <editview.hxx>
|
|
#include <editeng.hxx>
|
|
#include <edtspell.hxx>
|
|
#include <flditem.hxx>
|
|
#include <fontitem.hxx>
|
|
#include <svtools/intitem.hxx>
|
|
|
|
#ifndef _UNO_LINGU_HXX
|
|
#include <unolingu.hxx>
|
|
#endif
|
|
#ifndef _LINGUISTIC_LNGPROPS_HHX_
|
|
#include <linguistic/lngprops.hxx>
|
|
#endif
|
|
#ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_
|
|
#include <com/sun/star/beans/XPropertySet.hpp>
|
|
#endif
|
|
|
|
using namespace rtl;
|
|
using namespace com::sun::star::uno;
|
|
using namespace com::sun::star::beans;
|
|
using namespace com::sun::star::linguistic2;
|
|
|
|
|
|
EditSpellWrapper::EditSpellWrapper( Window* pWin,
|
|
Reference< XSpellChecker1 > &xChecker,
|
|
sal_Bool bIsStart, sal_Bool bIsAllRight, EditView* pView ) :
|
|
SvxSpellWrapper( pWin, xChecker, bIsStart, bIsAllRight )
|
|
{
|
|
DBG_ASSERT( pView, "Es muss eine View uebergeben werden!" );
|
|
// IgnoreList behalten, ReplaceList loeschen...
|
|
if (SvxGetChangeAllList().is())
|
|
SvxGetChangeAllList()->clear();
|
|
pEditView = pView;
|
|
}
|
|
|
|
void __EXPORT EditSpellWrapper::SpellStart( SvxSpellArea eArea )
|
|
{
|
|
ImpEditEngine* pImpEE = pEditView->GetImpEditEngine();
|
|
SpellInfo* pSpellInfo = pImpEE->GetSpellInfo();
|
|
sal_Bool bForward = sal_True;
|
|
|
|
if ( eArea == SVX_SPELL_BODY_START )
|
|
{
|
|
// Wird gerufen, wenn
|
|
// a) Spell-Forwad ist am Ende angekomment und soll von vorne beginnen
|
|
// IsEndDone() liefert auch sal_True, wenn Rueckwaerts-Spelling am Ende gestartet wird!
|
|
if ( IsEndDone() )
|
|
{
|
|
pSpellInfo->bSpellToEnd = sal_False;
|
|
pSpellInfo->aSpellTo = pSpellInfo->aSpellStart;
|
|
pEditView->GetImpEditView()->SetEditSelection(
|
|
pImpEE->GetEditDoc().GetStartPaM() );
|
|
}
|
|
else
|
|
{
|
|
pSpellInfo->bSpellToEnd = sal_True;
|
|
pSpellInfo->aSpellTo = pImpEE->CreateEPaM(
|
|
pImpEE->GetEditDoc().GetStartPaM() );
|
|
}
|
|
}
|
|
else if ( eArea == SVX_SPELL_BODY_END )
|
|
{
|
|
// Wird gerufen, wenn
|
|
// a) Spell-Forwad wird gestartet
|
|
// IsStartDone() liefert auch sal_True, wenn Vorwaerts-Spelling am Anfang gestartet wird!
|
|
if ( !IsStartDone() )
|
|
{
|
|
pSpellInfo->bSpellToEnd = sal_True;
|
|
pSpellInfo->aSpellTo = pImpEE->CreateEPaM(
|
|
pImpEE->GetEditDoc().GetEndPaM() );
|
|
}
|
|
else
|
|
{
|
|
pSpellInfo->bSpellToEnd = sal_False;
|
|
pSpellInfo->aSpellTo = pSpellInfo->aSpellStart;
|
|
pEditView->GetImpEditView()->SetEditSelection(
|
|
pImpEE->GetEditDoc().GetEndPaM() );
|
|
}
|
|
}
|
|
else if ( eArea == SVX_SPELL_BODY )
|
|
{
|
|
; // Wird ueber SpellNextDocument von App gehandelt
|
|
|
|
// pSpellInfo->bSpellToEnd = sal_True;
|
|
// pSpellInfo->aSpellTo = pImpEE->CreateEPaM( pImpEE->GetEditDoc().GetEndPaM() );
|
|
}
|
|
else
|
|
{
|
|
DBG_ERROR( "SpellStart: Unknown Area!" );
|
|
}
|
|
}
|
|
|
|
sal_Bool EditSpellWrapper::SpellContinue()
|
|
{
|
|
SetLast( pEditView->GetImpEditEngine()->ImpSpell( pEditView ) );
|
|
return GetLast().is();
|
|
}
|
|
|
|
void __EXPORT EditSpellWrapper::SpellEnd()
|
|
{
|
|
// Base class will show language errors...
|
|
SvxSpellWrapper::SpellEnd();
|
|
}
|
|
|
|
sal_Bool __EXPORT EditSpellWrapper::HasOtherCnt()
|
|
{
|
|
return sal_False;
|
|
}
|
|
|
|
sal_Bool __EXPORT EditSpellWrapper::SpellMore()
|
|
{
|
|
ImpEditEngine* pImpEE = pEditView->GetImpEditEngine();
|
|
SpellInfo* pSpellInfo = pImpEE->GetSpellInfo();
|
|
sal_Bool bMore = sal_False;
|
|
if ( pSpellInfo->bMultipleDoc )
|
|
{
|
|
bMore = pImpEE->GetEditEnginePtr()->SpellNextDocument();
|
|
if ( bMore )
|
|
{
|
|
// Der Text wurde in diese Engine getreten, bei Rueckwaerts
|
|
// muss die Selektion hinten sein.
|
|
Reference< XPropertySet > xProp( SvxGetLinguPropertySet() );
|
|
pEditView->GetImpEditView()->SetEditSelection(
|
|
pImpEE->GetEditDoc().GetStartPaM() );
|
|
}
|
|
}
|
|
return bMore;
|
|
}
|
|
|
|
void __EXPORT EditSpellWrapper::ScrollArea()
|
|
{
|
|
// Keine weitere Aktion noetig...
|
|
// Es sei denn, der Bereich soll in die Mitte gescrollt werden,
|
|
// und nicht irgendwo stehen.
|
|
}
|
|
|
|
void __EXPORT EditSpellWrapper::ReplaceAll( const String &rNewText,
|
|
sal_Int16 nLanguage )
|
|
{
|
|
// Wird gerufen, wenn Wort in ReplaceList des SpellCheckers
|
|
pEditView->InsertText( rNewText );
|
|
CheckSpellTo();
|
|
}
|
|
|
|
void __EXPORT EditSpellWrapper::ChangeWord( const String& rNewWord,
|
|
const sal_uInt16 nLang )
|
|
{
|
|
// Wird gerufen, wenn Wort Button Change
|
|
// bzw. intern von mir bei ChangeAll
|
|
|
|
// Wenn Punkt hinterm Wort, wird dieser nicht mitgegeben.
|
|
// Falls '"' => PreStripped.
|
|
String aNewWord( rNewWord );
|
|
pEditView->InsertText( aNewWord );
|
|
CheckSpellTo();
|
|
}
|
|
|
|
void __EXPORT EditSpellWrapper::ChangeThesWord( const String& rNewWord )
|
|
{
|
|
pEditView->InsertText( rNewWord );
|
|
CheckSpellTo();
|
|
}
|
|
|
|
void __EXPORT EditSpellWrapper::AutoCorrect( const String& rOldWord,
|
|
const String& rNewWord )
|
|
{
|
|
}
|
|
|
|
void EditSpellWrapper::CheckSpellTo()
|
|
{
|
|
ImpEditEngine* pImpEE = pEditView->GetImpEditEngine();
|
|
SpellInfo* pSpellInfo = pImpEE->GetSpellInfo();
|
|
EditPaM aPaM( pEditView->GetImpEditView()->GetEditSelection().Max() );
|
|
EPaM aEPaM = pImpEE->CreateEPaM( aPaM );
|
|
if ( aEPaM.nPara == pSpellInfo->aSpellTo.nPara )
|
|
{
|
|
// prueffen, ob SpellToEnd noch gueltiger Index, falls in dem Absatz
|
|
// ersetzt wurde.
|
|
if ( pSpellInfo->aSpellTo.nIndex > aPaM.GetNode()->Len() )
|
|
pSpellInfo->aSpellTo.nIndex = aPaM.GetNode()->Len();
|
|
}
|
|
}
|
|
SV_IMPL_VARARR( WrongRanges, WrongRange );
|
|
|
|
WrongList::WrongList()
|
|
{
|
|
nInvalidStart = 0;
|
|
nInvalidEnd = 0xFFFF;
|
|
}
|
|
|
|
WrongList::~WrongList()
|
|
{
|
|
}
|
|
|
|
void WrongList::TextInserted( sal_uInt16 nPos, sal_uInt16 nNew, sal_Bool bPosIsSep )
|
|
{
|
|
if ( !IsInvalid() )
|
|
{
|
|
nInvalidStart = nPos;
|
|
nInvalidEnd = nPos+nNew;
|
|
}
|
|
else
|
|
{
|
|
if ( nInvalidStart > nPos )
|
|
nInvalidStart = nPos;
|
|
if ( nInvalidEnd >= nPos )
|
|
nInvalidEnd += nNew;
|
|
else
|
|
nInvalidEnd = nPos+nNew;
|
|
}
|
|
|
|
for ( sal_uInt16 n = 0; n < Count(); n++ )
|
|
{
|
|
WrongRange& rWrong = GetObject( n );
|
|
sal_Bool bRefIsValid = sal_True;
|
|
if ( rWrong.nEnd >= nPos )
|
|
{
|
|
// Alle Wrongs hinter der Einfuegeposition verschieben...
|
|
if ( rWrong.nStart > nPos )
|
|
{
|
|
rWrong.nStart += nNew;
|
|
rWrong.nEnd += nNew;
|
|
}
|
|
// 1: Startet davor, geht bis nPos...
|
|
else if ( rWrong.nEnd == nPos )
|
|
{
|
|
// Sollte bei einem Blank unterbunden werden!
|
|
if ( !bPosIsSep )
|
|
rWrong.nEnd += nNew;
|
|
}
|
|
// 2: Startet davor, geht hinter Pos...
|
|
else if ( ( rWrong.nStart < nPos ) && ( rWrong.nEnd > nPos ) )
|
|
{
|
|
rWrong.nEnd += nNew;
|
|
// Bei einem Trenner das Wrong entfernen und neu pruefen
|
|
if ( bPosIsSep )
|
|
{
|
|
// Wrong aufteilen...
|
|
WrongRange aNewWrong( rWrong.nStart, nPos );
|
|
rWrong.nStart = nPos+1;
|
|
Insert( aNewWrong, n );
|
|
bRefIsValid = sal_False; // Referenz nach Insert nicht mehr gueltig, der andere wurde davor an dessen Position eingefuegt
|
|
n++; // Diesen nicht nochmal...
|
|
}
|
|
}
|
|
// 3: Attribut startet auf Pos...
|
|
else if ( rWrong.nStart == nPos )
|
|
{
|
|
rWrong.nEnd += nNew;
|
|
if ( bPosIsSep )
|
|
rWrong.nStart++;
|
|
}
|
|
}
|
|
DBG_ASSERT( !bRefIsValid || ( rWrong.nStart < rWrong.nEnd ),
|
|
"TextInserted, WrongRange: Start >= End?!" );
|
|
}
|
|
|
|
DBG_ASSERT( !DbgIsBuggy(), "InsertWrong: WrongList kaputt!" );
|
|
}
|
|
|
|
void WrongList::TextDeleted( sal_uInt16 nPos, sal_uInt16 nDeleted )
|
|
{
|
|
sal_uInt16 nEndChanges = nPos+nDeleted;
|
|
if ( !IsInvalid() )
|
|
{
|
|
nInvalidStart = nPos;
|
|
nInvalidEnd = nPos+1; // Nicht nDeleted, weil da ja wegfaellt.
|
|
}
|
|
else
|
|
{
|
|
if ( nInvalidStart > nPos )
|
|
nInvalidStart = nPos;
|
|
if ( nInvalidEnd > nPos )
|
|
{
|
|
if ( nInvalidEnd > nEndChanges )
|
|
nInvalidEnd -=nDeleted;
|
|
else
|
|
nInvalidEnd = nPos+1;
|
|
}
|
|
}
|
|
|
|
for ( sal_uInt16 n = 0; n < Count(); n++ )
|
|
{
|
|
WrongRange& rWrong = GetObject( n );
|
|
sal_Bool bDelWrong = sal_False;
|
|
if ( rWrong.nEnd >= nPos )
|
|
{
|
|
// Alles Wrongs hinter der Einfuegeposition verschieben...
|
|
if ( rWrong.nStart >= nEndChanges )
|
|
{
|
|
rWrong.nStart -= nDeleted;
|
|
rWrong.nEnd -= nDeleted;
|
|
}
|
|
// 1. Innenliegende Wrongs loeschen...
|
|
else if ( ( rWrong.nStart >= nPos ) && ( rWrong.nEnd <= nEndChanges ) )
|
|
{
|
|
bDelWrong = sal_True;
|
|
}
|
|
// 2. Wrong beginnt davor, endet drinnen oder dahinter...
|
|
else if ( ( rWrong.nStart <= nPos ) && ( rWrong.nEnd > nPos ) )
|
|
{
|
|
if ( rWrong.nEnd <= nEndChanges ) // endet drinnen
|
|
rWrong.nEnd = nPos;
|
|
else
|
|
rWrong.nEnd -= nDeleted; // endet dahinter
|
|
}
|
|
// 3. Wrong beginnt drinnen, endet dahinter...
|
|
else if ( ( rWrong.nStart >= nPos ) && ( rWrong.nEnd > nEndChanges ) )
|
|
{
|
|
rWrong.nStart = nEndChanges;
|
|
rWrong.nStart -= nDeleted;
|
|
rWrong.nEnd -= nDeleted;
|
|
}
|
|
}
|
|
DBG_ASSERT( rWrong.nStart < rWrong.nEnd,
|
|
"TextInserted, WrongRange: Start >= End?!" );
|
|
if ( bDelWrong )
|
|
{
|
|
Remove( n, 1 );
|
|
n--;
|
|
}
|
|
}
|
|
|
|
DBG_ASSERT( !DbgIsBuggy(), "InsertWrong: WrongList kaputt!" );
|
|
}
|
|
|
|
sal_Bool WrongList::NextWrong( sal_uInt16& rnStart, sal_uInt16& rnEnd ) const
|
|
{
|
|
/*
|
|
rnStart enthaelt die Startposition, wird ggf. auf Wrong-Start korrigiert
|
|
rnEnd braucht nicht inizialisiert sein.
|
|
*/
|
|
for ( sal_uInt16 n = 0; n < Count(); n++ )
|
|
{
|
|
WrongRange& rWrong = GetObject( n );
|
|
if ( rWrong.nEnd > rnStart )
|
|
{
|
|
rnStart = rWrong.nStart;
|
|
rnEnd = rWrong.nEnd;
|
|
return sal_True;
|
|
}
|
|
}
|
|
return sal_False;
|
|
}
|
|
|
|
sal_Bool WrongList::HasWrong( sal_uInt16 nStart, sal_uInt16 nEnd ) const
|
|
{
|
|
for ( sal_uInt16 n = 0; n < Count(); n++ )
|
|
{
|
|
WrongRange& rWrong = GetObject( n );
|
|
if ( ( rWrong.nStart == nStart ) && ( rWrong.nEnd == nEnd ) )
|
|
return sal_True;
|
|
else if ( rWrong.nStart >= nStart )
|
|
break;
|
|
}
|
|
return sal_False;
|
|
}
|
|
|
|
sal_Bool WrongList::HasAnyWrong( sal_uInt16 nStart, sal_uInt16 nEnd ) const
|
|
{
|
|
for ( sal_uInt16 n = 0; n < Count(); n++ )
|
|
{
|
|
WrongRange& rWrong = GetObject( n );
|
|
if ( ( rWrong.nEnd >= nStart ) && ( rWrong.nStart < nEnd ) )
|
|
return sal_True;
|
|
else if ( rWrong.nStart >= nEnd )
|
|
break;
|
|
}
|
|
return sal_False;
|
|
}
|
|
|
|
void WrongList::ClearWrongs( sal_uInt16 nStart, sal_uInt16 nEnd,
|
|
const ContentNode* pNode )
|
|
{
|
|
for ( sal_uInt16 n = 0; n < Count(); n++ )
|
|
{
|
|
WrongRange& rWrong = GetObject( n );
|
|
if ( ( rWrong.nEnd > nStart ) && ( rWrong.nStart < nEnd ) )
|
|
{
|
|
if ( rWrong.nEnd > nEnd ) // // Laeuft raus
|
|
{
|
|
rWrong.nStart = nEnd;
|
|
// Blanks?
|
|
while ( ( rWrong.nStart < pNode->Len() ) &&
|
|
( ( pNode->GetChar( rWrong.nStart ) == ' ' ) ||
|
|
( pNode->IsFeature( rWrong.nStart ) ) ) )
|
|
{
|
|
rWrong.nStart++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Remove( n, 1 );
|
|
n--;
|
|
}
|
|
}
|
|
}
|
|
|
|
DBG_ASSERT( !DbgIsBuggy(), "InsertWrong: WrongList kaputt!" );
|
|
}
|
|
|
|
void WrongList::InsertWrong( sal_uInt16 nStart, sal_uInt16 nEnd,
|
|
sal_Bool bClearRange )
|
|
{
|
|
sal_uInt16 nPos = Count();
|
|
for ( sal_uInt16 n = 0; n < Count(); n++ )
|
|
{
|
|
WrongRange& rWrong = GetObject( n );
|
|
if ( rWrong.nStart >= nStart )
|
|
{
|
|
nPos = n;
|
|
if ( bClearRange )
|
|
{
|
|
// Es kann eigentlich nur Passieren, dass der Wrong genau
|
|
// hier beginnt und weiter rauslauft, aber nicht, dass hier
|
|
// mehrere im Bereich liegen...
|
|
// Genau im Bereich darf keiner liegen, sonst darf diese Methode
|
|
// garnicht erst gerufen werden!
|
|
DBG_ASSERT( ( ( rWrong.nStart == nStart ) && ( rWrong.nEnd > nEnd ) )
|
|
|| ( rWrong.nStart > nEnd ), "InsertWrong: RangeMismatch!" );
|
|
if ( ( rWrong.nStart == nStart ) && ( rWrong.nEnd > nEnd ) )
|
|
rWrong.nStart = nEnd+1;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
Insert( WrongRange( nStart, nEnd ), nPos );
|
|
|
|
DBG_ASSERT( !DbgIsBuggy(), "InsertWrong: WrongList kaputt!" );
|
|
}
|
|
|
|
void WrongList::MarkWrongsInvalid()
|
|
{
|
|
if ( Count() )
|
|
MarkInvalid( GetObject( 0 ).nStart, GetObject( Count()-1 ).nEnd );
|
|
}
|
|
|
|
WrongList* WrongList::Clone() const
|
|
{
|
|
WrongList* pNew = new WrongList;
|
|
for ( sal_uInt16 n = 0; n < Count(); n++ )
|
|
{
|
|
WrongRange& rWrong = GetObject( n );
|
|
pNew->Insert( rWrong, pNew->Count() );
|
|
}
|
|
|
|
return pNew;
|
|
}
|
|
|
|
|
|
#ifdef DBG_UTIL
|
|
sal_Bool WrongList::DbgIsBuggy() const
|
|
{
|
|
// Pruefen, ob sich Bereiche ueberlappen
|
|
sal_Bool bError = sal_False;
|
|
for ( sal_uInt16 nA = 0; !bError && ( nA < Count() ); nA++ )
|
|
{
|
|
WrongRange& rWrong = GetObject( nA );
|
|
for ( sal_uInt16 nB = nA+1; !bError && ( nB < Count() ); nB++ )
|
|
{
|
|
WrongRange& rNextWrong = GetObject( nB );
|
|
// 1) Start davor, End hinterm anderen Start
|
|
if ( ( rWrong.nStart <= rNextWrong.nStart )
|
|
&& ( rWrong.nEnd >= rNextWrong.nStart ) )
|
|
bError = sal_True;
|
|
// 2) Start hinter anderen Start, aber noch vorm anderen End
|
|
else if ( ( rWrong.nStart >= rNextWrong.nStart)
|
|
&& ( rWrong.nStart <= rNextWrong.nEnd ) )
|
|
bError = sal_True;
|
|
}
|
|
}
|
|
return bError;
|
|
}
|
|
#endif
|
|
|
|
|
|
EdtAutoCorrDoc::EdtAutoCorrDoc( ImpEditEngine* pE, ContentNode* pN,
|
|
sal_uInt16 nCrsr, xub_Unicode cIns )
|
|
{
|
|
pImpEE = pE;
|
|
pCurNode = pN;
|
|
nCursor = nCrsr;
|
|
|
|
bUndoAction = sal_False;
|
|
bAllowUndoAction = cIns ? sal_True : sal_False;
|
|
}
|
|
|
|
EdtAutoCorrDoc::~EdtAutoCorrDoc()
|
|
{
|
|
if ( bUndoAction )
|
|
pImpEE->UndoActionEnd( EDITUNDO_INSERT );
|
|
}
|
|
|
|
sal_Bool EdtAutoCorrDoc::Delete( sal_uInt16 nStt, sal_uInt16 nEnd )
|
|
{
|
|
EditSelection aSel( EditPaM( pCurNode, nStt ), EditPaM( pCurNode, nEnd ) );
|
|
pImpEE->ImpDeleteSelection( aSel );
|
|
DBG_ASSERT( nCursor >= nEnd, "Cursor mitten im Geschehen ?!" );
|
|
nCursor -= ( nEnd-nStt );
|
|
bAllowUndoAction = sal_False;
|
|
return sal_True;
|
|
}
|
|
|
|
sal_Bool EdtAutoCorrDoc::Insert( sal_uInt16 nPos, const String& rTxt )
|
|
{
|
|
EditSelection aSel = EditPaM( pCurNode, nPos );
|
|
pImpEE->ImpInsertText( aSel, rTxt );
|
|
DBG_ASSERT( nCursor >= nPos, "Cursor mitten im Geschehen ?!" );
|
|
nCursor += rTxt.Len();
|
|
|
|
if ( bAllowUndoAction && ( rTxt.Len() == 1 ) )
|
|
ImplStartUndoAction();
|
|
bAllowUndoAction = sal_False;
|
|
|
|
return sal_True;
|
|
}
|
|
|
|
sal_Bool EdtAutoCorrDoc::Replace( sal_uInt16 nPos, const String& rTxt )
|
|
{
|
|
// Eigentlich ein Replace einfuehren => Entspr. UNDO
|
|
sal_uInt16 nEnd = nPos+rTxt.Len();
|
|
if ( nEnd > pCurNode->Len() )
|
|
nEnd = pCurNode->Len();
|
|
|
|
// #i5925# First insert new text behind to be deleted text, for keeping attributes.
|
|
pImpEE->ImpInsertText( EditSelection( EditPaM( pCurNode, nEnd ) ), rTxt );
|
|
pImpEE->ImpDeleteSelection( EditSelection( EditPaM( pCurNode, nPos ), EditPaM( pCurNode, nEnd ) ) );
|
|
|
|
if ( nPos == nCursor )
|
|
nCursor += rTxt.Len();
|
|
|
|
if ( bAllowUndoAction && ( rTxt.Len() == 1 ) )
|
|
ImplStartUndoAction();
|
|
|
|
bAllowUndoAction = sal_False;
|
|
|
|
return sal_True;
|
|
}
|
|
|
|
sal_Bool EdtAutoCorrDoc::SetAttr( sal_uInt16 nStt, sal_uInt16 nEnd,
|
|
sal_uInt16 nSlotId, SfxPoolItem& rItem )
|
|
{
|
|
SfxItemPool* pPool = &pImpEE->GetEditDoc().GetItemPool();
|
|
while ( pPool->GetSecondaryPool() &&
|
|
pPool->GetName().EqualsAscii( "EditEngineItemPool" ) )
|
|
{
|
|
pPool = pPool->GetSecondaryPool();
|
|
|
|
}
|
|
sal_uInt16 nWhich = pPool->GetWhich( nSlotId );
|
|
if ( nWhich )
|
|
{
|
|
rItem.SetWhich( nWhich );
|
|
|
|
SfxItemSet aSet( pImpEE->GetEmptyItemSet() );
|
|
aSet.Put( rItem );
|
|
|
|
EditSelection aSel( EditPaM( pCurNode, nStt ), EditPaM( pCurNode, nEnd ) );
|
|
aSel.Max().SetIndex( nEnd ); // ???
|
|
pImpEE->SetAttribs( aSel, aSet, ATTRSPECIAL_EDGE );
|
|
bAllowUndoAction = sal_False;
|
|
}
|
|
return sal_True;
|
|
}
|
|
|
|
sal_Bool EdtAutoCorrDoc::SetINetAttr( sal_uInt16 nStt, sal_uInt16 nEnd,
|
|
const String& rURL )
|
|
{
|
|
// Aus dem Text ein Feldbefehl machen...
|
|
EditSelection aSel( EditPaM( pCurNode, nStt ), EditPaM( pCurNode, nEnd ) );
|
|
String aText = pImpEE->GetSelected( aSel );
|
|
aSel = pImpEE->ImpDeleteSelection( aSel );
|
|
DBG_ASSERT( nCursor >= nEnd, "Cursor mitten im Geschehen ?!" );
|
|
nCursor -= ( nEnd-nStt );
|
|
SvxFieldItem aField( SvxURLField( rURL, aText, SVXURLFORMAT_REPR ),
|
|
EE_FEATURE_FIELD );
|
|
pImpEE->InsertField( aSel, aField );
|
|
nCursor++;
|
|
pImpEE->UpdateFields();
|
|
bAllowUndoAction = sal_False;
|
|
return sal_True;
|
|
}
|
|
|
|
sal_Bool EdtAutoCorrDoc::HasSymbolChars( sal_uInt16 nStt, sal_uInt16 nEnd )
|
|
{
|
|
USHORT nScriptType = pImpEE->GetScriptType( EditPaM( pCurNode, nStt ) );
|
|
USHORT nScriptFontInfoItemId = GetScriptItemId( EE_CHAR_FONTINFO, nScriptType );
|
|
|
|
CharAttribArray& rAttribs = pCurNode->GetCharAttribs().GetAttribs();
|
|
sal_uInt16 nAttrs = rAttribs.Count();
|
|
for ( sal_uInt16 n = 0; n < nAttrs; n++ )
|
|
{
|
|
EditCharAttrib* pAttr = rAttribs.GetObject( n );
|
|
if ( pAttr->GetStart() >= nEnd )
|
|
return sal_False;
|
|
|
|
if ( ( pAttr->Which() == nScriptFontInfoItemId ) &&
|
|
( ((SvxFontItem*)pAttr->GetItem())->GetCharSet() == RTL_TEXTENCODING_SYMBOL ) )
|
|
{
|
|
// Pruefen, ob das Attribt im Bereich liegt...
|
|
if ( pAttr->GetEnd() >= nStt )
|
|
return sal_True;
|
|
}
|
|
}
|
|
return sal_False;
|
|
}
|
|
|
|
const String* EdtAutoCorrDoc::GetPrevPara( sal_Bool bAtNormalPos )
|
|
{
|
|
// Vorherigen Absatz zurueck geben, damit ermittel werden kann,
|
|
// ob es sich beim aktuellen Wort um einen Satzanfang handelt.
|
|
|
|
bAllowUndoAction = sal_False; // Jetzt nicht mehr...
|
|
|
|
ContentList& rNodes = pImpEE->GetEditDoc();
|
|
sal_uInt16 nPos = rNodes.GetPos( pCurNode );
|
|
|
|
// Sonderbehandlung: Bullet => Absatzanfang => einfach NULL returnen...
|
|
const SfxUInt16Item& rBulletState = (const SfxUInt16Item&)
|
|
pImpEE->GetParaAttrib( nPos, EE_PARA_BULLETSTATE );
|
|
sal_Bool bBullet = rBulletState.GetValue() ? sal_True : sal_False;
|
|
if ( !bBullet && ( pImpEE->aStatus.GetControlWord() & EE_CNTRL_OUTLINER ) )
|
|
{
|
|
// Der Outliner hat im Gliederungsmodus auf Ebene 0 immer ein Bullet.
|
|
const SfxUInt16Item& rLevel = (const SfxUInt16Item&)
|
|
pImpEE->GetParaAttrib( nPos, EE_PARA_OUTLLEVEL );
|
|
if ( rLevel.GetValue() == 0 )
|
|
bBullet = sal_True;
|
|
}
|
|
if ( bBullet )
|
|
return NULL;
|
|
|
|
for ( sal_uInt16 n = nPos; n; )
|
|
{
|
|
n--;
|
|
ContentNode* pNode = rNodes[n];
|
|
if ( pNode->Len() )
|
|
return pNode;
|
|
}
|
|
return NULL;
|
|
|
|
}
|
|
|
|
sal_Bool EdtAutoCorrDoc::ChgAutoCorrWord( sal_uInt16& rSttPos,
|
|
sal_uInt16 nEndPos, SvxAutoCorrect& rACorrect,
|
|
const String** ppPara )
|
|
{
|
|
// Absatz-Anfang oder ein Blank gefunden, suche nach dem Wort
|
|
// Kuerzel im Auto
|
|
|
|
bAllowUndoAction = sal_False; // Jetzt nicht mehr...
|
|
|
|
String aShort( pCurNode->Copy( rSttPos, nEndPos - rSttPos ) );
|
|
sal_Bool bRet = sal_False;
|
|
|
|
if( !aShort.Len() )
|
|
return bRet;
|
|
|
|
LanguageType eLang = pImpEE->GetLanguage( EditPaM( pCurNode, rSttPos+1 ) );
|
|
const SvxAutocorrWord* pFnd = rACorrect.SearchWordsInList( *pCurNode, rSttPos, nEndPos, *this, eLang );
|
|
if( pFnd && pFnd->IsTextOnly() )
|
|
{
|
|
// dann mal ersetzen
|
|
EditSelection aSel( EditPaM( pCurNode, rSttPos ),
|
|
EditPaM( pCurNode, nEndPos ) );
|
|
aSel = pImpEE->ImpDeleteSelection( aSel );
|
|
DBG_ASSERT( nCursor >= nEndPos, "Cursor mitten im Geschehen ?!" );
|
|
nCursor -= ( nEndPos-rSttPos );
|
|
pImpEE->ImpInsertText( aSel, pFnd->GetLong() );
|
|
nCursor += pFnd->GetLong().Len();
|
|
if( ppPara )
|
|
*ppPara = pCurNode;
|
|
bRet = sal_True;
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
LanguageType EdtAutoCorrDoc::GetLanguage( sal_uInt16 nPos, sal_Bool bPrevPara ) const
|
|
{
|
|
return pImpEE->GetLanguage( EditPaM( pCurNode, nPos+1 ) );
|
|
}
|
|
|
|
void EdtAutoCorrDoc::ImplStartUndoAction()
|
|
{
|
|
sal_uInt16 nPara = pImpEE->GetEditDoc().GetPos( pCurNode );
|
|
ESelection aSel( nPara, nCursor, nPara, nCursor );
|
|
pImpEE->UndoActionStart( EDITUNDO_INSERT, aSel );
|
|
bUndoAction = sal_True;
|
|
bAllowUndoAction = sal_False;
|
|
}
|
|
|