summaryrefslogtreecommitdiffstats
path: root/editeng/source/editeng/impedit5.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'editeng/source/editeng/impedit5.cxx')
-rw-r--r--editeng/source/editeng/impedit5.cxx844
1 files changed, 844 insertions, 0 deletions
diff --git a/editeng/source/editeng/impedit5.cxx b/editeng/source/editeng/impedit5.cxx
new file mode 100644
index 000000000..b99d8c4a5
--- /dev/null
+++ b/editeng/source/editeng/impedit5.cxx
@@ -0,0 +1,844 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include <memory>
+#include "impedit.hxx"
+#include <editeng/editeng.hxx>
+#include <svl/hint.hxx>
+#include <sfx2/app.hxx>
+
+void ImpEditEngine::SetStyleSheetPool( SfxStyleSheetPool* pSPool )
+{
+ if ( pStylePool != pSPool )
+ {
+ pStylePool = pSPool;
+ }
+}
+
+const SfxStyleSheet* ImpEditEngine::GetStyleSheet( sal_Int32 nPara ) const
+{
+ const ContentNode* pNode = aEditDoc.GetObject( nPara );
+ return pNode ? pNode->GetContentAttribs().GetStyleSheet() : nullptr;
+}
+
+SfxStyleSheet* ImpEditEngine::GetStyleSheet( sal_Int32 nPara )
+{
+ ContentNode* pNode = aEditDoc.GetObject( nPara );
+ return pNode ? pNode->GetContentAttribs().GetStyleSheet() : nullptr;
+}
+
+void ImpEditEngine::SetStyleSheet( EditSelection aSel, SfxStyleSheet* pStyle )
+{
+ aSel.Adjust( aEditDoc );
+
+ sal_Int32 nStartPara = aEditDoc.GetPos( aSel.Min().GetNode() );
+ sal_Int32 nEndPara = aEditDoc.GetPos( aSel.Max().GetNode() );
+
+ bool _bUpdate = GetUpdateMode();
+ SetUpdateMode( false );
+
+ for ( sal_Int32 n = nStartPara; n <= nEndPara; n++ )
+ SetStyleSheet( n, pStyle );
+
+ SetUpdateMode( _bUpdate );
+}
+
+void ImpEditEngine::SetStyleSheet( sal_Int32 nPara, SfxStyleSheet* pStyle )
+{
+ DBG_ASSERT( GetStyleSheetPool() || !pStyle, "SetStyleSheet: No StyleSheetPool registered!" );
+ ContentNode* pNode = aEditDoc.GetObject( nPara );
+ SfxStyleSheet* pCurStyle = pNode->GetStyleSheet();
+ if ( pStyle != pCurStyle )
+ {
+ if ( IsUndoEnabled() && !IsInUndo() && aStatus.DoUndoAttribs() )
+ {
+ OUString aPrevStyleName;
+ if ( pCurStyle )
+ aPrevStyleName = pCurStyle->GetName();
+
+ OUString aNewStyleName;
+ if ( pStyle )
+ aNewStyleName = pStyle->GetName();
+
+ InsertUndo(
+ std::make_unique<EditUndoSetStyleSheet>(pEditEngine, aEditDoc.GetPos( pNode ),
+ aPrevStyleName, pCurStyle ? pCurStyle->GetFamily() : SfxStyleFamily::Para,
+ aNewStyleName, pStyle ? pStyle->GetFamily() : SfxStyleFamily::Para,
+ pNode->GetContentAttribs().GetItems() ) );
+ }
+ if ( pCurStyle )
+ EndListening( *pCurStyle );
+ pNode->SetStyleSheet( pStyle, aStatus.UseCharAttribs() );
+ if ( pStyle )
+ StartListening(*pStyle, DuplicateHandling::Prevent);
+ ParaAttribsChanged( pNode );
+ }
+ FormatAndUpdate();
+}
+
+void ImpEditEngine::UpdateParagraphsWithStyleSheet( SfxStyleSheet* pStyle )
+{
+ SvxFont aFontFromStyle;
+ CreateFont( aFontFromStyle, pStyle->GetItemSet() );
+
+ bool bUsed = false;
+ for ( sal_Int32 nNode = 0; nNode < aEditDoc.Count(); nNode++ )
+ {
+ ContentNode* pNode = aEditDoc.GetObject( nNode );
+ if ( pNode->GetStyleSheet() == pStyle )
+ {
+ bUsed = true;
+ if ( aStatus.UseCharAttribs() )
+ pNode->SetStyleSheet( pStyle, aFontFromStyle );
+ else
+ pNode->SetStyleSheet( pStyle, false );
+
+ ParaAttribsChanged( pNode );
+ }
+ }
+ if ( bUsed )
+ {
+ GetEditEnginePtr()->StyleSheetChanged( pStyle );
+ FormatAndUpdate();
+ }
+}
+
+void ImpEditEngine::RemoveStyleFromParagraphs( SfxStyleSheet const * pStyle )
+{
+ for ( sal_Int32 nNode = 0; nNode < aEditDoc.Count(); nNode++ )
+ {
+ ContentNode* pNode = aEditDoc.GetObject(nNode);
+ if ( pNode->GetStyleSheet() == pStyle )
+ {
+ pNode->SetStyleSheet( nullptr );
+ ParaAttribsChanged( pNode );
+ }
+ }
+ FormatAndUpdate();
+}
+
+void ImpEditEngine::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
+{
+ // So that not a lot of unnecessary formatting is done when destructing:
+ if ( !bDowning )
+ {
+
+ const SfxStyleSheetHint* pStyleSheetHint = dynamic_cast<const SfxStyleSheetHint*>(&rHint);
+ if ( pStyleSheetHint )
+ {
+ DBG_ASSERT( dynamic_cast< const SfxStyleSheet* >(pStyleSheetHint->GetStyleSheet()) != nullptr, "No SfxStyleSheet!" );
+ SfxStyleSheet* pStyle = static_cast<SfxStyleSheet*>( pStyleSheetHint->GetStyleSheet() );
+ SfxHintId nId = pStyleSheetHint->GetId();
+ if ( ( nId == SfxHintId::StyleSheetInDestruction ) ||
+ ( nId == SfxHintId::StyleSheetErased ) )
+ {
+ RemoveStyleFromParagraphs( pStyle );
+ }
+ else if ( nId == SfxHintId::StyleSheetModified )
+ {
+ UpdateParagraphsWithStyleSheet( pStyle );
+ }
+ }
+ else if ( dynamic_cast< const SfxStyleSheet* >(&rBC) != nullptr )
+ {
+ SfxStyleSheet* pStyle = static_cast<SfxStyleSheet*>(&rBC);
+ SfxHintId nId = rHint.GetId();
+ if ( nId == SfxHintId::Dying )
+ {
+ RemoveStyleFromParagraphs( pStyle );
+ }
+ else if ( nId == SfxHintId::DataChanged )
+ {
+ UpdateParagraphsWithStyleSheet( pStyle );
+ }
+ }
+ }
+ if(dynamic_cast<const SfxApplication*>(&rBC) != nullptr && rHint.GetId() == SfxHintId::Dying)
+ Dispose();
+}
+
+std::unique_ptr<EditUndoSetAttribs> ImpEditEngine::CreateAttribUndo( EditSelection aSel, const SfxItemSet& rSet )
+{
+ DBG_ASSERT( !aSel.DbgIsBuggy( aEditDoc ), "CreateAttribUndo: Incorrect selection ");
+ aSel.Adjust( aEditDoc );
+
+ ESelection aESel( CreateESel( aSel ) );
+
+ sal_Int32 nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() );
+ sal_Int32 nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() );
+
+ DBG_ASSERT( nStartNode <= nEndNode, "CreateAttribUndo: Start > End ?!" );
+
+ std::unique_ptr<EditUndoSetAttribs> pUndo;
+ if ( rSet.GetPool() != &aEditDoc.GetItemPool() )
+ {
+ SfxItemSet aTmpSet( GetEmptyItemSet() );
+ aTmpSet.Put( rSet );
+ pUndo.reset( new EditUndoSetAttribs(pEditEngine, aESel, aTmpSet) );
+ }
+ else
+ {
+ pUndo.reset( new EditUndoSetAttribs(pEditEngine, aESel, rSet) );
+ }
+
+ SfxItemPool* pPool = pUndo->GetNewAttribs().GetPool();
+
+ for ( sal_Int32 nPara = nStartNode; nPara <= nEndNode; nPara++ )
+ {
+ ContentNode* pNode = aEditDoc.GetObject( nPara );
+ DBG_ASSERT( aEditDoc.GetObject( nPara ), "Node not found: CreateAttribUndo" );
+ ContentAttribsInfo* pInf = new ContentAttribsInfo( pNode->GetContentAttribs().GetItems() );
+ pUndo->AppendContentInfo(pInf);
+
+ for ( sal_Int32 nAttr = 0; nAttr < pNode->GetCharAttribs().Count(); nAttr++ )
+ {
+ const EditCharAttrib& rAttr = *pNode->GetCharAttribs().GetAttribs()[nAttr];
+ if (rAttr.GetLen())
+ {
+ EditCharAttrib* pNew = MakeCharAttrib(*pPool, *rAttr.GetItem(), rAttr.GetStart(), rAttr.GetEnd());
+ pInf->AppendCharAttrib(pNew);
+ }
+ }
+ }
+ return pUndo;
+}
+
+ViewShellId ImpEditEngine::CreateViewShellId()
+{
+ ViewShellId nRet(-1);
+
+ const EditView* pEditView = pEditEngine ? pEditEngine->GetActiveView() : nullptr;
+ const OutlinerViewShell* pViewShell = pEditView ? pEditView->GetImpEditView()->GetViewShell() : nullptr;
+ if (pViewShell)
+ nRet = pViewShell->GetViewShellId();
+
+ return nRet;
+}
+
+void ImpEditEngine::UndoActionStart( sal_uInt16 nId, const ESelection& aSel )
+{
+ if ( IsUndoEnabled() && !IsInUndo() )
+ {
+ GetUndoManager().EnterListAction( GetEditEnginePtr()->GetUndoComment( nId ), OUString(), nId, CreateViewShellId() );
+ DBG_ASSERT( !pUndoMarkSelection, "UndoAction SelectionMarker?" );
+ pUndoMarkSelection.reset(new ESelection( aSel ));
+ }
+}
+
+void ImpEditEngine::UndoActionStart( sal_uInt16 nId )
+{
+ if ( IsUndoEnabled() && !IsInUndo() )
+ {
+ GetUndoManager().EnterListAction( GetEditEnginePtr()->GetUndoComment( nId ), OUString(), nId, CreateViewShellId() );
+ DBG_ASSERT( !pUndoMarkSelection, "UndoAction SelectionMarker?" );
+ }
+}
+
+void ImpEditEngine::UndoActionEnd()
+{
+ if ( IsUndoEnabled() && !IsInUndo() )
+ {
+ GetUndoManager().LeaveListAction();
+ pUndoMarkSelection.reset();
+ }
+}
+
+void ImpEditEngine::InsertUndo( std::unique_ptr<EditUndo> pUndo, bool bTryMerge )
+{
+ DBG_ASSERT( !IsInUndo(), "InsertUndo in Undo mode!" );
+ if ( pUndoMarkSelection )
+ {
+ GetUndoManager().AddUndoAction( std::make_unique<EditUndoMarkSelection>(pEditEngine, *pUndoMarkSelection) );
+ pUndoMarkSelection.reset();
+ }
+ GetUndoManager().AddUndoAction( std::move(pUndo), bTryMerge );
+
+ mbLastTryMerge = bTryMerge;
+}
+
+void ImpEditEngine::ResetUndoManager()
+{
+ if ( HasUndoManager() )
+ GetUndoManager().Clear();
+}
+
+void ImpEditEngine::EnableUndo( bool bEnable )
+{
+ // When switching the mode Delete list:
+ if ( bEnable != IsUndoEnabled() )
+ ResetUndoManager();
+
+ bUndoEnabled = bEnable;
+}
+
+void ImpEditEngine::Undo( EditView* pView )
+{
+ if ( HasUndoManager() && GetUndoManager().GetUndoActionCount() )
+ {
+ SetActiveView( pView );
+ GetUndoManager().Undo();
+ }
+}
+
+void ImpEditEngine::Redo( EditView* pView )
+{
+ if ( HasUndoManager() && GetUndoManager().GetRedoActionCount() )
+ {
+ SetActiveView( pView );
+ GetUndoManager().Redo();
+ }
+}
+
+SfxItemSet ImpEditEngine::GetAttribs( EditSelection aSel, EditEngineAttribs nOnlyHardAttrib )
+{
+
+ aSel.Adjust( aEditDoc );
+
+ SfxItemSet aCurSet( GetEmptyItemSet() );
+
+ sal_Int32 nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() );
+ sal_Int32 nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() );
+
+ // iterate over the paragraphs ...
+ for ( sal_Int32 nNode = nStartNode; nNode <= nEndNode; nNode++ )
+ {
+ ContentNode* pNode = aEditDoc.GetObject( nNode );
+ DBG_ASSERT( aEditDoc.GetObject( nNode ), "Node not found: GetAttrib" );
+
+ const sal_Int32 nStartPos = nNode==nStartNode ? aSel.Min().GetIndex() : 0;
+ const sal_Int32 nEndPos = nNode==nEndNode ? aSel.Max().GetIndex() : pNode->Len(); // Can also be == nStart!
+
+ // Problem: Templates...
+ // => Other way:
+ // 1) Hard character attributes, as usual...
+ // 2) Examine Style and paragraph attributes only when OFF...
+
+ // First the very hard formatting...
+ EditDoc::FindAttribs( pNode, nStartPos, nEndPos, aCurSet );
+
+ if( nOnlyHardAttrib != EditEngineAttribs::OnlyHard )
+ {
+ // and then paragraph formatting and template...
+ for ( sal_uInt16 nWhich = EE_ITEMS_START; nWhich <= EE_CHAR_END; nWhich++)
+ {
+ if ( aCurSet.GetItemState( nWhich ) == SfxItemState::DEFAULT )
+ {
+ if ( nOnlyHardAttrib == EditEngineAttribs::All )
+ {
+ const SfxPoolItem& rItem = pNode->GetContentAttribs().GetItem( nWhich );
+ aCurSet.Put( rItem );
+ }
+ else if ( pNode->GetContentAttribs().GetItems().GetItemState( nWhich ) == SfxItemState::SET )
+ {
+ const SfxPoolItem& rItem = pNode->GetContentAttribs().GetItems().Get( nWhich );
+ aCurSet.Put( rItem );
+ }
+ }
+ else if ( aCurSet.GetItemState( nWhich ) == SfxItemState::SET )
+ {
+ const SfxPoolItem* pItem = nullptr;
+ if ( nOnlyHardAttrib == EditEngineAttribs::All )
+ {
+ pItem = &pNode->GetContentAttribs().GetItem( nWhich );
+ }
+ else if ( pNode->GetContentAttribs().GetItems().GetItemState( nWhich ) == SfxItemState::SET )
+ {
+ pItem = &pNode->GetContentAttribs().GetItems().Get( nWhich );
+ }
+ // pItem can only be NULL when nOnlyHardAttrib...
+ if ( !pItem || ( *pItem != aCurSet.Get( nWhich ) ) )
+ {
+ // Problem: When Paragraph style with for example font,
+ // but the Font is hard and completely different,
+ // wrong in selection if invalidated....
+ // => better not invalidate, instead CHANGE!
+ // It would be better to fill each paragraph with
+ // an itemset and compare this in large.
+ if ( nWhich <= EE_PARA_END )
+ aCurSet.InvalidateItem( nWhich );
+ }
+ }
+ }
+ }
+ }
+
+ // fill empty slots with defaults ...
+ if ( nOnlyHardAttrib == EditEngineAttribs::All )
+ {
+ for ( sal_uInt16 nWhich = EE_ITEMS_START; nWhich <= EE_CHAR_END; nWhich++ )
+ {
+ if ( aCurSet.GetItemState( nWhich ) == SfxItemState::DEFAULT )
+ {
+ aCurSet.Put( aEditDoc.GetItemPool().GetDefaultItem( nWhich ) );
+ }
+ }
+ }
+ return aCurSet;
+}
+
+
+SfxItemSet ImpEditEngine::GetAttribs( sal_Int32 nPara, sal_Int32 nStart, sal_Int32 nEnd, GetAttribsFlags nFlags ) const
+{
+ // Optimized function with fewer Puts(), which cause unnecessary cloning from default items.
+ // If this works, change GetAttribs( EditSelection ) to use this for each paragraph and merge the results!
+
+
+ ContentNode* pNode = const_cast<ContentNode*>(aEditDoc.GetObject(nPara));
+ DBG_ASSERT( pNode, "GetAttribs - unknown paragraph!" );
+ DBG_ASSERT( nStart <= nEnd, "getAttribs: Start > End not supported!" );
+
+ SfxItemSet aAttribs( const_cast<ImpEditEngine*>(this)->GetEmptyItemSet() );
+
+ if ( pNode )
+ {
+ if ( nEnd > pNode->Len() )
+ nEnd = pNode->Len();
+
+ if ( nStart > nEnd )
+ nStart = nEnd;
+
+ // StyleSheet / Parattribs...
+
+ if ( pNode->GetStyleSheet() && ( nFlags & GetAttribsFlags::STYLESHEET ) )
+ aAttribs.Set(pNode->GetStyleSheet()->GetItemSet());
+
+ if ( nFlags & GetAttribsFlags::PARAATTRIBS )
+ aAttribs.Put( pNode->GetContentAttribs().GetItems() );
+
+ // CharAttribs...
+
+ if ( nFlags & GetAttribsFlags::CHARATTRIBS )
+ {
+ // Make testing easier...
+ const SfxItemPool& rPool = GetEditDoc().GetItemPool();
+ pNode->GetCharAttribs().OptimizeRanges(const_cast<SfxItemPool&>(rPool));
+
+ const CharAttribList::AttribsType& rAttrs = pNode->GetCharAttribs().GetAttribs();
+ for (const auto & nAttr : rAttrs)
+ {
+ const EditCharAttrib& rAttr = *nAttr;
+
+ if ( nStart == nEnd )
+ {
+ sal_Int32 nCursorPos = nStart;
+ if ( ( rAttr.GetStart() <= nCursorPos ) && ( rAttr.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 ( ( rAttr.GetStart() < nCursorPos ) || rAttr.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( *rAttr.GetItem() );
+ }
+ }
+ }
+ else
+ {
+ // Check every attribute covering the area, partial or full.
+ if ( ( rAttr.GetStart() < nEnd ) && ( rAttr.GetEnd() > nStart ) )
+ {
+ if ( ( rAttr.GetStart() <= nStart ) && ( rAttr.GetEnd() >= nEnd ) )
+ {
+ // full coverage
+ aAttribs.Put( *rAttr.GetItem() );
+ }
+ else
+ {
+ // OptimizeRanges() assures that not the same attr can follow for full coverage
+ // only partial, check with current, when using para/style, otherwise invalid.
+ if ( !( nFlags & (GetAttribsFlags::PARAATTRIBS|GetAttribsFlags::STYLESHEET) ) ||
+ ( *rAttr.GetItem() != aAttribs.Get( rAttr.Which() ) ) )
+ {
+ aAttribs.InvalidateItem( rAttr.Which() );
+ }
+ }
+ }
+ }
+
+ if ( rAttr.GetStart() > nEnd )
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ return aAttribs;
+}
+
+
+void ImpEditEngine::SetAttribs( EditSelection aSel, const SfxItemSet& rSet, SetAttribsMode nSpecial )
+{
+ aSel.Adjust( aEditDoc );
+
+ // When no selection => use the Attribute on the word.
+ // ( the RTF-parser should actually never call the Method without a Range )
+ if ( nSpecial == SetAttribsMode::WholeWord && !aSel.HasRange() )
+ aSel = SelectWord( aSel, css::i18n::WordType::ANYWORD_IGNOREWHITESPACES, false );
+
+ sal_Int32 nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() );
+ sal_Int32 nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() );
+
+ if ( IsUndoEnabled() && !IsInUndo() && aStatus.DoUndoAttribs() )
+ {
+ std::unique_ptr<EditUndoSetAttribs> pUndo = CreateAttribUndo( aSel, rSet );
+ pUndo->SetSpecial( nSpecial );
+ InsertUndo( std::move(pUndo) );
+ }
+
+ bool bCheckLanguage = false;
+ if ( GetStatus().DoOnlineSpelling() )
+ {
+ bCheckLanguage = ( rSet.GetItemState( EE_CHAR_LANGUAGE ) == SfxItemState::SET ) ||
+ ( rSet.GetItemState( EE_CHAR_LANGUAGE_CJK ) == SfxItemState::SET ) ||
+ ( rSet.GetItemState( EE_CHAR_LANGUAGE_CTL ) == SfxItemState::SET );
+ }
+
+ // iterate over the paragraphs ...
+ for ( sal_Int32 nNode = nStartNode; nNode <= nEndNode; nNode++ )
+ {
+ bool bParaAttribFound = false;
+ bool bCharAttribFound = false;
+
+ DBG_ASSERT( aEditDoc.GetObject( nNode ), "Node not found: SetAttribs" );
+ DBG_ASSERT( GetParaPortions().SafeGetObject( nNode ), "Portion not found: SetAttribs" );
+
+ ContentNode* pNode = aEditDoc.GetObject( nNode );
+ ParaPortion* pPortion = GetParaPortions()[nNode];
+
+ const sal_Int32 nStartPos = nNode==nStartNode ? aSel.Min().GetIndex() : 0;
+ const sal_Int32 nEndPos = nNode==nEndNode ? aSel.Max().GetIndex() : pNode->Len(); // can also be == nStart!
+
+ // Iterate over the Items...
+ for ( sal_uInt16 nWhich = EE_ITEMS_START; nWhich <= EE_CHAR_END; nWhich++)
+ {
+ if ( rSet.GetItemState( nWhich ) == SfxItemState::SET )
+ {
+ const SfxPoolItem& rItem = rSet.Get( nWhich );
+ if ( nWhich <= EE_PARA_END )
+ {
+ pNode->GetContentAttribs().GetItems().Put( rItem );
+ bParaAttribFound = true;
+ }
+ else
+ {
+ aEditDoc.InsertAttrib( pNode, nStartPos, nEndPos, rItem );
+ bCharAttribFound = true;
+ if ( nSpecial == SetAttribsMode::Edge )
+ {
+ CharAttribList::AttribsType& rAttribs = pNode->GetCharAttribs().GetAttribs();
+ for (std::unique_ptr<EditCharAttrib> & rAttrib : rAttribs)
+ {
+ EditCharAttrib& rAttr = *rAttrib;
+ if (rAttr.GetStart() > nEndPos)
+ break;
+
+ if (rAttr.GetEnd() == nEndPos && rAttr.Which() == nWhich)
+ {
+ rAttr.SetEdge(true);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if ( bParaAttribFound )
+ {
+ ParaAttribsChanged( pPortion->GetNode() );
+ }
+ else if ( bCharAttribFound )
+ {
+ bFormatted = false;
+ if ( !pNode->Len() || ( nStartPos != nEndPos ) )
+ {
+ pPortion->MarkSelectionInvalid( nStartPos );
+ if ( bCheckLanguage )
+ pNode->GetWrongList()->SetInvalidRange(nStartPos, nEndPos);
+ }
+ }
+ }
+}
+
+void ImpEditEngine::RemoveCharAttribs( EditSelection aSel, EERemoveParaAttribsMode eMode, sal_uInt16 nWhich )
+{
+ aSel.Adjust( aEditDoc );
+
+ sal_Int32 nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() );
+ sal_Int32 nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() );
+ bool bRemoveParaAttribs = eMode == EERemoveParaAttribsMode::RemoveAll;
+ const SfxItemSet* _pEmptyItemSet = bRemoveParaAttribs ? &GetEmptyItemSet() : nullptr;
+
+ if ( IsUndoEnabled() && !IsInUndo() && aStatus.DoUndoAttribs() )
+ {
+ // Possibly a special Undo, or itemset*
+ std::unique_ptr<EditUndoSetAttribs> pUndo = CreateAttribUndo( aSel, GetEmptyItemSet() );
+ pUndo->SetRemoveAttribs( true );
+ pUndo->SetRemoveParaAttribs( bRemoveParaAttribs );
+ pUndo->SetRemoveWhich( nWhich );
+ InsertUndo( std::move(pUndo) );
+ }
+
+ // iterate over the paragraphs ...
+ for ( sal_Int32 nNode = nStartNode; nNode <= nEndNode; nNode++ )
+ {
+ ContentNode* pNode = aEditDoc.GetObject( nNode );
+ ParaPortion* pPortion = GetParaPortions()[nNode];
+
+ DBG_ASSERT( aEditDoc.GetObject( nNode ), "Node not found: SetAttribs" );
+ DBG_ASSERT( GetParaPortions().SafeGetObject( nNode ), "Portion not found: SetAttribs" );
+
+ const sal_Int32 nStartPos = nNode==nStartNode ? aSel.Min().GetIndex() : 0;
+ const sal_Int32 nEndPos = nNode==nEndNode ? aSel.Max().GetIndex() : pNode->Len(); // can also be == nStart!
+
+ // Optimize: If whole paragraph, then RemoveCharAttribs (nPara)?
+ bool bChanged = aEditDoc.RemoveAttribs( pNode, nStartPos, nEndPos, nWhich );
+ if ( bRemoveParaAttribs )
+ {
+ SetParaAttribs( nNode, *_pEmptyItemSet ); // Invalidated
+ }
+ else if (eMode == EERemoveParaAttribsMode::RemoveCharItems)
+ {
+ // For 'Format-Standard' also the character attributes should
+ // disappear, which were set as paragraph attributes by the
+ // DrawingEngine. These could not have been set by the user anyway.
+
+ // #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 = false;
+ pPortion->MarkSelectionInvalid( nStartPos );
+ }
+ }
+}
+
+void ImpEditEngine::RemoveCharAttribs( sal_Int32 nPara, sal_uInt16 nWhich, bool bRemoveFeatures )
+{
+ ContentNode* pNode = aEditDoc.GetObject( nPara );
+ ParaPortion* pPortion = GetParaPortions().SafeGetObject( nPara );
+
+ DBG_ASSERT( pNode, "Node not found: RemoveCharAttribs" );
+ DBG_ASSERT( pPortion, "Portion not found: RemoveCharAttribs" );
+
+ if ( !pNode || !pPortion )
+ return;
+
+ size_t nAttr = 0;
+ CharAttribList::AttribsType& rAttrs = pNode->GetCharAttribs().GetAttribs();
+ EditCharAttrib* pAttr = GetAttrib(rAttrs, nAttr);
+ while ( pAttr )
+ {
+ if ( ( !pAttr->IsFeature() || bRemoveFeatures ) &&
+ ( !nWhich || ( pAttr->GetItem()->Which() == nWhich ) ) )
+ {
+ pNode->GetCharAttribs().Remove(nAttr);
+ nAttr--;
+ }
+ nAttr++;
+ pAttr = GetAttrib(rAttrs, nAttr);
+ }
+
+#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
+ CharAttribList::DbgCheckAttribs(pNode->GetCharAttribs());
+#endif
+
+ pPortion->MarkSelectionInvalid( 0 );
+}
+
+void ImpEditEngine::SetParaAttribs( sal_Int32 nPara, const SfxItemSet& rSet )
+{
+ ContentNode* pNode = aEditDoc.GetObject( nPara );
+
+ if ( !pNode )
+ return;
+
+ if ( pNode->GetContentAttribs().GetItems() == rSet )
+ return;
+
+ if ( IsUndoEnabled() && !IsInUndo() && aStatus.DoUndoAttribs() )
+ {
+ if ( rSet.GetPool() != &aEditDoc.GetItemPool() )
+ {
+ SfxItemSet aTmpSet( GetEmptyItemSet() );
+ aTmpSet.Put( rSet );
+ InsertUndo(std::make_unique<EditUndoSetParaAttribs>(pEditEngine, nPara, pNode->GetContentAttribs().GetItems(), aTmpSet));
+ }
+ else
+ {
+ InsertUndo(std::make_unique<EditUndoSetParaAttribs>(pEditEngine, nPara, pNode->GetContentAttribs().GetItems(), rSet));
+ }
+ }
+
+ bool bCheckLanguage = ( rSet.GetItemState( EE_CHAR_LANGUAGE ) == SfxItemState::SET ) ||
+ ( rSet.GetItemState( EE_CHAR_LANGUAGE_CJK ) == SfxItemState::SET ) ||
+ ( rSet.GetItemState( EE_CHAR_LANGUAGE_CTL ) == SfxItemState::SET );
+
+ pNode->GetContentAttribs().GetItems().Set( rSet );
+
+ if ( bCheckLanguage && pNode->GetWrongList() )
+ pNode->GetWrongList()->ResetInvalidRange(0, pNode->Len());
+
+ if ( aStatus.UseCharAttribs() )
+ pNode->CreateDefFont();
+
+ ParaAttribsChanged( pNode );
+}
+
+const SfxItemSet& ImpEditEngine::GetParaAttribs( sal_Int32 nPara ) const
+{
+ const ContentNode* pNode = aEditDoc.GetObject( nPara );
+ assert(pNode && "Node not found: GetParaAttribs");
+ return pNode->GetContentAttribs().GetItems();
+}
+
+bool ImpEditEngine::HasParaAttrib( sal_Int32 nPara, sal_uInt16 nWhich ) const
+{
+ const ContentNode* pNode = aEditDoc.GetObject( nPara );
+ assert(pNode && "Node not found: HasParaAttrib");
+ return pNode->GetContentAttribs().HasItem( nWhich );
+}
+
+const SfxPoolItem& ImpEditEngine::GetParaAttrib( sal_Int32 nPara, sal_uInt16 nWhich ) const
+{
+ const ContentNode* pNode = aEditDoc.GetObject(nPara);
+ assert(pNode && "Node not found: GetParaAttrib");
+ return pNode->GetContentAttribs().GetItem(nWhich);
+}
+
+void ImpEditEngine::GetCharAttribs( sal_Int32 nPara, std::vector<EECharAttrib>& rLst ) const
+{
+ rLst.clear();
+ const ContentNode* pNode = aEditDoc.GetObject( nPara );
+ if ( !pNode )
+ return;
+
+ rLst.reserve(pNode->GetCharAttribs().Count());
+ const CharAttribList::AttribsType& rAttrs = pNode->GetCharAttribs().GetAttribs();
+ for (const auto & i : rAttrs)
+ {
+ const EditCharAttrib& rAttr = *i;
+ EECharAttrib aEEAttr;
+ aEEAttr.pAttr = rAttr.GetItem();
+ aEEAttr.nStart = rAttr.GetStart();
+ aEEAttr.nEnd = rAttr.GetEnd();
+ rLst.push_back(aEEAttr);
+ }
+}
+
+void ImpEditEngine::ParaAttribsToCharAttribs( ContentNode* pNode )
+{
+ pNode->GetCharAttribs().DeleteEmptyAttribs( GetEditDoc().GetItemPool() );
+ sal_Int32 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 );
+ // Fill the gap:
+ sal_Int32 nLastEnd = 0;
+ const 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 ) : nullptr;
+ }
+
+ // And the Rest:
+ if ( nLastEnd < nEndPos )
+ aEditDoc.InsertAttrib( pNode, nLastEnd, nEndPos, rItem );
+ }
+ }
+ bFormatted = false;
+ // Portion does not need to be invalidated here, happens elsewhere.
+}
+
+IdleFormattter::IdleFormattter()
+{
+ pView = nullptr;
+ nRestarts = 0;
+}
+
+IdleFormattter::~IdleFormattter()
+{
+ pView = nullptr;
+}
+
+void IdleFormattter::DoIdleFormat( EditView* pV )
+{
+ pView = pV;
+
+ if ( IsActive() )
+ nRestarts++;
+
+ if ( nRestarts > 4 )
+ ForceTimeout();
+ else
+ Start();
+}
+
+void IdleFormattter::ForceTimeout()
+{
+ if ( IsActive() )
+ {
+ Stop();
+ Invoke();
+ }
+}
+
+ImplIMEInfos::ImplIMEInfos( const EditPaM& rPos, const OUString& rOldTextAfterStartPos )
+ : aOldTextAfterStartPos( rOldTextAfterStartPos ),
+ aPos(rPos),
+ nLen(0),
+ bWasCursorOverwrite(false)
+ {
+ }
+
+ImplIMEInfos::~ImplIMEInfos()
+{
+}
+
+void ImplIMEInfos::CopyAttribs( const ExtTextInputAttr* pA, sal_uInt16 nL )
+{
+ nLen = nL;
+ pAttribs.reset( new ExtTextInputAttr[ nL ] );
+ memcpy( pAttribs.get(), pA, nL*sizeof(ExtTextInputAttr) );
+}
+
+void ImplIMEInfos::DestroyAttribs()
+{
+ pAttribs.reset();
+ nLen = 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */