blob: 6ac1e34984e3e52496fc81e28835fa6c63e3c045 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_editeng.hxx"
#include <eeng_pch.hxx>
#include <impedit.hxx>
#include <editeng/editeng.hxx>
#include <editdbg.hxx>
#include <svl/smplhint.hxx>
#include <editeng/lrspitem.hxx>
void ImpEditEngine::SetStyleSheetPool( SfxStyleSheetPool* pSPool )
{
if ( pStylePool != pSPool )
{
// if ( pStylePool )
// EndListening( *pStylePool, sal_True );
pStylePool = pSPool;
// if ( pStylePool )
// StartListening( *pStylePool, sal_True );
}
}
SfxStyleSheet* ImpEditEngine::GetStyleSheet( sal_uInt16 nPara ) const
{
ContentNode* pNode = aEditDoc.SaveGetObject( nPara );
return pNode ? pNode->GetContentAttribs().GetStyleSheet() : NULL;
}
void ImpEditEngine::SetStyleSheet( EditSelection aSel, SfxStyleSheet* pStyle )
{
aSel.Adjust( aEditDoc );
sal_uInt16 nStartPara = aEditDoc.GetPos( aSel.Min().GetNode() );
sal_uInt16 nEndPara = aEditDoc.GetPos( aSel.Max().GetNode() );
sal_Bool _bUpdate = GetUpdateMode();
SetUpdateMode( sal_False );
for ( sal_uInt16 n = nStartPara; n <= nEndPara; n++ )
SetStyleSheet( n, pStyle );
SetUpdateMode( _bUpdate, 0 );
}
void ImpEditEngine::SetStyleSheet( sal_uInt16 nPara, SfxStyleSheet* pStyle )
{
DBG_ASSERT( GetStyleSheetPool() || !pStyle, "SetStyleSheet: No StyleSheetPool registered!" );
ContentNode* pNode = aEditDoc.SaveGetObject( nPara );
SfxStyleSheet* pCurStyle = pNode->GetStyleSheet();
if ( pStyle != pCurStyle )
{
if ( IsUndoEnabled() && !IsInUndo() && aStatus.DoUndoAttribs() )
{
XubString aPrevStyleName;
if ( pCurStyle )
aPrevStyleName = pCurStyle->GetName();
XubString aNewStyleName;
if ( pStyle )
aNewStyleName = pStyle->GetName();
InsertUndo(
new EditUndoSetStyleSheet( this, aEditDoc.GetPos( pNode ),
aPrevStyleName, pCurStyle ? pCurStyle->GetFamily() : SFX_STYLE_FAMILY_PARA,
aNewStyleName, pStyle ? pStyle->GetFamily() : SFX_STYLE_FAMILY_PARA,
pNode->GetContentAttribs().GetItems() ) );
}
if ( pCurStyle )
EndListening( *pCurStyle, sal_False );
pNode->SetStyleSheet( pStyle, aStatus.UseCharAttribs() );
if ( pStyle )
StartListening( *pStyle, sal_False );
ParaAttribsChanged( pNode );
}
FormatAndUpdate();
}
void ImpEditEngine::UpdateParagraphsWithStyleSheet( SfxStyleSheet* pStyle )
{
SvxFont aFontFromStyle;
CreateFont( aFontFromStyle, pStyle->GetItemSet() );
sal_Bool bUsed = sal_False;
for ( sal_uInt16 nNode = 0; nNode < aEditDoc.Count(); nNode++ )
{
ContentNode* pNode = aEditDoc.GetObject( nNode );
if ( pNode->GetStyleSheet() == pStyle )
{
bUsed = sal_True;
if ( aStatus.UseCharAttribs() )
pNode->SetStyleSheet( pStyle, aFontFromStyle );
else
pNode->SetStyleSheet( pStyle, sal_False );
ParaAttribsChanged( pNode );
}
}
if ( bUsed )
{
GetEditEnginePtr()->StyleSheetChanged( pStyle );
FormatAndUpdate();
}
}
void ImpEditEngine::RemoveStyleFromParagraphs( SfxStyleSheet* pStyle )
{
for ( sal_uInt16 nNode = 0; nNode < aEditDoc.Count(); nNode++ )
{
ContentNode* pNode = aEditDoc.GetObject(nNode);
if ( pNode->GetStyleSheet() == pStyle )
{
pNode->SetStyleSheet( NULL );
ParaAttribsChanged( pNode );
}
}
FormatAndUpdate();
}
void ImpEditEngine::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
{
// Damit nicht beim Destruieren unnoetig formatiert wird:
if ( !bDowning )
{
DBG_CHKOBJ( GetEditEnginePtr(), EditEngine, 0 );
SfxStyleSheet* pStyle = NULL;
sal_uLong nId = 0;
if ( rHint.ISA( SfxStyleSheetHint ) )
{
const SfxStyleSheetHint& rH = (const SfxStyleSheetHint&) rHint;
DBG_ASSERT( rH.GetStyleSheet()->ISA( SfxStyleSheet ), "Kein SfxStyleSheet!" );
pStyle = (SfxStyleSheet*) rH.GetStyleSheet();
nId = rH.GetHint();
}
else if ( ( rHint.Type() == TYPE(SfxSimpleHint ) ) && ( rBC.ISA( SfxStyleSheet ) ) )
{
pStyle = (SfxStyleSheet*)&rBC;
nId = ((SfxSimpleHint&)rHint).GetId();
}
if ( pStyle )
{
if ( ( nId == SFX_HINT_DYING ) ||
( nId == SFX_STYLESHEET_INDESTRUCTION ) ||
( nId == SFX_STYLESHEET_ERASED ) )
{
RemoveStyleFromParagraphs( pStyle );
}
else if ( ( nId == SFX_HINT_DATACHANGED ) ||
( nId == SFX_STYLESHEET_MODIFIED ) )
{
UpdateParagraphsWithStyleSheet( pStyle );
// Alle Absaetze mit EditStyles, die das geaenderte Style
// irgendwie als Parent haben, muessen formatiert werden.
// sal_uLong nStyles = pMyStylePool->GetStyles().Count();
// for ( sal_uLong nStyle = 0; nStyle < nStyles; nStyle++ )
// {
// EditStyleSheet* pES = (EditStyleSheet*)pMyStylePool->GetStyles().GetObject( nStyle );
// DBG_ASSERT( pES, "NULL-Pointer im StyleSheetPool!" );
// if ( pES->IsUsed() && pES->HasStyleAsAnyParent( *pStyle ) )
// UpdateParagraphsWithStyleSheet( pES );
// }
}
}
}
}
EditUndoSetAttribs* ImpEditEngine::CreateAttribUndo( EditSelection aSel, const SfxItemSet& rSet )
{
DBG_ASSERT( !aSel.DbgIsBuggy( aEditDoc ), "CreateAttribUndo: Fehlerhafte Selektion" );
aSel.Adjust( aEditDoc );
ESelection aESel( CreateESel( aSel ) );
sal_uInt16 nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() );
sal_uInt16 nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() );
DBG_ASSERT( nStartNode <= nEndNode, "CreateAttribUndo: Start > End ?!" );
EditUndoSetAttribs* pUndo = NULL;
if ( rSet.GetPool() != &aEditDoc.GetItemPool() )
{
SfxItemSet aTmpSet( GetEmptyItemSet() );
aTmpSet.Put( rSet );
pUndo = new EditUndoSetAttribs( this, aESel, aTmpSet );
}
else
{
pUndo = new EditUndoSetAttribs( this, aESel, rSet );
}
SfxItemPool* pPool = pUndo->GetNewAttribs().GetPool();
for ( sal_uInt16 nPara = nStartNode; nPara <= nEndNode; nPara++ )
{
ContentNode* pNode = aEditDoc.GetObject( nPara );
DBG_ASSERT( aEditDoc.SaveGetObject( nPara ), "Node nicht gefunden: CreateAttribUndo" );
ContentAttribsInfo* pInf = new ContentAttribsInfo( pNode->GetContentAttribs().GetItems() );
pUndo->GetContentInfos().Insert( pInf, pUndo->GetContentInfos().Count() );
for ( sal_uInt16 nAttr = 0; nAttr < pNode->GetCharAttribs().Count(); nAttr++ )
{
EditCharAttribPtr pAttr = pNode->GetCharAttribs().GetAttribs()[ nAttr ];
if ( pAttr->GetLen() )
{
EditCharAttribPtr pNew = MakeCharAttrib( *pPool, *pAttr->GetItem(), pAttr->GetStart(), pAttr->GetEnd() );
pInf->GetPrevCharAttribs().Insert( pNew, pInf->GetPrevCharAttribs().Count() );
}
}
}
return pUndo;
}
void ImpEditEngine::UndoActionStart( sal_uInt16 nId, const ESelection& aSel )
{
if ( IsUndoEnabled() && !IsInUndo() )
{
GetUndoManager().EnterListAction( GetEditEnginePtr()->GetUndoComment( nId ), XubString(), nId );
DBG_ASSERT( !pUndoMarkSelection, "UndoAction SelectionMarker?" );
pUndoMarkSelection = new ESelection( aSel );
}
}
void ImpEditEngine::UndoActionStart( sal_uInt16 nId )
{
if ( IsUndoEnabled() && !IsInUndo() )
{
GetUndoManager().EnterListAction( GetEditEnginePtr()->GetUndoComment( nId ), XubString(), nId );
DBG_ASSERT( !pUndoMarkSelection, "UndoAction SelectionMarker?" );
}
}
void ImpEditEngine::UndoActionEnd( sal_uInt16 )
{
if ( IsUndoEnabled() && !IsInUndo() )
{
GetUndoManager().LeaveListAction();
delete pUndoMarkSelection;
pUndoMarkSelection = NULL;
}
}
void ImpEditEngine::InsertUndo( EditUndo* pUndo, sal_Bool bTryMerge )
{
DBG_ASSERT( !IsInUndo(), "InsertUndo im Undomodus!" );
if ( pUndoMarkSelection )
{
EditUndoMarkSelection* pU = new EditUndoMarkSelection( this, *pUndoMarkSelection );
GetUndoManager().AddUndoAction( pU, sal_False );
delete pUndoMarkSelection;
pUndoMarkSelection = NULL;
}
GetUndoManager().AddUndoAction( pUndo, bTryMerge );
mbLastTryMerge = bTryMerge;
}
void ImpEditEngine::ResetUndoManager()
{
if ( HasUndoManager() )
GetUndoManager().Clear();
}
void ImpEditEngine::EnableUndo( sal_Bool bEnable )
{
// Beim Umschalten des Modus Liste loeschen:
if ( bEnable != IsUndoEnabled() )
ResetUndoManager();
bUndoEnabled = bEnable;
}
sal_Bool ImpEditEngine::Undo( EditView* pView )
{
if ( HasUndoManager() && GetUndoManager().GetUndoActionCount() )
{
SetActiveView( pView );
GetUndoManager().Undo();
return sal_True;
}
return sal_False;
}
sal_Bool ImpEditEngine::Redo( EditView* pView )
{
if ( HasUndoManager() && GetUndoManager().GetRedoActionCount() )
{
SetActiveView( pView );
GetUndoManager().Redo();
return sal_True;
}
return sal_False;
}
sal_Bool ImpEditEngine::Repeat( EditView* /* pView */ )
{
if ( HasUndoManager() && GetUndoManager().GetRepeatActionCount() )
{
DBG_WARNING( "Repeat nicht implementiert!" );
return sal_True;
}
return sal_False;
}
SfxItemSet ImpEditEngine::GetAttribs( EditSelection aSel, sal_Bool bOnlyHardAttrib )
{
DBG_CHKOBJ( GetEditEnginePtr(), EditEngine, 0 );
aSel.Adjust( aEditDoc );
#if OSL_DEBUG_LEVEL > 1
// if ( ( aSel.Min().GetNode() == aSel.Max().GetNode() ) && ( bOnlyHardAttrib == EditEngineAttribs_All ) )
// return GetAttribs( aEditDoc.GetPos( aSel.Min().GetNode() ), aSel.Min().GetIndex(), aSel.Max().GetIndex(), GETATTRIBS_ALL );
#endif
SfxItemSet aCurSet( GetEmptyItemSet() );
sal_uInt16 nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() );
sal_uInt16 nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() );
// ueber die Absaetze iterieren...
for ( sal_uInt16 nNode = nStartNode; nNode <= nEndNode; nNode++ )
{
ContentNode* pNode = aEditDoc.GetObject( nNode );
DBG_ASSERT( aEditDoc.SaveGetObject( nNode ), "Node nicht gefunden: GetAttrib" );
xub_StrLen nStartPos = 0;
xub_StrLen nEndPos = pNode->Len();
if ( nNode == nStartNode )
nStartPos = aSel.Min().GetIndex();
if ( nNode == nEndNode ) // kann auch == nStart sein!
nEndPos = aSel.Max().GetIndex();
// Problem: Vorlagen....
// => Andersrum:
// 1) Harte Zeichenattribute, wie gehabt...
// 2) Nur wenn OFF, Style and Absatzattr. pruefen...
// Erst die ganz harte Formatierung...
aEditDoc.FindAttribs( pNode, nStartPos, nEndPos, aCurSet );
if( bOnlyHardAttrib != EditEngineAttribs_OnlyHard )
{
// Und dann Absatzformatierung und Vorlage...
// SfxStyleSheet* pStyle = pNode->GetStyleSheet();
for ( sal_uInt16 nWhich = EE_ITEMS_START; nWhich <= EE_CHAR_END; nWhich++)
{
if ( aCurSet.GetItemState( nWhich ) == SFX_ITEM_OFF )
{
if ( bOnlyHardAttrib == EditEngineAttribs_All )
{
const SfxPoolItem& rItem = pNode->GetContentAttribs().GetItem( nWhich );
aCurSet.Put( rItem );
}
else if ( pNode->GetContentAttribs().GetItems().GetItemState( nWhich ) == SFX_ITEM_ON )
{
const SfxPoolItem& rItem = pNode->GetContentAttribs().GetItems().Get( nWhich );
aCurSet.Put( rItem );
}
}
else if ( aCurSet.GetItemState( nWhich ) == SFX_ITEM_ON )
{
const SfxPoolItem* pItem = NULL;
if ( bOnlyHardAttrib == EditEngineAttribs_All )
{
pItem = &pNode->GetContentAttribs().GetItem( nWhich );
}
else if ( pNode->GetContentAttribs().GetItems().GetItemState( nWhich ) == SFX_ITEM_ON )
{
pItem = &pNode->GetContentAttribs().GetItems().Get( nWhich );
}
// pItem can only be NULL when bOnlyHardAttrib...
if ( !pItem || ( *pItem != aCurSet.Get( nWhich ) ) )
{
// Problem: Wenn Absatzvorlage mit z.B. Font,
// aber Font hart und anders und komplett in Selektion
// Falsch, wenn invalidiert....
// => Lieber nicht invalidieren, UMSTELLEN!
// Besser waere, Absatzweise ein ItemSet zu fuellen
// und dieses mit dem gesmten vergleichen.
// aCurSet.InvalidateItem( nWhich );
if ( nWhich <= EE_PARA_END )
aCurSet.InvalidateItem( nWhich );
}
}
}
}
}
// Leere Slots mit Defaults fuellen...
if ( bOnlyHardAttrib == EditEngineAttribs_All )
{
for ( sal_uInt16 nWhich = EE_ITEMS_START; nWhich <= EE_CHAR_END; nWhich++ )
{
if ( aCurSet.GetItemState( nWhich ) == SFX_ITEM_OFF )
{
aCurSet.Put( aEditDoc.GetItemPool().GetDefaultItem( nWhich ) );
}
}
}
return aCurSet;
}
SfxItemSet ImpEditEngine::GetAttribs( sal_uInt16 nPara, sal_uInt16 nStart, sal_uInt16 nEnd, sal_uInt8 nFlags ) const
{
// MT: #94002# Optimized function with less Puts(), which cause unnecessary cloning from default items.
// If this works, change GetAttribs( EditSelection ) to use this for each paragraph and merge the results!
DBG_CHKOBJ( GetEditEnginePtr(), EditEngine, 0 );
ContentNode* pNode = aEditDoc.SaveGetObject( nPara );
DBG_ASSERT( pNode, "GetAttribs - unknown paragraph!" );
DBG_ASSERT( nStart <= nEnd, "getAttribs: Start > End not supported!" );
SfxItemSet aAttribs( ((ImpEditEngine*)this)->GetEmptyItemSet() );
if ( pNode )
{
if ( nEnd > pNode->Len() )
nEnd = pNode->Len();
if ( nStart > nEnd )
nStart = nEnd;
// StyleSheet / Parattribs...
if ( pNode->GetStyleSheet() && ( nFlags & GETATTRIBS_STYLESHEET ) )
aAttribs.Set( pNode->GetStyleSheet()->GetItemSet(), sal_True );
if ( nFlags & GETATTRIBS_PARAATTRIBS )
aAttribs.Put( pNode->GetContentAttribs().GetItems() );
// CharAttribs...
if ( nFlags & GETATTRIBS_CHARATTRIBS )
{
// Make testing easier...
pNode->GetCharAttribs().OptimizeRanges( ((ImpEditEngine*)this)->GetEditDoc().GetItemPool() );
const CharAttribArray& rAttrs = pNode->GetCharAttribs().GetAttribs();
for ( sal_uInt16 nAttr = 0; nAttr < rAttrs.Count(); nAttr++ )
{
EditCharAttrib* pAttr = rAttrs.GetObject( nAttr );
if ( nStart == nEnd )
{
sal_uInt16 nCursorPos = nStart;
if ( ( pAttr->GetStart() <= nCursorPos ) && ( pAttr->GetEnd() >= nCursorPos ) )
{
// To be used the attribute has to start BEFORE the position, or it must be a
// new empty attr AT the position, or we are on position 0.
if ( ( pAttr->GetStart() < nCursorPos ) || pAttr->IsEmpty() || !nCursorPos )
{
// maybe this attrib ends here and a new attrib with 0 Len may follow and be valid here,
// but that s no problem, the empty item will come later and win.
aAttribs.Put( *pAttr->GetItem() );
}
}
}
else
{
// Check every attribute covering the area, partial or full.
if ( ( pAttr->GetStart() < nEnd ) && ( pAttr->GetEnd() > nStart ) )
{
if ( ( pAttr->GetStart() <= nStart ) && ( pAttr->GetEnd() >= nEnd ) )
{
// full coverage
aAttribs.Put( *pAttr->GetItem() );
}
else
{
// OptimizeRagnge() assures that not the same attr can follow for full coverage
// only partial, check with current, when using para/styhe, otherwise invalid.
if ( !( nFlags & (GETATTRIBS_PARAATTRIBS|GETATTRIBS_STYLESHEET) ) ||
( *pAttr->GetItem() != aAttribs.Get( pAttr->Which() ) ) )
{
aAttribs.InvalidateItem( pAttr->Which() );
}
}
}
}
if ( pAttr->GetStart() > nEnd )
{
break;
}
}
}
}
return aAttribs;
}
void ImpEditEngine::SetAttribs( EditSelection aSel, const SfxItemSet& rSet, sal_uInt8 nSpecial )
{
aSel.Adjust( aEditDoc );
// Wenn keine Selektion => die Attribute aufs Wort anwenden.
// ( Der RTF-Perser sollte die Methode eigentlich nie ohne Range rufen )
if ( ( nSpecial == ATTRSPECIAL_WHOLEWORD ) && !aSel.HasRange() )
aSel = SelectWord( aSel, ::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_False );
sal_uInt16 nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() );
sal_uInt16 nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() );
if ( IsUndoEnabled() && !IsInUndo() && aStatus.DoUndoAttribs() )
{
EditUndoSetAttribs* pUndo = CreateAttribUndo( aSel, rSet );
pUndo->SetSpecial( nSpecial );
InsertUndo( pUndo );
}
sal_Bool bCheckLanguage = sal_False;
if ( GetStatus().DoOnlineSpelling() )
{
bCheckLanguage = ( rSet.GetItemState( EE_CHAR_LANGUAGE ) == SFX_ITEM_ON ) ||
( rSet.GetItemState( EE_CHAR_LANGUAGE_CJK ) == SFX_ITEM_ON ) ||
( rSet.GetItemState( EE_CHAR_LANGUAGE_CTL ) == SFX_ITEM_ON );
}
// ueber die Absaetze iterieren...
for ( sal_uInt16 nNode = nStartNode; nNode <= nEndNode; nNode++ )
{
sal_Bool bParaAttribFound = sal_False;
sal_Bool bCharAttribFound = sal_False;
ContentNode* pNode = aEditDoc.GetObject( nNode );
ParaPortion* pPortion = GetParaPortions().GetObject( nNode );
DBG_ASSERT( aEditDoc.SaveGetObject( nNode ), "Node nicht gefunden: SetAttribs" );
DBG_ASSERT( GetParaPortions().GetObject( nNode ), "Portion nicht gefunden: SetAttribs" );
xub_StrLen nStartPos = 0;
xub_StrLen nEndPos = pNode->Len();
if ( nNode == nStartNode )
nStartPos = aSel.Min().GetIndex();
if ( nNode == nEndNode ) // kann auch == nStart sein!
nEndPos = aSel.Max().GetIndex();
// ueber die Items iterieren...
#ifdef EDITDEBUG
// FILE* fp = fopen( "d:\\debug.log", "a" );
// if ( fp )
// {
// fprintf( fp, "\n \n=> Zeichen-Attribute: Absatz %i, %i-%i\n", nNode, nStartPos, nEndPos );
// DbgOutItemSet( fp, rSet, sal_True, sal_False );
// fclose( fp );
// }
#endif
for ( sal_uInt16 nWhich = EE_ITEMS_START; nWhich <= EE_CHAR_END; nWhich++)
{
if ( rSet.GetItemState( nWhich ) == SFX_ITEM_ON )
{
const SfxPoolItem& rItem = rSet.Get( nWhich );
if ( nWhich <= EE_PARA_END )
{
pNode->GetContentAttribs().GetItems().Put( rItem );
bParaAttribFound = sal_True;
}
else
{
aEditDoc.InsertAttrib( pNode, nStartPos, nEndPos, rItem );
bCharAttribFound = sal_True;
if ( nSpecial == ATTRSPECIAL_EDGE )
{
CharAttribArray& rAttribs = pNode->GetCharAttribs().GetAttribs();
sal_uInt16 nAttrs = rAttribs.Count();
for ( sal_uInt16 n = 0; n < nAttrs; n++ )
{
EditCharAttrib* pAttr = rAttribs.GetObject( n );
if ( pAttr->GetStart() > nEndPos )
break;
if ( ( pAttr->GetEnd() == nEndPos ) && ( pAttr->Which() == nWhich ) )
{
pAttr->SetEdge( sal_True );
break;
}
}
}
}
}
}
if ( bParaAttribFound )
{
ParaAttribsChanged( pPortion->GetNode() );
}
else if ( bCharAttribFound )
{
bFormatted = sal_False;
if ( !pNode->Len() || ( nStartPos != nEndPos ) )
{
pPortion->MarkSelectionInvalid( nStartPos, nEndPos-nStartPos );
if ( bCheckLanguage )
pNode->GetWrongList()->MarkInvalid( nStartPos, nEndPos );
}
}
}
}
void ImpEditEngine::RemoveCharAttribs( EditSelection aSel, sal_Bool bRemoveParaAttribs, sal_uInt16 nWhich )
{
aSel.Adjust( aEditDoc );
sal_uInt16 nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() );
sal_uInt16 nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() );
const SfxItemSet* _pEmptyItemSet = bRemoveParaAttribs ? &GetEmptyItemSet() : 0;
if ( IsUndoEnabled() && !IsInUndo() && aStatus.DoUndoAttribs() )
{
// Eventuel spezielles Undo, oder ItemSet*
EditUndoSetAttribs* pUndo = CreateAttribUndo( aSel, GetEmptyItemSet() );
pUndo->SetRemoveAttribs( sal_True );
pUndo->SetRemoveParaAttribs( bRemoveParaAttribs );
pUndo->SetRemoveWhich( nWhich );
InsertUndo( pUndo );
}
// ueber die Absaetze iterieren...
for ( sal_uInt16 nNode = nStartNode; nNode <= nEndNode; nNode++ )
{
ContentNode* pNode = aEditDoc.GetObject( nNode );
ParaPortion* pPortion = GetParaPortions().GetObject( nNode );
DBG_ASSERT( aEditDoc.SaveGetObject( nNode ), "Node nicht gefunden: SetAttribs" );
DBG_ASSERT( GetParaPortions().SaveGetObject( nNode ), "Portion nicht gefunden: SetAttribs" );
xub_StrLen nStartPos = 0;
xub_StrLen nEndPos = pNode->Len();
if ( nNode == nStartNode )
nStartPos = aSel.Min().GetIndex();
if ( nNode == nEndNode ) // kann auch == nStart sein!
nEndPos = aSel.Max().GetIndex();
// Optimieren: Wenn ganzer Absatz, dann RemoveCharAttribs( nPara )?!
sal_Bool bChanged = aEditDoc.RemoveAttribs( pNode, nStartPos, nEndPos, nWhich );
if ( bRemoveParaAttribs )
{
SetParaAttribs( nNode, *_pEmptyItemSet ); // Invalidiert
}
else
{
// Bei 'Format-Standard' sollen auch die Zeichenattribute verschwinden,
// die von der DrawingEngine als Absatzattribute eingestellt wurden.
// Diese koennen sowieso nicht vom Anwender eingestellt worden sein.
// #106871# Not when nWhich
// Would have been better to offer a separate method for format/standard...
if ( !nWhich )
{
SfxItemSet aAttribs( GetParaAttribs( nNode ) );
for ( sal_uInt16 nW = EE_CHAR_START; nW <= EE_CHAR_END; nW++ )
aAttribs.ClearItem( nW );
SetParaAttribs( nNode, aAttribs );
}
}
if ( bChanged && !bRemoveParaAttribs )
{
bFormatted = sal_False;
pPortion->MarkSelectionInvalid( nStartPos, nEndPos-nStartPos );
}
}
}
typedef EditCharAttrib* EditCharAttribPtr;
void ImpEditEngine::RemoveCharAttribs( sal_uInt16 nPara, sal_uInt16 nWhich, sal_Bool bRemoveFeatures )
{
ContentNode* pNode = aEditDoc.SaveGetObject( nPara );
ParaPortion* pPortion = GetParaPortions().SaveGetObject( nPara );
DBG_ASSERT( pNode, "Node nicht gefunden: RemoveCharAttribs" );
DBG_ASSERT( pPortion, "Portion nicht gefunden: RemoveCharAttribs" );
if ( !pNode )
return;
sal_uInt16 nAttr = 0;
EditCharAttribPtr pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
while ( pAttr )
{
if ( ( !pAttr->IsFeature() || bRemoveFeatures ) &&
( !nWhich || ( pAttr->GetItem()->Which() == nWhich ) ) )
{
pNode->GetCharAttribs().GetAttribs().Remove( nAttr );
delete pAttr;
nAttr--;
}
nAttr++;
pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr );
}
pPortion->MarkSelectionInvalid( 0, pNode->Len() );
}
void ImpEditEngine::SetParaAttribs( sal_uInt16 nPara, const SfxItemSet& rSet )
{
ContentNode* pNode = aEditDoc.SaveGetObject( nPara );
if ( !pNode )
return;
#ifdef EDITDEBUG
// FILE* fp = fopen( "d:\\debug.log", "a" );
// if ( fp )
// {
// fprintf( fp, "\n \n=> Absatz-Attribute: Absatz %i\n", nPara );
// DbgOutItemSet( fp, rSet, sal_True, sal_False );
// fclose( fp );
// }
#endif
if ( !( pNode->GetContentAttribs().GetItems() == rSet ) )
{
if ( IsUndoEnabled() && !IsInUndo() && aStatus.DoUndoAttribs() )
{
if ( rSet.GetPool() != &aEditDoc.GetItemPool() )
{
SfxItemSet aTmpSet( GetEmptyItemSet() );
aTmpSet.Put( rSet );
InsertUndo( new EditUndoSetParaAttribs( this, nPara, pNode->GetContentAttribs().GetItems(), aTmpSet ) );
}
else
{
InsertUndo( new EditUndoSetParaAttribs( this, nPara, pNode->GetContentAttribs().GetItems(), rSet ) );
}
}
pNode->GetContentAttribs().GetItems().Set( rSet );
if ( aStatus.UseCharAttribs() )
pNode->CreateDefFont();
ParaAttribsChanged( pNode );
}
}
const SfxItemSet& ImpEditEngine::GetParaAttribs( sal_uInt16 nPara ) const
{
ContentNode* pNode = aEditDoc.GetObject( nPara );
DBG_ASSERT( pNode, "Node nicht gefunden: GetParaAttribs" );
return pNode->GetContentAttribs().GetItems();
}
sal_Bool ImpEditEngine::HasParaAttrib( sal_uInt16 nPara, sal_uInt16 nWhich ) const
{
ContentNode* pNode = aEditDoc.GetObject( nPara );
DBG_ASSERT( pNode, "Node nicht gefunden: HasParaAttrib" );
return pNode->GetContentAttribs().HasItem( nWhich );
}
const SfxPoolItem& ImpEditEngine::GetParaAttrib( sal_uInt16 nPara, sal_uInt16 nWhich ) const
{
ContentNode* pNode = aEditDoc.GetObject( nPara );
DBG_ASSERT( pNode, "Node nicht gefunden: GetParaAttrib" );
return pNode->GetContentAttribs().GetItem( nWhich );
}
void ImpEditEngine::GetCharAttribs( sal_uInt16 nPara, EECharAttribArray& rLst ) const
{
rLst.Remove( 0, rLst.Count() );
ContentNode* pNode = aEditDoc.GetObject( nPara );
if ( pNode )
{
for ( sal_uInt16 nAttr = 0; nAttr < pNode->GetCharAttribs().Count(); nAttr++ )
{
EditCharAttribPtr pAttr = pNode->GetCharAttribs().GetAttribs()[ nAttr ];
EECharAttrib aEEAttr;
aEEAttr.pAttr = pAttr->GetItem();
aEEAttr.nPara = nPara;
aEEAttr.nStart = pAttr->GetStart();
aEEAttr.nEnd = pAttr->GetEnd();
rLst.Insert( aEEAttr, rLst.Count() );
}
}
}
void ImpEditEngine::ParaAttribsToCharAttribs( ContentNode* pNode )
{
pNode->GetCharAttribs().DeleteEmptyAttribs( GetEditDoc().GetItemPool() );
xub_StrLen nEndPos = pNode->Len();
for ( sal_uInt16 nWhich = EE_CHAR_START; nWhich <= EE_CHAR_END; nWhich++ )
{
if ( pNode->GetContentAttribs().HasItem( nWhich ) )
{
const SfxPoolItem& rItem = pNode->GetContentAttribs().GetItem( nWhich );
// Die Luecken auffuellen:
sal_uInt16 nLastEnd = 0;
EditCharAttrib* pAttr = pNode->GetCharAttribs().FindNextAttrib( nWhich, nLastEnd );
while ( pAttr )
{
nLastEnd = pAttr->GetEnd();
if ( pAttr->GetStart() > nLastEnd )
aEditDoc.InsertAttrib( pNode, nLastEnd, pAttr->GetStart(), rItem );
// #112831# Last Attr might go from 0xffff to 0x0000
pAttr = nLastEnd ? pNode->GetCharAttribs().FindNextAttrib( nWhich, nLastEnd ) : NULL;
}
// Und den Rest:
if ( nLastEnd < nEndPos )
aEditDoc.InsertAttrib( pNode, nLastEnd, nEndPos, rItem );
}
}
bFormatted = sal_False;
// Portion braucht hier nicht invalidiert werden, geschieht woanders.
}
IdleFormattter::IdleFormattter()
{
pView = 0;
nRestarts = 0;
}
IdleFormattter::~IdleFormattter()
{
pView = 0;
}
void IdleFormattter::DoIdleFormat( EditView* pV )
{
pView = pV;
if ( IsActive() )
nRestarts++;
if ( nRestarts > 4 )
ForceTimeout();
else
Start();
}
void IdleFormattter::ForceTimeout()
{
if ( IsActive() )
{
Stop();
((Link&)GetTimeoutHdl()).Call( this );
}
}
ImplIMEInfos::ImplIMEInfos( const EditPaM& rPos, const String& rOldTextAfterStartPos )
: aOldTextAfterStartPos( rOldTextAfterStartPos )
{
aPos = rPos;
nLen = 0;
bCursor = sal_True;
pAttribs = NULL;
bWasCursorOverwrite = sal_False;
}
ImplIMEInfos::~ImplIMEInfos()
{
delete[] pAttribs;
}
void ImplIMEInfos::CopyAttribs( const sal_uInt16* pA, sal_uInt16 nL )
{
nLen = nL;
delete pAttribs;
pAttribs = new sal_uInt16[ nL ];
memcpy( pAttribs, pA, nL*sizeof(sal_uInt16) );
}
void ImplIMEInfos::DestroyAttribs()
{
delete[] pAttribs;
pAttribs = NULL;
nLen = 0;
}