summaryrefslogtreecommitdiff
path: root/editeng/source/editeng/impedit2.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'editeng/source/editeng/impedit2.cxx')
-rw-r--r--editeng/source/editeng/impedit2.cxx2065
1 files changed, 1146 insertions, 919 deletions
diff --git a/editeng/source/editeng/impedit2.cxx b/editeng/source/editeng/impedit2.cxx
index 8ea35eb3e91f..da4d851b3315 100644
--- a/editeng/source/editeng/impedit2.cxx
+++ b/editeng/source/editeng/impedit2.cxx
@@ -30,6 +30,8 @@
#include "eeobj.hxx"
#include <editeng/txtrange.hxx>
#include <sfx2/app.hxx>
+#include <sfx2/mieclip.hxx>
+#include <sfx2/viewsh.hxx>
#include <svtools/colorcfg.hxx>
#include <svl/ctloptions.hxx>
#include <unotools/securityoptions.hxx>
@@ -39,6 +41,7 @@
#include <editeng/adjustitem.hxx>
#include <editeng/frmdiritem.hxx>
#include <editeng/justifyitem.hxx>
+#include <editeng/udlnitem.hxx>
#include <com/sun/star/i18n/CharacterIteratorMode.hpp>
#include <com/sun/star/i18n/WordType.hpp>
@@ -48,6 +51,7 @@
#include <com/sun/star/system/SystemShellExecute.hpp>
#include <com/sun/star/system/SystemShellExecuteFlags.hpp>
#include <com/sun/star/system/XSystemShellExecute.hpp>
+#include <com/sun/star/i18n/UnicodeType.hpp>
#include <rtl/character.hxx>
@@ -57,14 +61,17 @@
#include <sot/exchange.hxx>
#include <sot/formats.hxx>
#include <svl/asiancfg.hxx>
+#include <svl/voiditem.hxx>
#include <i18nutil/unicode.hxx>
-#include <tools/diagnose_ex.h>
+#include <comphelper/diagnose_ex.hxx>
+#include <comphelper/flagguard.hxx>
#include <comphelper/lok.hxx>
#include <comphelper/processfactory.hxx>
-#include <unotools/configmgr.hxx>
+#include <comphelper/configuration.hxx>
#include <unicode/ubidi.h>
#include <algorithm>
+#include <limits>
#include <memory>
#include <string_view>
#include <fstream>
@@ -82,70 +89,71 @@ static sal_uInt16 lcl_CalcExtraSpace( const SvxLineSpacingItem& rLSItem )
return nExtra;
}
+constexpr tools::Long constMaxPaperSize = 0x7FFFFFFF;
+
ImpEditEngine::ImpEditEngine( EditEngine* pEE, SfxItemPool* pItemPool ) :
pSharedVCL(EditDLL::Get().GetSharedVclResources()),
- aPaperSize( 0x7FFFFFFF, 0x7FFFFFFF ),
- aMinAutoPaperSize( 0x0, 0x0 ),
- aMaxAutoPaperSize( 0x7FFFFFFF, 0x7FFFFFFF ),
- aEditDoc( pItemPool ),
- pEditEngine(pEE),
- pActiveView(nullptr),
- pStylePool(nullptr),
- pTextObjectPool(nullptr),
- pUndoManager(nullptr),
- aWordDelimiters(" .,;:-`'?!_=\"{}()[]"),
+ maPaperSize(constMaxPaperSize, constMaxPaperSize),
+ maMinAutoPaperSize(0, 0),
+ maMaxAutoPaperSize(constMaxPaperSize, constMaxPaperSize),
+ maEditDoc( pItemPool ),
+ mpEditEngine(pEE),
+ mpActiveView(nullptr),
+ mpStylePool(nullptr),
+ mpTextObjectPool(nullptr),
+ mpUndoManager(nullptr),
+ maWordDelimiters(" .,;:-`'?!_=\"{}()[]"),
maBackgroundColor(COL_AUTO),
- nStretchX(100),
- nStretchY(100),
- nAsianCompressionMode(CharCompressType::NONE),
- eDefaultHorizontalTextDirection(EEHorizontalTextDirection::Default),
- nBigTextObjectStart(20),
- eDefLanguage(LANGUAGE_DONTKNOW),
- nCurTextHeight(0),
- nCurTextHeightNTP(0),
- bKernAsianPunctuation(false),
- bAddExtLeading(false),
- bIsFormatting(false),
- bFormatted(false),
- bInSelection(false),
- bIsInUndo(false),
- bUpdate(true),
- bUndoEnabled(true),
- bDowning(false),
- bUseAutoColor(true),
- bForceAutoColor(false),
- bCallParaInsertedOrDeleted(false),
- bFirstWordCapitalization(true),
+ mbRoundToNearestPt(false),
+ mnAsianCompressionMode(CharCompressType::NONE),
+ meDefaultHorizontalTextDirection(EEHorizontalTextDirection::Default),
+ mnBigTextObjectStart(20),
+ meDefLanguage(LANGUAGE_DONTKNOW),
+ mnCurTextHeight(0),
+ mnCurTextHeightNTP(0),
+ maOnlineSpellTimer("editeng::ImpEditEngine aOnlineSpellTimer"),
+ maStatusTimer("editeng::ImpEditEngine aStatusTimer"),
+ mbKernAsianPunctuation(false),
+ mbAddExtLeading(false),
+ mbIsFormatting(false),
+ mbFormatted(false),
+ mbInSelection(false),
+ mbIsInUndo(false),
+ mbUpdateLayout(true),
+ mbUndoEnabled(true),
+ mbDowning(false),
+ mbUseAutoColor(true),
+ mbForceAutoColor(false),
+ mbCallParaInsertedOrDeleted(false),
+ mbFirstWordCapitalization(true),
mbLastTryMerge(false),
mbReplaceLeadingSingleQuotationMark(true),
+ mbSkipOutsideFormat(false),
+ mbFuzzing(comphelper::IsFuzzing()),
mbNbspRunNext(false)
{
- aStatus.GetControlWord() = EEControlBits::USECHARATTRIBS | EEControlBits::DOIDLEFORMAT |
+ maStatus.GetControlWord() = EEControlBits::USECHARATTRIBS | EEControlBits::DOIDLEFORMAT |
EEControlBits::PASTESPECIAL | EEControlBits::UNDOATTRIBS |
- EEControlBits::ALLOWBIGOBJS | EEControlBits::RTFSTYLESHEETS |
- EEControlBits::FORMAT100;
+ EEControlBits::ALLOWBIGOBJS | EEControlBits::RTFSTYLESHEETS;
- aSelEngine.SetFunctionSet( &aSelFuncSet );
+ maSelEngine.SetFunctionSet(&maSelFuncSet);
- aStatusTimer.SetTimeout( 200 );
- aStatusTimer.SetInvokeHandler( LINK( this, ImpEditEngine, StatusTimerHdl ) );
- aStatusTimer.SetDebugName( "editeng::ImpEditEngine aStatusTimer" );
+ maStatusTimer.SetTimeout(200);
+ maStatusTimer.SetInvokeHandler(LINK(this, ImpEditEngine, StatusTimerHdl));
- aIdleFormatter.SetPriority( TaskPriority::REPAINT );
- aIdleFormatter.SetInvokeHandler( LINK( this, ImpEditEngine, IdleFormatHdl ) );
- aIdleFormatter.SetDebugName( "editeng::ImpEditEngine aIdleFormatter" );
+ maIdleFormatter.SetPriority(TaskPriority::REPAINT);
+ maIdleFormatter.SetInvokeHandler(LINK(this, ImpEditEngine, IdleFormatHdl));
- aOnlineSpellTimer.SetTimeout( 100 );
- aOnlineSpellTimer.SetInvokeHandler( LINK( this, ImpEditEngine, OnlineSpellHdl ) );
- aOnlineSpellTimer.SetDebugName( "editeng::ImpEditEngine aOnlineSpellTimer" );
+ maOnlineSpellTimer.SetTimeout(100);
+ maOnlineSpellTimer.SetInvokeHandler(LINK( this, ImpEditEngine, OnlineSpellHdl));
// Access data already from here on!
SetRefDevice( nullptr );
InitDoc( false );
- bCallParaInsertedOrDeleted = true;
+ mbCallParaInsertedOrDeleted = true;
- aEditDoc.SetModifyHdl( LINK( this, ImpEditEngine, DocModified ) );
+ maEditDoc.SetModifyHdl( LINK( this, ImpEditEngine, DocModified ) );
StartListening(*SfxGetpApp());
}
@@ -155,43 +163,42 @@ void ImpEditEngine::Dispose()
auto pApp = SfxApplication::Get();
if(pApp)
EndListening(*pApp);
- pVirtDev.disposeAndClear();
+ mpVirtDev.disposeAndClear();
mpOwnDev.disposeAndClear();
pSharedVCL.reset();
}
ImpEditEngine::~ImpEditEngine()
{
- aStatusTimer.Stop();
- aOnlineSpellTimer.Stop();
- aIdleFormatter.Stop();
+ maStatusTimer.Stop();
+ maOnlineSpellTimer.Stop();
+ maIdleFormatter.Stop();
// Destroying templates may otherwise cause unnecessary formatting,
// when a parent template is destroyed.
// And this after the destruction of the data!
- bDowning = true;
- SetUpdateMode( false );
+ mbDowning = true;
+ SetUpdateLayout( false );
Dispose();
- // it's only legal to delete the pUndoManager if it was created by
+ // it's only legal to delete the mpUndoManager if it was created by
// ImpEditEngine; if it was set by SetUndoManager() it must be cleared
// before destroying the ImpEditEngine!
- assert(!pUndoManager || typeid(*pUndoManager) == typeid(EditUndoManager));
- delete pUndoManager;
- pTextRanger.reset();
+ assert(!mpUndoManager || typeid(*mpUndoManager) == typeid(EditUndoManager));
+ delete mpUndoManager;
+ mpTextRanger.reset();
mpIMEInfos.reset();
- pCTLOptions.reset();
- pSpellInfo.reset();
+ mpSpellInfo.reset();
}
-void ImpEditEngine::SetRefDevice( OutputDevice* pRef )
+void ImpEditEngine::SetRefDevice(OutputDevice* pRef)
{
if (pRef)
- pRefDev = pRef;
+ mpRefDev = pRef;
else
- pRefDev = pSharedVCL->GetVirtualDevice();
+ mpRefDev = pSharedVCL->GetVirtualDevice();
- nOnePixelInRef = static_cast<sal_uInt16>(pRefDev->PixelToLogic( Size( 1, 0 ) ).Width());
+ mnOnePixelInRef = static_cast<sal_uInt16>(mpRefDev->PixelToLogic( Size( 1, 0 ) ).Width());
if ( IsFormatted() )
{
@@ -207,12 +214,12 @@ void ImpEditEngine::SetRefMapMode( const MapMode& rMapMode )
mpOwnDev.disposeAndClear();
mpOwnDev = VclPtr<VirtualDevice>::Create();
- pRefDev = mpOwnDev;
- pRefDev->SetMapMode(MapMode(MapUnit::MapTwip));
- SetRefDevice( pRefDev );
+ mpRefDev = mpOwnDev;
+ mpRefDev->SetMapMode(MapMode(MapUnit::MapTwip));
+ SetRefDevice(mpRefDev);
- pRefDev->SetMapMode( rMapMode );
- nOnePixelInRef = static_cast<sal_uInt16>(pRefDev->PixelToLogic( Size( 1, 0 ) ).Width());
+ mpRefDev->SetMapMode( rMapMode );
+ mnOnePixelInRef = static_cast<sal_uInt16>(mpRefDev->PixelToLogic(Size(1, 0)).Width());
if ( IsFormatted() )
{
FormatFullDoc();
@@ -222,23 +229,23 @@ void ImpEditEngine::SetRefMapMode( const MapMode& rMapMode )
void ImpEditEngine::InitDoc(bool bKeepParaAttribs)
{
- sal_Int32 nParas = aEditDoc.Count();
+ sal_Int32 nParas = maEditDoc.Count();
for ( sal_Int32 n = bKeepParaAttribs ? 1 : 0; n < nParas; n++ )
{
- if ( aEditDoc[n]->GetStyleSheet() )
- EndListening( *aEditDoc[n]->GetStyleSheet() );
+ if (maEditDoc.GetObject(n)->GetStyleSheet())
+ EndListening( *maEditDoc.GetObject(n)->GetStyleSheet() );
}
if ( bKeepParaAttribs )
- aEditDoc.RemoveText();
+ maEditDoc.RemoveText();
else
- aEditDoc.Clear();
+ maEditDoc.Clear();
GetParaPortions().Reset();
- GetParaPortions().Insert(0, std::make_unique<ParaPortion>( aEditDoc[0] ));
+ GetParaPortions().Insert(0, std::make_unique<ParaPortion>(maEditDoc.GetObject(0)));
- bFormatted = false;
+ mbFormatted = false;
if ( IsCallParaInsertedOrDeleted() )
{
@@ -247,7 +254,7 @@ void ImpEditEngine::InitDoc(bool bKeepParaAttribs)
}
if ( GetStatus().DoOnlineSpelling() )
- aEditDoc.GetObject( 0 )->CreateWrongList();
+ maEditDoc.GetObject( 0 )->CreateWrongList();
}
EditPaM ImpEditEngine::DeleteSelected(const EditSelection& rSel)
@@ -262,12 +269,12 @@ OUString ImpEditEngine::GetSelected( const EditSelection& rSel ) const
return OUString();
EditSelection aSel( rSel );
- aSel.Adjust( aEditDoc );
+ aSel.Adjust( maEditDoc );
ContentNode* pStartNode = aSel.Min().GetNode();
ContentNode* pEndNode = aSel.Max().GetNode();
- sal_Int32 nStartNode = aEditDoc.GetPos( pStartNode );
- sal_Int32 nEndNode = aEditDoc.GetPos( pEndNode );
+ sal_Int32 nStartNode = maEditDoc.GetPos( pStartNode );
+ sal_Int32 nEndNode = maEditDoc.GetPos( pEndNode );
OSL_ENSURE( nStartNode <= nEndNode, "Selection not sorted ?" );
@@ -277,8 +284,8 @@ OUString ImpEditEngine::GetSelected( const EditSelection& rSel ) const
// iterate over the paragraphs ...
for ( sal_Int32 nNode = nStartNode; nNode <= nEndNode; nNode++ )
{
- OSL_ENSURE( aEditDoc.GetObject( nNode ), "Node not found: GetSelected" );
- const ContentNode* pNode = aEditDoc.GetObject( nNode );
+ const ContentNode* pNode = maEditDoc.GetObject( nNode );
+ assert(pNode);
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!
@@ -300,33 +307,33 @@ bool ImpEditEngine::MouseButtonDown( const MouseEvent& rMEvt, EditView* pView )
GetSelEngine().SelMouseButtonDown( rMEvt );
// Special treatment
- EditSelection aCurSel( pView->pImpEditView->GetEditSelection() );
- if ( !rMEvt.IsShift() )
+ EditSelection aCurSel( pView->getImpl().GetEditSelection() );
+ if ( rMEvt.IsShift() )
+ return true;
+
+ if ( rMEvt.GetClicks() == 2 )
{
- if ( rMEvt.GetClicks() == 2 )
- {
- // So that the SelectionEngine knows about the anchor.
- aSelEngine.CursorPosChanging( true, false );
-
- EditSelection aNewSelection( SelectWord( aCurSel ) );
- pView->pImpEditView->DrawSelectionXOR();
- pView->pImpEditView->SetEditSelection( aNewSelection );
- pView->pImpEditView->DrawSelectionXOR();
- pView->ShowCursor();
- }
- else if ( rMEvt.GetClicks() == 3 )
- {
- // So that the SelectionEngine knows about the anchor.
- aSelEngine.CursorPosChanging( true, false );
-
- EditSelection aNewSelection( aCurSel );
- aNewSelection.Min().SetIndex( 0 );
- aNewSelection.Max().SetIndex( aCurSel.Min().GetNode()->Len() );
- pView->pImpEditView->DrawSelectionXOR();
- pView->pImpEditView->SetEditSelection( aNewSelection );
- pView->pImpEditView->DrawSelectionXOR();
- pView->ShowCursor();
- }
+ // So that the SelectionEngine knows about the anchor.
+ maSelEngine.CursorPosChanging( true, false );
+
+ EditSelection aNewSelection( SelectWord( aCurSel ) );
+ pView->getImpl().DrawSelectionXOR();
+ pView->getImpl().SetEditSelection( aNewSelection );
+ pView->getImpl().DrawSelectionXOR();
+ pView->ShowCursor();
+ }
+ else if ( rMEvt.GetClicks() == 3 )
+ {
+ // So that the SelectionEngine knows about the anchor.
+ maSelEngine.CursorPosChanging( true, false );
+
+ EditSelection aNewSelection( aCurSel );
+ aNewSelection.Min().SetIndex( 0 );
+ aNewSelection.Max().SetIndex( aCurSel.Min().GetNode()->Len() );
+ pView->getImpl().DrawSelectionXOR();
+ pView->getImpl().SetEditSelection( aNewSelection );
+ pView->getImpl().DrawSelectionXOR();
+ pView->ShowCursor();
}
return true;
}
@@ -339,61 +346,69 @@ bool ImpEditEngine::Command( const CommandEvent& rCEvt, EditView* pView )
SetActiveView( pView );
if ( rCEvt.GetCommand() == CommandEventId::StartExtTextInput )
{
- pView->DeleteSelected();
- mpIMEInfos.reset();
- EditPaM aPaM = pView->GetImpEditView()->GetEditSelection().Max();
- OUString aOldTextAfterStartPos = aPaM.GetNode()->Copy( aPaM.GetIndex() );
- sal_Int32 nMax = aOldTextAfterStartPos.indexOf( CH_FEATURE );
- if ( nMax != -1 ) // don't overwrite features!
- aOldTextAfterStartPos = aOldTextAfterStartPos.copy( 0, nMax );
- mpIMEInfos.reset( new ImplIMEInfos( aPaM, aOldTextAfterStartPos ) );
- mpIMEInfos->bWasCursorOverwrite = !pView->IsInsertMode();
- UndoActionStart( EDITUNDO_INSERT );
+ if (!pView->IsReadOnly())
+ {
+ pView->DeleteSelected();
+ mpIMEInfos.reset();
+ EditPaM aPaM = pView->getImpl().GetEditSelection().Max();
+ OUString aOldTextAfterStartPos = aPaM.GetNode()->Copy( aPaM.GetIndex() );
+ sal_Int32 nMax = aOldTextAfterStartPos.indexOf( CH_FEATURE );
+ if ( nMax != -1 ) // don't overwrite features!
+ aOldTextAfterStartPos = aOldTextAfterStartPos.copy( 0, nMax );
+ mpIMEInfos.reset( new ImplIMEInfos( aPaM, aOldTextAfterStartPos ) );
+ mpIMEInfos->bWasCursorOverwrite = !pView->IsInsertMode();
+ UndoActionStart( EDITUNDO_INSERT );
+ }
}
else if ( rCEvt.GetCommand() == CommandEventId::EndExtTextInput )
{
- OSL_ENSURE( mpIMEInfos, "CommandEventId::EndExtTextInput => No start ?" );
- if( mpIMEInfos )
+ if (!pView->IsReadOnly())
{
- // #102812# convert quotes in IME text
- // works on the last input character, this is especially in Korean text often done
- // quotes that are inside of the string are not replaced!
- // Borrowed from sw: edtwin.cxx
- if ( mpIMEInfos->nLen )
+ OSL_ENSURE( mpIMEInfos, "CommandEventId::EndExtTextInput => No start ?" );
+ if( mpIMEInfos )
{
- EditSelection aSel( mpIMEInfos->aPos );
- aSel.Min().SetIndex( aSel.Min().GetIndex() + mpIMEInfos->nLen-1 );
- aSel.Max().SetIndex( aSel.Max().GetIndex() + mpIMEInfos->nLen );
// #102812# convert quotes in IME text
// works on the last input character, this is especially in Korean text often done
// quotes that are inside of the string are not replaced!
- const sal_Unicode nCharCode = aSel.Min().GetNode()->GetChar( aSel.Min().GetIndex() );
- if ( ( GetStatus().DoAutoCorrect() ) && ( ( nCharCode == '\"' ) || ( nCharCode == '\'' ) ) )
+ // Borrowed from sw: edtwin.cxx
+ if ( mpIMEInfos->nLen )
{
- aSel = DeleteSelected( aSel );
- aSel = AutoCorrect( aSel, nCharCode, mpIMEInfos->bWasCursorOverwrite );
- pView->pImpEditView->SetEditSelection( aSel );
+ EditSelection aSel( mpIMEInfos->aPos );
+ aSel.Min().SetIndex( aSel.Min().GetIndex() + mpIMEInfos->nLen-1 );
+ aSel.Max().SetIndex( aSel.Max().GetIndex() + mpIMEInfos->nLen );
+ // #102812# convert quotes in IME text
+ // works on the last input character, this is especially in Korean text often done
+ // quotes that are inside of the string are not replaced!
+ // See also tdf#155350
+ const sal_Unicode nCharCode = aSel.Min().GetNode()->GetChar( aSel.Min().GetIndex() );
+ if ( ( GetStatus().DoAutoCorrect() ) && SvxAutoCorrect::IsAutoCorrectChar(nCharCode) )
+ {
+ aSel = DeleteSelected( aSel );
+ aSel = AutoCorrect( aSel, nCharCode, mpIMEInfos->bWasCursorOverwrite );
+ pView->getImpl().SetEditSelection( aSel );
+ }
}
- }
- ParaPortion* pPortion = FindParaPortion( mpIMEInfos->aPos.GetNode() );
- pPortion->MarkSelectionInvalid( mpIMEInfos->aPos.GetIndex() );
+ ParaPortion* pPortion = FindParaPortion( mpIMEInfos->aPos.GetNode() );
+ if (pPortion)
+ pPortion->MarkSelectionInvalid( mpIMEInfos->aPos.GetIndex() );
- bool bWasCursorOverwrite = mpIMEInfos->bWasCursorOverwrite;
+ bool bWasCursorOverwrite = mpIMEInfos->bWasCursorOverwrite;
- mpIMEInfos.reset();
+ mpIMEInfos.reset();
- FormatAndUpdate( pView );
+ FormatAndLayout( pView );
- pView->SetInsertMode( !bWasCursorOverwrite );
+ pView->SetInsertMode( !bWasCursorOverwrite );
+ }
+ UndoActionEnd();
}
- UndoActionEnd();
}
else if ( rCEvt.GetCommand() == CommandEventId::ExtTextInput )
{
- OSL_ENSURE( mpIMEInfos, "CommandEventId::ExtTextInput => No Start ?" );
- if( mpIMEInfos )
+ if( mpIMEInfos && !pView->IsReadOnly())
{
+ OSL_ENSURE( mpIMEInfos, "CommandEventId::ExtTextInput => No Start ?" );
const CommandExtTextInputData* pData = rCEvt.GetExtTextInputData();
if ( !pData->IsOnlyCursorChanged() )
@@ -444,7 +459,7 @@ bool ImpEditEngine::Command( const CommandEvent& rCEvt, EditView* pView )
ParaPortion* pPortion = FindParaPortion( mpIMEInfos->aPos.GetNode() );
pPortion->MarkSelectionInvalid( mpIMEInfos->aPos.GetIndex() );
- FormatAndUpdate( pView );
+ FormatAndLayout( pView );
}
EditSelection aNewSel = EditPaM( mpIMEInfos->aPos.GetNode(), mpIMEInfos->aPos.GetIndex()+pData->GetCursorPos() );
@@ -464,7 +479,7 @@ bool ImpEditEngine::Command( const CommandEvent& rCEvt, EditView* pView )
{
if (mpIMEInfos)
{
- EditPaM aPaM( pView->pImpEditView->GetEditSelection().Max() );
+ EditPaM aPaM( pView->getImpl().GetEditSelection().Max() );
tools::Rectangle aR1 = PaMtoEditCursor( aPaM );
sal_Int32 nInputEnd = mpIMEInfos->aPos.GetIndex() + mpIMEInfos->nLen;
@@ -479,8 +494,8 @@ bool ImpEditEngine::Command( const CommandEvent& rCEvt, EditView* pView )
const EditLine& rLine = pParaPortion->GetLines()[nLine];
if ( nInputEnd > rLine.GetEnd() )
nInputEnd = rLine.GetEnd();
- tools::Rectangle aR2 = PaMtoEditCursor( EditPaM( aPaM.GetNode(), nInputEnd ), GetCursorFlags::EndOfLine );
- tools::Rectangle aRect = pView->GetImpEditView()->GetWindowPos( aR1 );
+ tools::Rectangle aR2 = PaMtoEditCursor( EditPaM( aPaM.GetNode(), nInputEnd ), CursorFlags{ .bEndOfLine = true });
+ tools::Rectangle aRect = pView->getImpl().GetWindowPos( aR1 );
auto nExtTextInputWidth = aR2.Left() - aR1.Right();
if (EditViewCallbacks* pEditViewCallbacks = pView->getEditViewCallbacks())
pEditViewCallbacks->EditViewCursorRect(aRect, nExtTextInputWidth);
@@ -523,7 +538,7 @@ bool ImpEditEngine::Command( const CommandEvent& rCEvt, EditView* pView )
if ( aSelection.nStartPara != aSelection.nEndPara )
{
- sal_Int32 aParaLen = pEditEngine->GetTextLen( aSelection.nStartPara );
+ sal_Int32 aParaLen = mpEditEngine->GetTextLen( aSelection.nStartPara );
aSelection.nEndPara = aSelection.nStartPara;
aSelection.nEndPos = aParaLen;
pView->SetSelection( aSelection );
@@ -534,26 +549,49 @@ bool ImpEditEngine::Command( const CommandEvent& rCEvt, EditView* pView )
{
if (mpIMEInfos)
{
- EditPaM aPaM( pView->pImpEditView->GetEditSelection().Max() );
+ EditPaM aPaM( pView->getImpl().GetEditSelection().Max() );
if ( !IsFormatted() )
FormatDoc();
- ParaPortion* pParaPortion = GetParaPortions().SafeGetObject( GetEditDoc().GetPos( aPaM.GetNode() ) );
+ sal_Int32 nPortionPos = GetEditDoc().GetPos(aPaM.GetNode());
+ ParaPortion* pParaPortion = GetParaPortions().SafeGetObject(nPortionPos);
if (pParaPortion)
{
- sal_Int32 nLine = pParaPortion->GetLines().FindLine( aPaM.GetIndex(), true );
- const EditLine& rLine = pParaPortion->GetLines()[nLine];
- std::unique_ptr<tools::Rectangle[]> aRects(new tools::Rectangle[ mpIMEInfos->nLen ]);
- for (sal_Int32 i = 0; i < mpIMEInfos->nLen; ++i)
- {
- sal_Int32 nInputPos = mpIMEInfos->aPos.GetIndex() + i;
- if ( nInputPos > rLine.GetEnd() )
- nInputPos = rLine.GetEnd();
- tools::Rectangle aR2 = GetEditCursor( pParaPortion, nInputPos );
- aRects[ i ] = pView->GetImpEditView()->GetWindowPos( aR2 );
- }
+ const sal_Int32 nMinPos = mpIMEInfos->aPos.GetIndex();
+ const sal_Int32 nMaxPos = nMinPos + mpIMEInfos->nLen - 1;
+ std::vector<tools::Rectangle> aRects(mpIMEInfos->nLen);
+
+ auto CollectCharPositions = [&](const LineAreaInfo& rInfo) {
+ if (!rInfo.pLine) // Start of ParaPortion
+ {
+ if (rInfo.nPortion < nPortionPos)
+ return CallbackResult::SkipThisPortion;
+ if (rInfo.nPortion > nPortionPos)
+ return CallbackResult::Stop;
+ assert(&rInfo.rPortion == pParaPortion);
+ }
+ else // This is the needed ParaPortion
+ {
+ if (rInfo.pLine->GetStart() > nMaxPos)
+ return CallbackResult::Stop;
+ if (rInfo.pLine->GetEnd() < nMinPos)
+ return CallbackResult::Continue;
+ for (sal_Int32 n = nMinPos; n <= nMaxPos; ++n)
+ {
+ if (rInfo.pLine->IsIn(n))
+ {
+ tools::Rectangle aR = GetEditCursor(*pParaPortion, *rInfo.pLine, n, CursorFlags());
+ aR.Move(getTopLeftDocOffset(rInfo.aArea));
+ aRects[n - nMinPos] = pView->getImpl().GetWindowPos(aR);
+ }
+ }
+ }
+ return CallbackResult::Continue;
+ };
+ IterateLineAreas(CollectCharPositions, IterFlag::none);
+
if (vcl::Window* pWindow = pView->GetWindow())
- pWindow->SetCompositionCharRect( aRects.get(), mpIMEInfos->nLen );
+ pWindow->SetCompositionCharRect(aRects.data(), aRects.size());
}
}
}
@@ -574,37 +612,40 @@ bool ImpEditEngine::MouseButtonUp( const MouseEvent& rMEvt, EditView* pView )
// non-tiled-rendering case, but it has been here since 2000 (and before)
// so who knows what corner case it was supposed to solve back then
if (!comphelper::LibreOfficeKit::isActive())
- bInSelection = false;
+ mbInSelection = false;
// Special treatments
- EditSelection aCurSel( pView->pImpEditView->GetEditSelection() );
- if ( !aCurSel.HasRange() )
+ EditSelection aCurSel( pView->getImpl().GetEditSelection() );
+ if ( aCurSel.HasRange() )
+ return true;
+
+ if ( ( rMEvt.GetClicks() != 1 ) || !rMEvt.IsLeft() || rMEvt.IsMod2() )
+ return true;
+
+ const OutputDevice& rOutDev = pView->getEditViewCallbacks() ? pView->getEditViewCallbacks()->EditViewOutputDevice() : *pView->GetWindow()->GetOutDev();
+ Point aLogicClick = rOutDev.PixelToLogic(rMEvt.GetPosPixel());
+ const SvxFieldItem* pFld = pView->GetField(aLogicClick);
+ if (!pFld)
+ return true;
+
+ // tdf#121039 When in edit mode, editeng is responsible for opening the URL on mouse click
+ bool bUrlOpened = GetEditEnginePtr()->FieldClicked( *pFld );
+ if (bUrlOpened)
+ return true;
+
+ if (auto pUrlField = dynamic_cast<const SvxURLField*>(pFld->GetField()))
{
- if ( ( rMEvt.GetClicks() == 1 ) && rMEvt.IsLeft() && !rMEvt.IsMod2() )
+ bool bCtrlClickHappened = rMEvt.IsMod1();
+ bool bCtrlClickSecOption
+ = SvtSecurityOptions::IsOptionSet(SvtSecurityOptions::EOption::CtrlClickHyperlink);
+ if ((bCtrlClickHappened && bCtrlClickSecOption)
+ || (!bCtrlClickHappened && !bCtrlClickSecOption))
{
- const OutputDevice& rOutDev = pView->getEditViewCallbacks() ? pView->getEditViewCallbacks()->EditViewOutputDevice() : *pView->GetWindow();
- Point aLogicClick = rOutDev.PixelToLogic(rMEvt.GetPosPixel());
- if (const SvxFieldItem* pFld = pView->GetField(aLogicClick))
- {
- // tdf#121039 When in edit mode, editeng is responsible for opening the URL on mouse click
- if (auto pUrlField = dynamic_cast<const SvxURLField*>(pFld->GetField()))
- {
- SvtSecurityOptions aSecOpt;
- bool bCtrlClickHappened = rMEvt.IsMod1();
- bool bCtrlClickSecOption
- = aSecOpt.IsOptionSet(SvtSecurityOptions::EOption::CtrlClickHyperlink);
- if ((bCtrlClickHappened && bCtrlClickSecOption)
- || (!bCtrlClickHappened && !bCtrlClickSecOption))
- {
- css::uno::Reference<css::system::XSystemShellExecute> exec(
- css::system::SystemShellExecute::create(
- comphelper::getProcessComponentContext()));
- exec->execute(pUrlField->GetURL(), OUString(),
- css::system::SystemShellExecuteFlags::DEFAULTS);
- }
- }
- GetEditEnginePtr()->FieldClicked( *pFld );
- }
+ css::uno::Reference<css::system::XSystemShellExecute> exec(
+ css::system::SystemShellExecute::create(
+ comphelper::getProcessComponentContext()));
+ exec->execute(pUrlField->GetURL(), OUString(),
+ css::system::SystemShellExecuteFlags::DEFAULTS);
}
}
return true;
@@ -633,33 +674,39 @@ void ImpEditEngine::Clear()
{
InitDoc( false );
- EditPaM aPaM = aEditDoc.GetStartPaM();
+ EditPaM aPaM = maEditDoc.GetStartPaM();
EditSelection aSel( aPaM );
- nCurTextHeight = 0;
- nCurTextHeightNTP = 0;
+ mnCurTextHeight = 0;
+ mnCurTextHeightNTP = 0;
ResetUndoManager();
- for (size_t nView = aEditViews.size(); nView; )
+ for (size_t nView = maEditViews.size(); nView; )
{
- EditView* pView = aEditViews[--nView];
- pView->pImpEditView->SetEditSelection( aSel );
+ EditView* pView = maEditViews[--nView];
+ pView->getImpl().SetEditSelection( aSel );
}
+
+ // Related: tdf#82115 Fix crash when handling input method events.
+ // The nodes in mpIMEInfos may be deleted in ImpEditEngine::Clear() which
+ // causes a crash in the CommandEventId::ExtTextInput and
+ // CommandEventId::EndExtTextInput event handlers.
+ mpIMEInfos.reset();
}
EditPaM ImpEditEngine::RemoveText()
{
InitDoc( true );
- EditPaM aStartPaM = aEditDoc.GetStartPaM();
+ EditPaM aStartPaM = maEditDoc.GetStartPaM();
EditSelection aEmptySel( aStartPaM, aStartPaM );
- for (EditView* pView : aEditViews)
+ for (EditView* pView : maEditViews)
{
- pView->pImpEditView->SetEditSelection( aEmptySel );
+ pView->getImpl().SetEditSelection( aEmptySel );
}
ResetUndoManager();
- return aEditDoc.GetStartPaM();
+ return maEditDoc.GetStartPaM();
}
@@ -676,22 +723,23 @@ void ImpEditEngine::SetText(const OUString& rText)
if (!rText.isEmpty())
aPaM = ImpInsertText( aEmptySel, rText );
- for (EditView* pView : aEditViews)
+ for (EditView* pView : maEditViews)
{
- pView->pImpEditView->SetEditSelection( EditSelection( aPaM, aPaM ) );
+ pView->getImpl().SetEditSelection( EditSelection( aPaM, aPaM ) );
// If no text then also no Format&Update
// => The text remains.
- if (rText.isEmpty() && GetUpdateMode())
+ if (rText.isEmpty() && IsUpdateLayout())
{
tools::Rectangle aTmpRect( pView->GetOutputArea().TopLeft(),
- Size( aPaperSize.Width(), nCurTextHeight ) );
+ Size( maPaperSize.Width(), mnCurTextHeight ) );
aTmpRect.Intersection( pView->GetOutputArea() );
pView->InvalidateWindow( aTmpRect );
}
}
- if (rText.isEmpty()) { // otherwise it must be invalidated later, !bFormatted is enough.
- nCurTextHeight = 0;
- nCurTextHeightNTP = 0;
+ if (rText.isEmpty()) // otherwise it must be invalidated later, !bFormatted is enough.
+ {
+ mnCurTextHeight = 0;
+ mnCurTextHeightNTP = 0;
}
EnableUndo( bUndoCurrentlyEnabled );
OSL_ENSURE( !HasUndoManager() || !GetUndoManager().GetUndoActionCount(), "Undo after SetText?" );
@@ -702,7 +750,7 @@ const SfxItemSet& ImpEditEngine::GetEmptyItemSet() const
{
if ( !pEmptyItemSet )
{
- pEmptyItemSet = std::make_unique<SfxItemSet>(const_cast<SfxItemPool&>(aEditDoc.GetItemPool()), svl::Items<EE_ITEMS_START, EE_ITEMS_END>{});
+ pEmptyItemSet = std::make_unique<SfxItemSetFixed<EE_ITEMS_START, EE_ITEMS_END>>(const_cast<SfxItemPool&>(maEditDoc.GetItemPool()));
for ( sal_uInt16 nWhich = EE_ITEMS_START; nWhich <= EE_CHAR_END; nWhich++)
{
pEmptyItemSet->ClearItem( nWhich );
@@ -714,18 +762,9 @@ const SfxItemSet& ImpEditEngine::GetEmptyItemSet() const
// MISC
-void ImpEditEngine::CursorMoved( const ContentNode* pPrevNode )
-{
- // Delete empty attributes, but only if paragraph is not empty!
- if (pPrevNode->GetCharAttribs().HasEmptyAttribs() && pPrevNode->Len())
- {
- const_cast<ContentNode*>(pPrevNode)->GetCharAttribs().DeleteEmptyAttribs(aEditDoc.GetItemPool());
- }
-}
-
void ImpEditEngine::TextModified()
{
- bFormatted = false;
+ mbFormatted = false;
if ( GetNotifyHdl().IsSet() )
{
@@ -739,21 +778,21 @@ void ImpEditEngine::ParaAttribsChanged( ContentNode const * pNode, bool bIgnoreU
{
assert(pNode && "ParaAttribsChanged: Which one?");
- aEditDoc.SetModified( true );
- bFormatted = false;
+ maEditDoc.SetModified( true );
+ mbFormatted = false;
ParaPortion* pPortion = FindParaPortion( pNode );
- OSL_ENSURE( pPortion, "ParaAttribsChanged: Portion?" );
+ assert(pPortion);
pPortion->MarkSelectionInvalid( 0 );
- sal_Int32 nPara = aEditDoc.GetPos( pNode );
- if ( bIgnoreUndoCheck || pEditEngine->IsInUndo() )
- pEditEngine->ParaAttribsChanged( nPara );
+ sal_Int32 nPara = maEditDoc.GetPos( pNode );
+ if (bIgnoreUndoCheck || mpEditEngine->IsInUndo())
+ mpEditEngine->ParaAttribsChanged( nPara );
ParaPortion* pNextPortion = GetParaPortions().SafeGetObject( nPara+1 );
// => is formatted again anyway, if Invalid.
if ( pNextPortion && !pNextPortion->IsInvalid() )
- CalcHeight( pNextPortion );
+ CalcHeight(*pNextPortion);
}
@@ -765,14 +804,14 @@ EditSelection const & ImpEditEngine::MoveCursor( const KeyEvent& rKeyEvent, Edit
// Actually, only necessary for up/down, but whatever.
CheckIdleFormatter();
- EditPaM aPaM( pEditView->pImpEditView->GetEditSelection().Max() );
+ EditPaM aPaM(pEditView->getImpl().GetEditSelection().Max());
EditPaM aOldPaM( aPaM );
TextDirectionality eTextDirection = TextDirectionality::LeftToRight_TopToBottom;
- if (IsVertical() && IsTopToBottom())
+ if (IsEffectivelyVertical() && IsTopToBottom())
eTextDirection = TextDirectionality::TopToBottom_RightToLeft;
- else if (IsVertical() && !IsTopToBottom())
+ else if (IsEffectivelyVertical() && !IsTopToBottom())
eTextDirection = TextDirectionality::BottomToTop_LeftToRight;
else if ( IsRightToLeft( GetEditDoc().GetPos( aPaM.GetNode() ) ) )
eTextDirection = TextDirectionality::RightToLeft_TopToBottom;
@@ -905,41 +944,41 @@ EditSelection const & ImpEditEngine::MoveCursor( const KeyEvent& rKeyEvent, Edit
break;
}
- if ( aOldPaM != aPaM )
+ if ( aOldPaM != aPaM && nullptr != aOldPaM.GetNode() )
{
- CursorMoved( aOldPaM.GetNode() );
+ aOldPaM.GetNode()->checkAndDeleteEmptyAttribs();
}
// May cause, a CreateAnchor or deselection all
- aSelEngine.SetCurView( pEditView );
- aSelEngine.CursorPosChanging( bKeyModifySelection, aTranslatedKeyEvent.GetKeyCode().IsMod1() );
- EditPaM aOldEnd( pEditView->pImpEditView->GetEditSelection().Max() );
+ maSelEngine.SetCurView(pEditView);
+ maSelEngine.CursorPosChanging( bKeyModifySelection, aTranslatedKeyEvent.GetKeyCode().IsMod1() );
+ EditPaM aOldEnd(pEditView->getImpl().GetEditSelection().Max());
{
- EditSelection aNewSelection(pEditView->pImpEditView->GetEditSelection());
+ EditSelection aNewSelection(pEditView->getImpl().GetEditSelection());
aNewSelection.Max() = aPaM;
- pEditView->pImpEditView->SetEditSelection(aNewSelection);
- // const_cast<EditPaM&>(pEditView->pImpEditView->GetEditSelection().Max()) = aPaM;
+ pEditView->getImpl().SetEditSelection(aNewSelection);
+ // const_cast<EditPaM&>(pEditView->getImpl().GetEditSelection().Max()) = aPaM;
}
if ( bKeyModifySelection )
{
// Then the selection is expanded ... or the whole selection is painted in case of tiled rendering.
- EditSelection aTmpNewSel( comphelper::LibreOfficeKit::isActive() ? pEditView->pImpEditView->GetEditSelection().Min() : aOldEnd, aPaM );
- pEditView->pImpEditView->DrawSelectionXOR( aTmpNewSel );
+ EditSelection aTmpNewSel( comphelper::LibreOfficeKit::isActive() ? pEditView->getImpl().GetEditSelection().Min() : aOldEnd, aPaM );
+ pEditView->getImpl().DrawSelectionXOR( aTmpNewSel );
}
else
{
- EditSelection aNewSelection(pEditView->pImpEditView->GetEditSelection());
+ EditSelection aNewSelection(pEditView->getImpl().GetEditSelection());
aNewSelection.Min() = aPaM;
- pEditView->pImpEditView->SetEditSelection(aNewSelection);
- // const_cast<EditPaM&>(pEditView->pImpEditView->GetEditSelection().Min()) = aPaM;
+ pEditView->getImpl().SetEditSelection(aNewSelection);
+ // const_cast<EditPaM&>(pEditView->getImpl().GetEditSelection().Min()) = aPaM;
}
- return pEditView->pImpEditView->GetEditSelection();
+ return pEditView->getImpl().GetEditSelection();
}
-EditPaM ImpEditEngine::CursorVisualStartEnd( EditView const * pEditView, const EditPaM& rPaM, bool bStart )
+EditPaM ImpEditEngine::CursorVisualStartEnd( EditView const * mpEditView, const EditPaM& rPaM, bool bStart )
{
EditPaM aPaM( rPaM );
@@ -952,7 +991,7 @@ EditPaM ImpEditEngine::CursorVisualStartEnd( EditView const * pEditView, const E
const EditLine& rLine = pParaPortion->GetLines()[nLine];
bool bEmptyLine = rLine.GetStart() == rLine.GetEnd();
- pEditView->pImpEditView->nExtraCursorFlags = GetCursorFlags::NONE;
+ mpEditView->getImpl().maExtraCursorFlags = CursorFlags();
if ( !bEmptyLine )
{
@@ -978,15 +1017,15 @@ EditPaM ImpEditEngine::CursorVisualStartEnd( EditView const * pEditView, const E
if ( bStart )
{
- pEditView->pImpEditView->SetCursorBidiLevel( bPortionRTL ? 0 : 1 );
+ mpEditView->getImpl().SetCursorBidiLevel( bPortionRTL ? 0 : 1 );
// Maybe we must be *behind* the character
- if ( bPortionRTL && pEditView->IsInsertMode() )
+ if (bPortionRTL && mpEditView->IsInsertMode())
aPaM.SetIndex( aPaM.GetIndex()+1 );
}
else
{
- pEditView->pImpEditView->SetCursorBidiLevel( bPortionRTL ? 1 : 0 );
- if ( !bPortionRTL && pEditView->IsInsertMode() )
+ mpEditView->getImpl().SetCursorBidiLevel( bPortionRTL ? 1 : 0 );
+ if ( !bPortionRTL && mpEditView->IsInsertMode() )
aPaM.SetIndex( aPaM.GetIndex()+1 );
}
}
@@ -1007,7 +1046,7 @@ EditPaM ImpEditEngine::CursorVisualLeftRight( EditView const * pEditView, const
const EditLine& rLine = pParaPortion->GetLines()[nLine];
bool bEmptyLine = rLine.GetStart() == rLine.GetEnd();
- pEditView->pImpEditView->nExtraCursorFlags = GetCursorFlags::NONE;
+ pEditView->getImpl().maExtraCursorFlags = CursorFlags();
bool bParaRTL = IsRightToLeft( nPara );
@@ -1058,12 +1097,12 @@ EditPaM ImpEditEngine::CursorVisualLeftRight( EditView const * pEditView, const
if (bVisualToLeft != bool(nRTLLevel % 2))
{
aPaM = CursorLeft( aPaM, nCharacterIteratorMode );
- pEditView->pImpEditView->SetCursorBidiLevel( 1 );
+ pEditView->getImpl().SetCursorBidiLevel( 1 );
}
else
{
aPaM = CursorRight( aPaM, nCharacterIteratorMode );
- pEditView->pImpEditView->SetCursorBidiLevel( 0 );
+ pEditView->getImpl().SetCursorBidiLevel( 0 );
}
bDone = true;
}
@@ -1103,13 +1142,13 @@ EditPaM ImpEditEngine::CursorVisualLeftRight( EditView const * pEditView, const
if ( !bGotoEndOfPrevLine && !bGotoStartOfNextLine )
{
aPaM.SetIndex( rLine.GetStart() + ubidi_getLogicalIndex( pBidi, nVisPos, &nError ) );
- pEditView->pImpEditView->SetCursorBidiLevel( 0 );
+ pEditView->getImpl().SetCursorBidiLevel( 0 );
}
}
else
{
bool bWasBehind = false;
- bool bBeforePortion = !nPosInLine || pEditView->pImpEditView->GetCursorBidiLevel() == 1;
+ bool bBeforePortion = !nPosInLine || pEditView->getImpl().GetCursorBidiLevel() == 1;
if ( nPosInLine && ( !bBeforePortion ) ) // before the next portion
bWasBehind = true; // step one back, otherwise visual will be unusable when rtl portion follows.
@@ -1148,7 +1187,7 @@ EditPaM ImpEditEngine::CursorVisualLeftRight( EditView const * pEditView, const
else if ( !bVisualToLeft && bRTLPortion && ( bWasBehind || !_rTextPortion.IsRightToLeft() ) )
aPaM.SetIndex( aPaM.GetIndex()+1 );
- pEditView->pImpEditView->SetCursorBidiLevel( _nPortionStart );
+ pEditView->getImpl().SetCursorBidiLevel( _nPortionStart );
}
}
@@ -1230,24 +1269,24 @@ EditPaM ImpEditEngine::CursorUp( const EditPaM& rPaM, EditView const * pView )
assert(pView && "No View - No Cursor Movement!");
const ParaPortion* pPPortion = FindParaPortion( rPaM.GetNode() );
- OSL_ENSURE( pPPortion, "No matching portion found: CursorUp ");
+ assert(pPPortion);
sal_Int32 nLine = pPPortion->GetLineNumber( rPaM.GetIndex() );
const EditLine& rLine = pPPortion->GetLines()[nLine];
tools::Long nX;
- if ( pView->pImpEditView->nTravelXPos == TRAVEL_X_DONTKNOW )
+ if ( pView->getImpl().mnTravelXPos == TRAVEL_X_DONTKNOW )
{
- nX = GetXPos( pPPortion, &rLine, rPaM.GetIndex() );
- pView->pImpEditView->nTravelXPos = nX+nOnePixelInRef;
+ nX = GetXPos(*pPPortion, rLine, rPaM.GetIndex());
+ pView->getImpl().mnTravelXPos = nX + mnOnePixelInRef;
}
else
- nX = pView->pImpEditView->nTravelXPos;
+ nX = pView->getImpl().mnTravelXPos;
EditPaM aNewPaM( rPaM );
if ( nLine ) // same paragraph
{
const EditLine& rPrevLine = pPPortion->GetLines()[nLine-1];
- aNewPaM.SetIndex( GetChar( pPPortion, &rPrevLine, nX ) );
+ aNewPaM.SetIndex(GetChar(*pPPortion, rPrevLine, nX));
// If a previous automatically wrapped line, and one has to be exactly
// at the end of this line, the cursor lands on the current line at the
// beginning. See Problem: Last character of an automatically wrapped
@@ -1262,7 +1301,7 @@ EditPaM ImpEditEngine::CursorUp( const EditPaM& rPaM, EditView const * pView )
{
const EditLine& rLine2 = pPrevPortion->GetLines()[pPrevPortion->GetLines().Count()-1];
aNewPaM.SetNode( pPrevPortion->GetNode() );
- aNewPaM.SetIndex( GetChar( pPrevPortion, &rLine2, nX+nOnePixelInRef ) );
+ aNewPaM.SetIndex(GetChar(*pPrevPortion, rLine2, nX + mnOnePixelInRef));
}
}
@@ -1271,27 +1310,27 @@ EditPaM ImpEditEngine::CursorUp( const EditPaM& rPaM, EditView const * pView )
EditPaM ImpEditEngine::CursorDown( const EditPaM& rPaM, EditView const * pView )
{
- OSL_ENSURE( pView, "No View - No Cursor Movement!" );
+ assert(pView);
const ParaPortion* pPPortion = FindParaPortion( rPaM.GetNode() );
- OSL_ENSURE( pPPortion, "No matching portion found: CursorDown" );
+ assert(pPPortion);
sal_Int32 nLine = pPPortion->GetLineNumber( rPaM.GetIndex() );
tools::Long nX;
- if ( pView->pImpEditView->nTravelXPos == TRAVEL_X_DONTKNOW )
+ if ( pView->getImpl().mnTravelXPos == TRAVEL_X_DONTKNOW )
{
const EditLine& rLine = pPPortion->GetLines()[nLine];
- nX = GetXPos( pPPortion, &rLine, rPaM.GetIndex() );
- pView->pImpEditView->nTravelXPos = nX+nOnePixelInRef;
+ nX = GetXPos(*pPPortion, rLine, rPaM.GetIndex());
+ pView->getImpl().mnTravelXPos = nX + mnOnePixelInRef;
}
else
- nX = pView->pImpEditView->nTravelXPos;
+ nX = pView->getImpl().mnTravelXPos;
EditPaM aNewPaM( rPaM );
if ( nLine < pPPortion->GetLines().Count()-1 )
{
const EditLine& rNextLine = pPPortion->GetLines()[nLine+1];
- aNewPaM.SetIndex( GetChar( pPPortion, &rNextLine, nX ) );
+ aNewPaM.SetIndex(GetChar(*pPPortion, rNextLine, nX));
// Special treatment, see CursorUp ...
if ( ( aNewPaM.GetIndex() == rNextLine.GetEnd() ) && ( aNewPaM.GetIndex() > rNextLine.GetStart() ) && ( aNewPaM.GetIndex() < pPPortion->GetNode()->Len() ) )
aNewPaM = CursorLeft( aNewPaM );
@@ -1305,7 +1344,7 @@ EditPaM ImpEditEngine::CursorDown( const EditPaM& rPaM, EditView const * pView )
aNewPaM.SetNode( pNextPortion->GetNode() );
// Never at the very end when several lines, because then a line
// below the cursor appears.
- aNewPaM.SetIndex( GetChar( pNextPortion, &rLine, nX+nOnePixelInRef ) );
+ aNewPaM.SetIndex(GetChar(*pNextPortion, rLine, nX + mnOnePixelInRef));
if ( ( aNewPaM.GetIndex() == rLine.GetEnd() ) && ( aNewPaM.GetIndex() > rLine.GetStart() ) && ( pNextPortion->GetLines().Count() > 1 ) )
aNewPaM = CursorLeft( aNewPaM );
}
@@ -1317,7 +1356,7 @@ EditPaM ImpEditEngine::CursorDown( const EditPaM& rPaM, EditView const * pView )
EditPaM ImpEditEngine::CursorStartOfLine( const EditPaM& rPaM )
{
const ParaPortion* pCurPortion = FindParaPortion( rPaM.GetNode() );
- OSL_ENSURE( pCurPortion, "No Portion for the PaM ?" );
+ assert(pCurPortion);
sal_Int32 nLine = pCurPortion->GetLineNumber( rPaM.GetIndex() );
const EditLine& rLine = pCurPortion->GetLines()[nLine];
@@ -1329,7 +1368,7 @@ EditPaM ImpEditEngine::CursorStartOfLine( const EditPaM& rPaM )
EditPaM ImpEditEngine::CursorEndOfLine( const EditPaM& rPaM )
{
const ParaPortion* pCurPortion = FindParaPortion( rPaM.GetNode() );
- OSL_ENSURE( pCurPortion, "No Portion for the PaM ?" );
+ assert(pCurPortion);
sal_Int32 nLine = pCurPortion->GetLineNumber( rPaM.GetIndex() );
const EditLine& rLine = pCurPortion->GetLines()[nLine];
@@ -1371,14 +1410,14 @@ EditPaM ImpEditEngine::CursorEndOfParagraph( const EditPaM& rPaM )
EditPaM ImpEditEngine::CursorStartOfDoc()
{
- EditPaM aPaM( aEditDoc.GetObject( 0 ), 0 );
+ EditPaM aPaM( maEditDoc.GetObject( 0 ), 0 );
return aPaM;
}
EditPaM ImpEditEngine::CursorEndOfDoc()
{
- ContentNode* pLastNode = aEditDoc.GetObject( aEditDoc.Count()-1 );
- ParaPortion* pLastPortion = GetParaPortions().SafeGetObject( aEditDoc.Count()-1 );
+ ContentNode* pLastNode = maEditDoc.GetObject( maEditDoc.Count()-1 );
+ ParaPortion* pLastPortion = GetParaPortions().SafeGetObject( maEditDoc.Count()-1 );
OSL_ENSURE( pLastNode && pLastPortion, "CursorEndOfDoc: Node or Portion not found" );
if (!(pLastNode && pLastPortion))
return EditPaM();
@@ -1388,7 +1427,7 @@ EditPaM ImpEditEngine::CursorEndOfDoc()
pLastNode = GetPrevVisNode( pLastPortion->GetNode() );
OSL_ENSURE( pLastNode, "No visible paragraph?" );
if ( !pLastNode )
- pLastNode = aEditDoc.GetObject( aEditDoc.Count()-1 );
+ pLastNode = maEditDoc.GetObject( maEditDoc.Count()-1 );
}
EditPaM aPaM( pLastNode, pLastNode->Len() );
@@ -1400,7 +1439,7 @@ EditPaM ImpEditEngine::PageUp( const EditPaM& rPaM, EditView const * pView )
tools::Rectangle aRect = PaMtoEditCursor( rPaM );
Point aTopLeft = aRect.TopLeft();
aTopLeft.AdjustY( -(pView->GetVisArea().GetHeight() *9/10) );
- aTopLeft.AdjustX(nOnePixelInRef );
+ aTopLeft.AdjustX(mnOnePixelInRef);
if ( aTopLeft.Y() < 0 )
{
aTopLeft.setY( 0 );
@@ -1413,7 +1452,7 @@ EditPaM ImpEditEngine::PageDown( const EditPaM& rPaM, EditView const * pView )
tools::Rectangle aRect = PaMtoEditCursor( rPaM );
Point aBottomRight = aRect.BottomRight();
aBottomRight.AdjustY(pView->GetVisArea().GetHeight() *9/10 );
- aBottomRight.AdjustX(nOnePixelInRef );
+ aBottomRight.AdjustX(mnOnePixelInRef);
tools::Long nHeight = GetTextHeight();
if ( aBottomRight.Y() > nHeight )
{
@@ -1429,8 +1468,8 @@ EditPaM ImpEditEngine::WordLeft( const EditPaM& rPaM )
if ( nCurrentPos == 0 )
{
// Previous paragraph...
- sal_Int32 nCurPara = aEditDoc.GetPos( aNewPaM.GetNode() );
- ContentNode* pPrevNode = aEditDoc.GetObject( --nCurPara );
+ sal_Int32 nCurPara = maEditDoc.GetPos( aNewPaM.GetNode() );
+ ContentNode* pPrevNode = maEditDoc.GetObject( --nCurPara );
if ( pPrevNode )
{
aNewPaM.SetNode( pPrevNode );
@@ -1479,8 +1518,8 @@ EditPaM ImpEditEngine::WordRight( const EditPaM& rPaM, sal_Int16 nWordType )
if ( aNewPaM.GetIndex() >= nMax )
{
// Next paragraph ...
- sal_Int32 nCurPara = aEditDoc.GetPos( aNewPaM.GetNode() );
- ContentNode* pNextNode = aEditDoc.GetObject( ++nCurPara );
+ sal_Int32 nCurPara = maEditDoc.GetPos( aNewPaM.GetNode() );
+ ContentNode* pNextNode = maEditDoc.GetObject( ++nCurPara );
if ( pNextNode )
{
aNewPaM.SetNode( pNextNode );
@@ -1502,8 +1541,11 @@ EditPaM ImpEditEngine::StartOfWord( const EditPaM& rPaM )
lang::Locale aLocale( GetLocale( aTmpPaM ) );
uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() );
+ // tdf#135761 - since this function is only used when a selection is deleted at the left,
+ // change the search preference of the word boundary from forward to backward.
+ // For further details of a deletion of a selection check ImpEditEngine::DeleteLeftOrRight.
i18n::Boundary aBoundary = _xBI->getWordBoundary(
- rPaM.GetNode()->GetString(), rPaM.GetIndex(), aLocale, css::i18n::WordType::ANYWORD_IGNOREWHITESPACES, true);
+ rPaM.GetNode()->GetString(), rPaM.GetIndex(), aLocale, css::i18n::WordType::ANYWORD_IGNOREWHITESPACES, false);
aNewPaM.SetIndex( aBoundary.startPos );
return aNewPaM;
@@ -1528,7 +1570,7 @@ EditPaM ImpEditEngine::EndOfWord( const EditPaM& rPaM )
return aNewPaM;
}
-EditSelection ImpEditEngine::SelectWord( const EditSelection& rCurSel, sal_Int16 nWordType, bool bAcceptStartOfWord )
+EditSelection ImpEditEngine::SelectWord( const EditSelection& rCurSel, sal_Int16 nWordType, bool bAcceptStartOfWord, bool bAcceptEndOfWord )
{
EditSelection aNewSel( rCurSel );
EditPaM aPaM( rCurSel.Max() );
@@ -1550,7 +1592,7 @@ EditSelection ImpEditEngine::SelectWord( const EditSelection& rCurSel, sal_Int16
aPaM.GetNode()->GetString(), aPaM.GetIndex(), aLocale, nWordType, true);
// don't select when cursor at end of word
- if ( ( aBoundary.endPos > aPaM.GetIndex() ) &&
+ if ( ( aBoundary.endPos > aPaM.GetIndex() || ( bAcceptEndOfWord && aBoundary.endPos == aPaM.GetIndex() ) ) &&
( ( aBoundary.startPos < aPaM.GetIndex() ) || ( bAcceptStartOfWord && ( aBoundary.startPos == aPaM.GetIndex() ) ) ) )
{
aNewSel.Min().SetIndex( aBoundary.startPos );
@@ -1586,15 +1628,13 @@ EditSelection ImpEditEngine::SelectSentence( const EditSelection& rCurSel )
bool ImpEditEngine::IsInputSequenceCheckingRequired( sal_Unicode nChar, const EditSelection& rCurSel ) const
{
uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() );
- if (!pCTLOptions)
- pCTLOptions.reset( new SvtCTLOptions );
// get the index that really is first
const sal_Int32 nFirstPos = std::min(rCurSel.Min().GetIndex(), rCurSel.Max().GetIndex());
bool bIsSequenceChecking =
- pCTLOptions->IsCTLFontEnabled() &&
- pCTLOptions->IsCTLSequenceChecking() &&
+ SvtCTLOptions::IsCTLFontEnabled() &&
+ SvtCTLOptions::IsCTLSequenceChecking() &&
nFirstPos != 0 && /* first char needs not to be checked */
_xBI.is() && i18n::ScriptType::COMPLEX == _xBI->getScriptType( OUString( nChar ), 0 );
@@ -1621,7 +1661,7 @@ void ImpEditEngine::InitScriptTypes( sal_Int32 nPara )
if (!pParaPortion)
return;
- ScriptTypePosInfos& rTypes = pParaPortion->aScriptInfos;
+ ScriptTypePosInfos& rTypes = pParaPortion->getScriptTypePosInfos();
rTypes.clear();
ContentNode* pNode = pParaPortion->GetNode();
@@ -1640,7 +1680,7 @@ void ImpEditEngine::InitScriptTypes( sal_Int32 nPara )
const OUString aFldText = static_cast<const EditCharAttribField*>(pField)->GetFieldValue();
if ( !aFldText.isEmpty() )
{
- aText = aText.replaceAt( pField->GetStart(), 1, aFldText.copy(0,1) );
+ aText = aText.replaceAt( pField->GetStart(), 1, aFldText.subView(0,1) );
short nFldScriptType = _xBI->getScriptType( aFldText, 0 );
for ( sal_Int32 nCharInField = 1; nCharInField < aFldText.getLength(); nCharInField++ )
@@ -1651,14 +1691,14 @@ void ImpEditEngine::InitScriptTypes( sal_Int32 nPara )
if ( nFldScriptType == i18n::ScriptType::WEAK )
{
nFldScriptType = nTmpType;
- aText = aText.replaceAt( pField->GetStart(), 1, aFldText.copy(nCharInField,1) );
+ aText = aText.replaceAt( pField->GetStart(), 1, aFldText.subView(nCharInField,1) );
}
// ... but if the first one is LATIN, and there are CJK or CTL chars too,
// we prefer that ScriptType because we need another font.
if ( ( nTmpType == i18n::ScriptType::ASIAN ) || ( nTmpType == i18n::ScriptType::COMPLEX ) )
{
- aText = aText.replaceAt( pField->GetStart(), 1, aFldText.copy(nCharInField,1) );
+ aText = aText.replaceAt( pField->GetStart(), 1, aFldText.subView(nCharInField,1) );
break;
}
}
@@ -1687,14 +1727,19 @@ void ImpEditEngine::InitScriptTypes( sal_Int32 nPara )
}
else
{
- if ( _xBI->getScriptType( aText, nPos - 1 ) == i18n::ScriptType::WEAK )
+ auto nPrevPos = nPos;
+ auto nPrevChar = aText.iterateCodePoints(&nPrevPos, -1);
+ if (_xBI->getScriptType(aText, nPrevPos) == i18n::ScriptType::WEAK)
{
- switch ( u_charType(aText.iterateCodePoints(&nPos, 0) ) ) {
- case U_NON_SPACING_MARK:
- case U_ENCLOSING_MARK:
- case U_COMBINING_SPACING_MARK:
- --nPos;
- rTypes.back().nEndPos--;
+ auto nChar = aText.iterateCodePoints(&nPos, 0);
+ auto nType = unicode::getUnicodeType(nChar);
+ if (nType == css::i18n::UnicodeType::NON_SPACING_MARK ||
+ nType == css::i18n::UnicodeType::ENCLOSING_MARK ||
+ nType == css::i18n::UnicodeType::COMBINING_SPACING_MARK ||
+ (nPrevChar == 0x202F /* NNBSP, tdf#112594 */ &&
+ u_getIntPropertyValue(nChar, UCHAR_SCRIPT) == USCRIPT_MONGOLIAN))
+ {
+ rTypes.back().nEndPos = nPos = nPrevPos;
break;
}
}
@@ -1708,11 +1753,11 @@ void ImpEditEngine::InitScriptTypes( sal_Int32 nPara )
rTypes[0].nScriptType = ( rTypes.size() > 1 ) ? rTypes[1].nScriptType : SvtLanguageOptions::GetI18NScriptTypeOfLanguage( GetDefaultLanguage() );
// create writing direction information:
- if ( pParaPortion->aWritingDirectionInfos.empty() )
+ WritingDirectionInfos& rDirInfos = pParaPortion->getWritingDirectionInfos();
+ if (rDirInfos.empty())
InitWritingDirections( nPara );
// i89825: Use CTL font for numbers embedded into an RTL run:
- WritingDirectionInfos& rDirInfos = pParaPortion->aWritingDirectionInfos;
for (const WritingDirectionInfo & rDirInfo : rDirInfos)
{
const sal_Int32 nStart = rDirInfo.nStartPos;
@@ -1787,10 +1832,10 @@ sal_uInt16 ImpEditEngine::GetI18NScriptType( const EditPaM& rPaM, sal_Int32* pEn
const ParaPortion* pParaPortion = GetParaPortions().SafeGetObject( nPara );
if (pParaPortion)
{
- if ( pParaPortion->aScriptInfos.empty() )
- const_cast<ImpEditEngine*>(this)->InitScriptTypes( nPara );
+ const ScriptTypePosInfos& rTypes = pParaPortion->getScriptTypePosInfos();
- const ScriptTypePosInfos& rTypes = pParaPortion->aScriptInfos;
+ if (rTypes.empty())
+ const_cast<ImpEditEngine*>(this)->InitScriptTypes( nPara );
const sal_Int32 nPos = rPaM.GetIndex();
ScriptTypePosInfos::const_iterator itr = std::find_if(rTypes.begin(), rTypes.end(), FindByPos(nPos));
@@ -1808,7 +1853,7 @@ sal_uInt16 ImpEditEngine::GetI18NScriptType( const EditPaM& rPaM, sal_Int32* pEn
SvtScriptType ImpEditEngine::GetItemScriptType( const EditSelection& rSel ) const
{
EditSelection aSel( rSel );
- aSel.Adjust( aEditDoc );
+ aSel.Adjust( maEditDoc );
SvtScriptType nScriptType = SvtScriptType::NONE;
@@ -1821,10 +1866,10 @@ SvtScriptType ImpEditEngine::GetItemScriptType( const EditSelection& rSel ) cons
if (!pParaPortion)
continue;
- if ( pParaPortion->aScriptInfos.empty() )
- const_cast<ImpEditEngine*>(this)->InitScriptTypes( nPara );
+ ScriptTypePosInfos const& rTypes = pParaPortion->getScriptTypePosInfos();
- const ScriptTypePosInfos& rTypes = pParaPortion->aScriptInfos;
+ if (rTypes.empty())
+ const_cast<ImpEditEngine*>(this)->InitScriptTypes( nPara );
// find all the scripts of this range
sal_Int32 nS = ( nPara == nStartPara ) ? aSel.Min().GetIndex() : 0;
@@ -1867,10 +1912,11 @@ bool ImpEditEngine::IsScriptChange( const EditPaM& rPaM ) const
const ParaPortion* pParaPortion = GetParaPortions().SafeGetObject( nPara );
if (pParaPortion)
{
- if ( pParaPortion->aScriptInfos.empty() )
+ ScriptTypePosInfos const& rTypes = pParaPortion->getScriptTypePosInfos();
+
+ if (rTypes.empty())
const_cast<ImpEditEngine*>(this)->InitScriptTypes( nPara );
- const ScriptTypePosInfos& rTypes = pParaPortion->aScriptInfos;
const sal_Int32 nPos = rPaM.GetIndex();
for (const ScriptTypePosInfo & rType : rTypes)
{
@@ -1892,10 +1938,11 @@ bool ImpEditEngine::HasScriptType( sal_Int32 nPara, sal_uInt16 nType ) const
const ParaPortion* pParaPortion = GetParaPortions().SafeGetObject( nPara );
if (pParaPortion)
{
- if ( pParaPortion->aScriptInfos.empty() )
+ const ScriptTypePosInfos& rTypes = pParaPortion->getScriptTypePosInfos();
+
+ if (rTypes.empty())
const_cast<ImpEditEngine*>(this)->InitScriptTypes( nPara );
- const ScriptTypePosInfos& rTypes = pParaPortion->aScriptInfos;
for ( size_t n = rTypes.size(); n && !bTypeFound; )
{
if ( rTypes[--n].nScriptType == nType )
@@ -1911,10 +1958,10 @@ void ImpEditEngine::InitWritingDirections( sal_Int32 nPara )
if (!pParaPortion)
return;
- WritingDirectionInfos& rInfos = pParaPortion->aWritingDirectionInfos;
+ WritingDirectionInfos& rInfos = pParaPortion->getWritingDirectionInfos();
rInfos.clear();
- if (pParaPortion->GetNode()->Len())
+ if (pParaPortion->GetNode()->Len() && !mbFuzzing)
{
const OUString aText = pParaPortion->GetNode()->GetString();
@@ -1959,7 +2006,7 @@ bool ImpEditEngine::IsRightToLeft( sal_Int32 nPara ) const
bool bR2L = false;
const SvxFrameDirectionItem* pFrameDirItem = nullptr;
- if ( !IsVertical() )
+ if ( !IsEffectivelyVertical() )
{
bR2L = GetDefaultHorizontalTextDirection() == EEHorizontalTextDirection::R2L;
pFrameDirItem = &GetParaAttrib( nPara, EE_PARA_WRITINGDIR );
@@ -2011,16 +2058,16 @@ sal_uInt8 ImpEditEngine::GetRightToLeft( sal_Int32 nPara, sal_Int32 nPos, sal_In
{
sal_uInt8 nRightToLeft = 0;
- ContentNode* pNode = aEditDoc.GetObject( nPara );
+ ContentNode* pNode = maEditDoc.GetObject( nPara );
if ( pNode && pNode->Len() )
{
ParaPortion* pParaPortion = GetParaPortions().SafeGetObject( nPara );
if (pParaPortion)
{
- if ( pParaPortion->aWritingDirectionInfos.empty() )
+ WritingDirectionInfos& rDirInfos = pParaPortion->getWritingDirectionInfos();
+ if (rDirInfos.empty())
InitWritingDirections( nPara );
- WritingDirectionInfos& rDirInfos = pParaPortion->aWritingDirectionInfos;
for (const WritingDirectionInfo & rDirInfo : rDirInfos)
{
if ( ( rDirInfo.nStartPos <= nPos ) && ( rDirInfo.nEndPos >= nPos ) )
@@ -2042,7 +2089,7 @@ SvxAdjust ImpEditEngine::GetJustification( sal_Int32 nPara ) const
{
SvxAdjust eJustification = SvxAdjust::Left;
- if ( !aStatus.IsOutliner() )
+ if (!maStatus.IsOutliner())
{
eJustification = GetParaAttrib( nPara, EE_PARA_JUST ).GetAdjust();
@@ -2091,15 +2138,15 @@ void ImpEditEngine::ImpRemoveChars( const EditPaM& rPaM, sal_Int32 nChars )
break; // for
}
}
- InsertUndo(std::make_unique<EditUndoRemoveChars>(pEditEngine, CreateEPaM(rPaM), aStr));
+ InsertUndo(std::make_unique<EditUndoRemoveChars>(mpEditEngine, CreateEPaM(rPaM), aStr));
}
- aEditDoc.RemoveChars( rPaM, nChars );
+ maEditDoc.RemoveChars( rPaM, nChars );
}
EditSelection ImpEditEngine::ImpMoveParagraphs( Range aOldPositions, sal_Int32 nNewPos )
{
- aOldPositions.Justify();
+ aOldPositions.Normalize();
bool bValidAction = ( static_cast<tools::Long>(nNewPos) < aOldPositions.Min() ) || ( static_cast<tools::Long>(nNewPos) > aOldPositions.Max() );
OSL_ENSURE( bValidAction, "Move in itself?" );
OSL_ENSURE( aOldPositions.Max() <= static_cast<tools::Long>(GetParaPortions().Count()), "totally over it: MoveParagraphs" );
@@ -2108,7 +2155,7 @@ EditSelection ImpEditEngine::ImpMoveParagraphs( Range aOldPositions, sal_Int32 n
if ( !bValidAction )
{
- aSelection = aEditDoc.GetStartPaM();
+ aSelection = maEditDoc.GetStartPaM();
return aSelection;
}
@@ -2123,68 +2170,83 @@ EditSelection ImpEditEngine::ImpMoveParagraphs( Range aOldPositions, sal_Int32 n
ParaPortion* pRecalc3 = nullptr;
ParaPortion* pRecalc4 = nullptr;
- if ( nNewPos == 0 ) // Move to Start
+ if (nNewPos == 0) // Move to Start
{
- pRecalc1 = GetParaPortions()[0];
- pRecalc2 = GetParaPortions()[aOldPositions.Min()];
+ if (GetParaPortions().exists(0))
+ pRecalc1 = &GetParaPortions().getRef(0);
+ if (GetParaPortions().exists(aOldPositions.Min()))
+ pRecalc2 = &GetParaPortions().getRef(aOldPositions.Min());
}
- else if ( nNewPos == nParaCount )
+ else if (nNewPos == nParaCount)
{
- pRecalc1 = GetParaPortions()[nParaCount-1];
- pRecalc2 = GetParaPortions()[aOldPositions.Max()];
+ if (GetParaPortions().exists(nParaCount - 1))
+ pRecalc1 = &GetParaPortions().getRef(nParaCount - 1);
+ if (GetParaPortions().exists(aOldPositions.Max()))
+ pRecalc2 = &GetParaPortions().getRef(aOldPositions.Max());
}
- if ( aOldPositions.Min() == 0 ) // Move from Start
+ if (aOldPositions.Min() == 0) // Move from Start
{
- pRecalc3 = GetParaPortions()[0];
- pRecalc4 = GetParaPortions()[aOldPositions.Max()+1];
+ if (GetParaPortions().exists(0))
+ pRecalc3 = &GetParaPortions().getRef(0);
+ if (GetParaPortions().exists(aOldPositions.Max() + 1))
+ pRecalc4 = &GetParaPortions().getRef(aOldPositions.Max() + 1);
}
- else if ( aOldPositions.Max() == (nParaCount-1) )
+ else if (aOldPositions.Max() == nParaCount - 1)
{
- pRecalc3 = GetParaPortions()[aOldPositions.Max()];
- pRecalc4 = GetParaPortions()[aOldPositions.Min()-1];
+ if (GetParaPortions().exists(aOldPositions.Max()))
+ pRecalc3 = &GetParaPortions().getRef(aOldPositions.Max());
+ if (GetParaPortions().exists(aOldPositions.Min() - 1))
+ pRecalc4 = &GetParaPortions().getRef(aOldPositions.Min() - 1);
}
MoveParagraphsInfo aMoveParagraphsInfo( aOldPositions.Min(), aOldPositions.Max(), nNewPos );
- aBeginMovingParagraphsHdl.Call( aMoveParagraphsInfo );
+ maBeginMovingParagraphsHdl.Call( aMoveParagraphsInfo );
if ( IsUndoEnabled() && !IsInUndo())
- InsertUndo(std::make_unique<EditUndoMoveParagraphs>(pEditEngine, aOldPositions, nNewPos));
+ InsertUndo(std::make_unique<EditUndoMoveParagraphs>(mpEditEngine, aOldPositions, nNewPos));
// do not lose sight of the Position !
ParaPortion* pDestPortion = GetParaPortions().SafeGetObject( nNewPos );
- ParaPortionList aTmpPortionList;
+ // Temporary containers used for moving the paragraph portions and content nodes to a new location
+ std::vector<std::unique_ptr<ParaPortion>> aParagraphPortionVector;
+ std::vector<std::unique_ptr<ContentNode>> aContentNodeVector;
+
+ // Take the paragraph portions and content nodes out of its containers
for (tools::Long i = aOldPositions.Min(); i <= aOldPositions.Max(); i++ )
{
- // always aOldPositions.Min(), since Remove().
- std::unique_ptr<ParaPortion> pTmpPortion = GetParaPortions().Release(aOldPositions.Min());
- aEditDoc.Release( aOldPositions.Min() );
- aTmpPortionList.Append(std::move(pTmpPortion));
+ // always aOldPositions.Min() as the index, since we remove and the elements from the containers and the
+ // other elements shift to the left.
+ std::unique_ptr<ParaPortion> pPortion = GetParaPortions().Release(aOldPositions.Min());
+ aParagraphPortionVector.push_back(std::move(pPortion));
+
+ std::unique_ptr<ContentNode> pContentNode = maEditDoc.Release(aOldPositions.Min());
+ aContentNodeVector.push_back(std::move(pContentNode));
}
+ // Determine the new location for paragraphs
sal_Int32 nRealNewPos = pDestPortion ? GetParaPortions().GetPos( pDestPortion ) : GetParaPortions().Count();
- OSL_ENSURE( nRealNewPos != EE_PARA_NOT_FOUND, "ImpMoveParagraphs: Invalid Position!" );
+ assert( nRealNewPos != EE_PARA_NOT_FOUND && "ImpMoveParagraphs: Invalid Position!" );
+ // Add the paragraph portions and content nodes to a new position
sal_Int32 i = 0;
- while( aTmpPortionList.Count() > 0 )
+ for (auto& pPortion : aParagraphPortionVector)
{
- std::unique_ptr<ParaPortion> pTmpPortion = aTmpPortionList.Release(0);
- if ( i == 0 )
- aSelection.Min().SetNode( pTmpPortion->GetNode() );
-
- aSelection.Max().SetNode( pTmpPortion->GetNode() );
- aSelection.Max().SetIndex( pTmpPortion->GetNode()->Len() );
+ if (i == 0)
+ aSelection.Min().SetNode(pPortion->GetNode());
+ aSelection.Max().SetNode(pPortion->GetNode());
+ aSelection.Max().SetIndex(pPortion->GetNode()->Len());
- ContentNode* pN = pTmpPortion->GetNode();
- aEditDoc.Insert(nRealNewPos+i, pN);
+ maEditDoc.Insert(nRealNewPos + i, std::move(aContentNodeVector[i]));
+ GetParaPortions().Insert(nRealNewPos + i, std::move(pPortion));
- GetParaPortions().Insert(nRealNewPos+i, std::move(pTmpPortion));
++i;
}
- aEndMovingParagraphsHdl.Call( aMoveParagraphsInfo );
+ // Signal end of paragraph moving
+ maEndMovingParagraphsHdl.Call( aMoveParagraphsInfo );
if ( GetNotifyHdl().IsSet() )
{
@@ -2195,19 +2257,19 @@ EditSelection ImpEditEngine::ImpMoveParagraphs( Range aOldPositions, sal_Int32 n
GetNotifyHdl().Call( aNotify );
}
- aEditDoc.SetModified( true );
+ maEditDoc.SetModified( true );
- if ( pRecalc1 )
- CalcHeight( pRecalc1 );
- if ( pRecalc2 )
- CalcHeight( pRecalc2 );
- if ( pRecalc3 )
- CalcHeight( pRecalc3 );
- if ( pRecalc4 )
- CalcHeight( pRecalc4 );
+ if (pRecalc1)
+ CalcHeight(*pRecalc1);
+ if (pRecalc2)
+ CalcHeight(*pRecalc2);
+ if (pRecalc3)
+ CalcHeight(*pRecalc3);
+ if (pRecalc4)
+ CalcHeight(*pRecalc4);
#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
- ParaPortionList::DbgCheck(GetParaPortions(), aEditDoc);
+ ParaPortionList::DbgCheck(GetParaPortions(), maEditDoc);
#endif
return aSelection;
}
@@ -2216,28 +2278,28 @@ EditSelection ImpEditEngine::ImpMoveParagraphs( Range aOldPositions, sal_Int32 n
EditPaM ImpEditEngine::ImpConnectParagraphs( ContentNode* pLeft, ContentNode* pRight, bool bBackward )
{
OSL_ENSURE( pLeft != pRight, "Join together the same paragraph ?" );
- OSL_ENSURE( aEditDoc.GetPos( pLeft ) != EE_PARA_NOT_FOUND, "Inserted node not found (1)" );
- OSL_ENSURE( aEditDoc.GetPos( pRight ) != EE_PARA_NOT_FOUND, "Inserted node not found (2)" );
+ OSL_ENSURE( maEditDoc.GetPos( pLeft ) != EE_PARA_NOT_FOUND, "Inserted node not found (1)" );
+ OSL_ENSURE( maEditDoc.GetPos( pRight ) != EE_PARA_NOT_FOUND, "Inserted node not found (2)" );
// #i120020# it is possible that left and right are *not* in the desired order (left/right)
// so correct it. This correction is needed, else an invalid SfxLinkUndoAction will be
// created from ConnectParagraphs below. Assert this situation, it should be corrected by the
// caller.
- if(aEditDoc.GetPos( pLeft ) > aEditDoc.GetPos( pRight ))
+ if (maEditDoc.GetPos( pLeft ) > maEditDoc.GetPos( pRight ))
{
OSL_ENSURE(false, "ImpConnectParagraphs with wrong order of pLeft/pRight nodes (!)");
std::swap(pLeft, pRight);
}
- sal_Int32 nParagraphTobeDeleted = aEditDoc.GetPos( pRight );
- aDeletedNodes.push_back(std::make_unique<DeletedNodeInfo>( pRight, nParagraphTobeDeleted ));
+ sal_Int32 nParagraphTobeDeleted = maEditDoc.GetPos( pRight );
+ maDeletedNodes.push_back(std::make_unique<DeletedNodeInfo>( pRight, nParagraphTobeDeleted ));
- GetEditEnginePtr()->ParagraphConnected( aEditDoc.GetPos( pLeft ), aEditDoc.GetPos( pRight ) );
+ GetEditEnginePtr()->ParagraphConnected( maEditDoc.GetPos( pLeft ), maEditDoc.GetPos( pRight ) );
if ( IsUndoEnabled() && !IsInUndo() )
{
- InsertUndo( std::make_unique<EditUndoConnectParas>(pEditEngine,
- aEditDoc.GetPos( pLeft ), pLeft->Len(),
+ InsertUndo( std::make_unique<EditUndoConnectParas>(mpEditEngine,
+ maEditDoc.GetPos( pLeft ), pLeft->Len(),
pLeft->GetContentAttribs().GetItems(), pRight->GetContentAttribs().GetItems(),
pLeft->GetStyleSheet(), pRight->GetStyleSheet(), bBackward ) );
}
@@ -2255,7 +2317,7 @@ EditPaM ImpEditEngine::ImpConnectParagraphs( ContentNode* pLeft, ContentNode* pR
// First search for Portions since pRight is gone after ConnectParagraphs.
ParaPortion* pLeftPortion = FindParaPortion( pLeft );
- OSL_ENSURE( pLeftPortion, "Blind Portion in ImpConnectParagraphs(1)" );
+ assert(pLeftPortion);
if ( GetStatus().DoOnlineSpelling() )
{
@@ -2279,7 +2341,7 @@ EditPaM ImpEditEngine::ImpConnectParagraphs( ContentNode* pLeft, ContentNode* pR
if ( IsCallParaInsertedOrDeleted() )
GetEditEnginePtr()->ParagraphDeleted( nParagraphTobeDeleted );
- EditPaM aPaM = aEditDoc.ConnectParagraphs( pLeft, pRight );
+ EditPaM aPaM = maEditDoc.ConnectParagraphs( pLeft, pRight );
GetParaPortions().Remove( nParagraphTobeDeleted );
pLeftPortion->MarkSelectionInvalid( aPaM.GetIndex() );
@@ -2292,9 +2354,9 @@ EditPaM ImpEditEngine::ImpConnectParagraphs( ContentNode* pLeft, ContentNode* pR
// the change of the total text height too late...
for ( sal_Int32 n = nParagraphTobeDeleted; n < GetParaPortions().Count(); n++ )
{
- ParaPortion* pPP = GetParaPortions()[n];
- pPP->MarkSelectionInvalid( 0 );
- pPP->GetLines().Reset();
+ ParaPortion& rParaPortion = GetParaPortions().getRef(n);
+ rParaPortion.MarkSelectionInvalid(0);
+ rParaPortion.GetLines().Reset();
}
}
@@ -2305,7 +2367,7 @@ EditPaM ImpEditEngine::ImpConnectParagraphs( ContentNode* pLeft, ContentNode* pR
EditPaM ImpEditEngine::DeleteLeftOrRight( const EditSelection& rSel, sal_uInt8 nMode, DeleteMode nDelMode )
{
- OSL_ENSURE( !rSel.DbgIsBuggy( aEditDoc ), "Index out of range in DeleteLeftOrRight" );
+ OSL_ENSURE( !rSel.DbgIsBuggy( maEditDoc ), "Index out of range in DeleteLeftOrRight" );
if ( rSel.HasRange() ) // only then Delete Selection
return ImpDeleteSelection( rSel );
@@ -2318,17 +2380,15 @@ EditPaM ImpEditEngine::DeleteLeftOrRight( const EditSelection& rSel, sal_uInt8 n
if ( nDelMode == DeleteMode::Simple )
{
sal_uInt16 nCharMode = i18n::CharacterIteratorMode::SKIPCHARACTER;
- // Check if we are deleting a CJK ideograph variance sequence (IVS).
+ // If we are deleting a variation selector, we want to delete the
+ // whole sequence (cell).
sal_Int32 nIndex = aCurPos.GetIndex();
if (nIndex > 0)
{
const OUString& rString = aCurPos.GetNode()->GetString();
sal_Int32 nCode = rString.iterateCodePoints(&nIndex, -1);
- if (unicode::isIVSSelector(nCode) && nIndex > 0 &&
- unicode::isCJKIVSCharacter(rString.iterateCodePoints(&nIndex, -1)))
- {
+ if (unicode::isVariationSelector(nCode))
nCharMode = i18n::CharacterIteratorMode::SKIPCELL;
- }
}
aDelStart = CursorLeft(aCurPos, nCharMode);
}
@@ -2402,18 +2462,20 @@ EditPaM ImpEditEngine::ImpDeleteSelection(const EditSelection& rCurSel)
return rCurSel.Min();
EditSelection aCurSel(rCurSel);
- aCurSel.Adjust( aEditDoc );
+ aCurSel.Adjust( maEditDoc );
EditPaM aStartPaM(aCurSel.Min());
EditPaM aEndPaM(aCurSel.Max());
- CursorMoved( aStartPaM.GetNode() ); // only so that newly set Attributes disappear...
- CursorMoved( aEndPaM.GetNode() ); // only so that newly set Attributes disappear...
+ if( nullptr != aStartPaM.GetNode() )
+ aStartPaM.GetNode()->checkAndDeleteEmptyAttribs(); // only so that newly set Attributes disappear...
+ if( nullptr != aEndPaM.GetNode() )
+ aEndPaM.GetNode()->checkAndDeleteEmptyAttribs(); // only so that newly set Attributes disappear...
OSL_ENSURE( aStartPaM.GetIndex() <= aStartPaM.GetNode()->Len(), "Index out of range in ImpDeleteSelection" );
OSL_ENSURE( aEndPaM.GetIndex() <= aEndPaM.GetNode()->Len(), "Index out of range in ImpDeleteSelection" );
- sal_Int32 nStartNode = aEditDoc.GetPos( aStartPaM.GetNode() );
- sal_Int32 nEndNode = aEditDoc.GetPos( aEndPaM.GetNode() );
+ sal_Int32 nStartNode = maEditDoc.GetPos( aStartPaM.GetNode() );
+ sal_Int32 nEndNode = maEditDoc.GetPos( aEndPaM.GetNode() );
OSL_ENSURE( nEndNode != EE_PARA_NOT_FOUND, "Start > End ?!" );
OSL_ENSURE( nStartNode <= nEndNode, "Start > End ?!" );
@@ -2430,7 +2492,7 @@ EditPaM ImpEditEngine::ImpDeleteSelection(const EditSelection& rCurSel)
// The Rest of the StartNodes...
ImpRemoveChars( aStartPaM, aStartPaM.GetNode()->Len() - aStartPaM.GetIndex() );
ParaPortion* pPortion = FindParaPortion( aStartPaM.GetNode() );
- OSL_ENSURE( pPortion, "Blind Portion in ImpDeleteSelection(3)" );
+ assert(pPortion);
pPortion->MarkSelectionInvalid( aStartPaM.GetIndex() );
// The beginning of the EndNodes...
@@ -2438,7 +2500,7 @@ EditPaM ImpEditEngine::ImpDeleteSelection(const EditSelection& rCurSel)
aEndPaM.SetIndex( 0 );
ImpRemoveChars( aEndPaM, nChars );
pPortion = FindParaPortion( aEndPaM.GetNode() );
- OSL_ENSURE( pPortion, "Blind Portion in ImpDeleteSelection(4)" );
+ assert(pPortion);
pPortion->MarkSelectionInvalid( 0 );
// Join together...
aStartPaM = ImpConnectParagraphs( aStartPaM.GetNode(), aEndPaM.GetNode() );
@@ -2447,7 +2509,7 @@ EditPaM ImpEditEngine::ImpDeleteSelection(const EditSelection& rCurSel)
{
ImpRemoveChars( aStartPaM, aEndPaM.GetIndex() - aStartPaM.GetIndex() );
ParaPortion* pPortion = FindParaPortion( aStartPaM.GetNode() );
- OSL_ENSURE( pPortion, "Blind Portion in ImpDeleteSelection(5)" );
+ assert(pPortion);
pPortion->MarkInvalid( aEndPaM.GetIndex(), aStartPaM.GetIndex() - aEndPaM.GetIndex() );
}
@@ -2458,15 +2520,15 @@ EditPaM ImpEditEngine::ImpDeleteSelection(const EditSelection& rCurSel)
void ImpEditEngine::ImpRemoveParagraph( sal_Int32 nPara )
{
- ContentNode* pNode = aEditDoc.GetObject( nPara );
- ContentNode* pNextNode = aEditDoc.GetObject( nPara+1 );
+ assert(maEditDoc.GetObject(nPara));
- OSL_ENSURE( pNode, "Blind Node in ImpRemoveParagraph" );
+ ContentNode* pNextNode = maEditDoc.GetObject( nPara+1 );
- aDeletedNodes.push_back(std::make_unique<DeletedNodeInfo>( pNode, nPara ));
+ std::unique_ptr<ContentNode> pNode = maEditDoc.Release(nPara);
+ maDeletedNodes.push_back(std::make_unique<DeletedNodeInfo>(pNode.get(), nPara));
// The node is managed by the undo and possibly destroyed!
- aEditDoc.Release( nPara );
+
GetParaPortions().Remove( nPara );
if ( IsCallParaInsertedOrDeleted() )
@@ -2480,14 +2542,15 @@ void ImpEditEngine::ImpRemoveParagraph( sal_Int32 nPara )
if ( pNextNode )
ParaAttribsChanged( pNextNode );
- if ( IsUndoEnabled() && !IsInUndo() )
- InsertUndo(std::make_unique<EditUndoDelContent>(pEditEngine, pNode, nPara));
+ if (IsUndoEnabled() && !IsInUndo())
+ {
+ InsertUndo(std::make_unique<EditUndoDelContent>(mpEditEngine, std::move(pNode), nPara));
+ }
else
{
- aEditDoc.RemoveItemsFromPool(*pNode);
if ( pNode->GetStyleSheet() )
- EndListening( *pNode->GetStyleSheet() );
- delete pNode;
+ EndListening(*pNode->GetStyleSheet());
+ pNode.reset();
}
}
@@ -2548,7 +2611,7 @@ EditPaM ImpEditEngine::AutoCorrect( const EditSelection& rCurSel, sal_Unicode c,
ContentNode* pNode = aSel.Max().GetNode();
const sal_Int32 nIndex = aSel.Max().GetIndex();
- EdtAutoCorrDoc aAuto(pEditEngine, pNode, nIndex, c);
+ EdtAutoCorrDoc aAuto(mpEditEngine, pNode, nIndex, c);
// FIXME: this _must_ be called with reference to the actual node text!
OUString const& rNodeString(pNode->GetString());
pAutoCorrect->DoAutoCorrect(
@@ -2588,7 +2651,7 @@ EditPaM ImpEditEngine::InsertTextUserInput( const EditSelection& rCurSel,
// If selected, then do not also overwrite a character!
EditSelection aTmpSel( aPaM );
aTmpSel.Max().SetIndex( aTmpSel.Max().GetIndex()+1 );
- OSL_ENSURE( !aTmpSel.DbgIsBuggy( aEditDoc ), "Overwrite: Wrong selection! ");
+ OSL_ENSURE( !aTmpSel.DbgIsBuggy( maEditDoc ), "Overwrite: Wrong selection! ");
ImpDeleteSelection( aTmpSel );
}
@@ -2597,20 +2660,18 @@ EditPaM ImpEditEngine::InsertTextUserInput( const EditSelection& rCurSel,
if (IsInputSequenceCheckingRequired( c, rCurSel ))
{
uno::Reference < i18n::XExtendedInputSequenceChecker > _xISC( ImplGetInputSequenceChecker() );
- if (!pCTLOptions)
- pCTLOptions.reset( new SvtCTLOptions );
if (_xISC)
{
const sal_Int32 nTmpPos = aPaM.GetIndex();
- sal_Int16 nCheckMode = pCTLOptions->IsCTLSequenceCheckingRestricted() ?
+ sal_Int16 nCheckMode = SvtCTLOptions::IsCTLSequenceCheckingRestricted() ?
i18n::InputSequenceCheckMode::STRICT : i18n::InputSequenceCheckMode::BASIC;
// the text that needs to be checked is only the one
// before the current cursor position
const OUString aOldText( aPaM.GetNode()->Copy(0, nTmpPos) );
OUString aNewText( aOldText );
- if (pCTLOptions->IsCTLSequenceCheckingTypeAndReplace())
+ if (SvtCTLOptions::IsCTLSequenceCheckingTypeAndReplace())
{
_xISC->correctInputSequence(aNewText, nTmpPos - 1, c, nCheckMode);
@@ -2647,14 +2708,14 @@ EditPaM ImpEditEngine::InsertTextUserInput( const EditSelection& rCurSel,
if ( IsUndoEnabled() && !IsInUndo() )
{
- std::unique_ptr<EditUndoInsertChars> pNewUndo(new EditUndoInsertChars(pEditEngine, CreateEPaM(aPaM), OUString(c)));
+ std::unique_ptr<EditUndoInsertChars> pNewUndo(new EditUndoInsertChars(mpEditEngine, CreateEPaM(aPaM), OUString(c)));
bool bTryMerge = !bDoOverwrite && ( c != ' ' );
InsertUndo( std::move(pNewUndo), bTryMerge );
}
- aEditDoc.InsertText( aPaM, OUString(c) );
+ maEditDoc.InsertText( aPaM, OUStringChar(c) );
ParaPortion* pPortion = FindParaPortion( aPaM.GetNode() );
- OSL_ENSURE( pPortion, "Blind Portion in InsertText" );
+ assert(pPortion);
pPortion->MarkInvalid( aPaM.GetIndex(), 1 );
aPaM.SetIndex( aPaM.GetIndex()+1 ); // does not do EditDoc-Method anymore
}
@@ -2688,7 +2749,7 @@ EditPaM ImpEditEngine::ImpInsertText(const EditSelection& aCurSel, const OUStrin
aCurWord = SelectWord( aCurPaM, i18n::WordType::DICTIONARY_WORD );
OUString aText(convertLineEnd(rStr, LINEEND_LF));
- if (utl::ConfigManager::IsFuzzing()) //tab expansion performance in editeng is appalling
+ if (mbFuzzing) //tab expansion performance in editeng is appalling
aText = aText.replaceAll("\t","-");
SfxVoidItem aTabItem( EE_FEATURE_TAB );
@@ -2699,7 +2760,8 @@ EditPaM ImpEditEngine::ImpInsertText(const EditSelection& aCurSel, const OUStrin
sal_Int32 nStart = 0;
while ( nStart < aText.getLength() )
{
- sal_Int32 nEnd = aText.indexOf( LINE_SEP, nStart );
+ sal_Int32 nEnd = !maStatus.IsSingleLine() ?
+ aText.indexOf( LINE_SEP, nStart ) : -1;
if ( nEnd == -1 )
nEnd = aText.getLength(); // not dereference!
@@ -2712,14 +2774,64 @@ EditPaM ImpEditEngine::ImpInsertText(const EditSelection& aCurSel, const OUStrin
if (nChars > MAXCHARSINPARA)
{
sal_Int32 nMaxNewChars = std::max<sal_Int32>(0, MAXCHARSINPARA - nExistingChars);
- nEnd -= ( aLine.getLength() - nMaxNewChars ); // Then the characters end up in the next paragraph.
- aLine = aLine.copy( 0, nMaxNewChars ); // Delete the Rest...
+ // Wherever we break, it may be wrong. However, try to find the
+ // previous non-alnum/non-letter character. Note this is only
+ // in the to be appended data, otherwise already existing
+ // characters would have to be moved and PaM to be updated.
+ // Restrict to 2*42, if not found by then assume other data or
+ // language-script uses only letters or idiographs.
+ sal_Int32 nPos = nMaxNewChars;
+ while (nPos-- > 0 && (nMaxNewChars - nPos) <= 84)
+ {
+ auto nNextPos = nPos;
+ const auto c = aLine.iterateCodePoints(&nNextPos);
+ switch (unicode::getUnicodeType(c))
+ {
+ case css::i18n::UnicodeType::UPPERCASE_LETTER:
+ case css::i18n::UnicodeType::LOWERCASE_LETTER:
+ case css::i18n::UnicodeType::TITLECASE_LETTER:
+ case css::i18n::UnicodeType::MODIFIER_LETTER:
+ case css::i18n::UnicodeType::OTHER_LETTER:
+ case css::i18n::UnicodeType::DECIMAL_DIGIT_NUMBER:
+ case css::i18n::UnicodeType::LETTER_NUMBER:
+ case css::i18n::UnicodeType::OTHER_NUMBER:
+ case css::i18n::UnicodeType::CURRENCY_SYMBOL:
+ break;
+ default:
+ {
+ // Ignore NO-BREAK spaces, NBSP, NNBSP, ZWNBSP.
+ if (c == 0x00A0 || c == 0x202F || c == 0xFEFF)
+ break;
+ const auto n = aLine.iterateCodePoints(&nNextPos, 0);
+ if (c == '-' && nNextPos < nMaxNewChars)
+ {
+ // Keep HYPHEN-MINUS with a number to the right.
+ const sal_Int16 t = unicode::getUnicodeType(n);
+ if ( t == css::i18n::UnicodeType::DECIMAL_DIGIT_NUMBER ||
+ t == css::i18n::UnicodeType::LETTER_NUMBER ||
+ t == css::i18n::UnicodeType::OTHER_NUMBER)
+ nMaxNewChars = nPos; // line break before
+ else
+ nMaxNewChars = nNextPos; // line break after
+ }
+ else
+ {
+ nMaxNewChars = nNextPos; // line break after
+ }
+ nPos = 0; // will break loop
+ }
+ }
+ }
+ // Remaining characters end up in the next paragraph. Note that
+ // new nStart will be nEnd+1 below so decrement by one more.
+ nEnd -= (aLine.getLength() - nMaxNewChars + 1);
+ aLine = aLine.copy( 0, nMaxNewChars ); // Delete the Rest...
}
if ( IsUndoEnabled() && !IsInUndo() )
- InsertUndo(std::make_unique<EditUndoInsertChars>(pEditEngine, CreateEPaM(aPaM), aLine));
+ InsertUndo(std::make_unique<EditUndoInsertChars>(mpEditEngine, CreateEPaM(aPaM), aLine));
// Tabs ?
if ( aLine.indexOf( '\t' ) == -1 )
- aPaM = aEditDoc.InsertText( aPaM, aLine );
+ aPaM = maEditDoc.InsertText( aPaM, aLine );
else
{
sal_Int32 nStart2 = 0;
@@ -2730,16 +2842,16 @@ EditPaM ImpEditEngine::ImpInsertText(const EditSelection& aCurSel, const OUStrin
nEnd2 = aLine.getLength(); // not dereference!
if ( nEnd2 > nStart2 )
- aPaM = aEditDoc.InsertText( aPaM, aLine.copy( nStart2, nEnd2-nStart2 ) );
+ aPaM = maEditDoc.InsertText( aPaM, aLine.subView( nStart2, nEnd2-nStart2 ) );
if ( nEnd2 < aLine.getLength() )
{
- aPaM = aEditDoc.InsertFeature( aPaM, aTabItem );
+ aPaM = maEditDoc.InsertFeature( aPaM, aTabItem );
}
nStart2 = nEnd2+1;
}
}
ParaPortion* pPortion = FindParaPortion( aPaM.GetNode() );
- OSL_ENSURE( pPortion, "Blind Portion in InsertText" );
+ assert(pPortion);
if ( GetStatus().DoOnlineSpelling() )
{
@@ -2774,9 +2886,9 @@ EditPaM ImpEditEngine::ImpFastInsertText( EditPaM aPaM, const OUString& rStr )
if ( ( aPaM.GetNode()->Len() + rStr.getLength() ) < MAXCHARSINPARA )
{
if ( IsUndoEnabled() && !IsInUndo() )
- InsertUndo(std::make_unique<EditUndoInsertChars>(pEditEngine, CreateEPaM(aPaM), rStr));
+ InsertUndo(std::make_unique<EditUndoInsertChars>(mpEditEngine, CreateEPaM(aPaM), rStr));
- aPaM = aEditDoc.InsertText( aPaM, rStr );
+ aPaM = maEditDoc.InsertText( aPaM, rStr );
TextModified();
}
else
@@ -2799,12 +2911,12 @@ EditPaM ImpEditEngine::ImpInsertFeature(const EditSelection& rCurSel, const SfxP
return aPaM;
if ( IsUndoEnabled() && !IsInUndo() )
- InsertUndo(std::make_unique<EditUndoInsertFeature>(pEditEngine, CreateEPaM(aPaM), rItem));
- aPaM = aEditDoc.InsertFeature( aPaM, rItem );
+ InsertUndo(std::make_unique<EditUndoInsertFeature>(mpEditEngine, CreateEPaM(aPaM), rItem));
+ aPaM = maEditDoc.InsertFeature( aPaM, rItem );
UpdateFields();
ParaPortion* pPortion = FindParaPortion( aPaM.GetNode() );
- OSL_ENSURE( pPortion, "Blind Portion in InsertFeature" );
+ assert(pPortion);
pPortion->MarkInvalid( aPaM.GetIndex()-1, 1 );
TextModified();
@@ -2825,7 +2937,7 @@ EditPaM ImpEditEngine::ImpInsertParaBreak( const EditSelection& rCurSel )
EditPaM ImpEditEngine::ImpInsertParaBreak( EditPaM& rPaM, bool bKeepEndingAttribs )
{
- if ( aEditDoc.Count() >= EE_PARA_MAX_COUNT )
+ if ( maEditDoc.Count() >= EE_PARA_MAX_COUNT )
{
SAL_WARN( "editeng", "ImpEditEngine::ImpInsertParaBreak - can't process more than "
<< EE_PARA_MAX_COUNT << " paragraphs!");
@@ -2833,9 +2945,11 @@ EditPaM ImpEditEngine::ImpInsertParaBreak( EditPaM& rPaM, bool bKeepEndingAttrib
}
if ( IsUndoEnabled() && !IsInUndo() )
- InsertUndo(std::make_unique<EditUndoSplitPara>(pEditEngine, aEditDoc.GetPos(rPaM.GetNode()), rPaM.GetIndex()));
+ InsertUndo(std::make_unique<EditUndoSplitPara>(mpEditEngine, maEditDoc.GetPos(rPaM.GetNode()), rPaM.GetIndex()));
- EditPaM aPaM( aEditDoc.InsertParaBreak( rPaM, bKeepEndingAttribs ) );
+ EditPaM aPaM( maEditDoc.InsertParaBreak( rPaM, bKeepEndingAttribs ) );
+ if (auto pStyle = aPaM.GetNode()->GetStyleSheet())
+ StartListening(*pStyle, DuplicateHandling::Allow);
if ( GetStatus().DoOnlineSpelling() )
{
@@ -2868,7 +2982,7 @@ EditPaM ImpEditEngine::ImpInsertParaBreak( EditPaM& rPaM, bool bKeepEndingAttrib
}
ParaPortion* pPortion = FindParaPortion( rPaM.GetNode() );
- OSL_ENSURE( pPortion, "Blind Portion in ImpInsertParaBreak" );
+ assert(pPortion);
pPortion->MarkInvalid( rPaM.GetIndex(), 0 );
// Optimization: Do not place unnecessarily many getPos to Listen!
@@ -2880,7 +2994,9 @@ EditPaM ImpEditEngine::ImpInsertParaBreak( EditPaM& rPaM, bool bKeepEndingAttrib
if ( IsCallParaInsertedOrDeleted() )
GetEditEnginePtr()->ParagraphInserted( nPos+1 );
- CursorMoved( rPaM.GetNode() ); // if empty Attributes have emerged.
+ if( nullptr != rPaM.GetNode() )
+ rPaM.GetNode()->checkAndDeleteEmptyAttribs(); // if empty Attributes have emerged.
+
TextModified();
return aPaM;
}
@@ -2891,21 +3007,21 @@ EditPaM ImpEditEngine::ImpFastInsertParagraph( sal_Int32 nPara )
{
if ( nPara )
{
- OSL_ENSURE( aEditDoc.GetObject( nPara-1 ), "FastInsertParagraph: Prev does not exist" );
- InsertUndo(std::make_unique<EditUndoSplitPara>(pEditEngine, nPara-1, aEditDoc.GetObject( nPara-1 )->Len()));
+ assert(maEditDoc.GetObject(nPara - 1));
+ InsertUndo(std::make_unique<EditUndoSplitPara>(mpEditEngine, nPara-1, maEditDoc.GetObject(nPara - 1)->Len()));
}
else
- InsertUndo(std::make_unique<EditUndoSplitPara>(pEditEngine, 0, 0));
+ InsertUndo(std::make_unique<EditUndoSplitPara>(mpEditEngine, 0, 0));
}
- ContentNode* pNode = new ContentNode( aEditDoc.GetItemPool() );
+ ContentNode* pNode = new ContentNode( maEditDoc.GetItemPool() );
// If flat mode, then later no Font is set:
- pNode->GetCharAttribs().GetDefFont() = aEditDoc.GetDefFont();
+ pNode->GetCharAttribs().GetDefFont() = maEditDoc.GetDefFont();
if ( GetStatus().DoOnlineSpelling() )
pNode->CreateWrongList();
- aEditDoc.Insert(nPara, pNode);
+ maEditDoc.Insert(nPara, std::unique_ptr<ContentNode>(pNode));
GetParaPortions().Insert(nPara, std::make_unique<ParaPortion>( pNode ));
if ( IsCallParaInsertedOrDeleted() )
@@ -2917,9 +3033,9 @@ EditPaM ImpEditEngine::ImpFastInsertParagraph( sal_Int32 nPara )
EditPaM ImpEditEngine::InsertParaBreak(const EditSelection& rCurSel)
{
EditPaM aPaM(ImpInsertParaBreak(rCurSel));
- if ( aStatus.DoAutoIndenting() )
+ if ( maStatus.DoAutoIndenting() )
{
- sal_Int32 nPara = aEditDoc.GetPos( aPaM.GetNode() );
+ sal_Int32 nPara = maEditDoc.GetPos( aPaM.GetNode() );
OSL_ENSURE( nPara > 0, "AutoIndenting: Error!" );
const OUString aPrevParaText( GetEditDoc().GetParaAsString( nPara-1 ) );
sal_Int32 n = 0;
@@ -2956,7 +3072,7 @@ bool ImpEditEngine::UpdateFields()
{
bool bChangesInPara = false;
ContentNode* pNode = GetEditDoc().GetObject( nPara );
- OSL_ENSURE( pNode, "NULL-Pointer in Doc" );
+ assert(pNode);
CharAttribList::AttribsType& rAttribs = pNode->GetCharAttribs().GetAttribs();
for (std::unique_ptr<EditCharAttrib> & rAttrib : rAttribs)
{
@@ -2964,13 +3080,13 @@ bool ImpEditEngine::UpdateFields()
if (rAttr.Which() == EE_FEATURE_FIELD)
{
EditCharAttribField& rField = static_cast<EditCharAttribField&>(rAttr);
- std::unique_ptr<EditCharAttribField> pCurrent(new EditCharAttribField(rField));
+ EditCharAttribField aCurrent(rField);
rField.Reset();
- if (!aStatus.MarkNonUrlFields() && !aStatus.MarkUrlFields())
+ if (!maStatus.MarkNonUrlFields() && !maStatus.MarkUrlFields())
; // nothing marked
- else if (aStatus.MarkNonUrlFields() && aStatus.MarkUrlFields())
- rField.GetFieldColor() = GetColorConfig().GetColorValue( svtools::WRITERFIELDSHADINGS ).nColor;
+ else if (maStatus.MarkNonUrlFields() && maStatus.MarkUrlFields())
+ rField.GetFieldColor() = GetColorConfig().GetColorValue(svtools::WRITERFIELDSHADINGS).nColor;
else
{
bool bURL = false;
@@ -2979,17 +3095,17 @@ bool ImpEditEngine::UpdateFields()
if (const SvxFieldData* pFieldData = pFieldItem->GetField())
bURL = (dynamic_cast<const SvxURLField* >(pFieldData) != nullptr);
}
- if ((bURL && aStatus.MarkUrlFields()) || (!bURL && aStatus.MarkNonUrlFields()))
+ if ((bURL && maStatus.MarkUrlFields()) || (!bURL && maStatus.MarkNonUrlFields()))
rField.GetFieldColor() = GetColorConfig().GetColorValue( svtools::WRITERFIELDSHADINGS ).nColor;
}
const OUString aFldValue =
GetEditEnginePtr()->CalcFieldValue(
static_cast<const SvxFieldItem&>(*rField.GetItem()),
- nPara, rField.GetStart(), rField.GetTextColor(), rField.GetFieldColor());
+ nPara, rField.GetStart(), rField.GetTextColor(), rField.GetFieldColor(), rField.GetFldLineStyle() );
rField.SetFieldValue(aFldValue);
- if (rField != *pCurrent)
+ if (rField != aCurrent)
{
bChanges = true;
bChangesInPara = true;
@@ -2999,9 +3115,9 @@ bool ImpEditEngine::UpdateFields()
if ( bChangesInPara )
{
// If possible be more precise when invalidate.
- ParaPortion* pPortion = GetParaPortions()[nPara];
- OSL_ENSURE( pPortion, "NULL-Pointer in Doc" );
- pPortion->MarkSelectionInvalid( 0 );
+ assert(GetParaPortions().exists(nPara));
+ ParaPortion& rPortion = GetParaPortions().getRef(nPara);
+ rPortion.MarkSelectionInvalid( 0 );
}
}
return bChanges;
@@ -3016,78 +3132,251 @@ EditPaM ImpEditEngine::InsertLineBreak(const EditSelection& aCurSel)
// Helper functions
-tools::Rectangle ImpEditEngine::PaMtoEditCursor( EditPaM aPaM, GetCursorFlags nFlags )
+tools::Rectangle ImpEditEngine::GetEditCursor(ParaPortion const& rPortion, EditLine const& rLine,
+ sal_Int32 nIndex, CursorFlags aFlags)
+{
+ // nIndex might be not in the line
+ // Search within the line...
+ tools::Long nX;
+
+ if (nIndex == rLine.GetStart() && aFlags.bStartOfLine)
+ {
+ Range aXRange = GetLineXPosStartEnd(rPortion, rLine);
+ nX = !IsRightToLeft(GetEditDoc().GetPos(rPortion.GetNode())) ? aXRange.Min()
+ : aXRange.Max();
+ }
+ else if (nIndex == rLine.GetEnd() && aFlags.bEndOfLine)
+ {
+ Range aXRange = GetLineXPosStartEnd(rPortion, rLine);
+ nX = !IsRightToLeft(GetEditDoc().GetPos(rPortion.GetNode())) ? aXRange.Max()
+ : aXRange.Min();
+ }
+ else
+ {
+ nX = GetXPos(rPortion, rLine, nIndex, aFlags.bPreferPortionStart);
+ }
+
+ tools::Rectangle aEditCursor;
+ aEditCursor.SetLeft(nX);
+ aEditCursor.SetRight(nX);
+
+ aEditCursor.SetBottom(rLine.GetHeight() - 1);
+ if (aFlags.bTextOnly)
+ aEditCursor.SetTop(aEditCursor.Bottom() - rLine.GetTxtHeight() + 1);
+ else
+ aEditCursor.SetTop(aEditCursor.Bottom() - std::min(rLine.GetTxtHeight(), rLine.GetHeight()) + 1);
+ return aEditCursor;
+}
+
+tools::Rectangle ImpEditEngine::PaMtoEditCursor( EditPaM aPaM, CursorFlags aFlags)
{
- OSL_ENSURE( GetUpdateMode(), "Must not be reached when Update=FALSE: PaMtoEditCursor" );
+ assert( IsUpdateLayout() && "Must not be reached when Update=FALSE: PaMtoEditCursor" );
tools::Rectangle aEditCursor;
- tools::Long nY = 0;
- for ( sal_Int32 nPortion = 0; nPortion < GetParaPortions().Count(); nPortion++ )
+ const sal_Int32 nIndex = aPaM.GetIndex();
+ const ParaPortion* pPortion = nullptr;
+ const EditLine* pLastLine = nullptr;
+ tools::Rectangle aLineArea;
+
+ auto FindPortionLineAndArea = [&, bEOL(aFlags.bEndOfLine)](const LineAreaInfo& rInfo)
{
- ParaPortion* pPortion = GetParaPortions()[nPortion];
- ContentNode* pNode = pPortion->GetNode();
- OSL_ENSURE( pNode, "Invalid Node in Portion!" );
- if ( pNode != aPaM.GetNode() )
+ if (!rInfo.pLine) // start of ParaPortion
{
- nY += pPortion->GetHeight();
+ ContentNode* pNode = rInfo.rPortion.GetNode();
+ OSL_ENSURE(pNode, "Invalid Node in Portion!");
+ if (pNode != aPaM.GetNode())
+ return CallbackResult::SkipThisPortion;
+ pPortion = &rInfo.rPortion;
}
- else
+ else // guaranteed that this is the correct ParaPortion
{
- aEditCursor = GetEditCursor( pPortion, aPaM.GetIndex(), nFlags );
- aEditCursor.AdjustTop(nY );
- aEditCursor.AdjustBottom(nY );
- return aEditCursor;
+ pLastLine = rInfo.pLine;
+ aLineArea = rInfo.aArea;
+ if ((rInfo.pLine->GetStart() == nIndex) || (rInfo.pLine->IsIn(nIndex, bEOL)))
+ return CallbackResult::Stop;
}
+ return CallbackResult::Continue;
+ };
+ IterateLineAreas(FindPortionLineAndArea, IterFlag::none);
+
+ if (pLastLine && pPortion)
+ {
+ aEditCursor = GetEditCursor(*pPortion, *pLastLine, nIndex, aFlags);
+ aEditCursor.Move(getTopLeftDocOffset(aLineArea));
}
- OSL_FAIL( "Portion not found!" );
+ else
+ OSL_FAIL("Line not found!");
+
return aEditCursor;
}
-EditPaM ImpEditEngine::GetPaM( Point aDocPos, bool bSmart )
+void ImpEditEngine::IterateLineAreas(const IterateLinesAreasFunc& f, IterFlag eOptions)
{
- OSL_ENSURE( GetUpdateMode(), "Must not be reached when Update=FALSE: GetPaM" );
-
- tools::Long nY = 0;
- EditPaM aPaM;
- sal_Int32 nPortion;
- for ( nPortion = 0; nPortion < GetParaPortions().Count(); nPortion++ )
- {
- ParaPortion* pPortion = GetParaPortions()[nPortion];
- const tools::Long nTmpHeight = pPortion->GetHeight(); // should also be correct for !bVisible!
- nY += nTmpHeight;
- if ( nY > aDocPos.Y() )
+ const Point aOrigin(0, 0);
+ Point aLineStart(aOrigin);
+ const tools::Long nVertLineSpacing = CalcVertLineSpacing(aLineStart);
+ const tools::Long nColumnWidth = GetColumnWidth(maPaperSize);
+ sal_Int16 nColumn = 0;
+ for (sal_Int32 n = 0, nPortions = GetParaPortions().Count(); n < nPortions; ++n)
+ {
+ ParaPortion& rPortion = GetParaPortions().getRef(n);
+ bool bSkipThis = true;
+ if (rPortion.IsVisible())
{
- nY -= nTmpHeight;
- aDocPos.AdjustY( -nY );
- // Skip invisible Portions:
- while ( pPortion && !pPortion->IsVisible() )
+ // when typing idle formatting, asynchronous Paint. Invisible Portions may be invalid.
+ if (rPortion.IsInvalid())
+ return;
+
+ LineAreaInfo aInfo{
+ rPortion,
+ nullptr, // pLine
+ 0, // nHeightNeededToNotWrap
+ { aLineStart, Size{ nColumnWidth, rPortion.GetFirstLineOffset() } }, // aArea
+ n, // nPortion
+ 0, // nLine
+ nColumn // nColumn
+ };
+ auto eResult = f(aInfo);
+ if (eResult == CallbackResult::Stop)
+ return;
+ bSkipThis = eResult == CallbackResult::SkipThisPortion;
+
+ sal_uInt16 nSBL = 0;
+ if (!maStatus.IsOutliner())
{
- nPortion++;
- pPortion = GetParaPortions().SafeGetObject( nPortion );
+ const SvxLineSpacingItem& rLSItem
+ = rPortion.GetNode()->GetContentAttribs().GetItem(EE_PARA_SBL);
+ nSBL = (rLSItem.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Fix)
+ ? scaleYSpacingValue(rLSItem.GetInterLineSpace())
+ : 0;
}
- SAL_WARN_IF(!pPortion, "editeng", "worrying lack of any visible paragraph");
- if (!pPortion)
- return aPaM;
- return GetPaM(pPortion, aDocPos, bSmart);
+ adjustYDirectionAware(aLineStart, rPortion.GetFirstLineOffset());
+ for (sal_Int32 nLine = 0, nLines = rPortion.GetLines().Count(); nLine < nLines; nLine++)
+ {
+ EditLine& rLine = rPortion.GetLines()[nLine];
+ tools::Long nLineHeight = rLine.GetHeight();
+ if (nLine != nLines - 1)
+ nLineHeight += nVertLineSpacing;
+ MoveToNextLine(aLineStart, nLineHeight, nColumn, aOrigin,
+ &aInfo.nHeightNeededToNotWrap);
+ const bool bInclILS = eOptions & IterFlag::inclILS;
+ if (bInclILS && (nLine != nLines - 1) && !maStatus.IsOutliner())
+ {
+ adjustYDirectionAware(aLineStart, nSBL);
+ nLineHeight += nSBL;
+ }
+
+ if (!bSkipThis)
+ {
+ Point aOtherCorner(aLineStart);
+ adjustXDirectionAware(aOtherCorner, nColumnWidth);
+ adjustYDirectionAware(aOtherCorner, -nLineHeight);
+
+ // Calls to f() for each line
+ aInfo.nColumn = nColumn;
+ aInfo.pLine = &rLine;
+ aInfo.nLine = nLine;
+ aInfo.aArea = tools::Rectangle::Normalize(aLineStart, aOtherCorner);
+ eResult = f(aInfo);
+ if (eResult == CallbackResult::Stop)
+ return;
+ bSkipThis = eResult == CallbackResult::SkipThisPortion;
+ }
+
+ if (!bInclILS && (nLine != nLines - 1) && !maStatus.IsOutliner())
+ adjustYDirectionAware(aLineStart, nSBL);
+ }
+ if (!maStatus.IsOutliner())
+ {
+ const SvxULSpaceItem& rULItem = rPortion.GetNode()->GetContentAttribs().GetItem(EE_PARA_ULSPACE);
+ tools::Long nUL = scaleYSpacingValue(rULItem.GetLower());
+ adjustYDirectionAware(aLineStart, nUL);
+ }
}
+ // Invisible ParaPortion has no height (see ParaPortion::GetHeight), don't handle it
}
- // Then search for the last visible:
- nPortion = GetParaPortions().Count()-1;
- while ( nPortion && !GetParaPortions()[nPortion]->IsVisible() )
- nPortion--;
+}
- OSL_ENSURE( GetParaPortions()[nPortion]->IsVisible(), "No visible paragraph found: GetPaM" );
- aPaM.SetNode( GetParaPortions()[nPortion]->GetNode() );
- aPaM.SetIndex( GetParaPortions()[nPortion]->GetNode()->Len() );
- return aPaM;
+std::tuple<const ParaPortion*, const EditLine*, tools::Long>
+ImpEditEngine::GetPortionAndLine(Point aDocPos)
+{
+ // First find the column from the point
+ sal_Int32 nClickColumn = 0;
+ for (tools::Long nColumnStart = 0, nColumnWidth = GetColumnWidth(maPaperSize);;
+ nColumnStart += mnColumnSpacing + nColumnWidth, ++nClickColumn)
+ {
+ if (aDocPos.X() <= nColumnStart + nColumnWidth + mnColumnSpacing / 2)
+ break;
+ if (nClickColumn >= mnColumns - 1)
+ break;
+ }
+
+ const ParaPortion* pLastPortion = nullptr;
+ const EditLine* pLastLine = nullptr;
+ tools::Long nLineStartX = 0;
+ Point aPos;
+ adjustYDirectionAware(aPos, aDocPos.Y());
+
+ auto FindLastMatchingPortionAndLine = [&](const LineAreaInfo& rInfo) {
+ if (rInfo.pLine) // Only handle lines, not ParaPortion starts
+ {
+ if (rInfo.nColumn > nClickColumn)
+ return CallbackResult::Stop;
+ pLastPortion = &rInfo.rPortion; // Candidate paragraph
+ pLastLine = rInfo.pLine; // Last visible line not later than click position
+ nLineStartX = getTopLeftDocOffset(rInfo.aArea).Width();
+ if (rInfo.nColumn == nClickColumn && getYOverflowDirectionAware(aPos, rInfo.aArea) == 0)
+ return CallbackResult::Stop; // Found it
+ }
+ return CallbackResult::Continue;
+ };
+ IterateLineAreas(FindLastMatchingPortionAndLine, IterFlag::inclILS);
+
+ return { pLastPortion, pLastLine, nLineStartX };
+}
+
+EditPaM ImpEditEngine::GetPaM( Point aDocPos, bool bSmart )
+{
+ assert( IsUpdateLayout() && "Must not be reached when Update=FALSE: GetPaM" );
+
+ if (const auto& [pPortion, pLine, nLineStartX] = GetPortionAndLine(aDocPos); pPortion)
+ {
+ assert(pLine);
+ assert(pPortion);
+ sal_Int32 nCurIndex = GetChar(*pPortion, *pLine, aDocPos.X() - nLineStartX, bSmart);
+ EditPaM aPaM(pPortion->GetNode(), nCurIndex);
+
+ if (nCurIndex && (nCurIndex == pLine->GetEnd())
+ && (pLine != &pPortion->GetLines()[pPortion->GetLines().Count() - 1]))
+ {
+ aPaM = CursorLeft(aPaM);
+ }
+
+ return aPaM;
+ }
+ return {};
+}
+
+bool ImpEditEngine::IsTextPos(const Point& rDocPos, sal_uInt16 nBorder)
+{
+ if (const auto& [pPortion, pLine, nLineStartX] = GetPortionAndLine(rDocPos); pPortion)
+ {
+ assert(pLine);
+ assert(pPortion);
+ Range aLineXPosStartEnd = GetLineXPosStartEnd(*pPortion, *pLine);
+ if ((rDocPos.X() >= nLineStartX + aLineXPosStartEnd.Min() - nBorder)
+ && (rDocPos.X() <= nLineStartX + aLineXPosStartEnd.Max() + nBorder))
+ return true;
+ }
+ return false;
}
sal_uInt32 ImpEditEngine::GetTextHeight() const
{
- OSL_ENSURE( GetUpdateMode(), "Should not be used for Update=FALSE: GetTextHeight" );
+ assert( IsUpdateLayout() && "Should not be used for Update=FALSE: GetTextHeight" );
OSL_ENSURE( IsFormatted() || IsFormatting(), "GetTextHeight: Not formatted" );
- return nCurTextHeight;
+ return mnCurTextHeight;
}
sal_uInt32 ImpEditEngine::CalcTextWidth( bool bIgnoreExtraSpace )
@@ -3121,8 +3410,8 @@ sal_uInt32 ImpEditEngine::CalcParaWidth( sal_Int32 nPara, bool bIgnoreExtraSpace
// Over all the paragraphs ...
- OSL_ENSURE( 0 <= nPara && nPara < GetParaPortions().Count(), "CalcParaWidth: Out of range" );
- ParaPortion* pPortion = GetParaPortions()[nPara];
+ OSL_ENSURE(GetParaPortions().exists(nPara), "CalcParaWidth: Out of range");
+ ParaPortion* pPortion = GetParaPortions().SafeGetObject(nPara);
if ( pPortion && pPortion->IsVisible() )
{
const SvxLRSpaceItem& rLRItem = GetLRSpaceItem( pPortion->GetNode() );
@@ -3134,16 +3423,16 @@ sal_uInt32 ImpEditEngine::CalcParaWidth( sal_Int32 nPara, bool bIgnoreExtraSpace
sal_Int32 nLines = pPortion->GetLines().Count();
for ( sal_Int32 nLine = 0; nLine < nLines; nLine++ )
{
- EditLine& rLine = pPortion->GetLines()[nLine];
+ EditLine const& rLine = pPortion->GetLines()[nLine];
// nCurWidth = pLine->GetStartPosX();
// For Center- or Right- alignment it depends on the paper
// width, here not preferred. I general, it is best not leave it
// to StartPosX, also the right indents have to be taken into
// account!
- tools::Long nCurWidth = GetXValue( rLRItem.GetTextLeft() + nSpaceBeforeAndMinLabelWidth );
+ tools::Long nCurWidth = scaleXSpacingValue(rLRItem.GetTextLeft() + nSpaceBeforeAndMinLabelWidth);
if ( nLine == 0 )
{
- tools::Long nFI = GetXValue( rLRItem.GetTextFirstLineOffset() );
+ tools::Long nFI = scaleXSpacingValue(rLRItem.GetTextFirstLineOffset());
nCurWidth -= nFI;
if ( pPortion->GetBulletX() > nCurWidth )
{
@@ -3152,8 +3441,8 @@ sal_uInt32 ImpEditEngine::CalcParaWidth( sal_Int32 nPara, bool bIgnoreExtraSpace
nCurWidth = pPortion->GetBulletX();
}
}
- nCurWidth += GetXValue( rLRItem.GetRight() );
- nCurWidth += CalcLineWidth( pPortion, &rLine, bIgnoreExtraSpace );
+ nCurWidth += scaleXSpacingValue(rLRItem.GetRight());
+ nCurWidth += CalcLineWidth(*pPortion, rLine, bIgnoreExtraSpace);
if ( nCurWidth > nMaxWidth )
{
nMaxWidth = nCurWidth;
@@ -3165,24 +3454,24 @@ sal_uInt32 ImpEditEngine::CalcParaWidth( sal_Int32 nPara, bool bIgnoreExtraSpace
return static_cast<sal_uInt32>(nMaxWidth);
}
-sal_uInt32 ImpEditEngine::CalcLineWidth( ParaPortion* pPortion, EditLine* pLine, bool bIgnoreExtraSpace )
+sal_uInt32 ImpEditEngine::CalcLineWidth(ParaPortion const& rPortion, EditLine const& rLine, bool bIgnoreExtraSpace)
{
- sal_Int32 nPara = GetEditDoc().GetPos( pPortion->GetNode() );
+ sal_Int32 nPara = GetEditDoc().GetPos(rPortion.GetNode());
// #114278# Saving both layout mode and language (since I'm
// potentially changing both)
- GetRefDevice()->Push( PushFlags::TEXTLAYOUTMODE|PushFlags::TEXTLANGUAGE );
+ GetRefDevice()->Push( vcl::PushFlags::TEXTLAYOUTMODE|vcl::PushFlags::TEXTLANGUAGE );
- ImplInitLayoutMode( GetRefDevice(), nPara, -1 );
+ ImplInitLayoutMode(*GetRefDevice(), nPara, -1);
SvxAdjust eJustification = GetJustification( nPara );
// Calculation of the width without the Indents ...
sal_uInt32 nWidth = 0;
- sal_Int32 nPos = pLine->GetStart();
- for ( sal_Int32 nTP = pLine->GetStartPortion(); nTP <= pLine->GetEndPortion(); nTP++ )
+ sal_Int32 nPos = rLine.GetStart();
+ for ( sal_Int32 nTP = rLine.GetStartPortion(); nTP <= rLine.GetEndPortion(); nTP++ )
{
- const TextPortion& rTextPortion = pPortion->GetTextPortions()[nTP];
+ const TextPortion& rTextPortion = rPortion.GetTextPortions()[nTP];
switch ( rTextPortion.GetKind() )
{
case PortionKind::FIELD:
@@ -3200,11 +3489,12 @@ sal_uInt32 ImpEditEngine::CalcLineWidth( ParaPortion* pPortion, EditLine* pLine,
}
else
{
- SvxFont aTmpFont( pPortion->GetNode()->GetCharAttribs().GetDefFont() );
- SeekCursor( pPortion->GetNode(), nPos+1, aTmpFont );
- aTmpFont.SetPhysFont( GetRefDevice() );
- ImplInitDigitMode(GetRefDevice(), aTmpFont.GetLanguage());
- nWidth += aTmpFont.QuickGetTextSize( GetRefDevice(), pPortion->GetNode()->GetString(), nPos, rTextPortion.GetLen() ).Width();
+ SvxFont aTmpFont(rPortion.GetNode()->GetCharAttribs().GetDefFont());
+ SeekCursor(rPortion.GetNode(), nPos + 1, aTmpFont);
+ aTmpFont.SetPhysFont(*GetRefDevice());
+ ImplInitDigitMode(*GetRefDevice(), aTmpFont.GetLanguage());
+ nWidth += aTmpFont.QuickGetTextSize( GetRefDevice(),
+ rPortion.GetNode()->GetString(), nPos, rTextPortion.GetLen(), nullptr ).Width();
}
}
break;
@@ -3220,39 +3510,130 @@ sal_uInt32 ImpEditEngine::CalcLineWidth( ParaPortion* pPortion, EditLine* pLine,
sal_uInt32 ImpEditEngine::GetTextHeightNTP() const
{
- DBG_ASSERT( GetUpdateMode(), "Should not be used for Update=FALSE: GetTextHeight" );
+ assert( IsUpdateLayout() && "Should not be used for Update=FALSE: GetTextHeight" );
DBG_ASSERT( IsFormatted() || IsFormatting(), "GetTextHeight: Not formatted" );
- return nCurTextHeightNTP;
+ return mnCurTextHeightNTP;
}
-sal_uInt32 ImpEditEngine::CalcTextHeight( sal_uInt32* pHeightNTP )
+tools::Long ImpEditEngine::Calc1ColumnTextHeight(tools::Long* pHeightNTP)
{
- OSL_ENSURE( GetUpdateMode(), "Should not be used when Update=FALSE: CalcTextHeight" );
- sal_uInt32 nY = 0;
- sal_uInt32 nPH;
- sal_uInt32 nEmptyHeight = 0;
- for ( sal_Int32 nPortion = 0; nPortion < GetParaPortions().Count(); nPortion++ ) {
- ParaPortion* pPortion = GetParaPortions()[nPortion];
- nPH = pPortion->GetHeight();
- nY += nPH;
- if( pHeightNTP ) {
- if ( pPortion->IsEmpty() )
- nEmptyHeight += nPH;
- else
- nEmptyHeight = 0;
+ tools::Long nHeight = 0;
+ if (pHeightNTP)
+ *pHeightNTP = 0;
+ // Pretend that we have ~infinite height to get total height
+ comphelper::ValueRestorationGuard aGuard(mnCurTextHeight, std::numeric_limits<tools::Long>::max());
+
+ IterateLinesAreasFunc FindLastLineBottom = [&](const LineAreaInfo& rInfo) {
+ if (rInfo.pLine)
+ {
+ // bottom coordinate does not belong to area, so no need to do +1
+ nHeight = getBottomDocOffset(rInfo.aArea);
+ if (pHeightNTP && !rInfo.rPortion.IsEmpty())
+ *pHeightNTP = nHeight;
}
- }
-
- if ( pHeightNTP )
- *pHeightNTP = nY - nEmptyHeight;
+ return CallbackResult::Continue;
+ };
+ IterateLineAreas(FindLastLineBottom, IterFlag::none);
+ return nHeight;
+}
- return nY;
+tools::Long ImpEditEngine::CalcTextHeight(tools::Long* pHeightNTP)
+{
+ assert( IsUpdateLayout() && "Should not be used when Update=FALSE: CalcTextHeight" );
+
+ if (mnColumns <= 1)
+ return Calc1ColumnTextHeight(pHeightNTP); // All text fits into a single column - done!
+
+ // The final column height can be smaller than total height divided by number of columns (taking
+ // into account first line offset and interline spacing, that aren't considered in positioning
+ // after the wrap). The wrap should only happen after the minimal height is exceeded.
+ tools::Long nTentativeColHeight = mnMinColumnWrapHeight;
+ tools::Long nWantedIncrease = 0;
+ tools::Long nCurrentTextHeight;
+
+ // This does the necessary column balancing for the case when the text does not fit min height.
+ // When the height of column (taken from mnCurTextHeight) is too small, the last column will
+ // overflow, so the resulting height of the text will exceed the set column height. Increasing
+ // the column height step by step by the minimal value that allows one of columns to accommodate
+ // one line more, we finally get to the point where all the text fits. At each iteration, the
+ // height is only increased, so it's impossible to have infinite layout loops. The found value
+ // is the global minimum.
+ //
+ // E.g., given the following four line heights:
+ // Line 1: 10;
+ // Line 2: 12;
+ // Line 3: 10;
+ // Line 4: 10;
+ // number of columns 3, and the minimal paper height of 5, the iterations would be:
+ // * Tentative column height is set to 5
+ // <ITERATION 1>
+ // * Line 1 is attempted to go to column 0. Overflow is 5 => moved to column 1.
+ // * Line 2 is attempted to go to column 1 after Line 1; overflow is 17 => moved to column 2.
+ // * Line 3 is attempted to go to column 2 after Line 2; overflow is 17, stays in max column 2.
+ // * Line 4 goes to column 2 after Line 3.
+ // * Final iteration columns are: {empty}, {Line 1}, {Line 2, Line 3, Line 4}
+ // * Total text height is max({0, 10, 32}) == 32 > Tentative column height 5 => NEXT ITERATION
+ // * Minimal height increase that allows at least one column to accommodate one more line is
+ // min({5, 17, 17}) = 5.
+ // * Tentative column height is set to 5 + 5 = 10.
+ // <ITERATION 2>
+ // * Line 1 goes to column 0, no overflow.
+ // * Line 2 is attempted to go to column 0 after Line 1; overflow is 12 => moved to column 1.
+ // * Line 3 is attempted to go to column 1 after Line 2; overflow is 12 => moved to column 2.
+ // * Line 4 is attempted to go to column 2 after Line 3; overflow is 10, stays in max column 2.
+ // * Final iteration columns are: {Line 1}, {Line 2}, {Line 3, Line 4}
+ // * Total text height is max({10, 12, 20}) == 20 > Tentative column height 10 => NEXT ITERATION
+ // * Minimal height increase that allows at least one column to accommodate one more line is
+ // min({12, 12, 10}) = 10.
+ // * Tentative column height is set to 10 + 10 == 20.
+ // <ITERATION 3>
+ // * Line 1 goes to column 0, no overflow.
+ // * Line 2 is attempted to go to column 0 after Line 1; overflow is 2 => moved to column 1.
+ // * Line 3 is attempted to go to column 1 after Line 2; overflow is 2 => moved to column 2.
+ // * Line 4 is attempted to go to column 2 after Line 3; no overflow.
+ // * Final iteration columns are: {Line 1}, {Line 2}, {Line 3, Line 4}
+ // * Total text height is max({10, 12, 20}) == 20 == Tentative column height 20 => END.
+ do
+ {
+ nTentativeColHeight += nWantedIncrease;
+ nWantedIncrease = std::numeric_limits<tools::Long>::max();
+ nCurrentTextHeight = 0;
+ if (pHeightNTP)
+ *pHeightNTP = 0;
+ auto GetHeightAndWantedIncrease = [&, minHeight = tools::Long(0), lastCol = sal_Int16(0)](
+ const LineAreaInfo& rInfo) mutable {
+ if (rInfo.pLine)
+ {
+ if (lastCol != rInfo.nColumn)
+ {
+ minHeight = std::max(nCurrentTextHeight,
+ minHeight); // total height can't be less than previous columns
+ nWantedIncrease = std::min(rInfo.nHeightNeededToNotWrap, nWantedIncrease);
+ lastCol = rInfo.nColumn;
+ }
+ // bottom coordinate does not belong to area, so no need to do +1
+ nCurrentTextHeight = std::max(getBottomDocOffset(rInfo.aArea), minHeight);
+ if (pHeightNTP)
+ {
+ if (rInfo.rPortion.IsEmpty())
+ *pHeightNTP = std::max(*pHeightNTP, minHeight);
+ else
+ *pHeightNTP = nCurrentTextHeight;
+ }
+ }
+ return CallbackResult::Continue;
+ };
+ comphelper::ValueRestorationGuard aGuard(mnCurTextHeight, nTentativeColHeight);
+ IterateLineAreas(GetHeightAndWantedIncrease, IterFlag::none);
+ } while (nCurrentTextHeight > nTentativeColHeight && nWantedIncrease > 0
+ && nWantedIncrease != std::numeric_limits<tools::Long>::max());
+ return nCurrentTextHeight;
}
sal_Int32 ImpEditEngine::GetLineCount( sal_Int32 nParagraph ) const
{
- OSL_ENSURE( 0 <= nParagraph && nParagraph < GetParaPortions().Count(), "GetLineCount: Out of range" );
- const ParaPortion* pPPortion = GetParaPortions().SafeGetObject( nParagraph );
+ OSL_ENSURE(GetParaPortions().exists(nParagraph), "GetLineCount: Out of range");
+ const ParaPortion* pPPortion = GetParaPortions().SafeGetObject(nParagraph);
OSL_ENSURE( pPPortion, "Paragraph not found: GetLineCount" );
if ( pPPortion )
return pPPortion->GetLines().Count();
@@ -3262,9 +3643,9 @@ sal_Int32 ImpEditEngine::GetLineCount( sal_Int32 nParagraph ) const
sal_Int32 ImpEditEngine::GetLineLen( sal_Int32 nParagraph, sal_Int32 nLine ) const
{
- OSL_ENSURE( 0 <= nParagraph && nParagraph < GetParaPortions().Count(), "GetLineLen: Out of range" );
- const ParaPortion* pPPortion = GetParaPortions().SafeGetObject( nParagraph );
- OSL_ENSURE( pPPortion, "Paragraph not found: GetLineLen" );
+ OSL_ENSURE(GetParaPortions().exists(nParagraph), "GetLineLen: Out of range");
+ const ParaPortion* pPPortion = GetParaPortions().SafeGetObject(nParagraph);
+ OSL_ENSURE(pPPortion, "Paragraph not found: GetLineLen");
if ( pPPortion && ( nLine < pPPortion->GetLines().Count() ) )
{
const EditLine& rLine = pPPortion->GetLines()[nLine];
@@ -3276,7 +3657,7 @@ sal_Int32 ImpEditEngine::GetLineLen( sal_Int32 nParagraph, sal_Int32 nLine ) con
void ImpEditEngine::GetLineBoundaries( /*out*/sal_Int32 &rStart, /*out*/sal_Int32 &rEnd, sal_Int32 nParagraph, sal_Int32 nLine ) const
{
- OSL_ENSURE( 0 <= nParagraph && nParagraph < GetParaPortions().Count(), "GetLineCount: Out of range" );
+ OSL_ENSURE(GetParaPortions().exists(nParagraph), "GetLineCount: Out of range");
const ParaPortion* pPPortion = GetParaPortions().SafeGetObject( nParagraph );
OSL_ENSURE( pPPortion, "Paragraph not found: GetLineBoundaries" );
rStart = rEnd = -1; // default values in case of error
@@ -3317,7 +3698,7 @@ sal_Int32 ImpEditEngine::GetLineNumberAtIndex( sal_Int32 nPara, sal_Int32 nIndex
sal_uInt16 ImpEditEngine::GetLineHeight( sal_Int32 nParagraph, sal_Int32 nLine )
{
- OSL_ENSURE( 0 <= nParagraph && nParagraph < GetParaPortions().Count(), "GetLineCount: Out of range" );
+ OSL_ENSURE(GetParaPortions().exists(nParagraph), "GetLineCount: Out of range");
ParaPortion* pPPortion = GetParaPortions().SafeGetObject( nParagraph );
OSL_ENSURE( pPPortion, "Paragraph not found: GetLineHeight" );
if ( pPPortion && ( nLine < pPPortion->GetLines().Count() ) )
@@ -3329,11 +3710,11 @@ sal_uInt16 ImpEditEngine::GetLineHeight( sal_Int32 nParagraph, sal_Int32 nLine )
return 0xFFFF;
}
-sal_uInt32 ImpEditEngine::GetParaHeight( sal_Int32 nParagraph )
+sal_uInt32 ImpEditEngine::GetParaHeight(sal_Int32 nParagraph) const
{
sal_uInt32 nHeight = 0;
- ParaPortion* pPPortion = GetParaPortions().SafeGetObject( nParagraph );
+ ParaPortion const* pPPortion = GetParaPortions().SafeGetObject( nParagraph );
OSL_ENSURE( pPPortion, "Paragraph not found: GetParaHeight" );
if ( pPPortion )
@@ -3346,11 +3727,11 @@ void ImpEditEngine::UpdateSelections()
{
// Check whether one of the selections is at a deleted node...
// If the node is valid, the index has yet to be examined!
- for (EditView* pView : aEditViews)
+ for (EditView* pView : maEditViews)
{
- EditSelection aCurSel( pView->pImpEditView->GetEditSelection() );
+ EditSelection aCurSel( pView->getImpl().GetEditSelection() );
bool bChanged = false;
- for (const std::unique_ptr<DeletedNodeInfo> & aDeletedNode : aDeletedNodes)
+ for (const std::unique_ptr<DeletedNodeInfo> & aDeletedNode : maDeletedNodes)
{
const DeletedNodeInfo& rInf = *aDeletedNode;
if ( ( aCurSel.Min().GetNode() == rInf.GetNode() ) ||
@@ -3359,27 +3740,27 @@ void ImpEditEngine::UpdateSelections()
// Use ParaPortions, as now also hidden paragraphs have to be
// taken into account!
sal_Int32 nPara = rInf.GetPosition();
- if (!GetParaPortions().SafeGetObject(nPara)) // Last paragraph
+ if (!GetParaPortions().exists(nPara)) // Last paragraph
{
- nPara = GetParaPortions().Count()-1;
+ nPara = GetParaPortions().lastIndex();
}
- assert(GetParaPortions()[nPara] && "Empty Document in UpdateSelections ?");
+ assert(GetParaPortions().exists(nPara) && "Empty Document in UpdateSelections ?");
// Do not end up from a hidden paragraph:
- sal_Int32 nCurPara = nPara;
- sal_Int32 nLastPara = GetParaPortions().Count()-1;
- while ( nPara <= nLastPara && !GetParaPortions()[nPara]->IsVisible() )
+ sal_Int32 nCurrentPara = nPara;
+ sal_Int32 nLastParaIndex = GetParaPortions().lastIndex();
+ while (nPara <= nLastParaIndex && !GetParaPortions().getRef(nPara).IsVisible())
nPara++;
- if ( nPara > nLastPara ) // then also backwards ...
+ if (nPara > nLastParaIndex) // then also backwards ...
{
- nPara = nCurPara;
- while ( nPara && !GetParaPortions()[nPara]->IsVisible() )
+ nPara = nCurrentPara;
+ while ( nPara && !GetParaPortions().getRef(nPara).IsVisible() )
nPara--;
}
- OSL_ENSURE( GetParaPortions()[nPara]->IsVisible(), "No visible paragraph found: UpdateSelections" );
+ OSL_ENSURE(GetParaPortions().getRef(nPara).IsVisible(), "No visible paragraph found: UpdateSelections" );
- ParaPortion* pParaPortion = GetParaPortions()[nPara];
- EditSelection aTmpSelection( EditPaM( pParaPortion->GetNode(), 0 ) );
- pView->pImpEditView->SetEditSelection( aTmpSelection );
+ ParaPortion& rParaPortion = GetParaPortions().getRef(nPara);
+ EditSelection aTmpSelection(EditPaM(rParaPortion.GetNode(), 0));
+ pView->getImpl().SetEditSelection( aTmpSelection );
bChanged=true;
break; // for loop
}
@@ -3390,16 +3771,16 @@ void ImpEditEngine::UpdateSelections()
if ( aCurSel.Min().GetIndex() > aCurSel.Min().GetNode()->Len() )
{
aCurSel.Min().SetIndex( aCurSel.Min().GetNode()->Len() );
- pView->pImpEditView->SetEditSelection( aCurSel );
+ pView->getImpl().SetEditSelection( aCurSel );
}
if ( aCurSel.Max().GetIndex() > aCurSel.Max().GetNode()->Len() )
{
aCurSel.Max().SetIndex( aCurSel.Max().GetNode()->Len() );
- pView->pImpEditView->SetEditSelection( aCurSel );
+ pView->getImpl().SetEditSelection( aCurSel );
}
}
}
- aDeletedNodes.clear();
+ maDeletedNodes.clear();
}
EditSelection ImpEditEngine::ConvertSelection(
@@ -3408,11 +3789,11 @@ EditSelection ImpEditEngine::ConvertSelection(
EditSelection aNewSelection;
// Start...
- ContentNode* pNode = aEditDoc.GetObject( nStartPara );
+ ContentNode* pNode = maEditDoc.GetObject( nStartPara );
sal_Int32 nIndex = nStartPos;
if ( !pNode )
{
- pNode = aEditDoc[ aEditDoc.Count()-1 ];
+ pNode = maEditDoc.GetObject(maEditDoc.Count() - 1);
nIndex = pNode->Len();
}
else if ( nIndex > pNode->Len() )
@@ -3422,11 +3803,11 @@ EditSelection ImpEditEngine::ConvertSelection(
aNewSelection.Min().SetIndex( nIndex );
// End...
- pNode = aEditDoc.GetObject( nEndPara );
+ pNode = maEditDoc.GetObject( nEndPara );
nIndex = nEndPos;
if ( !pNode )
{
- pNode = aEditDoc[ aEditDoc.Count()-1 ];
+ pNode = maEditDoc.GetObject(maEditDoc.Count() - 1);
nIndex = pNode->Len();
}
else if ( nIndex > pNode->Len() )
@@ -3443,16 +3824,16 @@ void ImpEditEngine::SetActiveView( EditView* pView )
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Actually, now bHasVisSel and HideSelection would be necessary !!!
- if ( pView == pActiveView )
+ if (pView == mpActiveView)
return;
- if ( pActiveView && pActiveView->HasSelection() )
- pActiveView->pImpEditView->DrawSelectionXOR();
+ if (mpActiveView && mpActiveView->HasSelection())
+ mpActiveView->getImpl().DrawSelectionXOR();
- pActiveView = pView;
+ mpActiveView = pView;
- if ( pActiveView && pActiveView->HasSelection() )
- pActiveView->pImpEditView->DrawSelectionXOR();
+ if (mpActiveView && mpActiveView->HasSelection())
+ mpActiveView->getImpl().DrawSelectionXOR();
// NN: Quick fix for #78668#:
// When editing of a cell in Calc is ended, the edit engine is not deleted,
@@ -3473,8 +3854,7 @@ uno::Reference< datatransfer::XTransferable > ImpEditEngine::CreateTransferable(
EditSelection aSelection( rSelection );
aSelection.Adjust( GetEditDoc() );
- EditDataObject* pDataObj = new EditDataObject;
- uno::Reference< datatransfer::XTransferable > xDataObj = pDataObj;
+ rtl::Reference<EditDataObject> pDataObj = new EditDataObject;
pDataObj->GetString() = convertLineEnd(GetSelected(aSelection), GetSystemLineEnd()); // System specific
@@ -3513,10 +3893,10 @@ uno::Reference< datatransfer::XTransferable > ImpEditEngine::CreateTransferable(
}
}
- return xDataObj;
+ return pDataObj;
}
-EditSelection ImpEditEngine::PasteText( uno::Reference< datatransfer::XTransferable > const & rxDataObj, const OUString& rBaseURL, const EditPaM& rPaM, bool bUseSpecial )
+EditSelection ImpEditEngine::PasteText( uno::Reference< datatransfer::XTransferable > const & rxDataObj, const OUString& rBaseURL, const EditPaM& rPaM, bool bUseSpecial, SotClipboardFormatId format)
{
EditSelection aNewSelection( rPaM );
@@ -3530,7 +3910,7 @@ EditSelection ImpEditEngine::PasteText( uno::Reference< datatransfer::XTransfera
{
// XML
SotExchange::GetFormatDataFlavor( SotClipboardFormatId::EDITENGINE_ODF_TEXT_FLAT, aFlavor );
- if ( rxDataObj->isDataFlavorSupported( aFlavor ) )
+ if ( rxDataObj->isDataFlavorSupported( aFlavor ) && (SotClipboardFormatId::NONE == format || SotClipboardFormatId::EDITENGINE_ODF_TEXT_FLAT == format))
{
try
{
@@ -3558,7 +3938,7 @@ EditSelection ImpEditEngine::PasteText( uno::Reference< datatransfer::XTransfera
SotExchange::GetFormatDataFlavor( SotClipboardFormatId::RICHTEXT, aFlavorRichtext );
bool bRtfSupported = rxDataObj->isDataFlavorSupported( aFlavor );
bool bRichtextSupported = rxDataObj->isDataFlavorSupported( aFlavorRichtext );
- if ( bRtfSupported || bRichtextSupported )
+ if ( (bRtfSupported || bRichtextSupported) && (SotClipboardFormatId::NONE == format || SotClipboardFormatId::RICHTEXT == format || SotClipboardFormatId::RTF == format))
{
if(bRichtextSupported)
{
@@ -3580,6 +3960,55 @@ EditSelection ImpEditEngine::PasteText( uno::Reference< datatransfer::XTransfera
}
}
}
+ if (!bDone) {
+ // HTML_SIMPLE
+ SotExchange::GetFormatDataFlavor(SotClipboardFormatId::HTML_SIMPLE, aFlavor);
+ bool bHtmlSupported = rxDataObj->isDataFlavorSupported(aFlavor);
+ if (bHtmlSupported && (SotClipboardFormatId::NONE == format || SotClipboardFormatId::HTML_SIMPLE == format)) {
+ MSE40HTMLClipFormatObj aMSE40HTMLClipFormatObj;
+ try
+ {
+ uno::Any aData = rxDataObj->getTransferData(aFlavor);
+ uno::Sequence< sal_Int8 > aSeq;
+ aData >>= aSeq;
+ {
+ SvMemoryStream aHtmlStream(aSeq.getArray(), aSeq.getLength(), StreamMode::READ);
+ SvStream* pHtmlStream = aMSE40HTMLClipFormatObj.IsValid(aHtmlStream);
+ if (pHtmlStream != nullptr) {
+ aNewSelection = Read(*pHtmlStream, rBaseURL, EETextFormat::Html, rPaM);
+ }
+ }
+ bDone = true;
+ }
+ catch (const css::uno::Exception&)
+ {
+ }
+ }
+ }
+
+ if (!bDone)
+ {
+ // HTML
+ SotExchange::GetFormatDataFlavor(SotClipboardFormatId::HTML, aFlavor);
+ bool bHtmlSupported = rxDataObj->isDataFlavorSupported(aFlavor);
+ if (bHtmlSupported
+ && (format == SotClipboardFormatId::NONE || format == SotClipboardFormatId::HTML))
+ {
+ try
+ {
+ uno::Any aData = rxDataObj->getTransferData(aFlavor);
+ uno::Sequence<sal_Int8> aSeq;
+ aData >>= aSeq;
+ SvMemoryStream aHtmlStream(aSeq.getArray(), aSeq.getLength(), StreamMode::READ);
+ aNewSelection = Read(aHtmlStream, rBaseURL, EETextFormat::Html, rPaM);
+ bDone = true;
+ }
+ catch (const css::uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("editeng", "HTML paste failed");
+ }
+ }
+ }
}
if ( !bDone )
{
@@ -3603,145 +4032,17 @@ EditSelection ImpEditEngine::PasteText( uno::Reference< datatransfer::XTransfera
return aNewSelection;
}
-Range ImpEditEngine::GetInvalidYOffsets( ParaPortion* pPortion )
-{
- Range aRange( 0, 0 );
-
- if ( pPortion->IsVisible() )
- {
- const SvxULSpaceItem& rULSpace = pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE );
- const SvxLineSpacingItem& rLSItem = pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL );
- sal_uInt16 nSBL = ( rLSItem.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Fix )
- ? GetYValue( rLSItem.GetInterLineSpace() ) : 0;
-
- // only from the top ...
- sal_Int32 nFirstInvalid = -1;
- sal_Int32 nLine;
- for ( nLine = 0; nLine < pPortion->GetLines().Count(); nLine++ )
- {
- const EditLine& rL = pPortion->GetLines()[nLine];
- if ( rL.IsInvalid() )
- {
- nFirstInvalid = nLine;
- break;
- }
- if ( nLine && !aStatus.IsOutliner() ) // not the first line
- aRange.Min() += nSBL;
- aRange.Min() += rL.GetHeight();
- }
- OSL_ENSURE( nFirstInvalid != -1, "No invalid line found in GetInvalidYOffset(1)" );
-
-
- // Syndicate and more ...
- aRange.Max() = aRange.Min();
- aRange.Max() += pPortion->GetFirstLineOffset();
- if (nFirstInvalid >= 0) // Only if the first line is invalid
- aRange.Min() = aRange.Max();
-
- sal_Int32 nLastInvalid = pPortion->GetLines().Count()-1;
- if (nFirstInvalid >= 0)
- {
- for ( nLine = nFirstInvalid; nLine < pPortion->GetLines().Count(); nLine++ )
- {
- const EditLine& rL = pPortion->GetLines()[nLine];
- if ( rL.IsValid() )
- {
- nLastInvalid = nLine;
- break;
- }
- if ( nLine && !aStatus.IsOutliner() )
- aRange.Max() += nSBL;
- aRange.Max() += rL.GetHeight();
- }
-
- sal_uInt16 nPropLineSpace = rLSItem.GetPropLineSpace();
- if ( ( rLSItem.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Prop )
- && nPropLineSpace && ( nPropLineSpace < 100 ) )
- {
- const EditLine& rL = pPortion->GetLines()[nFirstInvalid];
- auto n = rL.GetTxtHeight() * ( 100 - nPropLineSpace );
- n /= 100;
- aRange.Min() -= n;
- aRange.Max() += n;
- }
-
- if ( ( nLastInvalid == pPortion->GetLines().Count()-1 ) && ( !aStatus.IsOutliner() ) )
- aRange.Max() += GetYValue( rULSpace.GetLower() );
- }
- }
- return aRange;
-}
-
-EditPaM ImpEditEngine::GetPaM( ParaPortion* pPortion, Point aDocPos, bool bSmart )
-{
- OSL_ENSURE( pPortion->IsVisible(), "Why GetPaM() for an invisible paragraph?" );
- OSL_ENSURE( IsFormatted(), "GetPaM: Not formatted" );
-
- sal_Int32 nCurIndex = 0;
- EditPaM aPaM;
- aPaM.SetNode( pPortion->GetNode() );
-
- const SvxLineSpacingItem& rLSItem = pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL );
- sal_uInt16 nSBL = ( rLSItem.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Fix )
- ? GetYValue( rLSItem.GetInterLineSpace() ) : 0;
-
- tools::Long nY = pPortion->GetFirstLineOffset();
-
- OSL_ENSURE( pPortion->GetLines().Count(), "Empty ParaPortion in GetPaM!" );
-
- const EditLine* pLine = nullptr;
- for ( sal_Int32 nLine = 0; nLine < pPortion->GetLines().Count(); nLine++ )
- {
- const EditLine& rTmpLine = pPortion->GetLines()[nLine];
- nY += rTmpLine.GetHeight();
- if ( !aStatus.IsOutliner() )
- nY += nSBL;
- if ( nY > aDocPos.Y() )
- {
- pLine = &rTmpLine;
- break; // correct Y-position is not of interest
- }
-
- nCurIndex = nCurIndex + rTmpLine.GetLen();
- }
-
- if ( !pLine ) // may happen only in the range of SA!
- {
-#if OSL_DEBUG_LEVEL > 0
- const SvxULSpaceItem& rULSpace = pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE );
- OSL_ENSURE( nY+GetYValue( rULSpace.GetLower() ) >= aDocPos.Y() , "Index in no line, GetPaM ?" );
-#endif
- aPaM.SetIndex( pPortion->GetNode()->Len() );
- return aPaM;
- }
-
- // If no line found, only just X-Position => Index
- nCurIndex = GetChar( pPortion, pLine, aDocPos.X(), bSmart );
- aPaM.SetIndex( nCurIndex );
-
- if ( nCurIndex && ( nCurIndex == pLine->GetEnd() ) &&
- ( pLine != &pPortion->GetLines()[pPortion->GetLines().Count()-1] ) )
- {
- aPaM = CursorLeft( aPaM );
- }
-
- return aPaM;
-}
-
-sal_Int32 ImpEditEngine::GetChar(
- const ParaPortion* pParaPortion, const EditLine* pLine, tools::Long nXPos, bool bSmart)
+sal_Int32 ImpEditEngine::GetChar(ParaPortion const& rParaPortion, EditLine const& rLine, tools::Long nXPos, bool bSmart)
{
- OSL_ENSURE( pLine, "No line received: GetChar" );
-
sal_Int32 nChar = -1;
- sal_Int32 nCurIndex = pLine->GetStart();
+ sal_Int32 nCurIndex = rLine.GetStart();
// Search best matching portion with GetPortionXOffset()
- for ( sal_Int32 i = pLine->GetStartPortion(); i <= pLine->GetEndPortion(); i++ )
+ for ( sal_Int32 i = rLine.GetStartPortion(); i <= rLine.GetEndPortion(); i++ )
{
- const TextPortion& rPortion = pParaPortion->GetTextPortions()[i];
- tools::Long nXLeft = GetPortionXOffset( pParaPortion, pLine, i );
+ const TextPortion& rPortion = rParaPortion.GetTextPortions()[i];
+ tools::Long nXLeft = GetPortionXOffset(rParaPortion, rLine, i);
tools::Long nXRight = nXLeft + rPortion.GetSize().Width();
if ( ( nXLeft <= nXPos ) && ( nXRight >= nXPos ) )
{
@@ -3765,7 +4066,7 @@ sal_Int32 ImpEditEngine::GetChar(
{
sal_Int32 nMax = rPortion.GetLen();
sal_Int32 nOffset = -1;
- sal_Int32 nTmpCurIndex = nChar - pLine->GetStart();
+ sal_Int32 nTmpCurIndex = nChar - rLine.GetStart();
tools::Long nXInPortion = nXPos - nXLeft;
if ( rPortion.IsRightToLeft() )
@@ -3774,25 +4075,26 @@ sal_Int32 ImpEditEngine::GetChar(
// Search in Array...
for ( sal_Int32 x = 0; x < nMax; x++ )
{
- tools::Long nTmpPosMax = pLine->GetCharPosArray()[nTmpCurIndex+x];
+ tools::Long nTmpPosMax = rLine.GetCharPosArray()[nTmpCurIndex+x];
if ( nTmpPosMax > nXInPortion )
{
// Check whether this or the previous...
- tools::Long nTmpPosMin = x ? pLine->GetCharPosArray()[nTmpCurIndex+x-1] : 0;
+ tools::Long nTmpPosMin = x ? rLine.GetCharPosArray()[nTmpCurIndex+x-1] : 0;
tools::Long nDiffLeft = nXInPortion - nTmpPosMin;
tools::Long nDiffRight = nTmpPosMax - nXInPortion;
OSL_ENSURE( nDiffLeft >= 0, "DiffLeft negative" );
OSL_ENSURE( nDiffRight >= 0, "DiffRight negative" );
- nOffset = ( bSmart && ( nDiffRight < nDiffLeft ) ) ? x+1 : x;
- // I18N: If there are character position with the length of 0,
- // they belong to the same character, we can not use this position as an index.
- // Skip all 0-positions, cheaper than using XBreakIterator:
- if ( nOffset < nMax )
+
+ if (bSmart && nDiffRight < nDiffLeft)
{
- const tools::Long nX = pLine->GetCharPosArray()[nOffset];
- while ( ( (nOffset+1) < nMax ) && ( pLine->GetCharPosArray()[nOffset+1] == nX ) )
- nOffset++;
+ // I18N: If there are character position with the length of 0,
+ // they belong to the same character, we can not use this position as an index.
+ // Skip all 0-positions, cheaper than using XBreakIterator:
+ tools::Long nX = rLine.GetCharPosArray()[nTmpCurIndex + x];
+ while(x < nMax && rLine.GetCharPosArray()[nTmpCurIndex + x] == nX)
+ ++x;
}
+ nOffset = x;
break;
}
}
@@ -3808,9 +4110,9 @@ sal_Int32 ImpEditEngine::GetChar(
nChar = nChar + nOffset;
// Check if index is within a cell:
- if ( nChar && ( nChar < pParaPortion->GetNode()->Len() ) )
+ if ( nChar && ( nChar < rParaPortion.GetNode()->Len() ) )
{
- EditPaM aPaM( pParaPortion->GetNode(), nChar+1 );
+ EditPaM aPaM( rParaPortion.GetNode(), nChar+1 );
sal_uInt16 nScriptType = GetI18NScriptType( aPaM );
if ( nScriptType == i18n::ScriptType::COMPLEX )
{
@@ -3818,9 +4120,9 @@ sal_Int32 ImpEditEngine::GetChar(
sal_Int32 nCount = 1;
lang::Locale aLocale = GetLocale( aPaM );
sal_Int32 nRight = _xBI->nextCharacters(
- pParaPortion->GetNode()->GetString(), nChar, aLocale, css::i18n::CharacterIteratorMode::SKIPCELL, nCount, nCount );
+ rParaPortion.GetNode()->GetString(), nChar, aLocale, css::i18n::CharacterIteratorMode::SKIPCELL, nCount, nCount );
sal_Int32 nLeft = _xBI->previousCharacters(
- pParaPortion->GetNode()->GetString(), nRight, aLocale, css::i18n::CharacterIteratorMode::SKIPCELL, nCount, nCount );
+ rParaPortion.GetNode()->GetString(), nRight, aLocale, css::i18n::CharacterIteratorMode::SKIPCELL, nCount, nCount );
if ( ( nLeft != nChar ) && ( nRight != nChar ) )
{
nChar = ( std::abs( nRight - nChar ) < std::abs( nLeft - nChar ) ) ? nRight : nLeft;
@@ -3828,7 +4130,7 @@ sal_Int32 ImpEditEngine::GetChar(
}
else
{
- OUString aStr(pParaPortion->GetNode()->GetString());
+ OUString aStr(rParaPortion.GetNode()->GetString());
// tdf#102625: don't select middle of a pair of surrogates with mouse cursor
if (rtl::isSurrogate(aStr[nChar]))
--nChar;
@@ -3842,40 +4144,38 @@ sal_Int32 ImpEditEngine::GetChar(
if ( nChar == -1 )
{
- nChar = ( nXPos <= pLine->GetStartPosX() ) ? pLine->GetStart() : pLine->GetEnd();
+ nChar = ( nXPos <= rLine.GetStartPosX() ) ? rLine.GetStart() : rLine.GetEnd();
}
return nChar;
}
-Range ImpEditEngine::GetLineXPosStartEnd( const ParaPortion* pParaPortion, const EditLine* pLine ) const
+Range ImpEditEngine::GetLineXPosStartEnd(ParaPortion const& rParaPortion, EditLine const& rLine) const
{
Range aLineXPosStartEnd;
- sal_Int32 nPara = GetEditDoc().GetPos( pParaPortion->GetNode() );
+ sal_Int32 nPara = GetEditDoc().GetPos(rParaPortion.GetNode());
if ( !IsRightToLeft( nPara ) )
{
- aLineXPosStartEnd.Min() = pLine->GetStartPosX();
- aLineXPosStartEnd.Max() = pLine->GetStartPosX() + pLine->GetTextWidth();
+ aLineXPosStartEnd.Min() = rLine.GetStartPosX();
+ aLineXPosStartEnd.Max() = rLine.GetStartPosX() + rLine.GetTextWidth();
}
else
{
- aLineXPosStartEnd.Min() = GetPaperSize().Width() - ( pLine->GetStartPosX() + pLine->GetTextWidth() );
- aLineXPosStartEnd.Max() = GetPaperSize().Width() - pLine->GetStartPosX();
+ aLineXPosStartEnd.Min() = GetPaperSize().Width() - (rLine.GetStartPosX() + rLine.GetTextWidth());
+ aLineXPosStartEnd.Max() = GetPaperSize().Width() - rLine.GetStartPosX();
}
-
return aLineXPosStartEnd;
}
-tools::Long ImpEditEngine::GetPortionXOffset(
- const ParaPortion* pParaPortion, const EditLine* pLine, sal_Int32 nTextPortion) const
+tools::Long ImpEditEngine::GetPortionXOffset(ParaPortion const& rParaPortion, EditLine const& rLine, sal_Int32 nTextPortion) const
{
- tools::Long nX = pLine->GetStartPosX();
+ tools::Long nX = rLine.GetStartPosX();
- for ( sal_Int32 i = pLine->GetStartPortion(); i < nTextPortion; i++ )
+ for ( sal_Int32 i = rLine.GetStartPortion(); i < nTextPortion; i++ )
{
- const TextPortion& rPortion = pParaPortion->GetTextPortions()[i];
+ const TextPortion& rPortion = rParaPortion.GetTextPortions()[i];
switch ( rPortion.GetKind() )
{
case PortionKind::FIELD:
@@ -3890,19 +4190,19 @@ tools::Long ImpEditEngine::GetPortionXOffset(
}
}
- sal_Int32 nPara = GetEditDoc().GetPos( pParaPortion->GetNode() );
+ sal_Int32 nPara = GetEditDoc().GetPos(rParaPortion.GetNode());
bool bR2LPara = IsRightToLeft( nPara );
- const TextPortion& rDestPortion = pParaPortion->GetTextPortions()[nTextPortion];
+ const TextPortion& rDestPortion = rParaPortion.GetTextPortions()[nTextPortion];
if ( rDestPortion.GetKind() != PortionKind::TAB )
{
if ( !bR2LPara && rDestPortion.GetRightToLeftLevel() )
{
// Portions behind must be added, visual before this portion
sal_Int32 nTmpPortion = nTextPortion+1;
- while ( nTmpPortion <= pLine->GetEndPortion() )
+ while ( nTmpPortion <= rLine.GetEndPortion() )
{
- const TextPortion& rNextTextPortion = pParaPortion->GetTextPortions()[nTmpPortion];
+ const TextPortion& rNextTextPortion = rParaPortion.GetTextPortions()[nTmpPortion];
if ( rNextTextPortion.GetRightToLeftLevel() && ( rNextTextPortion.GetKind() != PortionKind::TAB ) )
nX += rNextTextPortion.GetSize().Width();
else
@@ -3911,10 +4211,10 @@ tools::Long ImpEditEngine::GetPortionXOffset(
}
// Portions before must be removed, visual behind this portion
nTmpPortion = nTextPortion;
- while ( nTmpPortion > pLine->GetStartPortion() )
+ while ( nTmpPortion > rLine.GetStartPortion() )
{
--nTmpPortion;
- const TextPortion& rPrevTextPortion = pParaPortion->GetTextPortions()[nTmpPortion];
+ const TextPortion& rPrevTextPortion = rParaPortion.GetTextPortions()[nTmpPortion];
if ( rPrevTextPortion.GetRightToLeftLevel() && ( rPrevTextPortion.GetKind() != PortionKind::TAB ) )
nX -= rPrevTextPortion.GetSize().Width();
else
@@ -3925,9 +4225,9 @@ tools::Long ImpEditEngine::GetPortionXOffset(
{
// Portions behind must be removed, visual behind this portion
sal_Int32 nTmpPortion = nTextPortion+1;
- while ( nTmpPortion <= pLine->GetEndPortion() )
+ while ( nTmpPortion <= rLine.GetEndPortion() )
{
- const TextPortion& rNextTextPortion = pParaPortion->GetTextPortions()[nTmpPortion];
+ const TextPortion& rNextTextPortion = rParaPortion.GetTextPortions()[nTmpPortion];
if ( !rNextTextPortion.IsRightToLeft() && ( rNextTextPortion.GetKind() != PortionKind::TAB ) )
nX += rNextTextPortion.GetSize().Width();
else
@@ -3936,10 +4236,10 @@ tools::Long ImpEditEngine::GetPortionXOffset(
}
// Portions before must be added, visual before this portion
nTmpPortion = nTextPortion;
- while ( nTmpPortion > pLine->GetStartPortion() )
+ while ( nTmpPortion > rLine.GetStartPortion() )
{
--nTmpPortion;
- const TextPortion& rPrevTextPortion = pParaPortion->GetTextPortions()[nTmpPortion];
+ const TextPortion& rPrevTextPortion = rParaPortion.GetTextPortions()[nTmpPortion];
if ( !rPrevTextPortion.IsRightToLeft() && ( rPrevTextPortion.GetKind() != PortionKind::TAB ) )
nX -= rPrevTextPortion.GetSize().Width();
else
@@ -3959,33 +4259,31 @@ tools::Long ImpEditEngine::GetPortionXOffset(
return nX;
}
-tools::Long ImpEditEngine::GetXPos(
- const ParaPortion* pParaPortion, const EditLine* pLine, sal_Int32 nIndex, bool bPreferPortionStart) const
+tools::Long ImpEditEngine::GetXPos(ParaPortion const& rParaPortion, EditLine const& rLine, sal_Int32 nIndex, bool bPreferPortionStart) const
{
- OSL_ENSURE( pLine, "No line received: GetXPos" );
- OSL_ENSURE( ( nIndex >= pLine->GetStart() ) && ( nIndex <= pLine->GetEnd() ) , "GetXPos has to be called properly!" );
+ OSL_ENSURE( ( nIndex >= rLine.GetStart() ) && ( nIndex <= rLine.GetEnd() ) , "GetXPos has to be called properly!" );
bool bDoPreferPortionStart = bPreferPortionStart;
// Assure that the portion belongs to this line:
- if ( nIndex == pLine->GetStart() )
+ if ( nIndex == rLine.GetStart() )
bDoPreferPortionStart = true;
- else if ( nIndex == pLine->GetEnd() )
+ else if ( nIndex == rLine.GetEnd() )
bDoPreferPortionStart = false;
sal_Int32 nTextPortionStart = 0;
- sal_Int32 nTextPortion = pParaPortion->GetTextPortions().FindPortion( nIndex, nTextPortionStart, bDoPreferPortionStart );
+ sal_Int32 nTextPortion = rParaPortion.GetTextPortions().FindPortion( nIndex, nTextPortionStart, bDoPreferPortionStart );
- OSL_ENSURE( ( nTextPortion >= pLine->GetStartPortion() ) && ( nTextPortion <= pLine->GetEndPortion() ), "GetXPos: Portion not in current line! " );
+ OSL_ENSURE( ( nTextPortion >= rLine.GetStartPortion() ) && ( nTextPortion <= rLine.GetEndPortion() ), "GetXPos: Portion not in current line! " );
- const TextPortion& rPortion = pParaPortion->GetTextPortions()[nTextPortion];
+ const TextPortion& rPortion = rParaPortion.GetTextPortions()[nTextPortion];
- tools::Long nX = GetPortionXOffset( pParaPortion, pLine, nTextPortion );
+ tools::Long nX = GetPortionXOffset(rParaPortion, rLine, nTextPortion);
// calc text width, portion size may include CJK/CTL spacing...
// But the array might not be init yet, if using text ranger this method is called within CreateLines()...
tools::Long nPortionTextWidth = rPortion.GetSize().Width();
if ( ( rPortion.GetKind() == PortionKind::TEXT ) && rPortion.GetLen() && !GetTextRanger() )
- nPortionTextWidth = pLine->GetCharPosArray()[nTextPortionStart + rPortion.GetLen() - 1 - pLine->GetStart()];
+ nPortionTextWidth = rLine.GetCharPosArray()[nTextPortionStart + rPortion.GetLen() - 1 - rLine.GetStart()];
if ( nTextPortionStart != nIndex )
{
@@ -3995,18 +4293,18 @@ tools::Long ImpEditEngine::GetXPos(
// End of Portion
if ( rPortion.GetKind() == PortionKind::TAB )
{
- if ( nTextPortion+1 < pParaPortion->GetTextPortions().Count() )
+ if ( nTextPortion+1 < rParaPortion.GetTextPortions().Count() )
{
- const TextPortion& rNextPortion = pParaPortion->GetTextPortions()[nTextPortion+1];
+ const TextPortion& rNextPortion = rParaPortion.GetTextPortions()[nTextPortion+1];
if ( rNextPortion.GetKind() != PortionKind::TAB )
{
if ( !bPreferPortionStart )
- nX = GetXPos( pParaPortion, pLine, nIndex, true );
- else if ( !IsRightToLeft( GetEditDoc().GetPos( pParaPortion->GetNode() ) ) )
+ nX = GetXPos(rParaPortion, rLine, nIndex, true );
+ else if ( !IsRightToLeft( GetEditDoc().GetPos(rParaPortion.GetNode()) ) )
nX += nPortionTextWidth;
}
}
- else if ( !IsRightToLeft( GetEditDoc().GetPos( pParaPortion->GetNode() ) ) )
+ else if ( !IsRightToLeft( GetEditDoc().GetPos(rParaPortion.GetNode()) ) )
{
nX += nPortionTextWidth;
}
@@ -4018,20 +4316,20 @@ tools::Long ImpEditEngine::GetXPos(
}
else if ( rPortion.GetKind() == PortionKind::TEXT )
{
- OSL_ENSURE( nIndex != pLine->GetStart(), "Strange behavior in new GetXPos()" );
- OSL_ENSURE( pLine && !pLine->GetCharPosArray().empty(), "svx::ImpEditEngine::GetXPos(), portion in an empty line?" );
+ OSL_ENSURE( nIndex != rLine.GetStart(), "Strange behavior in new GetXPos()" );
+ OSL_ENSURE( !rLine.GetCharPosArray().empty(), "svx::ImpEditEngine::GetXPos(), portion in an empty line?" );
- if( !pLine->GetCharPosArray().empty() )
+ if( !rLine.GetCharPosArray().empty() )
{
- sal_Int32 nPos = nIndex - 1 - pLine->GetStart();
- if (nPos < 0 || nPos >= static_cast<sal_Int32>(pLine->GetCharPosArray().size()))
+ sal_Int32 nPos = nIndex - 1 - rLine.GetStart();
+ if (nPos < 0 || o3tl::make_unsigned(nPos) >= rLine.GetCharPosArray().size())
{
- nPos = pLine->GetCharPosArray().size()-1;
+ nPos = rLine.GetCharPosArray().size()-1;
OSL_FAIL("svx::ImpEditEngine::GetXPos(), index out of range!");
}
// old code restored see #i112788 (which leaves #i74188 unfixed again)
- tools::Long nPosInPortion = pLine->GetCharPosArray()[nPos];
+ tools::Long nPosInPortion = rLine.GetCharPosArray()[nPos];
if ( !rPortion.IsRightToLeft() )
{
@@ -4047,17 +4345,17 @@ tools::Long ImpEditEngine::GetXPos(
nX += rPortion.GetExtraInfos()->nPortionOffsetX;
if ( rPortion.GetExtraInfos()->nAsianCompressionTypes & AsianCompressionFlags::PunctuationRight )
{
- AsianCompressionFlags nType = GetCharTypeForCompression( pParaPortion->GetNode()->GetChar( nIndex ) );
- if ( nType == AsianCompressionFlags::PunctuationRight && !pLine->GetCharPosArray().empty() )
+ AsianCompressionFlags nType = GetCharTypeForCompression(rParaPortion.GetNode()->GetChar(nIndex));
+ if ( nType == AsianCompressionFlags::PunctuationRight && !rLine.GetCharPosArray().empty() )
{
sal_Int32 n = nIndex - nTextPortionStart;
- const tools::Long* pDXArray = pLine->GetCharPosArray().data()+( nTextPortionStart-pLine->GetStart() );
+ const sal_Int32* pDXArray = rLine.GetCharPosArray().data() + (nTextPortionStart - rLine.GetStart());
sal_Int32 nCharWidth = ( ( (n+1) < rPortion.GetLen() ) ? pDXArray[n] : rPortion.GetSize().Width() )
- ( n ? pDXArray[n-1] : 0 );
if ( (n+1) < rPortion.GetLen() )
{
// smaller, when char behind is AsianCompressionFlags::PunctuationRight also
- nType = GetCharTypeForCompression( pParaPortion->GetNode()->GetChar( nIndex+1 ) );
+ nType = GetCharTypeForCompression(rParaPortion.GetNode()->GetChar(nIndex + 1));
if ( nType == AsianCompressionFlags::PunctuationRight )
{
sal_Int32 nNextCharWidth = ( ( (n+2) < rPortion.GetLen() ) ? pDXArray[n+1] : rPortion.GetSize().Width() )
@@ -4079,7 +4377,7 @@ tools::Long ImpEditEngine::GetXPos(
}
}
}
- else // if ( nIndex == pLine->GetStart() )
+ else // if ( nIndex == rLine.GetStart() )
{
if ( rPortion.IsRightToLeft() )
{
@@ -4090,48 +4388,66 @@ tools::Long ImpEditEngine::GetXPos(
return nX;
}
-void ImpEditEngine::CalcHeight( ParaPortion* pPortion )
+/** Is true if paragraph is in the empty cluster of paragraphs at the end */
+bool ImpEditEngine::isInEmptyClusterAtTheEnd(ParaPortion& rPortion)
{
- pPortion->nHeight = 0;
- pPortion->nFirstLineOffset = 0;
+ sal_Int32 nPortion = GetParaPortions().GetPos(&rPortion);
- if ( !pPortion->IsVisible() )
+ auto& rParagraphs = GetParaPortions();
+ if (rParagraphs.Count() <= 0)
+ return false;
+
+ sal_Int32 nCurrent = rParagraphs.lastIndex();
+ while (nCurrent > 0 && rParagraphs.getRef(nCurrent).IsEmpty())
+ {
+ if (nCurrent == nPortion)
+ return true;
+ nCurrent--;
+ }
+ return false;
+}
+
+void ImpEditEngine::CalcHeight(ParaPortion& rPortion)
+{
+ rPortion.mnHeight = 0;
+ rPortion.mnFirstLineOffset = 0;
+
+ if (!rPortion.IsVisible() || isInEmptyClusterAtTheEnd(rPortion))
return;
- OSL_ENSURE( pPortion->GetLines().Count(), "Paragraph with no lines in ParaPortion::CalcHeight" );
- for (sal_Int32 nLine = 0; nLine < pPortion->GetLines().Count(); ++nLine)
- pPortion->nHeight += pPortion->GetLines()[nLine].GetHeight();
+ OSL_ENSURE(rPortion.GetLines().Count(), "Paragraph with no lines in ParaPortion::CalcHeight");
+ for (sal_Int32 nLine = 0; nLine < rPortion.GetLines().Count(); ++nLine)
+ rPortion.mnHeight += rPortion.GetLines()[nLine].GetHeight();
- if ( aStatus.IsOutliner() )
+ if (maStatus.IsOutliner())
return;
- const SvxULSpaceItem& rULItem = pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE );
- const SvxLineSpacingItem& rLSItem = pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL );
- sal_Int32 nSBL = ( rLSItem.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Fix ) ? GetYValue( rLSItem.GetInterLineSpace() ) : 0;
+ const SvxULSpaceItem& rULItem = rPortion.GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE );
+ const SvxLineSpacingItem& rLSItem = rPortion.GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL );
+ sal_Int32 nSBL = ( rLSItem.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Fix ) ? scaleYSpacingValue(rLSItem.GetInterLineSpace()) : 0;
if ( nSBL )
{
- if ( pPortion->GetLines().Count() > 1 )
- pPortion->nHeight += ( pPortion->GetLines().Count() - 1 ) * nSBL;
- if ( aStatus.ULSpaceSummation() )
- pPortion->nHeight += nSBL;
+ if (rPortion.GetLines().Count() > 1)
+ rPortion.mnHeight += (rPortion.GetLines().Count() - 1) * nSBL;
+ if (maStatus.ULSpaceSummation())
+ rPortion.mnHeight += nSBL;
}
- sal_Int32 nPortion = GetParaPortions().GetPos( pPortion );
+ sal_Int32 nPortion = GetParaPortions().GetPos(&rPortion);
if ( nPortion )
{
- sal_uInt16 nUpper = GetYValue( rULItem.GetUpper() );
- pPortion->nHeight += nUpper;
- pPortion->nFirstLineOffset = nUpper;
+ sal_uInt16 nUpper = scaleYSpacingValue(rULItem.GetUpper());
+ rPortion.mnHeight += nUpper;
+ rPortion.mnFirstLineOffset = nUpper;
}
- if ( nPortion != (GetParaPortions().Count()-1) )
+ if (nPortion != GetParaPortions().lastIndex())
{
- pPortion->nHeight += GetYValue( rULItem.GetLower() ); // not in the last
+ rPortion.mnHeight += scaleYSpacingValue(rULItem.GetLower()); // not in the last
}
-
- if ( !nPortion || aStatus.ULSpaceSummation() )
+ if ( !nPortion || maStatus.ULSpaceSummation() )
return;
ParaPortion* pPrev = GetParaPortions().SafeGetObject( nPortion-1 );
@@ -4147,30 +4463,29 @@ void ImpEditEngine::CalcHeight( ParaPortion* pPortion )
// Only Writer3: Do not add up, but minimum distance.
// check if distance by LineSpacing > Upper:
- sal_uInt16 nExtraSpace = GetYValue( lcl_CalcExtraSpace( rLSItem ) );
- if ( nExtraSpace > pPortion->nFirstLineOffset )
+ sal_uInt16 nExtraSpace = scaleYSpacingValue(lcl_CalcExtraSpace(rLSItem));
+ if (nExtraSpace > rPortion.mnFirstLineOffset)
{
// Paragraph becomes 'bigger':
- pPortion->nHeight += ( nExtraSpace - pPortion->nFirstLineOffset );
- pPortion->nFirstLineOffset = nExtraSpace;
+ rPortion.mnHeight += (nExtraSpace - rPortion.mnFirstLineOffset);
+ rPortion.mnFirstLineOffset = nExtraSpace;
}
// Determine nFirstLineOffset now f(pNode) => now f(pNode, pPrev):
- sal_uInt16 nPrevLower = GetYValue( rPrevULItem.GetLower() );
+ sal_uInt16 nPrevLower = scaleYSpacingValue(rPrevULItem.GetLower());
// This PrevLower is still in the height of PrevPortion ...
- if ( nPrevLower > pPortion->nFirstLineOffset )
+ if (nPrevLower > rPortion.mnFirstLineOffset)
{
// Paragraph is 'small':
- pPortion->nHeight -= pPortion->nFirstLineOffset;
- pPortion->nFirstLineOffset = 0;
+ rPortion.mnHeight -= rPortion.mnFirstLineOffset;
+ rPortion.mnFirstLineOffset = 0;
}
else if ( nPrevLower )
{
// Paragraph becomes 'somewhat smaller':
- pPortion->nHeight -= nPrevLower;
- pPortion->nFirstLineOffset =
- pPortion->nFirstLineOffset - nPrevLower;
+ rPortion.mnHeight -= nPrevLower;
+ rPortion.mnFirstLineOffset = rPortion.mnFirstLineOffset - nPrevLower;
}
// I find it not so good, but Writer3 feature:
// Check if distance by LineSpacing > Lower: this value is not
@@ -4178,124 +4493,39 @@ void ImpEditEngine::CalcHeight( ParaPortion* pPortion )
if ( pPrev->IsInvalid() )
return;
- nExtraSpace = GetYValue( lcl_CalcExtraSpace( rPrevLSItem ) );
+ nExtraSpace = scaleYSpacingValue(lcl_CalcExtraSpace(rPrevLSItem));
if ( nExtraSpace > nPrevLower )
{
sal_uInt16 nMoreLower = nExtraSpace - nPrevLower;
// Paragraph becomes 'bigger', 'grows' downwards:
- if ( nMoreLower > pPortion->nFirstLineOffset )
+ if ( nMoreLower > rPortion.mnFirstLineOffset )
{
- pPortion->nHeight += ( nMoreLower - pPortion->nFirstLineOffset );
- pPortion->nFirstLineOffset = nMoreLower;
+ rPortion.mnHeight += (nMoreLower - rPortion.mnFirstLineOffset);
+ rPortion.mnFirstLineOffset = nMoreLower;
}
}
}
-tools::Rectangle ImpEditEngine::GetEditCursor( ParaPortion* pPortion, sal_Int32 nIndex, GetCursorFlags nFlags )
-{
- OSL_ENSURE( pPortion->IsVisible(), "Why GetEditCursor() for an invisible paragraph?" );
- OSL_ENSURE( IsFormatted() || GetTextRanger(), "GetEditCursor: Not formatted" );
-
- /*
- GetCursorFlags::EndOfLine: If after the last character of a wrapped line, remaining
- at the end of the line, not the beginning of the next one.
- Purpose: - END => really after the last character
- - Selection...
- */
-
- tools::Long nY = pPortion->GetFirstLineOffset();
-
- const SvxLineSpacingItem& rLSItem = pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL );
- sal_uInt16 nSBL = ( rLSItem.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Fix )
- ? GetYValue( rLSItem.GetInterLineSpace() ) : 0;
-
- sal_Int32 nCurIndex = 0;
- sal_Int32 nLineCount = pPortion->GetLines().Count();
- OSL_ENSURE( nLineCount, "Empty ParaPortion in GetEditCursor!" );
- if (nLineCount == 0)
- return tools::Rectangle();
- const EditLine* pLine = nullptr;
- bool bEOL( nFlags & GetCursorFlags::EndOfLine );
- for (sal_Int32 nLine = 0; nLine < nLineCount; ++nLine)
- {
- const EditLine& rTmpLine = pPortion->GetLines()[nLine];
- if ( ( rTmpLine.GetStart() == nIndex ) || ( rTmpLine.IsIn( nIndex, bEOL ) ) )
- {
- pLine = &rTmpLine;
- break;
- }
-
- nCurIndex = nCurIndex + rTmpLine.GetLen();
- nY += rTmpLine.GetHeight();
- if ( !aStatus.IsOutliner() )
- nY += nSBL;
- }
- if ( !pLine )
- {
- // Cursor at the End of the paragraph.
- OSL_ENSURE( nIndex == nCurIndex, "Index dead wrong in GetEditCursor!" );
-
- pLine = &pPortion->GetLines()[nLineCount-1];
- nY -= pLine->GetHeight();
- if ( !aStatus.IsOutliner() )
- nY -= nSBL;
- }
-
- tools::Rectangle aEditCursor;
-
- aEditCursor.SetTop( nY );
- nY += pLine->GetHeight();
- aEditCursor.SetBottom( nY-1 );
-
- // Search within the line...
- tools::Long nX;
-
- if ( ( nIndex == pLine->GetStart() ) && ( nFlags & GetCursorFlags::StartOfLine ) )
- {
- Range aXRange = GetLineXPosStartEnd( pPortion, pLine );
- nX = !IsRightToLeft( GetEditDoc().GetPos( pPortion->GetNode() ) ) ? aXRange.Min() : aXRange.Max();
- }
- else if ( ( nIndex == pLine->GetEnd() ) && ( nFlags & GetCursorFlags::EndOfLine ) )
- {
- Range aXRange = GetLineXPosStartEnd( pPortion, pLine );
- nX = !IsRightToLeft( GetEditDoc().GetPos( pPortion->GetNode() ) ) ? aXRange.Max() : aXRange.Min();
- }
- else
- {
- nX = GetXPos( pPortion, pLine, nIndex, bool( nFlags & GetCursorFlags::PreferPortionStart ) );
- }
-
- aEditCursor.SetLeft(nX);
- aEditCursor.SetRight(nX);
-
- if ( nFlags & GetCursorFlags::TextOnly )
- aEditCursor.SetTop( aEditCursor.Bottom() - pLine->GetTxtHeight() + 1 );
- else
- aEditCursor.SetTop( aEditCursor.Bottom() - std::min( pLine->GetTxtHeight(), pLine->GetHeight() ) + 1 );
-
- return aEditCursor;
-}
-
void ImpEditEngine::SetValidPaperSize( const Size& rNewSz )
{
- aPaperSize = rNewSz;
+ maPaperSize = rNewSz;
- tools::Long nMinWidth = aStatus.AutoPageWidth() ? aMinAutoPaperSize.Width() : 0;
- tools::Long nMaxWidth = aStatus.AutoPageWidth() ? aMaxAutoPaperSize.Width() : 0x7FFFFFFF;
- tools::Long nMinHeight = aStatus.AutoPageHeight() ? aMinAutoPaperSize.Height() : 0;
- tools::Long nMaxHeight = aStatus.AutoPageHeight() ? aMaxAutoPaperSize.Height() : 0x7FFFFFFF;
+ tools::Long nMinWidth = maStatus.AutoPageWidth() ? maMinAutoPaperSize.Width() : 0;
+ tools::Long nMaxWidth = maStatus.AutoPageWidth() ? maMaxAutoPaperSize.Width() : 0x7FFFFFFF;
+ tools::Long nMinHeight = maStatus.AutoPageHeight() ? maMinAutoPaperSize.Height() : 0;
+ tools::Long nMaxHeight = maStatus.AutoPageHeight() ? maMaxAutoPaperSize.Height() : 0x7FFFFFFF;
// Minimum/Maximum width:
- if ( aPaperSize.Width() < nMinWidth )
- aPaperSize.setWidth( nMinWidth );
- else if ( aPaperSize.Width() > nMaxWidth )
- aPaperSize.setWidth( nMaxWidth );
+ if ( maPaperSize.Width() < nMinWidth )
+ maPaperSize.setWidth( nMinWidth );
+ else if ( maPaperSize.Width() > nMaxWidth )
+ maPaperSize.setWidth( nMaxWidth );
// Minimum/Maximum height:
- if ( aPaperSize.Height() < nMinHeight )
- aPaperSize.setHeight( nMinHeight );
- else if ( aPaperSize.Height() > nMaxHeight )
- aPaperSize.setHeight( nMaxHeight );
+ if ( maPaperSize.Height() < nMinHeight )
+ maPaperSize.setHeight( nMinHeight );
+ else if ( maPaperSize.Height() > nMaxHeight )
+ maPaperSize.setHeight( nMaxHeight );
}
std::shared_ptr<SvxForbiddenCharactersTable> const & ImpEditEngine::GetForbiddenCharsTable()
@@ -4312,10 +4542,7 @@ bool ImpEditEngine::IsVisualCursorTravelingEnabled()
{
bool bVisualCursorTravaling = false;
- if( !pCTLOptions )
- pCTLOptions.reset( new SvtCTLOptions );
-
- if ( pCTLOptions->IsCTLFontEnabled() && ( pCTLOptions->GetCTLCursorMovement() == SvtCTLOptions::MOVEMENT_VISUAL ) )
+ if ( SvtCTLOptions::IsCTLFontEnabled() && ( SvtCTLOptions::GetCTLCursorMovement() == SvtCTLOptions::MOVEMENT_VISUAL ) )
{
bVisualCursorTravaling = true;
}
@@ -4332,7 +4559,7 @@ bool ImpEditEngine::DoVisualCursorTraveling()
IMPL_LINK_NOARG(ImpEditEngine, DocModified, LinkParamNone*, void)
{
- aModifyHdl.Call( nullptr /*GetEditEnginePtr()*/ ); // NULL, because also used for Outliner
+ maModifyHdl.Call( nullptr /*GetEditEnginePtr()*/ ); // NULL, because also used for Outliner
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */