/* -*- 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 #include "impedit.hxx" #include #include "editdbg.hxx" #include #include #include 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(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(&rHint); if ( pStyleSheetHint ) { DBG_ASSERT( dynamic_cast< const SfxStyleSheet* >(pStyleSheetHint->GetStyleSheet()) != nullptr, "No SfxStyleSheet!" ); SfxStyleSheet* pStyle = static_cast( 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(&rBC); SfxHintId nId = rHint.GetId(); if ( nId == SfxHintId::Dying ) { RemoveStyleFromParagraphs( pStyle ); } else if ( nId == SfxHintId::DataChanged ) { UpdateParagraphsWithStyleSheet( pStyle ); } } } if(dynamic_cast(&rBC) != nullptr && rHint.GetId() == SfxHintId::Dying) Dispose(); } std::unique_ptr 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 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].get(); 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 pUndo, bool bTryMerge ) { DBG_ASSERT( !IsInUndo(), "InsertUndo in Undo mode!" ); if ( pUndoMarkSelection ) { GetUndoManager().AddUndoAction( std::make_unique(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 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! ContentNode* pNode = const_cast(aEditDoc.GetObject(nPara)); DBG_ASSERT( pNode, "GetAttribs - unknown paragraph!" ); DBG_ASSERT( nStart <= nEnd, "getAttribs: Start > End not supported!" ); SfxItemSet aAttribs( const_cast(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(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 { // OptimizeRagnge() 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 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 & 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, bool bRemoveParaAttribs, sal_uInt16 nWhich ) { aSel.Adjust( aEditDoc ); sal_Int32 nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() ); sal_Int32 nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() ); const SfxItemSet* _pEmptyItemSet = bRemoveParaAttribs ? &GetEmptyItemSet() : nullptr; if ( IsUndoEnabled() && !IsInUndo() && aStatus.DoUndoAttribs() ) { // Possibly a special Undo, or itemset* std::unique_ptr 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 { // 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 ) ) { if ( IsUndoEnabled() && !IsInUndo() && aStatus.DoUndoAttribs() ) { if ( rSet.GetPool() != &aEditDoc.GetItemPool() ) { SfxItemSet aTmpSet( GetEmptyItemSet() ); aTmpSet.Put( rSet ); InsertUndo(std::make_unique(pEditEngine, nPara, pNode->GetContentAttribs().GetItems(), aTmpSet)); } else { InsertUndo(std::make_unique(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& rLst ) const { rLst.clear(); const ContentNode* pNode = aEditDoc.GetObject( nPara ); if ( pNode ) { 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: */