File: | home/maarten/src/libreoffice/core/include/rtl/ref.hxx |
Warning: | line 192, column 9 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ | |||
2 | /* | |||
3 | * This file is part of the LibreOffice project. | |||
4 | * | |||
5 | * This Source Code Form is subject to the terms of the Mozilla Public | |||
6 | * License, v. 2.0. If a copy of the MPL was not distributed with this | |||
7 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. | |||
8 | * | |||
9 | * This file incorporates work covered by the following license notice: | |||
10 | * | |||
11 | * Licensed to the Apache Software Foundation (ASF) under one or more | |||
12 | * contributor license agreements. See the NOTICE file distributed | |||
13 | * with this work for additional information regarding copyright | |||
14 | * ownership. The ASF licenses this file to you under the Apache | |||
15 | * License, Version 2.0 (the "License"); you may not use this file | |||
16 | * except in compliance with the License. You may obtain a copy of | |||
17 | * the License at http://www.apache.org/licenses/LICENSE-2.0 . | |||
18 | */ | |||
19 | ||||
20 | #include <vcl/svapp.hxx> | |||
21 | #include <vcl/window.hxx> | |||
22 | #include <editeng/lspcitem.hxx> | |||
23 | #include <editeng/flditem.hxx> | |||
24 | #include "impedit.hxx" | |||
25 | #include <editeng/editeng.hxx> | |||
26 | #include <editeng/editview.hxx> | |||
27 | #include <eerdll2.hxx> | |||
28 | #include <editeng/eerdll.hxx> | |||
29 | #include <edtspell.hxx> | |||
30 | #include "eeobj.hxx" | |||
31 | #include <editeng/txtrange.hxx> | |||
32 | #include <sfx2/app.hxx> | |||
33 | #include <svtools/colorcfg.hxx> | |||
34 | #include <svl/ctloptions.hxx> | |||
35 | #include <unotools/securityoptions.hxx> | |||
36 | #include <editeng/acorrcfg.hxx> | |||
37 | #include <editeng/lrspitem.hxx> | |||
38 | #include <editeng/ulspitem.hxx> | |||
39 | #include <editeng/adjustitem.hxx> | |||
40 | #include <editeng/frmdiritem.hxx> | |||
41 | #include <editeng/justifyitem.hxx> | |||
42 | ||||
43 | #include <com/sun/star/i18n/CharacterIteratorMode.hpp> | |||
44 | #include <com/sun/star/i18n/WordType.hpp> | |||
45 | #include <com/sun/star/i18n/ScriptType.hpp> | |||
46 | #include <com/sun/star/lang/Locale.hpp> | |||
47 | #include <com/sun/star/i18n/InputSequenceCheckMode.hpp> | |||
48 | #include <com/sun/star/system/SystemShellExecute.hpp> | |||
49 | #include <com/sun/star/system/SystemShellExecuteFlags.hpp> | |||
50 | #include <com/sun/star/system/XSystemShellExecute.hpp> | |||
51 | ||||
52 | #include <rtl/character.hxx> | |||
53 | ||||
54 | #include <sal/log.hxx> | |||
55 | #include <o3tl/safeint.hxx> | |||
56 | #include <osl/diagnose.h> | |||
57 | #include <sot/exchange.hxx> | |||
58 | #include <sot/formats.hxx> | |||
59 | #include <svl/asiancfg.hxx> | |||
60 | #include <i18nutil/unicode.hxx> | |||
61 | #include <tools/diagnose_ex.h> | |||
62 | #include <comphelper/lok.hxx> | |||
63 | #include <comphelper/processfactory.hxx> | |||
64 | #include <unotools/configmgr.hxx> | |||
65 | ||||
66 | #include <unicode/ubidi.h> | |||
67 | #include <algorithm> | |||
68 | #include <memory> | |||
69 | ||||
70 | #include <fstream> | |||
71 | ||||
72 | using namespace ::com::sun::star; | |||
73 | ||||
74 | static sal_uInt16 lcl_CalcExtraSpace( const SvxLineSpacingItem& rLSItem ) | |||
75 | { | |||
76 | sal_uInt16 nExtra = 0; | |||
77 | if ( rLSItem.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Fix ) | |||
78 | { | |||
79 | nExtra = rLSItem.GetInterLineSpace(); | |||
80 | } | |||
81 | ||||
82 | return nExtra; | |||
83 | } | |||
84 | ||||
85 | ImpEditEngine::ImpEditEngine( EditEngine* pEE, SfxItemPool* pItemPool ) : | |||
86 | pSharedVCL(EditDLL::Get().GetSharedVclResources()), | |||
87 | aPaperSize( 0x7FFFFFFF, 0x7FFFFFFF ), | |||
88 | aMinAutoPaperSize( 0x0, 0x0 ), | |||
89 | aMaxAutoPaperSize( 0x7FFFFFFF, 0x7FFFFFFF ), | |||
90 | aEditDoc( pItemPool ), | |||
91 | pEditEngine(pEE), | |||
92 | pActiveView(nullptr), | |||
93 | pStylePool(nullptr), | |||
94 | pTextObjectPool(nullptr), | |||
95 | pUndoManager(nullptr), | |||
96 | aWordDelimiters(" .,;:-`'?!_=\"{}()[]"), | |||
97 | maBackgroundColor(COL_AUTO), | |||
98 | nStretchX(100), | |||
99 | nStretchY(100), | |||
100 | nAsianCompressionMode(CharCompressType::NONE), | |||
101 | eDefaultHorizontalTextDirection(EEHorizontalTextDirection::Default), | |||
102 | nBigTextObjectStart(20), | |||
103 | eDefLanguage(LANGUAGE_DONTKNOWLanguageType(0x03FF)), | |||
104 | nCurTextHeight(0), | |||
105 | nCurTextHeightNTP(0), | |||
106 | bKernAsianPunctuation(false), | |||
107 | bAddExtLeading(false), | |||
108 | bIsFormatting(false), | |||
109 | bFormatted(false), | |||
110 | bInSelection(false), | |||
111 | bIsInUndo(false), | |||
112 | bUpdate(true), | |||
113 | bUndoEnabled(true), | |||
114 | bDowning(false), | |||
115 | bUseAutoColor(true), | |||
116 | bForceAutoColor(false), | |||
117 | bCallParaInsertedOrDeleted(false), | |||
118 | bFirstWordCapitalization(true), | |||
119 | mbLastTryMerge(false), | |||
120 | mbReplaceLeadingSingleQuotationMark(true), | |||
121 | mbNbspRunNext(false) | |||
122 | { | |||
123 | aStatus.GetControlWord() = EEControlBits::USECHARATTRIBS | EEControlBits::DOIDLEFORMAT | | |||
124 | EEControlBits::PASTESPECIAL | EEControlBits::UNDOATTRIBS | | |||
125 | EEControlBits::ALLOWBIGOBJS | EEControlBits::RTFSTYLESHEETS | | |||
126 | EEControlBits::FORMAT100; | |||
127 | ||||
128 | aSelEngine.SetFunctionSet( &aSelFuncSet ); | |||
129 | ||||
130 | aStatusTimer.SetTimeout( 200 ); | |||
131 | aStatusTimer.SetInvokeHandler( LINK( this, ImpEditEngine, StatusTimerHdl )::tools::detail::makeLink( ::tools::detail::castTo<ImpEditEngine *>(this), &ImpEditEngine::LinkStubStatusTimerHdl) ); | |||
132 | aStatusTimer.SetDebugName( "editeng::ImpEditEngine aStatusTimer" ); | |||
133 | ||||
134 | aIdleFormatter.SetPriority( TaskPriority::REPAINT ); | |||
135 | aIdleFormatter.SetInvokeHandler( LINK( this, ImpEditEngine, IdleFormatHdl )::tools::detail::makeLink( ::tools::detail::castTo<ImpEditEngine *>(this), &ImpEditEngine::LinkStubIdleFormatHdl) ); | |||
136 | aIdleFormatter.SetDebugName( "editeng::ImpEditEngine aIdleFormatter" ); | |||
137 | ||||
138 | aOnlineSpellTimer.SetTimeout( 100 ); | |||
139 | aOnlineSpellTimer.SetInvokeHandler( LINK( this, ImpEditEngine, OnlineSpellHdl )::tools::detail::makeLink( ::tools::detail::castTo<ImpEditEngine *>(this), &ImpEditEngine::LinkStubOnlineSpellHdl) ); | |||
140 | aOnlineSpellTimer.SetDebugName( "editeng::ImpEditEngine aOnlineSpellTimer" ); | |||
141 | ||||
142 | // Access data already from here on! | |||
143 | SetRefDevice( nullptr ); | |||
144 | InitDoc( false ); | |||
145 | ||||
146 | bCallParaInsertedOrDeleted = true; | |||
147 | ||||
148 | aEditDoc.SetModifyHdl( LINK( this, ImpEditEngine, DocModified )::tools::detail::makeLink( ::tools::detail::castTo<ImpEditEngine *>(this), &ImpEditEngine::LinkStubDocModified) ); | |||
149 | StartListening(*SfxGetpApp()); | |||
150 | } | |||
151 | ||||
152 | void ImpEditEngine::Dispose() | |||
153 | { | |||
154 | SolarMutexGuard g; | |||
155 | auto pApp = SfxApplication::Get(); | |||
156 | if(pApp) | |||
157 | EndListening(*pApp); | |||
158 | pVirtDev.disposeAndClear(); | |||
159 | mpOwnDev.disposeAndClear(); | |||
160 | pSharedVCL.reset(); | |||
161 | } | |||
162 | ||||
163 | ImpEditEngine::~ImpEditEngine() | |||
164 | { | |||
165 | aStatusTimer.Stop(); | |||
166 | aOnlineSpellTimer.Stop(); | |||
167 | aIdleFormatter.Stop(); | |||
168 | ||||
169 | // Destroying templates may otherwise cause unnecessary formatting, | |||
170 | // when a parent template is destroyed. | |||
171 | // And this after the destruction of the data! | |||
172 | bDowning = true; | |||
173 | SetUpdateMode( false ); | |||
174 | ||||
175 | Dispose(); | |||
176 | // it's only legal to delete the pUndoManager if it was created by | |||
177 | // ImpEditEngine; if it was set by SetUndoManager() it must be cleared | |||
178 | // before destroying the ImpEditEngine! | |||
179 | assert(!pUndoManager || typeid(*pUndoManager) == typeid(EditUndoManager))(static_cast <bool> (!pUndoManager || typeid(*pUndoManager ) == typeid(EditUndoManager)) ? void (0) : __assert_fail ("!pUndoManager || typeid(*pUndoManager) == typeid(EditUndoManager)" , "/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" , 179, __extension__ __PRETTY_FUNCTION__)); | |||
180 | delete pUndoManager; | |||
181 | pTextRanger.reset(); | |||
182 | mpIMEInfos.reset(); | |||
183 | pCTLOptions.reset(); | |||
184 | pSpellInfo.reset(); | |||
185 | } | |||
186 | ||||
187 | void ImpEditEngine::SetRefDevice( OutputDevice* pRef ) | |||
188 | { | |||
189 | if (pRef) | |||
190 | pRefDev = pRef; | |||
191 | else | |||
192 | pRefDev = pSharedVCL->GetVirtualDevice(); | |||
193 | ||||
194 | nOnePixelInRef = static_cast<sal_uInt16>(pRefDev->PixelToLogic( Size( 1, 0 ) ).Width()); | |||
195 | ||||
196 | if ( IsFormatted() ) | |||
197 | { | |||
198 | FormatFullDoc(); | |||
199 | UpdateViews(); | |||
200 | } | |||
201 | } | |||
202 | ||||
203 | void ImpEditEngine::SetRefMapMode( const MapMode& rMapMode ) | |||
204 | { | |||
205 | if ( GetRefDevice()->GetMapMode() == rMapMode ) | |||
| ||||
206 | return; | |||
207 | ||||
208 | mpOwnDev.disposeAndClear(); | |||
209 | mpOwnDev = VclPtr<VirtualDevice>::Create(); | |||
210 | pRefDev = mpOwnDev; | |||
211 | pRefDev->SetMapMode(MapMode(MapUnit::MapTwip)); | |||
212 | SetRefDevice( pRefDev ); | |||
213 | ||||
214 | pRefDev->SetMapMode( rMapMode ); | |||
215 | nOnePixelInRef = static_cast<sal_uInt16>(pRefDev->PixelToLogic( Size( 1, 0 ) ).Width()); | |||
216 | if ( IsFormatted() ) | |||
217 | { | |||
218 | FormatFullDoc(); | |||
219 | UpdateViews(); | |||
220 | } | |||
221 | } | |||
222 | ||||
223 | void ImpEditEngine::InitDoc(bool bKeepParaAttribs) | |||
224 | { | |||
225 | sal_Int32 nParas = aEditDoc.Count(); | |||
226 | for ( sal_Int32 n = bKeepParaAttribs ? 1 : 0; n < nParas; n++ ) | |||
227 | { | |||
228 | if ( aEditDoc[n]->GetStyleSheet() ) | |||
229 | EndListening( *aEditDoc[n]->GetStyleSheet() ); | |||
230 | } | |||
231 | ||||
232 | if ( bKeepParaAttribs ) | |||
233 | aEditDoc.RemoveText(); | |||
234 | else | |||
235 | aEditDoc.Clear(); | |||
236 | ||||
237 | GetParaPortions().Reset(); | |||
238 | ||||
239 | GetParaPortions().Insert(0, std::make_unique<ParaPortion>( aEditDoc[0] )); | |||
240 | ||||
241 | bFormatted = false; | |||
242 | ||||
243 | if ( IsCallParaInsertedOrDeleted() ) | |||
244 | { | |||
245 | GetEditEnginePtr()->ParagraphDeleted( EE_PARA_ALL((sal_Int32) 0x7FFFFFFF) ); | |||
246 | GetEditEnginePtr()->ParagraphInserted( 0 ); | |||
247 | } | |||
248 | ||||
249 | if ( GetStatus().DoOnlineSpelling() ) | |||
250 | aEditDoc.GetObject( 0 )->CreateWrongList(); | |||
251 | } | |||
252 | ||||
253 | EditPaM ImpEditEngine::DeleteSelected(const EditSelection& rSel) | |||
254 | { | |||
255 | EditPaM aPaM (ImpDeleteSelection(rSel)); | |||
256 | return aPaM; | |||
257 | } | |||
258 | ||||
259 | OUString ImpEditEngine::GetSelected( const EditSelection& rSel ) const | |||
260 | { | |||
261 | if ( !rSel.HasRange() ) | |||
262 | return OUString(); | |||
263 | ||||
264 | EditSelection aSel( rSel ); | |||
265 | aSel.Adjust( aEditDoc ); | |||
266 | ||||
267 | ContentNode* pStartNode = aSel.Min().GetNode(); | |||
268 | ContentNode* pEndNode = aSel.Max().GetNode(); | |||
269 | sal_Int32 nStartNode = aEditDoc.GetPos( pStartNode ); | |||
270 | sal_Int32 nEndNode = aEditDoc.GetPos( pEndNode ); | |||
271 | ||||
272 | OSL_ENSURE( nStartNode <= nEndNode, "Selection not sorted ?" )do { if (true && (!(nStartNode <= nEndNode))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "272" ": "), "%s", "Selection not sorted ?"); } } while ( false); | |||
273 | ||||
274 | OUStringBuffer aText(256); | |||
275 | const OUString aSep = EditDoc::GetSepStr( LINEEND_LF ); | |||
276 | ||||
277 | // iterate over the paragraphs ... | |||
278 | for ( sal_Int32 nNode = nStartNode; nNode <= nEndNode; nNode++ ) | |||
279 | { | |||
280 | OSL_ENSURE( aEditDoc.GetObject( nNode ), "Node not found: GetSelected" )do { if (true && (!(aEditDoc.GetObject( nNode )))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "280" ": "), "%s", "Node not found: GetSelected"); } } while (false); | |||
281 | const ContentNode* pNode = aEditDoc.GetObject( nNode ); | |||
282 | ||||
283 | const sal_Int32 nStartPos = nNode==nStartNode ? aSel.Min().GetIndex() : 0; | |||
284 | const sal_Int32 nEndPos = nNode==nEndNode ? aSel.Max().GetIndex() : pNode->Len(); // can also be == nStart! | |||
285 | ||||
286 | aText.append(EditDoc::GetParaAsString( pNode, nStartPos, nEndPos )); | |||
287 | if ( nNode < nEndNode ) | |||
288 | aText.append(aSep); | |||
289 | } | |||
290 | return aText.makeStringAndClear(); | |||
291 | } | |||
292 | ||||
293 | bool ImpEditEngine::MouseButtonDown( const MouseEvent& rMEvt, EditView* pView ) | |||
294 | { | |||
295 | GetSelEngine().SetCurView( pView ); | |||
296 | SetActiveView( pView ); | |||
297 | ||||
298 | if (!GetAutoCompleteText().isEmpty()) | |||
299 | SetAutoCompleteText( OUString(), true ); | |||
300 | ||||
301 | GetSelEngine().SelMouseButtonDown( rMEvt ); | |||
302 | // Special treatment | |||
303 | EditSelection aCurSel( pView->pImpEditView->GetEditSelection() ); | |||
304 | if ( !rMEvt.IsShift() ) | |||
305 | { | |||
306 | if ( rMEvt.GetClicks() == 2 ) | |||
307 | { | |||
308 | // So that the SelectionEngine knows about the anchor. | |||
309 | aSelEngine.CursorPosChanging( true, false ); | |||
310 | ||||
311 | EditSelection aNewSelection( SelectWord( aCurSel ) ); | |||
312 | pView->pImpEditView->DrawSelectionXOR(); | |||
313 | pView->pImpEditView->SetEditSelection( aNewSelection ); | |||
314 | pView->pImpEditView->DrawSelectionXOR(); | |||
315 | pView->ShowCursor(); | |||
316 | } | |||
317 | else if ( rMEvt.GetClicks() == 3 ) | |||
318 | { | |||
319 | // So that the SelectionEngine knows about the anchor. | |||
320 | aSelEngine.CursorPosChanging( true, false ); | |||
321 | ||||
322 | EditSelection aNewSelection( aCurSel ); | |||
323 | aNewSelection.Min().SetIndex( 0 ); | |||
324 | aNewSelection.Max().SetIndex( aCurSel.Min().GetNode()->Len() ); | |||
325 | pView->pImpEditView->DrawSelectionXOR(); | |||
326 | pView->pImpEditView->SetEditSelection( aNewSelection ); | |||
327 | pView->pImpEditView->DrawSelectionXOR(); | |||
328 | pView->ShowCursor(); | |||
329 | } | |||
330 | } | |||
331 | return true; | |||
332 | } | |||
333 | ||||
334 | void ImpEditEngine::Command( const CommandEvent& rCEvt, EditView* pView ) | |||
335 | { | |||
336 | GetSelEngine().SetCurView( pView ); | |||
337 | SetActiveView( pView ); | |||
338 | if ( rCEvt.GetCommand() == CommandEventId::StartExtTextInput ) | |||
339 | { | |||
340 | pView->DeleteSelected(); | |||
341 | mpIMEInfos.reset(); | |||
342 | EditPaM aPaM = pView->GetImpEditView()->GetEditSelection().Max(); | |||
343 | OUString aOldTextAfterStartPos = aPaM.GetNode()->Copy( aPaM.GetIndex() ); | |||
344 | sal_Int32 nMax = aOldTextAfterStartPos.indexOf( CH_FEATUREu'\x0001' ); | |||
345 | if ( nMax != -1 ) // don't overwrite features! | |||
346 | aOldTextAfterStartPos = aOldTextAfterStartPos.copy( 0, nMax ); | |||
347 | mpIMEInfos.reset( new ImplIMEInfos( aPaM, aOldTextAfterStartPos ) ); | |||
348 | mpIMEInfos->bWasCursorOverwrite = !pView->IsInsertMode(); | |||
349 | UndoActionStart( EDITUNDO_INSERT111 ); | |||
350 | } | |||
351 | else if ( rCEvt.GetCommand() == CommandEventId::EndExtTextInput ) | |||
352 | { | |||
353 | OSL_ENSURE( mpIMEInfos, "CommandEventId::EndExtTextInput => No start ?" )do { if (true && (!(mpIMEInfos))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "353" ": "), "%s", "CommandEventId::EndExtTextInput => No start ?" ); } } while (false); | |||
354 | if( mpIMEInfos ) | |||
355 | { | |||
356 | // #102812# convert quotes in IME text | |||
357 | // works on the last input character, this is especially in Korean text often done | |||
358 | // quotes that are inside of the string are not replaced! | |||
359 | // Borrowed from sw: edtwin.cxx | |||
360 | if ( mpIMEInfos->nLen ) | |||
361 | { | |||
362 | EditSelection aSel( mpIMEInfos->aPos ); | |||
363 | aSel.Min().SetIndex( aSel.Min().GetIndex() + mpIMEInfos->nLen-1 ); | |||
364 | aSel.Max().SetIndex( aSel.Max().GetIndex() + mpIMEInfos->nLen ); | |||
365 | // #102812# convert quotes in IME text | |||
366 | // works on the last input character, this is especially in Korean text often done | |||
367 | // quotes that are inside of the string are not replaced! | |||
368 | const sal_Unicode nCharCode = aSel.Min().GetNode()->GetChar( aSel.Min().GetIndex() ); | |||
369 | if ( ( GetStatus().DoAutoCorrect() ) && ( ( nCharCode == '\"' ) || ( nCharCode == '\'' ) ) ) | |||
370 | { | |||
371 | aSel = DeleteSelected( aSel ); | |||
372 | aSel = AutoCorrect( aSel, nCharCode, mpIMEInfos->bWasCursorOverwrite ); | |||
373 | pView->pImpEditView->SetEditSelection( aSel ); | |||
374 | } | |||
375 | } | |||
376 | ||||
377 | ParaPortion* pPortion = FindParaPortion( mpIMEInfos->aPos.GetNode() ); | |||
378 | pPortion->MarkSelectionInvalid( mpIMEInfos->aPos.GetIndex() ); | |||
379 | ||||
380 | bool bWasCursorOverwrite = mpIMEInfos->bWasCursorOverwrite; | |||
381 | ||||
382 | mpIMEInfos.reset(); | |||
383 | ||||
384 | FormatAndUpdate( pView ); | |||
385 | ||||
386 | pView->SetInsertMode( !bWasCursorOverwrite ); | |||
387 | } | |||
388 | UndoActionEnd(); | |||
389 | } | |||
390 | else if ( rCEvt.GetCommand() == CommandEventId::ExtTextInput ) | |||
391 | { | |||
392 | OSL_ENSURE( mpIMEInfos, "CommandEventId::ExtTextInput => No Start ?" )do { if (true && (!(mpIMEInfos))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "392" ": "), "%s", "CommandEventId::ExtTextInput => No Start ?" ); } } while (false); | |||
393 | if( mpIMEInfos ) | |||
394 | { | |||
395 | const CommandExtTextInputData* pData = rCEvt.GetExtTextInputData(); | |||
396 | ||||
397 | if ( !pData->IsOnlyCursorChanged() ) | |||
398 | { | |||
399 | EditSelection aSel( mpIMEInfos->aPos ); | |||
400 | aSel.Max().SetIndex( aSel.Max().GetIndex() + mpIMEInfos->nLen ); | |||
401 | aSel = DeleteSelected( aSel ); | |||
402 | aSel = ImpInsertText( aSel, pData->GetText() ); | |||
403 | ||||
404 | if ( mpIMEInfos->bWasCursorOverwrite ) | |||
405 | { | |||
406 | sal_Int32 nOldIMETextLen = mpIMEInfos->nLen; | |||
407 | sal_Int32 nNewIMETextLen = pData->GetText().getLength(); | |||
408 | ||||
409 | if ( ( nOldIMETextLen > nNewIMETextLen ) && | |||
410 | ( nNewIMETextLen < mpIMEInfos->aOldTextAfterStartPos.getLength() ) ) | |||
411 | { | |||
412 | // restore old characters | |||
413 | sal_Int32 nRestore = nOldIMETextLen - nNewIMETextLen; | |||
414 | EditPaM aPaM( mpIMEInfos->aPos ); | |||
415 | aPaM.SetIndex( aPaM.GetIndex() + nNewIMETextLen ); | |||
416 | ImpInsertText( aPaM, mpIMEInfos->aOldTextAfterStartPos.copy( nNewIMETextLen, nRestore ) ); | |||
417 | } | |||
418 | else if ( ( nOldIMETextLen < nNewIMETextLen ) && | |||
419 | ( nOldIMETextLen < mpIMEInfos->aOldTextAfterStartPos.getLength() ) ) | |||
420 | { | |||
421 | // overwrite | |||
422 | sal_Int32 nOverwrite = nNewIMETextLen - nOldIMETextLen; | |||
423 | if ( ( nOldIMETextLen + nOverwrite ) > mpIMEInfos->aOldTextAfterStartPos.getLength() ) | |||
424 | nOverwrite = mpIMEInfos->aOldTextAfterStartPos.getLength() - nOldIMETextLen; | |||
425 | OSL_ENSURE( nOverwrite && (nOverwrite < 0xFF00), "IME Overwrite?!" )do { if (true && (!(nOverwrite && (nOverwrite < 0xFF00)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "425" ": "), "%s", "IME Overwrite?!"); } } while (false); | |||
426 | EditPaM aPaM( mpIMEInfos->aPos ); | |||
427 | aPaM.SetIndex( aPaM.GetIndex() + nNewIMETextLen ); | |||
428 | EditSelection _aSel( aPaM ); | |||
429 | _aSel.Max().SetIndex( _aSel.Max().GetIndex() + nOverwrite ); | |||
430 | DeleteSelected( _aSel ); | |||
431 | } | |||
432 | } | |||
433 | if ( pData->GetTextAttr() ) | |||
434 | { | |||
435 | mpIMEInfos->CopyAttribs( pData->GetTextAttr(), pData->GetText().getLength() ); | |||
436 | } | |||
437 | else | |||
438 | { | |||
439 | mpIMEInfos->DestroyAttribs(); | |||
440 | mpIMEInfos->nLen = pData->GetText().getLength(); | |||
441 | } | |||
442 | ||||
443 | ParaPortion* pPortion = FindParaPortion( mpIMEInfos->aPos.GetNode() ); | |||
444 | pPortion->MarkSelectionInvalid( mpIMEInfos->aPos.GetIndex() ); | |||
445 | FormatAndUpdate( pView ); | |||
446 | } | |||
447 | ||||
448 | EditSelection aNewSel = EditPaM( mpIMEInfos->aPos.GetNode(), mpIMEInfos->aPos.GetIndex()+pData->GetCursorPos() ); | |||
449 | pView->SetSelection( CreateESel( aNewSel ) ); | |||
450 | pView->SetInsertMode( !pData->IsCursorOverwrite() ); | |||
451 | ||||
452 | if ( pData->IsCursorVisible() ) | |||
453 | pView->ShowCursor(); | |||
454 | else | |||
455 | pView->HideCursor(); | |||
456 | } | |||
457 | } | |||
458 | else if ( rCEvt.GetCommand() == CommandEventId::InputContextChange ) | |||
459 | { | |||
460 | } | |||
461 | else if ( rCEvt.GetCommand() == CommandEventId::CursorPos ) | |||
462 | { | |||
463 | if (mpIMEInfos) | |||
464 | { | |||
465 | EditPaM aPaM( pView->pImpEditView->GetEditSelection().Max() ); | |||
466 | tools::Rectangle aR1 = PaMtoEditCursor( aPaM ); | |||
467 | ||||
468 | sal_Int32 nInputEnd = mpIMEInfos->aPos.GetIndex() + mpIMEInfos->nLen; | |||
469 | ||||
470 | if ( !IsFormatted() ) | |||
471 | FormatDoc(); | |||
472 | ||||
473 | ParaPortion* pParaPortion = GetParaPortions().SafeGetObject( GetEditDoc().GetPos( aPaM.GetNode() ) ); | |||
474 | if (pParaPortion) | |||
475 | { | |||
476 | sal_Int32 nLine = pParaPortion->GetLines().FindLine( aPaM.GetIndex(), true ); | |||
477 | const EditLine& rLine = pParaPortion->GetLines()[nLine]; | |||
478 | if ( nInputEnd > rLine.GetEnd() ) | |||
479 | nInputEnd = rLine.GetEnd(); | |||
480 | tools::Rectangle aR2 = PaMtoEditCursor( EditPaM( aPaM.GetNode(), nInputEnd ), GetCursorFlags::EndOfLine ); | |||
481 | tools::Rectangle aRect = pView->GetImpEditView()->GetWindowPos( aR1 ); | |||
482 | auto nExtTextInputWidth = aR2.Left() - aR1.Right(); | |||
483 | if (EditViewCallbacks* pEditViewCallbacks = pView->getEditViewCallbacks()) | |||
484 | pEditViewCallbacks->EditViewCursorRect(aRect, nExtTextInputWidth); | |||
485 | else if (vcl::Window* pWindow = pView->GetWindow()) | |||
486 | pWindow->SetCursorRect(&aRect, nExtTextInputWidth); | |||
487 | } | |||
488 | } | |||
489 | else | |||
490 | { | |||
491 | if (vcl::Window* pWindow = pView->GetWindow()) | |||
492 | pWindow->SetCursorRect(); | |||
493 | } | |||
494 | } | |||
495 | else if ( rCEvt.GetCommand() == CommandEventId::SelectionChange ) | |||
496 | { | |||
497 | const CommandSelectionChangeData *pData = rCEvt.GetSelectionChangeData(); | |||
498 | ||||
499 | ESelection aSelection = pView->GetSelection(); | |||
500 | aSelection.Adjust(); | |||
501 | ||||
502 | if( pView->HasSelection() ) | |||
503 | { | |||
504 | aSelection.nEndPos = aSelection.nStartPos; | |||
505 | aSelection.nStartPos += pData->GetStart(); | |||
506 | aSelection.nEndPos += pData->GetEnd(); | |||
507 | } | |||
508 | else | |||
509 | { | |||
510 | aSelection.nStartPos = pData->GetStart(); | |||
511 | aSelection.nEndPos = pData->GetEnd(); | |||
512 | } | |||
513 | pView->SetSelection( aSelection ); | |||
514 | } | |||
515 | else if ( rCEvt.GetCommand() == CommandEventId::PrepareReconversion ) | |||
516 | { | |||
517 | if ( pView->HasSelection() ) | |||
518 | { | |||
519 | ESelection aSelection = pView->GetSelection(); | |||
520 | aSelection.Adjust(); | |||
521 | ||||
522 | if ( aSelection.nStartPara != aSelection.nEndPara ) | |||
523 | { | |||
524 | sal_Int32 aParaLen = pEditEngine->GetTextLen( aSelection.nStartPara ); | |||
525 | aSelection.nEndPara = aSelection.nStartPara; | |||
526 | aSelection.nEndPos = aParaLen; | |||
527 | pView->SetSelection( aSelection ); | |||
528 | } | |||
529 | } | |||
530 | } | |||
531 | else if ( rCEvt.GetCommand() == CommandEventId::QueryCharPosition ) | |||
532 | { | |||
533 | if (mpIMEInfos) | |||
534 | { | |||
535 | EditPaM aPaM( pView->pImpEditView->GetEditSelection().Max() ); | |||
536 | if ( !IsFormatted() ) | |||
537 | FormatDoc(); | |||
538 | ||||
539 | ParaPortion* pParaPortion = GetParaPortions().SafeGetObject( GetEditDoc().GetPos( aPaM.GetNode() ) ); | |||
540 | if (pParaPortion) | |||
541 | { | |||
542 | sal_Int32 nLine = pParaPortion->GetLines().FindLine( aPaM.GetIndex(), true ); | |||
543 | const EditLine& rLine = pParaPortion->GetLines()[nLine]; | |||
544 | std::unique_ptr<tools::Rectangle[]> aRects(new tools::Rectangle[ mpIMEInfos->nLen ]); | |||
545 | for (sal_Int32 i = 0; i < mpIMEInfos->nLen; ++i) | |||
546 | { | |||
547 | sal_Int32 nInputPos = mpIMEInfos->aPos.GetIndex() + i; | |||
548 | if ( nInputPos > rLine.GetEnd() ) | |||
549 | nInputPos = rLine.GetEnd(); | |||
550 | tools::Rectangle aR2 = GetEditCursor( pParaPortion, nInputPos ); | |||
551 | aRects[ i ] = pView->GetImpEditView()->GetWindowPos( aR2 ); | |||
552 | } | |||
553 | if (vcl::Window* pWindow = pView->GetWindow()) | |||
554 | pWindow->SetCompositionCharRect( aRects.get(), mpIMEInfos->nLen ); | |||
555 | } | |||
556 | } | |||
557 | } | |||
558 | ||||
559 | GetSelEngine().Command( rCEvt ); | |||
560 | } | |||
561 | ||||
562 | bool ImpEditEngine::MouseButtonUp( const MouseEvent& rMEvt, EditView* pView ) | |||
563 | { | |||
564 | GetSelEngine().SetCurView( pView ); | |||
565 | GetSelEngine().SelMouseButtonUp( rMEvt ); | |||
566 | ||||
567 | // in the tiled rendering case, setting bInSelection here has unexpected | |||
568 | // consequences - further tiles painting removes the selection | |||
569 | // FIXME I believe resetting bInSelection should not be here even in the | |||
570 | // non-tiled-rendering case, but it has been here since 2000 (and before) | |||
571 | // so who knows what corner case it was supposed to solve back then | |||
572 | if (!comphelper::LibreOfficeKit::isActive()) | |||
573 | bInSelection = false; | |||
574 | ||||
575 | // Special treatments | |||
576 | EditSelection aCurSel( pView->pImpEditView->GetEditSelection() ); | |||
577 | if ( !aCurSel.HasRange() ) | |||
578 | { | |||
579 | if ( ( rMEvt.GetClicks() == 1 ) && rMEvt.IsLeft() && !rMEvt.IsMod2() ) | |||
580 | { | |||
581 | const OutputDevice& rOutDev = pView->getEditViewCallbacks() ? pView->getEditViewCallbacks()->EditViewOutputDevice() : *pView->GetWindow(); | |||
582 | Point aLogicClick = rOutDev.PixelToLogic(rMEvt.GetPosPixel()); | |||
583 | if (const SvxFieldItem* pFld = pView->GetField(aLogicClick)) | |||
584 | { | |||
585 | // tdf#121039 When in edit mode, editeng is responsible for opening the URL on mouse click | |||
586 | if (auto pUrlField = dynamic_cast<const SvxURLField*>(pFld->GetField())) | |||
587 | { | |||
588 | SvtSecurityOptions aSecOpt; | |||
589 | bool bCtrlClickHappened = rMEvt.IsMod1(); | |||
590 | bool bCtrlClickSecOption | |||
591 | = aSecOpt.IsOptionSet(SvtSecurityOptions::EOption::CtrlClickHyperlink); | |||
592 | if ((bCtrlClickHappened && bCtrlClickSecOption) | |||
593 | || (!bCtrlClickHappened && !bCtrlClickSecOption)) | |||
594 | { | |||
595 | css::uno::Reference<css::system::XSystemShellExecute> exec( | |||
596 | css::system::SystemShellExecute::create( | |||
597 | comphelper::getProcessComponentContext())); | |||
598 | exec->execute(pUrlField->GetURL(), OUString(), | |||
599 | css::system::SystemShellExecuteFlags::DEFAULTS); | |||
600 | } | |||
601 | } | |||
602 | GetEditEnginePtr()->FieldClicked( *pFld ); | |||
603 | } | |||
604 | } | |||
605 | } | |||
606 | return true; | |||
607 | } | |||
608 | ||||
609 | void ImpEditEngine::ReleaseMouse() | |||
610 | { | |||
611 | GetSelEngine().ReleaseMouse(); | |||
612 | } | |||
613 | ||||
614 | bool ImpEditEngine::MouseMove( const MouseEvent& rMEvt, EditView* pView ) | |||
615 | { | |||
616 | // MouseMove is called directly after ShowQuickHelp()! | |||
617 | GetSelEngine().SetCurView( pView ); | |||
618 | GetSelEngine().SelMouseMove( rMEvt ); | |||
619 | return true; | |||
620 | } | |||
621 | ||||
622 | EditPaM ImpEditEngine::InsertText(const EditSelection& aSel, const OUString& rStr) | |||
623 | { | |||
624 | EditPaM aPaM = ImpInsertText( aSel, rStr ); | |||
625 | return aPaM; | |||
626 | } | |||
627 | ||||
628 | void ImpEditEngine::Clear() | |||
629 | { | |||
630 | InitDoc( false ); | |||
631 | ||||
632 | EditPaM aPaM = aEditDoc.GetStartPaM(); | |||
633 | EditSelection aSel( aPaM ); | |||
634 | ||||
635 | nCurTextHeight = 0; | |||
636 | nCurTextHeightNTP = 0; | |||
637 | ||||
638 | ResetUndoManager(); | |||
639 | ||||
640 | for (size_t nView = aEditViews.size(); nView; ) | |||
641 | { | |||
642 | EditView* pView = aEditViews[--nView]; | |||
643 | pView->pImpEditView->SetEditSelection( aSel ); | |||
644 | } | |||
645 | } | |||
646 | ||||
647 | EditPaM ImpEditEngine::RemoveText() | |||
648 | { | |||
649 | InitDoc( true ); | |||
650 | ||||
651 | EditPaM aStartPaM = aEditDoc.GetStartPaM(); | |||
652 | EditSelection aEmptySel( aStartPaM, aStartPaM ); | |||
653 | for (EditView* pView : aEditViews) | |||
654 | { | |||
655 | pView->pImpEditView->SetEditSelection( aEmptySel ); | |||
656 | } | |||
657 | ResetUndoManager(); | |||
658 | return aEditDoc.GetStartPaM(); | |||
659 | } | |||
660 | ||||
661 | ||||
662 | void ImpEditEngine::SetText(const OUString& rText) | |||
663 | { | |||
664 | // RemoveText deletes the undo list! | |||
665 | EditPaM aStartPaM = RemoveText(); | |||
666 | bool bUndoCurrentlyEnabled = IsUndoEnabled(); | |||
667 | // The text inserted manually can not be made reversible by the user | |||
668 | EnableUndo( false ); | |||
669 | ||||
670 | EditSelection aEmptySel( aStartPaM, aStartPaM ); | |||
671 | EditPaM aPaM = aStartPaM; | |||
672 | if (!rText.isEmpty()) | |||
673 | aPaM = ImpInsertText( aEmptySel, rText ); | |||
674 | ||||
675 | for (EditView* pView : aEditViews) | |||
676 | { | |||
677 | pView->pImpEditView->SetEditSelection( EditSelection( aPaM, aPaM ) ); | |||
678 | // If no text then also no Format&Update | |||
679 | // => The text remains. | |||
680 | if (rText.isEmpty() && GetUpdateMode()) | |||
681 | { | |||
682 | tools::Rectangle aTmpRect( pView->GetOutputArea().TopLeft(), | |||
683 | Size( aPaperSize.Width(), nCurTextHeight ) ); | |||
684 | aTmpRect.Intersection( pView->GetOutputArea() ); | |||
685 | pView->InvalidateWindow( aTmpRect ); | |||
686 | } | |||
687 | } | |||
688 | if (rText.isEmpty()) { // otherwise it must be invalidated later, !bFormatted is enough. | |||
689 | nCurTextHeight = 0; | |||
690 | nCurTextHeightNTP = 0; | |||
691 | } | |||
692 | EnableUndo( bUndoCurrentlyEnabled ); | |||
693 | OSL_ENSURE( !HasUndoManager() || !GetUndoManager().GetUndoActionCount(), "Undo after SetText?" )do { if (true && (!(!HasUndoManager() || !GetUndoManager ().GetUndoActionCount()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "693" ": "), "%s", "Undo after SetText?"); } } while (false ); | |||
694 | } | |||
695 | ||||
696 | ||||
697 | const SfxItemSet& ImpEditEngine::GetEmptyItemSet() const | |||
698 | { | |||
699 | if ( !pEmptyItemSet ) | |||
700 | { | |||
701 | pEmptyItemSet = std::make_unique<SfxItemSet>(const_cast<SfxItemPool&>(aEditDoc.GetItemPool()), svl::Items<EE_ITEMS_START, EE_ITEMS_END>{}); | |||
702 | for ( sal_uInt16 nWhich = EE_ITEMS_START; nWhich <= EE_CHAR_END; nWhich++) | |||
703 | { | |||
704 | pEmptyItemSet->ClearItem( nWhich ); | |||
705 | } | |||
706 | } | |||
707 | return *pEmptyItemSet; | |||
708 | } | |||
709 | ||||
710 | ||||
711 | // MISC | |||
712 | ||||
713 | void ImpEditEngine::CursorMoved( const ContentNode* pPrevNode ) | |||
714 | { | |||
715 | // Delete empty attributes, but only if paragraph is not empty! | |||
716 | if (pPrevNode->GetCharAttribs().HasEmptyAttribs() && pPrevNode->Len()) | |||
717 | { | |||
718 | const_cast<ContentNode*>(pPrevNode)->GetCharAttribs().DeleteEmptyAttribs(aEditDoc.GetItemPool()); | |||
719 | } | |||
720 | } | |||
721 | ||||
722 | void ImpEditEngine::TextModified() | |||
723 | { | |||
724 | bFormatted = false; | |||
725 | ||||
726 | if ( GetNotifyHdl().IsSet() ) | |||
727 | { | |||
728 | EENotify aNotify( EE_NOTIFY_TEXTMODIFIED ); | |||
729 | GetNotifyHdl().Call( aNotify ); | |||
730 | } | |||
731 | } | |||
732 | ||||
733 | ||||
734 | void ImpEditEngine::ParaAttribsChanged( ContentNode const * pNode, bool bIgnoreUndoCheck ) | |||
735 | { | |||
736 | assert(pNode && "ParaAttribsChanged: Which one?")(static_cast <bool> (pNode && "ParaAttribsChanged: Which one?" ) ? void (0) : __assert_fail ("pNode && \"ParaAttribsChanged: Which one?\"" , "/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" , 736, __extension__ __PRETTY_FUNCTION__)); | |||
737 | ||||
738 | aEditDoc.SetModified( true ); | |||
739 | bFormatted = false; | |||
740 | ||||
741 | ParaPortion* pPortion = FindParaPortion( pNode ); | |||
742 | OSL_ENSURE( pPortion, "ParaAttribsChanged: Portion?" )do { if (true && (!(pPortion))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "742" ": "), "%s", "ParaAttribsChanged: Portion?"); } } while (false); | |||
743 | pPortion->MarkSelectionInvalid( 0 ); | |||
744 | ||||
745 | sal_Int32 nPara = aEditDoc.GetPos( pNode ); | |||
746 | if ( bIgnoreUndoCheck || pEditEngine->IsInUndo() ) | |||
747 | pEditEngine->ParaAttribsChanged( nPara ); | |||
748 | ||||
749 | ParaPortion* pNextPortion = GetParaPortions().SafeGetObject( nPara+1 ); | |||
750 | // => is formatted again anyway, if Invalid. | |||
751 | if ( pNextPortion && !pNextPortion->IsInvalid() ) | |||
752 | CalcHeight( pNextPortion ); | |||
753 | } | |||
754 | ||||
755 | ||||
756 | // Cursor movements | |||
757 | ||||
758 | ||||
759 | EditSelection const & ImpEditEngine::MoveCursor( const KeyEvent& rKeyEvent, EditView* pEditView ) | |||
760 | { | |||
761 | // Actually, only necessary for up/down, but whatever. | |||
762 | CheckIdleFormatter(); | |||
763 | ||||
764 | EditPaM aPaM( pEditView->pImpEditView->GetEditSelection().Max() ); | |||
765 | ||||
766 | EditPaM aOldPaM( aPaM ); | |||
767 | ||||
768 | TextDirectionality eTextDirection = TextDirectionality::LeftToRight_TopToBottom; | |||
769 | if (IsVertical() && IsTopToBottom()) | |||
770 | eTextDirection = TextDirectionality::TopToBottom_RightToLeft; | |||
771 | else if (IsVertical() && !IsTopToBottom()) | |||
772 | eTextDirection = TextDirectionality::BottomToTop_LeftToRight; | |||
773 | else if ( IsRightToLeft( GetEditDoc().GetPos( aPaM.GetNode() ) ) ) | |||
774 | eTextDirection = TextDirectionality::RightToLeft_TopToBottom; | |||
775 | ||||
776 | KeyEvent aTranslatedKeyEvent = rKeyEvent.LogicalTextDirectionality( eTextDirection ); | |||
777 | ||||
778 | bool bCtrl = aTranslatedKeyEvent.GetKeyCode().IsMod1(); | |||
779 | sal_uInt16 nCode = aTranslatedKeyEvent.GetKeyCode().GetCode(); | |||
780 | ||||
781 | if ( DoVisualCursorTraveling() ) | |||
782 | { | |||
783 | // Only for simple cursor movement... | |||
784 | if ( !bCtrl && ( ( nCode == KEY_LEFT ) || ( nCode == KEY_RIGHT ) ) ) | |||
785 | { | |||
786 | aPaM = CursorVisualLeftRight( pEditView, aPaM, rKeyEvent.GetKeyCode().IsMod2() ? i18n::CharacterIteratorMode::SKIPCHARACTER : i18n::CharacterIteratorMode::SKIPCELL, rKeyEvent.GetKeyCode().GetCode() == KEY_LEFT ); | |||
787 | nCode = 0; // skip switch statement | |||
788 | } | |||
789 | } | |||
790 | ||||
791 | bool bKeyModifySelection = aTranslatedKeyEvent.GetKeyCode().IsShift(); | |||
792 | switch ( nCode ) | |||
793 | { | |||
794 | case KEY_UP: aPaM = CursorUp( aPaM, pEditView ); | |||
795 | break; | |||
796 | case KEY_DOWN: aPaM = CursorDown( aPaM, pEditView ); | |||
797 | break; | |||
798 | case KEY_LEFT: aPaM = bCtrl ? WordLeft( aPaM ) : CursorLeft( aPaM, aTranslatedKeyEvent.GetKeyCode().IsMod2() ? i18n::CharacterIteratorMode::SKIPCHARACTER : i18n::CharacterIteratorMode::SKIPCELL ); | |||
799 | break; | |||
800 | case KEY_RIGHT: aPaM = bCtrl ? WordRight( aPaM ) : CursorRight( aPaM, aTranslatedKeyEvent.GetKeyCode().IsMod2() ? i18n::CharacterIteratorMode::SKIPCHARACTER : i18n::CharacterIteratorMode::SKIPCELL ); | |||
801 | break; | |||
802 | case KEY_HOME: aPaM = bCtrl ? CursorStartOfDoc() : CursorStartOfLine( aPaM ); | |||
803 | break; | |||
804 | case KEY_END: aPaM = bCtrl ? CursorEndOfDoc() : CursorEndOfLine( aPaM ); | |||
805 | break; | |||
806 | case KEY_PAGEUP: aPaM = bCtrl ? CursorStartOfDoc() : PageUp( aPaM, pEditView ); | |||
807 | break; | |||
808 | case KEY_PAGEDOWN: aPaM = bCtrl ? CursorEndOfDoc() : PageDown( aPaM, pEditView ); | |||
809 | break; | |||
810 | case css::awt::Key::MOVE_TO_BEGIN_OF_LINE: | |||
811 | aPaM = CursorStartOfLine( aPaM ); | |||
812 | bKeyModifySelection = false; | |||
813 | break; | |||
814 | case css::awt::Key::MOVE_TO_END_OF_LINE: | |||
815 | aPaM = CursorEndOfLine( aPaM ); | |||
816 | bKeyModifySelection = false; | |||
817 | break; | |||
818 | case css::awt::Key::MOVE_WORD_BACKWARD: | |||
819 | aPaM = WordLeft( aPaM ); | |||
820 | bKeyModifySelection = false; | |||
821 | break; | |||
822 | case css::awt::Key::MOVE_WORD_FORWARD: | |||
823 | aPaM = WordRight( aPaM ); | |||
824 | bKeyModifySelection = false; | |||
825 | break; | |||
826 | case css::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH: | |||
827 | aPaM = CursorStartOfParagraph( aPaM ); | |||
828 | if( aPaM == aOldPaM ) | |||
829 | { | |||
830 | aPaM = CursorLeft( aPaM ); | |||
831 | aPaM = CursorStartOfParagraph( aPaM ); | |||
832 | } | |||
833 | bKeyModifySelection = false; | |||
834 | break; | |||
835 | case css::awt::Key::MOVE_TO_END_OF_PARAGRAPH: | |||
836 | aPaM = CursorEndOfParagraph( aPaM ); | |||
837 | if( aPaM == aOldPaM ) | |||
838 | { | |||
839 | aPaM = CursorRight( aPaM ); | |||
840 | aPaM = CursorEndOfParagraph( aPaM ); | |||
841 | } | |||
842 | bKeyModifySelection = false; | |||
843 | break; | |||
844 | case css::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT: | |||
845 | aPaM = CursorStartOfDoc(); | |||
846 | bKeyModifySelection = false; | |||
847 | break; | |||
848 | case css::awt::Key::MOVE_TO_END_OF_DOCUMENT: | |||
849 | aPaM = CursorEndOfDoc(); | |||
850 | bKeyModifySelection = false; | |||
851 | break; | |||
852 | case css::awt::Key::SELECT_TO_BEGIN_OF_LINE: | |||
853 | aPaM = CursorStartOfLine( aPaM ); | |||
854 | bKeyModifySelection = true; | |||
855 | break; | |||
856 | case css::awt::Key::SELECT_TO_END_OF_LINE: | |||
857 | aPaM = CursorEndOfLine( aPaM ); | |||
858 | bKeyModifySelection = true; | |||
859 | break; | |||
860 | case css::awt::Key::SELECT_BACKWARD: | |||
861 | aPaM = CursorLeft( aPaM ); | |||
862 | bKeyModifySelection = true; | |||
863 | break; | |||
864 | case css::awt::Key::SELECT_FORWARD: | |||
865 | aPaM = CursorRight( aPaM ); | |||
866 | bKeyModifySelection = true; | |||
867 | break; | |||
868 | case css::awt::Key::SELECT_WORD_BACKWARD: | |||
869 | aPaM = WordLeft( aPaM ); | |||
870 | bKeyModifySelection = true; | |||
871 | break; | |||
872 | case css::awt::Key::SELECT_WORD_FORWARD: | |||
873 | aPaM = WordRight( aPaM ); | |||
874 | bKeyModifySelection = true; | |||
875 | break; | |||
876 | case css::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH: | |||
877 | aPaM = CursorStartOfParagraph( aPaM ); | |||
878 | if( aPaM == aOldPaM ) | |||
879 | { | |||
880 | aPaM = CursorLeft( aPaM ); | |||
881 | aPaM = CursorStartOfParagraph( aPaM ); | |||
882 | } | |||
883 | bKeyModifySelection = true; | |||
884 | break; | |||
885 | case css::awt::Key::SELECT_TO_END_OF_PARAGRAPH: | |||
886 | aPaM = CursorEndOfParagraph( aPaM ); | |||
887 | if( aPaM == aOldPaM ) | |||
888 | { | |||
889 | aPaM = CursorRight( aPaM ); | |||
890 | aPaM = CursorEndOfParagraph( aPaM ); | |||
891 | } | |||
892 | bKeyModifySelection = true; | |||
893 | break; | |||
894 | case css::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT: | |||
895 | aPaM = CursorStartOfDoc(); | |||
896 | bKeyModifySelection = true; | |||
897 | break; | |||
898 | case css::awt::Key::SELECT_TO_END_OF_DOCUMENT: | |||
899 | aPaM = CursorEndOfDoc(); | |||
900 | bKeyModifySelection = true; | |||
901 | break; | |||
902 | } | |||
903 | ||||
904 | if ( aOldPaM != aPaM ) | |||
905 | { | |||
906 | CursorMoved( aOldPaM.GetNode() ); | |||
907 | } | |||
908 | ||||
909 | // May cause, a CreateAnchor or deselection all | |||
910 | aSelEngine.SetCurView( pEditView ); | |||
911 | aSelEngine.CursorPosChanging( bKeyModifySelection, aTranslatedKeyEvent.GetKeyCode().IsMod1() ); | |||
912 | EditPaM aOldEnd( pEditView->pImpEditView->GetEditSelection().Max() ); | |||
913 | ||||
914 | { | |||
915 | EditSelection aNewSelection(pEditView->pImpEditView->GetEditSelection()); | |||
916 | aNewSelection.Max() = aPaM; | |||
917 | pEditView->pImpEditView->SetEditSelection(aNewSelection); | |||
918 | // const_cast<EditPaM&>(pEditView->pImpEditView->GetEditSelection().Max()) = aPaM; | |||
919 | } | |||
920 | ||||
921 | if ( bKeyModifySelection ) | |||
922 | { | |||
923 | // Then the selection is expanded ... or the whole selection is painted in case of tiled rendering. | |||
924 | EditSelection aTmpNewSel( comphelper::LibreOfficeKit::isActive() ? pEditView->pImpEditView->GetEditSelection().Min() : aOldEnd, aPaM ); | |||
925 | pEditView->pImpEditView->DrawSelectionXOR( aTmpNewSel ); | |||
926 | } | |||
927 | else | |||
928 | { | |||
929 | EditSelection aNewSelection(pEditView->pImpEditView->GetEditSelection()); | |||
930 | aNewSelection.Min() = aPaM; | |||
931 | pEditView->pImpEditView->SetEditSelection(aNewSelection); | |||
932 | // const_cast<EditPaM&>(pEditView->pImpEditView->GetEditSelection().Min()) = aPaM; | |||
933 | } | |||
934 | ||||
935 | return pEditView->pImpEditView->GetEditSelection(); | |||
936 | } | |||
937 | ||||
938 | EditPaM ImpEditEngine::CursorVisualStartEnd( EditView const * pEditView, const EditPaM& rPaM, bool bStart ) | |||
939 | { | |||
940 | EditPaM aPaM( rPaM ); | |||
941 | ||||
942 | sal_Int32 nPara = GetEditDoc().GetPos( aPaM.GetNode() ); | |||
943 | ParaPortion* pParaPortion = GetParaPortions().SafeGetObject( nPara ); | |||
944 | if (!pParaPortion) | |||
945 | return aPaM; | |||
946 | ||||
947 | sal_Int32 nLine = pParaPortion->GetLines().FindLine( aPaM.GetIndex(), false ); | |||
948 | const EditLine& rLine = pParaPortion->GetLines()[nLine]; | |||
949 | bool bEmptyLine = rLine.GetStart() == rLine.GetEnd(); | |||
950 | ||||
951 | pEditView->pImpEditView->nExtraCursorFlags = GetCursorFlags::NONE; | |||
952 | ||||
953 | if ( !bEmptyLine ) | |||
954 | { | |||
955 | OUString aLine = aPaM.GetNode()->GetString().copy(rLine.GetStart(), rLine.GetEnd() - rLine.GetStart()); | |||
956 | ||||
957 | UErrorCode nError = U_ZERO_ERROR; | |||
958 | UBiDi* pBidi = ubidi_openSizedubidi_openSized_67( aLine.getLength(), 0, &nError ); | |||
959 | ||||
960 | const UBiDiLevel nBidiLevel = IsRightToLeft( nPara ) ? 1 /*RTL*/ : 0 /*LTR*/; | |||
961 | ubidi_setParaubidi_setPara_67( pBidi, reinterpret_cast<const UChar *>(aLine.getStr()), aLine.getLength(), nBidiLevel, nullptr, &nError ); | |||
962 | ||||
963 | sal_Int32 nVisPos = bStart ? 0 : aLine.getLength()-1; | |||
964 | const sal_Int32 nLogPos = ubidi_getLogicalIndexubidi_getLogicalIndex_67( pBidi, nVisPos, &nError ); | |||
965 | ||||
966 | ubidi_closeubidi_close_67( pBidi ); | |||
967 | ||||
968 | aPaM.SetIndex( nLogPos + rLine.GetStart() ); | |||
969 | ||||
970 | sal_Int32 nTmp; | |||
971 | sal_Int32 nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), nTmp, true ); | |||
972 | const TextPortion& rTextPortion = pParaPortion->GetTextPortions()[nTextPortion]; | |||
973 | bool bPortionRTL = rTextPortion.IsRightToLeft(); | |||
974 | ||||
975 | if ( bStart ) | |||
976 | { | |||
977 | pEditView->pImpEditView->SetCursorBidiLevel( bPortionRTL ? 0 : 1 ); | |||
978 | // Maybe we must be *behind* the character | |||
979 | if ( bPortionRTL && pEditView->IsInsertMode() ) | |||
980 | aPaM.SetIndex( aPaM.GetIndex()+1 ); | |||
981 | } | |||
982 | else | |||
983 | { | |||
984 | pEditView->pImpEditView->SetCursorBidiLevel( bPortionRTL ? 1 : 0 ); | |||
985 | if ( !bPortionRTL && pEditView->IsInsertMode() ) | |||
986 | aPaM.SetIndex( aPaM.GetIndex()+1 ); | |||
987 | } | |||
988 | } | |||
989 | ||||
990 | return aPaM; | |||
991 | } | |||
992 | ||||
993 | EditPaM ImpEditEngine::CursorVisualLeftRight( EditView const * pEditView, const EditPaM& rPaM, sal_uInt16 nCharacterIteratorMode, bool bVisualToLeft ) | |||
994 | { | |||
995 | EditPaM aPaM( rPaM ); | |||
996 | ||||
997 | sal_Int32 nPara = GetEditDoc().GetPos( aPaM.GetNode() ); | |||
998 | ParaPortion* pParaPortion = GetParaPortions().SafeGetObject( nPara ); | |||
999 | if (!pParaPortion) | |||
1000 | return aPaM; | |||
1001 | ||||
1002 | sal_Int32 nLine = pParaPortion->GetLines().FindLine( aPaM.GetIndex(), false ); | |||
1003 | const EditLine& rLine = pParaPortion->GetLines()[nLine]; | |||
1004 | bool bEmptyLine = rLine.GetStart() == rLine.GetEnd(); | |||
1005 | ||||
1006 | pEditView->pImpEditView->nExtraCursorFlags = GetCursorFlags::NONE; | |||
1007 | ||||
1008 | bool bParaRTL = IsRightToLeft( nPara ); | |||
1009 | ||||
1010 | bool bDone = false; | |||
1011 | ||||
1012 | if ( bEmptyLine ) | |||
1013 | { | |||
1014 | if ( bVisualToLeft ) | |||
1015 | { | |||
1016 | aPaM = CursorUp( aPaM, pEditView ); | |||
1017 | if ( aPaM != rPaM ) | |||
1018 | aPaM = CursorVisualStartEnd( pEditView, aPaM, false ); | |||
1019 | } | |||
1020 | else | |||
1021 | { | |||
1022 | aPaM = CursorDown( aPaM, pEditView ); | |||
1023 | if ( aPaM != rPaM ) | |||
1024 | aPaM = CursorVisualStartEnd( pEditView, aPaM, true ); | |||
1025 | } | |||
1026 | ||||
1027 | bDone = true; | |||
1028 | } | |||
1029 | ||||
1030 | bool bLogicalBackward = bParaRTL ? !bVisualToLeft : bVisualToLeft; | |||
1031 | ||||
1032 | if ( !bDone && pEditView->IsInsertMode() ) | |||
1033 | { | |||
1034 | // Check if we are within a portion and don't have overwrite mode, then it's easy... | |||
1035 | sal_Int32 nPortionStart; | |||
1036 | sal_Int32 nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), nPortionStart ); | |||
1037 | const TextPortion& rTextPortion = pParaPortion->GetTextPortions()[nTextPortion]; | |||
1038 | ||||
1039 | bool bPortionBoundary = ( aPaM.GetIndex() == nPortionStart ) || ( aPaM.GetIndex() == (nPortionStart+rTextPortion.GetLen()) ); | |||
1040 | sal_uInt16 nRTLLevel = rTextPortion.GetRightToLeftLevel(); | |||
1041 | ||||
1042 | // Portion boundary doesn't matter if both have same RTL level | |||
1043 | sal_Int32 nRTLLevelNextPortion = -1; | |||
1044 | if ( bPortionBoundary && aPaM.GetIndex() && ( aPaM.GetIndex() < aPaM.GetNode()->Len() ) ) | |||
1045 | { | |||
1046 | sal_Int32 nTmp; | |||
1047 | sal_Int32 nNextTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex()+1, nTmp, !bLogicalBackward ); | |||
1048 | const TextPortion& rNextTextPortion = pParaPortion->GetTextPortions()[nNextTextPortion]; | |||
1049 | nRTLLevelNextPortion = rNextTextPortion.GetRightToLeftLevel(); | |||
1050 | } | |||
1051 | ||||
1052 | if ( !bPortionBoundary || ( nRTLLevel == nRTLLevelNextPortion ) ) | |||
1053 | { | |||
1054 | if (bVisualToLeft != bool(nRTLLevel % 2)) | |||
1055 | { | |||
1056 | aPaM = CursorLeft( aPaM, nCharacterIteratorMode ); | |||
1057 | pEditView->pImpEditView->SetCursorBidiLevel( 1 ); | |||
1058 | } | |||
1059 | else | |||
1060 | { | |||
1061 | aPaM = CursorRight( aPaM, nCharacterIteratorMode ); | |||
1062 | pEditView->pImpEditView->SetCursorBidiLevel( 0 ); | |||
1063 | } | |||
1064 | bDone = true; | |||
1065 | } | |||
1066 | } | |||
1067 | ||||
1068 | if ( !bDone ) | |||
1069 | { | |||
1070 | bool bGotoStartOfNextLine = false; | |||
1071 | bool bGotoEndOfPrevLine = false; | |||
1072 | ||||
1073 | OUString aLine = aPaM.GetNode()->GetString().copy(rLine.GetStart(), rLine.GetEnd() - rLine.GetStart()); | |||
1074 | const sal_Int32 nPosInLine = aPaM.GetIndex() - rLine.GetStart(); | |||
1075 | ||||
1076 | UErrorCode nError = U_ZERO_ERROR; | |||
1077 | UBiDi* pBidi = ubidi_openSizedubidi_openSized_67( aLine.getLength(), 0, &nError ); | |||
1078 | ||||
1079 | const UBiDiLevel nBidiLevel = IsRightToLeft( nPara ) ? 1 /*RTL*/ : 0 /*LTR*/; | |||
1080 | ubidi_setParaubidi_setPara_67( pBidi, reinterpret_cast<const UChar *>(aLine.getStr()), aLine.getLength(), nBidiLevel, nullptr, &nError ); | |||
1081 | ||||
1082 | if ( !pEditView->IsInsertMode() ) | |||
1083 | { | |||
1084 | bool bEndOfLine = nPosInLine == aLine.getLength(); | |||
1085 | sal_Int32 nVisPos = ubidi_getVisualIndexubidi_getVisualIndex_67( pBidi, !bEndOfLine ? nPosInLine : nPosInLine-1, &nError ); | |||
1086 | if ( bVisualToLeft ) | |||
1087 | { | |||
1088 | bGotoEndOfPrevLine = nVisPos == 0; | |||
1089 | if ( !bEndOfLine ) | |||
1090 | nVisPos--; | |||
1091 | } | |||
1092 | else | |||
1093 | { | |||
1094 | bGotoStartOfNextLine = nVisPos == (aLine.getLength() - 1); | |||
1095 | if ( !bEndOfLine ) | |||
1096 | nVisPos++; | |||
1097 | } | |||
1098 | ||||
1099 | if ( !bGotoEndOfPrevLine && !bGotoStartOfNextLine ) | |||
1100 | { | |||
1101 | aPaM.SetIndex( rLine.GetStart() + ubidi_getLogicalIndexubidi_getLogicalIndex_67( pBidi, nVisPos, &nError ) ); | |||
1102 | pEditView->pImpEditView->SetCursorBidiLevel( 0 ); | |||
1103 | } | |||
1104 | } | |||
1105 | else | |||
1106 | { | |||
1107 | bool bWasBehind = false; | |||
1108 | bool bBeforePortion = !nPosInLine || pEditView->pImpEditView->GetCursorBidiLevel() == 1; | |||
1109 | if ( nPosInLine && ( !bBeforePortion ) ) // before the next portion | |||
1110 | bWasBehind = true; // step one back, otherwise visual will be unusable when rtl portion follows. | |||
1111 | ||||
1112 | sal_Int32 nPortionStart; | |||
1113 | sal_Int32 nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), nPortionStart, bBeforePortion ); | |||
1114 | const TextPortion& rTextPortion = pParaPortion->GetTextPortions()[nTextPortion]; | |||
1115 | bool bRTLPortion = rTextPortion.IsRightToLeft(); | |||
1116 | ||||
1117 | // -1: We are 'behind' the character | |||
1118 | long nVisPos = static_cast<long>(ubidi_getVisualIndexubidi_getVisualIndex_67( pBidi, bWasBehind ? nPosInLine-1 : nPosInLine, &nError )); | |||
1119 | if ( bVisualToLeft ) | |||
1120 | { | |||
1121 | if ( !bWasBehind || bRTLPortion ) | |||
1122 | nVisPos--; | |||
1123 | } | |||
1124 | else | |||
1125 | { | |||
1126 | if ( bWasBehind || bRTLPortion || bBeforePortion ) | |||
1127 | nVisPos++; | |||
1128 | } | |||
1129 | ||||
1130 | bGotoEndOfPrevLine = nVisPos < 0; | |||
1131 | bGotoStartOfNextLine = nVisPos >= aLine.getLength(); | |||
1132 | ||||
1133 | if ( !bGotoEndOfPrevLine && !bGotoStartOfNextLine ) | |||
1134 | { | |||
1135 | aPaM.SetIndex( rLine.GetStart() + ubidi_getLogicalIndexubidi_getLogicalIndex_67( pBidi, nVisPos, &nError ) ); | |||
1136 | ||||
1137 | // RTL portion, stay visually on the left side. | |||
1138 | sal_Int32 _nPortionStart; | |||
1139 | // sal_uInt16 nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), nPortionStart, !bRTLPortion ); | |||
1140 | sal_Int32 _nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), _nPortionStart, true ); | |||
1141 | const TextPortion& _rTextPortion = pParaPortion->GetTextPortions()[_nTextPortion]; | |||
1142 | if ( bVisualToLeft && !bRTLPortion && _rTextPortion.IsRightToLeft() ) | |||
1143 | aPaM.SetIndex( aPaM.GetIndex()+1 ); | |||
1144 | else if ( !bVisualToLeft && bRTLPortion && ( bWasBehind || !_rTextPortion.IsRightToLeft() ) ) | |||
1145 | aPaM.SetIndex( aPaM.GetIndex()+1 ); | |||
1146 | ||||
1147 | pEditView->pImpEditView->SetCursorBidiLevel( _nPortionStart ); | |||
1148 | } | |||
1149 | } | |||
1150 | ||||
1151 | ubidi_closeubidi_close_67( pBidi ); | |||
1152 | ||||
1153 | if ( bGotoEndOfPrevLine ) | |||
1154 | { | |||
1155 | aPaM = CursorUp( aPaM, pEditView ); | |||
1156 | if ( aPaM != rPaM ) | |||
1157 | aPaM = CursorVisualStartEnd( pEditView, aPaM, false ); | |||
1158 | } | |||
1159 | else if ( bGotoStartOfNextLine ) | |||
1160 | { | |||
1161 | aPaM = CursorDown( aPaM, pEditView ); | |||
1162 | if ( aPaM != rPaM ) | |||
1163 | aPaM = CursorVisualStartEnd( pEditView, aPaM, true ); | |||
1164 | } | |||
1165 | } | |||
1166 | return aPaM; | |||
1167 | } | |||
1168 | ||||
1169 | ||||
1170 | EditPaM ImpEditEngine::CursorLeft( const EditPaM& rPaM, sal_uInt16 nCharacterIteratorMode ) | |||
1171 | { | |||
1172 | EditPaM aCurPaM( rPaM ); | |||
1173 | EditPaM aNewPaM( aCurPaM ); | |||
1174 | ||||
1175 | if ( aCurPaM.GetIndex() ) | |||
1176 | { | |||
1177 | sal_Int32 nCount = 1; | |||
1178 | uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() ); | |||
1179 | aNewPaM.SetIndex( | |||
1180 | _xBI->previousCharacters( | |||
1181 | aNewPaM.GetNode()->GetString(), aNewPaM.GetIndex(), GetLocale( aNewPaM ), nCharacterIteratorMode, nCount, nCount)); | |||
1182 | } | |||
1183 | else | |||
1184 | { | |||
1185 | ContentNode* pNode = aCurPaM.GetNode(); | |||
1186 | pNode = GetPrevVisNode( pNode ); | |||
1187 | if ( pNode ) | |||
1188 | { | |||
1189 | aNewPaM.SetNode( pNode ); | |||
1190 | aNewPaM.SetIndex( pNode->Len() ); | |||
1191 | } | |||
1192 | } | |||
1193 | ||||
1194 | return aNewPaM; | |||
1195 | } | |||
1196 | ||||
1197 | EditPaM ImpEditEngine::CursorRight( const EditPaM& rPaM, sal_uInt16 nCharacterIteratorMode ) | |||
1198 | { | |||
1199 | EditPaM aCurPaM( rPaM ); | |||
1200 | EditPaM aNewPaM( aCurPaM ); | |||
1201 | ||||
1202 | if ( aCurPaM.GetIndex() < aCurPaM.GetNode()->Len() ) | |||
1203 | { | |||
1204 | uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() ); | |||
1205 | sal_Int32 nCount = 1; | |||
1206 | aNewPaM.SetIndex( | |||
1207 | _xBI->nextCharacters( | |||
1208 | aNewPaM.GetNode()->GetString(), aNewPaM.GetIndex(), GetLocale( aNewPaM ), nCharacterIteratorMode, nCount, nCount)); | |||
1209 | } | |||
1210 | else | |||
1211 | { | |||
1212 | ContentNode* pNode = aCurPaM.GetNode(); | |||
1213 | pNode = GetNextVisNode( pNode ); | |||
1214 | if ( pNode ) | |||
1215 | { | |||
1216 | aNewPaM.SetNode( pNode ); | |||
1217 | aNewPaM.SetIndex( 0 ); | |||
1218 | } | |||
1219 | } | |||
1220 | ||||
1221 | return aNewPaM; | |||
1222 | } | |||
1223 | ||||
1224 | EditPaM ImpEditEngine::CursorUp( const EditPaM& rPaM, EditView const * pView ) | |||
1225 | { | |||
1226 | assert(pView && "No View - No Cursor Movement!")(static_cast <bool> (pView && "No View - No Cursor Movement!" ) ? void (0) : __assert_fail ("pView && \"No View - No Cursor Movement!\"" , "/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" , 1226, __extension__ __PRETTY_FUNCTION__)); | |||
1227 | ||||
1228 | const ParaPortion* pPPortion = FindParaPortion( rPaM.GetNode() ); | |||
1229 | OSL_ENSURE( pPPortion, "No matching portion found: CursorUp ")do { if (true && (!(pPPortion))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "1229" ": "), "%s", "No matching portion found: CursorUp " ); } } while (false); | |||
1230 | sal_Int32 nLine = pPPortion->GetLineNumber( rPaM.GetIndex() ); | |||
1231 | const EditLine& rLine = pPPortion->GetLines()[nLine]; | |||
1232 | ||||
1233 | long nX; | |||
1234 | if ( pView->pImpEditView->nTravelXPos == TRAVEL_X_DONTKNOW0xFFFFFFFF ) | |||
1235 | { | |||
1236 | nX = GetXPos( pPPortion, &rLine, rPaM.GetIndex() ); | |||
1237 | pView->pImpEditView->nTravelXPos = nX+nOnePixelInRef; | |||
1238 | } | |||
1239 | else | |||
1240 | nX = pView->pImpEditView->nTravelXPos; | |||
1241 | ||||
1242 | EditPaM aNewPaM( rPaM ); | |||
1243 | if ( nLine ) // same paragraph | |||
1244 | { | |||
1245 | const EditLine& rPrevLine = pPPortion->GetLines()[nLine-1]; | |||
1246 | aNewPaM.SetIndex( GetChar( pPPortion, &rPrevLine, nX ) ); | |||
1247 | // If a previous automatically wrapped line, and one has to be exactly | |||
1248 | // at the end of this line, the cursor lands on the current line at the | |||
1249 | // beginning. See Problem: Last character of an automatically wrapped | |||
1250 | // Row = cursor | |||
1251 | if ( aNewPaM.GetIndex() && ( aNewPaM.GetIndex() == rLine.GetStart() ) ) | |||
1252 | aNewPaM = CursorLeft( aNewPaM ); | |||
1253 | } | |||
1254 | else // previous paragraph | |||
1255 | { | |||
1256 | const ParaPortion* pPrevPortion = GetPrevVisPortion( pPPortion ); | |||
1257 | if ( pPrevPortion ) | |||
1258 | { | |||
1259 | const EditLine& rLine2 = pPrevPortion->GetLines()[pPrevPortion->GetLines().Count()-1]; | |||
1260 | aNewPaM.SetNode( pPrevPortion->GetNode() ); | |||
1261 | aNewPaM.SetIndex( GetChar( pPrevPortion, &rLine2, nX+nOnePixelInRef ) ); | |||
1262 | } | |||
1263 | } | |||
1264 | ||||
1265 | return aNewPaM; | |||
1266 | } | |||
1267 | ||||
1268 | EditPaM ImpEditEngine::CursorDown( const EditPaM& rPaM, EditView const * pView ) | |||
1269 | { | |||
1270 | OSL_ENSURE( pView, "No View - No Cursor Movement!" )do { if (true && (!(pView))) { sal_detail_logFormat(( SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "1270" ": "), "%s", "No View - No Cursor Movement!"); } } while (false); | |||
1271 | ||||
1272 | const ParaPortion* pPPortion = FindParaPortion( rPaM.GetNode() ); | |||
1273 | OSL_ENSURE( pPPortion, "No matching portion found: CursorDown" )do { if (true && (!(pPPortion))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "1273" ": "), "%s", "No matching portion found: CursorDown" ); } } while (false); | |||
1274 | sal_Int32 nLine = pPPortion->GetLineNumber( rPaM.GetIndex() ); | |||
1275 | ||||
1276 | long nX; | |||
1277 | if ( pView->pImpEditView->nTravelXPos == TRAVEL_X_DONTKNOW0xFFFFFFFF ) | |||
1278 | { | |||
1279 | const EditLine& rLine = pPPortion->GetLines()[nLine]; | |||
1280 | nX = GetXPos( pPPortion, &rLine, rPaM.GetIndex() ); | |||
1281 | pView->pImpEditView->nTravelXPos = nX+nOnePixelInRef; | |||
1282 | } | |||
1283 | else | |||
1284 | nX = pView->pImpEditView->nTravelXPos; | |||
1285 | ||||
1286 | EditPaM aNewPaM( rPaM ); | |||
1287 | if ( nLine < pPPortion->GetLines().Count()-1 ) | |||
1288 | { | |||
1289 | const EditLine& rNextLine = pPPortion->GetLines()[nLine+1]; | |||
1290 | aNewPaM.SetIndex( GetChar( pPPortion, &rNextLine, nX ) ); | |||
1291 | // Special treatment, see CursorUp ... | |||
1292 | if ( ( aNewPaM.GetIndex() == rNextLine.GetEnd() ) && ( aNewPaM.GetIndex() > rNextLine.GetStart() ) && ( aNewPaM.GetIndex() < pPPortion->GetNode()->Len() ) ) | |||
1293 | aNewPaM = CursorLeft( aNewPaM ); | |||
1294 | } | |||
1295 | else // next paragraph | |||
1296 | { | |||
1297 | const ParaPortion* pNextPortion = GetNextVisPortion( pPPortion ); | |||
1298 | if ( pNextPortion ) | |||
1299 | { | |||
1300 | const EditLine& rLine = pNextPortion->GetLines()[0]; | |||
1301 | aNewPaM.SetNode( pNextPortion->GetNode() ); | |||
1302 | // Never at the very end when several lines, because then a line | |||
1303 | // below the cursor appears. | |||
1304 | aNewPaM.SetIndex( GetChar( pNextPortion, &rLine, nX+nOnePixelInRef ) ); | |||
1305 | if ( ( aNewPaM.GetIndex() == rLine.GetEnd() ) && ( aNewPaM.GetIndex() > rLine.GetStart() ) && ( pNextPortion->GetLines().Count() > 1 ) ) | |||
1306 | aNewPaM = CursorLeft( aNewPaM ); | |||
1307 | } | |||
1308 | } | |||
1309 | ||||
1310 | return aNewPaM; | |||
1311 | } | |||
1312 | ||||
1313 | EditPaM ImpEditEngine::CursorStartOfLine( const EditPaM& rPaM ) | |||
1314 | { | |||
1315 | const ParaPortion* pCurPortion = FindParaPortion( rPaM.GetNode() ); | |||
1316 | OSL_ENSURE( pCurPortion, "No Portion for the PaM ?" )do { if (true && (!(pCurPortion))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "1316" ": "), "%s", "No Portion for the PaM ?"); } } while (false); | |||
1317 | sal_Int32 nLine = pCurPortion->GetLineNumber( rPaM.GetIndex() ); | |||
1318 | const EditLine& rLine = pCurPortion->GetLines()[nLine]; | |||
1319 | ||||
1320 | EditPaM aNewPaM( rPaM ); | |||
1321 | aNewPaM.SetIndex( rLine.GetStart() ); | |||
1322 | return aNewPaM; | |||
1323 | } | |||
1324 | ||||
1325 | EditPaM ImpEditEngine::CursorEndOfLine( const EditPaM& rPaM ) | |||
1326 | { | |||
1327 | const ParaPortion* pCurPortion = FindParaPortion( rPaM.GetNode() ); | |||
1328 | OSL_ENSURE( pCurPortion, "No Portion for the PaM ?" )do { if (true && (!(pCurPortion))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "1328" ": "), "%s", "No Portion for the PaM ?"); } } while (false); | |||
1329 | sal_Int32 nLine = pCurPortion->GetLineNumber( rPaM.GetIndex() ); | |||
1330 | const EditLine& rLine = pCurPortion->GetLines()[nLine]; | |||
1331 | ||||
1332 | EditPaM aNewPaM( rPaM ); | |||
1333 | aNewPaM.SetIndex( rLine.GetEnd() ); | |||
1334 | if ( rLine.GetEnd() > rLine.GetStart() ) | |||
1335 | { | |||
1336 | if ( aNewPaM.GetNode()->IsFeature( aNewPaM.GetIndex() - 1 ) ) | |||
1337 | { | |||
1338 | // When a soft break, be in front of it! | |||
1339 | const EditCharAttrib* pNextFeature = aNewPaM.GetNode()->GetCharAttribs().FindFeature( aNewPaM.GetIndex()-1 ); | |||
1340 | if ( pNextFeature && ( pNextFeature->GetItem()->Which() == EE_FEATURE_LINEBR ) ) | |||
1341 | aNewPaM = CursorLeft( aNewPaM ); | |||
1342 | } | |||
1343 | else if ( ( aNewPaM.GetNode()->GetChar( aNewPaM.GetIndex() - 1 ) == ' ' ) && ( aNewPaM.GetIndex() != aNewPaM.GetNode()->Len() ) ) | |||
1344 | { | |||
1345 | // For a Blank in an auto wrapped line, it makes sense, to stand | |||
1346 | // in front of it, since the user wants to be after the word. | |||
1347 | // If this is changed, special treatment for Pos1 to End! | |||
1348 | aNewPaM = CursorLeft( aNewPaM ); | |||
1349 | } | |||
1350 | } | |||
1351 | return aNewPaM; | |||
1352 | } | |||
1353 | ||||
1354 | EditPaM ImpEditEngine::CursorStartOfParagraph( const EditPaM& rPaM ) | |||
1355 | { | |||
1356 | EditPaM aPaM(rPaM); | |||
1357 | aPaM.SetIndex(0); | |||
1358 | return aPaM; | |||
1359 | } | |||
1360 | ||||
1361 | EditPaM ImpEditEngine::CursorEndOfParagraph( const EditPaM& rPaM ) | |||
1362 | { | |||
1363 | EditPaM aPaM(rPaM); | |||
1364 | aPaM.SetIndex(rPaM.GetNode()->Len()); | |||
1365 | return aPaM; | |||
1366 | } | |||
1367 | ||||
1368 | EditPaM ImpEditEngine::CursorStartOfDoc() | |||
1369 | { | |||
1370 | EditPaM aPaM( aEditDoc.GetObject( 0 ), 0 ); | |||
1371 | return aPaM; | |||
1372 | } | |||
1373 | ||||
1374 | EditPaM ImpEditEngine::CursorEndOfDoc() | |||
1375 | { | |||
1376 | ContentNode* pLastNode = aEditDoc.GetObject( aEditDoc.Count()-1 ); | |||
1377 | ParaPortion* pLastPortion = GetParaPortions().SafeGetObject( aEditDoc.Count()-1 ); | |||
1378 | OSL_ENSURE( pLastNode && pLastPortion, "CursorEndOfDoc: Node or Portion not found" )do { if (true && (!(pLastNode && pLastPortion ))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "1378" ": "), "%s", "CursorEndOfDoc: Node or Portion not found" ); } } while (false); | |||
1379 | if (!(pLastNode && pLastPortion)) | |||
1380 | return EditPaM(); | |||
1381 | ||||
1382 | if ( !pLastPortion->IsVisible() ) | |||
1383 | { | |||
1384 | pLastNode = GetPrevVisNode( pLastPortion->GetNode() ); | |||
1385 | OSL_ENSURE( pLastNode, "No visible paragraph?" )do { if (true && (!(pLastNode))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "1385" ": "), "%s", "No visible paragraph?"); } } while ( false); | |||
1386 | if ( !pLastNode ) | |||
1387 | pLastNode = aEditDoc.GetObject( aEditDoc.Count()-1 ); | |||
1388 | } | |||
1389 | ||||
1390 | EditPaM aPaM( pLastNode, pLastNode->Len() ); | |||
1391 | return aPaM; | |||
1392 | } | |||
1393 | ||||
1394 | EditPaM ImpEditEngine::PageUp( const EditPaM& rPaM, EditView const * pView ) | |||
1395 | { | |||
1396 | tools::Rectangle aRect = PaMtoEditCursor( rPaM ); | |||
1397 | Point aTopLeft = aRect.TopLeft(); | |||
1398 | aTopLeft.AdjustY( -(pView->GetVisArea().GetHeight() *9/10) ); | |||
1399 | aTopLeft.AdjustX(nOnePixelInRef ); | |||
1400 | if ( aTopLeft.Y() < 0 ) | |||
1401 | { | |||
1402 | aTopLeft.setY( 0 ); | |||
1403 | } | |||
1404 | return GetPaM( aTopLeft ); | |||
1405 | } | |||
1406 | ||||
1407 | EditPaM ImpEditEngine::PageDown( const EditPaM& rPaM, EditView const * pView ) | |||
1408 | { | |||
1409 | tools::Rectangle aRect = PaMtoEditCursor( rPaM ); | |||
1410 | Point aBottomRight = aRect.BottomRight(); | |||
1411 | aBottomRight.AdjustY(pView->GetVisArea().GetHeight() *9/10 ); | |||
1412 | aBottomRight.AdjustX(nOnePixelInRef ); | |||
1413 | long nHeight = GetTextHeight(); | |||
1414 | if ( aBottomRight.Y() > nHeight ) | |||
1415 | { | |||
1416 | aBottomRight.setY( nHeight-2 ); | |||
1417 | } | |||
1418 | return GetPaM( aBottomRight ); | |||
1419 | } | |||
1420 | ||||
1421 | EditPaM ImpEditEngine::WordLeft( const EditPaM& rPaM ) | |||
1422 | { | |||
1423 | const sal_Int32 nCurrentPos = rPaM.GetIndex(); | |||
1424 | EditPaM aNewPaM( rPaM ); | |||
1425 | if ( nCurrentPos == 0 ) | |||
1426 | { | |||
1427 | // Previous paragraph... | |||
1428 | sal_Int32 nCurPara = aEditDoc.GetPos( aNewPaM.GetNode() ); | |||
1429 | ContentNode* pPrevNode = aEditDoc.GetObject( --nCurPara ); | |||
1430 | if ( pPrevNode ) | |||
1431 | { | |||
1432 | aNewPaM.SetNode( pPrevNode ); | |||
1433 | aNewPaM.SetIndex( pPrevNode->Len() ); | |||
1434 | } | |||
1435 | } | |||
1436 | else | |||
1437 | { | |||
1438 | // we need to increase the position by 1 when retrieving the locale | |||
1439 | // since the attribute for the char left to the cursor position is returned | |||
1440 | EditPaM aTmpPaM( aNewPaM ); | |||
1441 | if ( aTmpPaM.GetIndex() < rPaM.GetNode()->Len() ) | |||
1442 | aTmpPaM.SetIndex( aTmpPaM.GetIndex() + 1 ); | |||
1443 | lang::Locale aLocale( GetLocale( aTmpPaM ) ); | |||
1444 | ||||
1445 | uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() ); | |||
1446 | i18n::Boundary aBoundary = | |||
1447 | _xBI->getWordBoundary(aNewPaM.GetNode()->GetString(), nCurrentPos, aLocale, css::i18n::WordType::ANYWORD_IGNOREWHITESPACES, true); | |||
1448 | if ( aBoundary.startPos >= nCurrentPos ) | |||
1449 | aBoundary = _xBI->previousWord( | |||
1450 | aNewPaM.GetNode()->GetString(), nCurrentPos, aLocale, css::i18n::WordType::ANYWORD_IGNOREWHITESPACES); | |||
1451 | aNewPaM.SetIndex( ( aBoundary.startPos != -1 ) ? aBoundary.startPos : 0 ); | |||
1452 | } | |||
1453 | ||||
1454 | return aNewPaM; | |||
1455 | } | |||
1456 | ||||
1457 | EditPaM ImpEditEngine::WordRight( const EditPaM& rPaM, sal_Int16 nWordType ) | |||
1458 | { | |||
1459 | const sal_Int32 nMax = rPaM.GetNode()->Len(); | |||
1460 | EditPaM aNewPaM( rPaM ); | |||
1461 | if ( aNewPaM.GetIndex() < nMax ) | |||
1462 | { | |||
1463 | // we need to increase the position by 1 when retrieving the locale | |||
1464 | // since the attribute for the char left to the cursor position is returned | |||
1465 | EditPaM aTmpPaM( aNewPaM ); | |||
1466 | aTmpPaM.SetIndex( aTmpPaM.GetIndex() + 1 ); | |||
1467 | lang::Locale aLocale( GetLocale( aTmpPaM ) ); | |||
1468 | ||||
1469 | uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() ); | |||
1470 | i18n::Boundary aBoundary = _xBI->nextWord( | |||
1471 | aNewPaM.GetNode()->GetString(), aNewPaM.GetIndex(), aLocale, nWordType); | |||
1472 | aNewPaM.SetIndex( aBoundary.startPos ); | |||
1473 | } | |||
1474 | // not 'else', maybe the index reached nMax now... | |||
1475 | if ( aNewPaM.GetIndex() >= nMax ) | |||
1476 | { | |||
1477 | // Next paragraph ... | |||
1478 | sal_Int32 nCurPara = aEditDoc.GetPos( aNewPaM.GetNode() ); | |||
1479 | ContentNode* pNextNode = aEditDoc.GetObject( ++nCurPara ); | |||
1480 | if ( pNextNode ) | |||
1481 | { | |||
1482 | aNewPaM.SetNode( pNextNode ); | |||
1483 | aNewPaM.SetIndex( 0 ); | |||
1484 | } | |||
1485 | } | |||
1486 | return aNewPaM; | |||
1487 | } | |||
1488 | ||||
1489 | EditPaM ImpEditEngine::StartOfWord( const EditPaM& rPaM ) | |||
1490 | { | |||
1491 | EditPaM aNewPaM( rPaM ); | |||
1492 | ||||
1493 | // we need to increase the position by 1 when retrieving the locale | |||
1494 | // since the attribute for the char left to the cursor position is returned | |||
1495 | EditPaM aTmpPaM( aNewPaM ); | |||
1496 | if ( aTmpPaM.GetIndex() < rPaM.GetNode()->Len() ) | |||
1497 | aTmpPaM.SetIndex( aTmpPaM.GetIndex() + 1 ); | |||
1498 | lang::Locale aLocale( GetLocale( aTmpPaM ) ); | |||
1499 | ||||
1500 | uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() ); | |||
1501 | i18n::Boundary aBoundary = _xBI->getWordBoundary( | |||
1502 | rPaM.GetNode()->GetString(), rPaM.GetIndex(), aLocale, css::i18n::WordType::ANYWORD_IGNOREWHITESPACES, true); | |||
1503 | ||||
1504 | aNewPaM.SetIndex( aBoundary.startPos ); | |||
1505 | return aNewPaM; | |||
1506 | } | |||
1507 | ||||
1508 | EditPaM ImpEditEngine::EndOfWord( const EditPaM& rPaM ) | |||
1509 | { | |||
1510 | EditPaM aNewPaM( rPaM ); | |||
1511 | ||||
1512 | // we need to increase the position by 1 when retrieving the locale | |||
1513 | // since the attribute for the char left to the cursor position is returned | |||
1514 | EditPaM aTmpPaM( aNewPaM ); | |||
1515 | if ( aTmpPaM.GetIndex() < rPaM.GetNode()->Len() ) | |||
1516 | aTmpPaM.SetIndex( aTmpPaM.GetIndex() + 1 ); | |||
1517 | lang::Locale aLocale( GetLocale( aTmpPaM ) ); | |||
1518 | ||||
1519 | uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() ); | |||
1520 | i18n::Boundary aBoundary = _xBI->getWordBoundary( | |||
1521 | rPaM.GetNode()->GetString(), rPaM.GetIndex(), aLocale, css::i18n::WordType::ANYWORD_IGNOREWHITESPACES, true); | |||
1522 | ||||
1523 | aNewPaM.SetIndex( aBoundary.endPos ); | |||
1524 | return aNewPaM; | |||
1525 | } | |||
1526 | ||||
1527 | EditSelection ImpEditEngine::SelectWord( const EditSelection& rCurSel, sal_Int16 nWordType, bool bAcceptStartOfWord ) | |||
1528 | { | |||
1529 | EditSelection aNewSel( rCurSel ); | |||
1530 | EditPaM aPaM( rCurSel.Max() ); | |||
1531 | ||||
1532 | // we need to increase the position by 1 when retrieving the locale | |||
1533 | // since the attribute for the char left to the cursor position is returned | |||
1534 | EditPaM aTmpPaM( aPaM ); | |||
1535 | if ( aTmpPaM.GetIndex() < aPaM.GetNode()->Len() ) | |||
1536 | aTmpPaM.SetIndex( aTmpPaM.GetIndex() + 1 ); | |||
1537 | lang::Locale aLocale( GetLocale( aTmpPaM ) ); | |||
1538 | ||||
1539 | uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() ); | |||
1540 | sal_Int16 nType = _xBI->getWordType( | |||
1541 | aPaM.GetNode()->GetString(), aPaM.GetIndex(), aLocale); | |||
1542 | ||||
1543 | if ( nType == i18n::WordType::ANY_WORD ) | |||
1544 | { | |||
1545 | i18n::Boundary aBoundary = _xBI->getWordBoundary( | |||
1546 | aPaM.GetNode()->GetString(), aPaM.GetIndex(), aLocale, nWordType, true); | |||
1547 | ||||
1548 | // don't select when cursor at end of word | |||
1549 | if ( ( aBoundary.endPos > aPaM.GetIndex() ) && | |||
1550 | ( ( aBoundary.startPos < aPaM.GetIndex() ) || ( bAcceptStartOfWord && ( aBoundary.startPos == aPaM.GetIndex() ) ) ) ) | |||
1551 | { | |||
1552 | aNewSel.Min().SetIndex( aBoundary.startPos ); | |||
1553 | aNewSel.Max().SetIndex( aBoundary.endPos ); | |||
1554 | } | |||
1555 | } | |||
1556 | ||||
1557 | return aNewSel; | |||
1558 | } | |||
1559 | ||||
1560 | EditSelection ImpEditEngine::SelectSentence( const EditSelection& rCurSel ) | |||
1561 | const | |||
1562 | { | |||
1563 | uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() ); | |||
1564 | const EditPaM& rPaM = rCurSel.Min(); | |||
1565 | const ContentNode* pNode = rPaM.GetNode(); | |||
1566 | // #i50710# line breaks are marked with 0x01 - the break iterator prefers 0x0a for that | |||
1567 | const OUString sParagraph = pNode->GetString().replaceAll("\x01", "\x0a"); | |||
1568 | //return Null if search starts at the beginning of the string | |||
1569 | sal_Int32 nStart = rPaM.GetIndex() ? _xBI->beginOfSentence( sParagraph, rPaM.GetIndex(), GetLocale( rPaM ) ) : 0; | |||
1570 | ||||
1571 | sal_Int32 nEnd = _xBI->endOfSentence( | |||
1572 | pNode->GetString(), rPaM.GetIndex(), GetLocale(rPaM)); | |||
1573 | ||||
1574 | EditSelection aNewSel( rCurSel ); | |||
1575 | OSL_ENSURE(pNode->Len() ? (nStart < pNode->Len()) : (nStart == 0), "sentence start index out of range")do { if (true && (!(pNode->Len() ? (nStart < pNode ->Len()) : (nStart == 0)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "1575" ": "), "%s", "sentence start index out of range") ; } } while (false); | |||
1576 | OSL_ENSURE(nEnd <= pNode->Len(), "sentence end index out of range")do { if (true && (!(nEnd <= pNode->Len()))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "1576" ": "), "%s", "sentence end index out of range"); } } while (false); | |||
1577 | aNewSel.Min().SetIndex( nStart ); | |||
1578 | aNewSel.Max().SetIndex( nEnd ); | |||
1579 | return aNewSel; | |||
1580 | } | |||
1581 | ||||
1582 | bool ImpEditEngine::IsInputSequenceCheckingRequired( sal_Unicode nChar, const EditSelection& rCurSel ) const | |||
1583 | { | |||
1584 | uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() ); | |||
1585 | if (!pCTLOptions) | |||
1586 | pCTLOptions.reset( new SvtCTLOptions ); | |||
1587 | ||||
1588 | // get the index that really is first | |||
1589 | const sal_Int32 nFirstPos = std::min(rCurSel.Min().GetIndex(), rCurSel.Max().GetIndex()); | |||
1590 | ||||
1591 | bool bIsSequenceChecking = | |||
1592 | pCTLOptions->IsCTLFontEnabled() && | |||
1593 | pCTLOptions->IsCTLSequenceChecking() && | |||
1594 | nFirstPos != 0 && /* first char needs not to be checked */ | |||
1595 | _xBI.is() && i18n::ScriptType::COMPLEX == _xBI->getScriptType( OUString( nChar ), 0 ); | |||
1596 | ||||
1597 | return bIsSequenceChecking; | |||
1598 | } | |||
1599 | ||||
1600 | static bool lcl_HasStrongLTR ( const OUString& rTxt, sal_Int32 nStart, sal_Int32 nEnd ) | |||
1601 | { | |||
1602 | for( sal_Int32 nCharIdx = nStart; nCharIdx < nEnd; ++nCharIdx ) | |||
1603 | { | |||
1604 | const UCharDirection nCharDir = u_charDirectionu_charDirection_67 ( rTxt[ nCharIdx ] ); | |||
1605 | if ( nCharDir == U_LEFT_TO_RIGHT || | |||
1606 | nCharDir == U_LEFT_TO_RIGHT_EMBEDDING || | |||
1607 | nCharDir == U_LEFT_TO_RIGHT_OVERRIDE ) | |||
1608 | return true; | |||
1609 | } | |||
1610 | return false; | |||
1611 | } | |||
1612 | ||||
1613 | ||||
1614 | void ImpEditEngine::InitScriptTypes( sal_Int32 nPara ) | |||
1615 | { | |||
1616 | ParaPortion* pParaPortion = GetParaPortions().SafeGetObject( nPara ); | |||
1617 | if (!pParaPortion) | |||
1618 | return; | |||
1619 | ||||
1620 | ScriptTypePosInfos& rTypes = pParaPortion->aScriptInfos; | |||
1621 | rTypes.clear(); | |||
1622 | ||||
1623 | ContentNode* pNode = pParaPortion->GetNode(); | |||
1624 | if ( !pNode->Len() ) | |||
1625 | return; | |||
1626 | ||||
1627 | uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() ); | |||
1628 | ||||
1629 | OUString aText = pNode->GetString(); | |||
1630 | ||||
1631 | // To handle fields put the character from the field in the string, | |||
1632 | // because endOfScript( ... ) will skip the CH_FEATURE, because this is WEAK | |||
1633 | const EditCharAttrib* pField = pNode->GetCharAttribs().FindNextAttrib( EE_FEATURE_FIELD, 0 ); | |||
1634 | while ( pField ) | |||
1635 | { | |||
1636 | const OUString aFldText = static_cast<const EditCharAttribField*>(pField)->GetFieldValue(); | |||
1637 | if ( !aFldText.isEmpty() ) | |||
1638 | { | |||
1639 | aText = aText.replaceAt( pField->GetStart(), 1, aFldText.copy(0,1) ); | |||
1640 | short nFldScriptType = _xBI->getScriptType( aFldText, 0 ); | |||
1641 | ||||
1642 | for ( sal_Int32 nCharInField = 1; nCharInField < aFldText.getLength(); nCharInField++ ) | |||
1643 | { | |||
1644 | short nTmpType = _xBI->getScriptType( aFldText, nCharInField ); | |||
1645 | ||||
1646 | // First char from field wins... | |||
1647 | if ( nFldScriptType == i18n::ScriptType::WEAK ) | |||
1648 | { | |||
1649 | nFldScriptType = nTmpType; | |||
1650 | aText = aText.replaceAt( pField->GetStart(), 1, aFldText.copy(nCharInField,1) ); | |||
1651 | } | |||
1652 | ||||
1653 | // ... but if the first one is LATIN, and there are CJK or CTL chars too, | |||
1654 | // we prefer that ScriptType because we need another font. | |||
1655 | if ( ( nTmpType == i18n::ScriptType::ASIAN ) || ( nTmpType == i18n::ScriptType::COMPLEX ) ) | |||
1656 | { | |||
1657 | aText = aText.replaceAt( pField->GetStart(), 1, aFldText.copy(nCharInField,1) ); | |||
1658 | break; | |||
1659 | } | |||
1660 | } | |||
1661 | } | |||
1662 | // #112831# Last Field might go from 0xffff to 0x0000 | |||
1663 | pField = pField->GetEnd() ? pNode->GetCharAttribs().FindNextAttrib( EE_FEATURE_FIELD, pField->GetEnd() ) : nullptr; | |||
1664 | } | |||
1665 | ||||
1666 | sal_Int32 nTextLen = aText.getLength(); | |||
1667 | ||||
1668 | sal_Int32 nPos = 0; | |||
1669 | short nScriptType = _xBI->getScriptType( aText, nPos ); | |||
1670 | rTypes.emplace_back( nScriptType, nPos, nTextLen ); | |||
1671 | nPos = _xBI->endOfScript( aText, nPos, nScriptType ); | |||
1672 | while ( ( nPos != -1 ) && ( nPos < nTextLen ) ) | |||
1673 | { | |||
1674 | rTypes.back().nEndPos = nPos; | |||
1675 | ||||
1676 | nScriptType = _xBI->getScriptType( aText, nPos ); | |||
1677 | long nEndPos = _xBI->endOfScript( aText, nPos, nScriptType ); | |||
1678 | ||||
1679 | if ( ( nScriptType == i18n::ScriptType::WEAK ) || ( nScriptType == rTypes.back().nScriptType ) ) | |||
1680 | { | |||
1681 | // Expand last ScriptTypePosInfo, don't create weak or unnecessary portions | |||
1682 | rTypes.back().nEndPos = nEndPos; | |||
1683 | } | |||
1684 | else | |||
1685 | { | |||
1686 | if ( _xBI->getScriptType( aText, nPos - 1 ) == i18n::ScriptType::WEAK ) | |||
1687 | { | |||
1688 | switch ( u_charTypeu_charType_67(aText.iterateCodePoints(&nPos, 0) ) ) { | |||
1689 | case U_NON_SPACING_MARK: | |||
1690 | case U_ENCLOSING_MARK: | |||
1691 | case U_COMBINING_SPACING_MARK: | |||
1692 | --nPos; | |||
1693 | rTypes.back().nEndPos--; | |||
1694 | break; | |||
1695 | } | |||
1696 | } | |||
1697 | rTypes.emplace_back( nScriptType, nPos, nTextLen ); | |||
1698 | } | |||
1699 | ||||
1700 | nPos = nEndPos; | |||
1701 | } | |||
1702 | ||||
1703 | if ( rTypes[0].nScriptType == i18n::ScriptType::WEAK ) | |||
1704 | rTypes[0].nScriptType = ( rTypes.size() > 1 ) ? rTypes[1].nScriptType : SvtLanguageOptions::GetI18NScriptTypeOfLanguage( GetDefaultLanguage() ); | |||
1705 | ||||
1706 | // create writing direction information: | |||
1707 | if ( pParaPortion->aWritingDirectionInfos.empty() ) | |||
1708 | InitWritingDirections( nPara ); | |||
1709 | ||||
1710 | // i89825: Use CTL font for numbers embedded into an RTL run: | |||
1711 | WritingDirectionInfos& rDirInfos = pParaPortion->aWritingDirectionInfos; | |||
1712 | for (const WritingDirectionInfo & rDirInfo : rDirInfos) | |||
1713 | { | |||
1714 | const sal_Int32 nStart = rDirInfo.nStartPos; | |||
1715 | const sal_Int32 nEnd = rDirInfo.nEndPos; | |||
1716 | const sal_uInt8 nCurrDirType = rDirInfo.nType; | |||
1717 | ||||
1718 | if ( nCurrDirType % 2 == UBIDI_RTL || // text in RTL run | |||
1719 | ( nCurrDirType > UBIDI_LTR && !lcl_HasStrongLTR( aText, nStart, nEnd ) ) ) // non-strong text in embedded LTR run | |||
1720 | { | |||
1721 | size_t nIdx = 0; | |||
1722 | ||||
1723 | // Skip entries in ScriptArray which are not inside the RTL run: | |||
1724 | while ( nIdx < rTypes.size() && rTypes[nIdx].nStartPos < nStart ) | |||
1725 | ++nIdx; | |||
1726 | ||||
1727 | // Remove any entries *inside* the current run: | |||
1728 | while (nIdx < rTypes.size() && rTypes[nIdx].nEndPos <= nEnd) | |||
1729 | { | |||
1730 | // coverity[use_iterator] - we're protected from a bad iterator by the above condition | |||
1731 | rTypes.erase(rTypes.begin() + nIdx); | |||
1732 | } | |||
1733 | ||||
1734 | // special case: | |||
1735 | if(nIdx < rTypes.size() && rTypes[nIdx].nStartPos < nStart && rTypes[nIdx].nEndPos > nEnd) | |||
1736 | { | |||
1737 | rTypes.insert( rTypes.begin()+nIdx, ScriptTypePosInfo( rTypes[nIdx].nScriptType, nEnd, rTypes[nIdx].nEndPos ) ); | |||
1738 | rTypes[nIdx].nEndPos = nStart; | |||
1739 | } | |||
1740 | ||||
1741 | if( nIdx ) | |||
1742 | rTypes[nIdx - 1].nEndPos = nStart; | |||
1743 | ||||
1744 | rTypes.insert( rTypes.begin()+nIdx, ScriptTypePosInfo( i18n::ScriptType::COMPLEX, nStart, nEnd) ); | |||
1745 | ++nIdx; | |||
1746 | ||||
1747 | if( nIdx < rTypes.size() ) | |||
1748 | rTypes[nIdx].nStartPos = nEnd; | |||
1749 | } | |||
1750 | } | |||
1751 | } | |||
1752 | ||||
1753 | namespace { | |||
1754 | ||||
1755 | struct FindByPos | |||
1756 | { | |||
1757 | explicit FindByPos(sal_Int32 nPos) | |||
1758 | : mnPos(nPos) | |||
1759 | { | |||
1760 | } | |||
1761 | ||||
1762 | bool operator()(const ScriptTypePosInfos::value_type& rValue) | |||
1763 | { | |||
1764 | return rValue.nStartPos <= mnPos && rValue.nEndPos >= mnPos; | |||
1765 | } | |||
1766 | ||||
1767 | private: | |||
1768 | sal_Int32 mnPos; | |||
1769 | }; | |||
1770 | ||||
1771 | } | |||
1772 | ||||
1773 | sal_uInt16 ImpEditEngine::GetI18NScriptType( const EditPaM& rPaM, sal_Int32* pEndPos ) const | |||
1774 | { | |||
1775 | sal_uInt16 nScriptType = 0; | |||
1776 | ||||
1777 | if ( pEndPos ) | |||
1778 | *pEndPos = rPaM.GetNode()->Len(); | |||
1779 | ||||
1780 | if ( rPaM.GetNode()->Len() ) | |||
1781 | { | |||
1782 | sal_Int32 nPara = GetEditDoc().GetPos( rPaM.GetNode() ); | |||
1783 | const ParaPortion* pParaPortion = GetParaPortions().SafeGetObject( nPara ); | |||
1784 | if (pParaPortion) | |||
1785 | { | |||
1786 | if ( pParaPortion->aScriptInfos.empty() ) | |||
1787 | const_cast<ImpEditEngine*>(this)->InitScriptTypes( nPara ); | |||
1788 | ||||
1789 | const ScriptTypePosInfos& rTypes = pParaPortion->aScriptInfos; | |||
1790 | ||||
1791 | const sal_Int32 nPos = rPaM.GetIndex(); | |||
1792 | ScriptTypePosInfos::const_iterator itr = std::find_if(rTypes.begin(), rTypes.end(), FindByPos(nPos)); | |||
1793 | if(itr != rTypes.end()) | |||
1794 | { | |||
1795 | nScriptType = itr->nScriptType; | |||
1796 | if( pEndPos ) | |||
1797 | *pEndPos = itr->nEndPos; | |||
1798 | } | |||
1799 | } | |||
1800 | } | |||
1801 | return nScriptType ? nScriptType : SvtLanguageOptions::GetI18NScriptTypeOfLanguage( GetDefaultLanguage() ); | |||
1802 | } | |||
1803 | ||||
1804 | SvtScriptType ImpEditEngine::GetItemScriptType( const EditSelection& rSel ) const | |||
1805 | { | |||
1806 | EditSelection aSel( rSel ); | |||
1807 | aSel.Adjust( aEditDoc ); | |||
1808 | ||||
1809 | SvtScriptType nScriptType = SvtScriptType::NONE; | |||
1810 | ||||
1811 | sal_Int32 nStartPara = GetEditDoc().GetPos( aSel.Min().GetNode() ); | |||
1812 | sal_Int32 nEndPara = GetEditDoc().GetPos( aSel.Max().GetNode() ); | |||
1813 | ||||
1814 | for ( sal_Int32 nPara = nStartPara; nPara <= nEndPara; nPara++ ) | |||
1815 | { | |||
1816 | const ParaPortion* pParaPortion = GetParaPortions().SafeGetObject( nPara ); | |||
1817 | if (!pParaPortion) | |||
1818 | continue; | |||
1819 | ||||
1820 | if ( pParaPortion->aScriptInfos.empty() ) | |||
1821 | const_cast<ImpEditEngine*>(this)->InitScriptTypes( nPara ); | |||
1822 | ||||
1823 | const ScriptTypePosInfos& rTypes = pParaPortion->aScriptInfos; | |||
1824 | ||||
1825 | // find all the scripts of this range | |||
1826 | sal_Int32 nS = ( nPara == nStartPara ) ? aSel.Min().GetIndex() : 0; | |||
1827 | sal_Int32 nE = ( nPara == nEndPara ) ? aSel.Max().GetIndex() : pParaPortion->GetNode()->Len(); | |||
1828 | ||||
1829 | //no selection, just bare cursor | |||
1830 | if (nStartPara == nEndPara && nS == nE) | |||
1831 | { | |||
1832 | //If we are not at the start of the paragraph we want the properties of the | |||
1833 | //preceding character. Otherwise get the properties of the next (or what the | |||
1834 | //next would have if it existed) | |||
1835 | if (nS != 0) | |||
1836 | --nS; | |||
1837 | else | |||
1838 | ++nE; | |||
1839 | } | |||
1840 | ||||
1841 | for (const ScriptTypePosInfo & rType : rTypes) | |||
1842 | { | |||
1843 | bool bStartInRange = rType.nStartPos <= nS && nS < rType.nEndPos; | |||
1844 | bool bEndInRange = rType.nStartPos < nE && nE <= rType.nEndPos; | |||
1845 | ||||
1846 | if (bStartInRange || bEndInRange) | |||
1847 | { | |||
1848 | if ( rType.nScriptType != i18n::ScriptType::WEAK ) | |||
1849 | nScriptType |= SvtLanguageOptions::FromI18NToSvtScriptType( rType.nScriptType ); | |||
1850 | } | |||
1851 | } | |||
1852 | } | |||
1853 | return bool(nScriptType) ? nScriptType : SvtLanguageOptions::GetScriptTypeOfLanguage( GetDefaultLanguage() ); | |||
1854 | } | |||
1855 | ||||
1856 | bool ImpEditEngine::IsScriptChange( const EditPaM& rPaM ) const | |||
1857 | { | |||
1858 | bool bScriptChange = false; | |||
1859 | ||||
1860 | if ( rPaM.GetNode()->Len() ) | |||
1861 | { | |||
1862 | sal_Int32 nPara = GetEditDoc().GetPos( rPaM.GetNode() ); | |||
1863 | const ParaPortion* pParaPortion = GetParaPortions().SafeGetObject( nPara ); | |||
1864 | if (pParaPortion) | |||
1865 | { | |||
1866 | if ( pParaPortion->aScriptInfos.empty() ) | |||
1867 | const_cast<ImpEditEngine*>(this)->InitScriptTypes( nPara ); | |||
1868 | ||||
1869 | const ScriptTypePosInfos& rTypes = pParaPortion->aScriptInfos; | |||
1870 | const sal_Int32 nPos = rPaM.GetIndex(); | |||
1871 | for (const ScriptTypePosInfo & rType : rTypes) | |||
1872 | { | |||
1873 | if ( rType.nStartPos == nPos ) | |||
1874 | { | |||
1875 | bScriptChange = true; | |||
1876 | break; | |||
1877 | } | |||
1878 | } | |||
1879 | } | |||
1880 | } | |||
1881 | return bScriptChange; | |||
1882 | } | |||
1883 | ||||
1884 | bool ImpEditEngine::HasScriptType( sal_Int32 nPara, sal_uInt16 nType ) const | |||
1885 | { | |||
1886 | bool bTypeFound = false; | |||
1887 | ||||
1888 | const ParaPortion* pParaPortion = GetParaPortions().SafeGetObject( nPara ); | |||
1889 | if (pParaPortion) | |||
1890 | { | |||
1891 | if ( pParaPortion->aScriptInfos.empty() ) | |||
1892 | const_cast<ImpEditEngine*>(this)->InitScriptTypes( nPara ); | |||
1893 | ||||
1894 | const ScriptTypePosInfos& rTypes = pParaPortion->aScriptInfos; | |||
1895 | for ( size_t n = rTypes.size(); n && !bTypeFound; ) | |||
1896 | { | |||
1897 | if ( rTypes[--n].nScriptType == nType ) | |||
1898 | bTypeFound = true; | |||
1899 | } | |||
1900 | } | |||
1901 | return bTypeFound; | |||
1902 | } | |||
1903 | ||||
1904 | void ImpEditEngine::InitWritingDirections( sal_Int32 nPara ) | |||
1905 | { | |||
1906 | ParaPortion* pParaPortion = GetParaPortions().SafeGetObject( nPara ); | |||
1907 | if (!pParaPortion) | |||
1908 | return; | |||
1909 | ||||
1910 | WritingDirectionInfos& rInfos = pParaPortion->aWritingDirectionInfos; | |||
1911 | rInfos.clear(); | |||
1912 | ||||
1913 | if (pParaPortion->GetNode()->Len()) | |||
1914 | { | |||
1915 | const OUString aText = pParaPortion->GetNode()->GetString(); | |||
1916 | ||||
1917 | // Bidi functions from icu 2.0 | |||
1918 | ||||
1919 | UErrorCode nError = U_ZERO_ERROR; | |||
1920 | UBiDi* pBidi = ubidi_openSizedubidi_openSized_67( aText.getLength(), 0, &nError ); | |||
1921 | nError = U_ZERO_ERROR; | |||
1922 | ||||
1923 | const UBiDiLevel nBidiLevel = IsRightToLeft(nPara) ? 1 /*RTL*/ : 0 /*LTR*/; | |||
1924 | ubidi_setParaubidi_setPara_67( pBidi, reinterpret_cast<const UChar *>(aText.getStr()), aText.getLength(), nBidiLevel, nullptr, &nError ); | |||
1925 | nError = U_ZERO_ERROR; | |||
1926 | ||||
1927 | int32_t nCount = ubidi_countRunsubidi_countRuns_67( pBidi, &nError ); | |||
1928 | ||||
1929 | /* ubidi_countRuns can return -1 in case of error */ | |||
1930 | if (nCount > 0) | |||
1931 | { | |||
1932 | int32_t nStart = 0; | |||
1933 | int32_t nEnd; | |||
1934 | UBiDiLevel nCurrDir; | |||
1935 | ||||
1936 | for (int32_t nIdx = 0; nIdx < nCount; ++nIdx) | |||
1937 | { | |||
1938 | ubidi_getLogicalRunubidi_getLogicalRun_67( pBidi, nStart, &nEnd, &nCurrDir ); | |||
1939 | rInfos.emplace_back( nCurrDir, nStart, nEnd ); | |||
1940 | nStart = nEnd; | |||
1941 | } | |||
1942 | } | |||
1943 | ||||
1944 | ubidi_closeubidi_close_67( pBidi ); | |||
1945 | } | |||
1946 | ||||
1947 | // No infos mean ubidi error, default to LTR | |||
1948 | if ( rInfos.empty() ) | |||
1949 | rInfos.emplace_back( 0, 0, pParaPortion->GetNode()->Len() ); | |||
1950 | ||||
1951 | } | |||
1952 | ||||
1953 | bool ImpEditEngine::IsRightToLeft( sal_Int32 nPara ) const | |||
1954 | { | |||
1955 | bool bR2L = false; | |||
1956 | const SvxFrameDirectionItem* pFrameDirItem = nullptr; | |||
1957 | ||||
1958 | if ( !IsVertical() ) | |||
1959 | { | |||
1960 | bR2L = GetDefaultHorizontalTextDirection() == EEHorizontalTextDirection::R2L; | |||
1961 | pFrameDirItem = &GetParaAttrib( nPara, EE_PARA_WRITINGDIR ); | |||
1962 | if ( pFrameDirItem->GetValue() == SvxFrameDirection::Environment ) | |||
1963 | { | |||
1964 | // #103045# if DefaultHorizontalTextDirection is set, use that value, otherwise pool default. | |||
1965 | if ( GetDefaultHorizontalTextDirection() != EEHorizontalTextDirection::Default ) | |||
1966 | { | |||
1967 | pFrameDirItem = nullptr; // bR2L already set to default horizontal text direction | |||
1968 | } | |||
1969 | else | |||
1970 | { | |||
1971 | // Use pool default | |||
1972 | pFrameDirItem = &GetEmptyItemSet().Get(EE_PARA_WRITINGDIR); | |||
1973 | } | |||
1974 | } | |||
1975 | } | |||
1976 | ||||
1977 | if ( pFrameDirItem ) | |||
1978 | bR2L = pFrameDirItem->GetValue() == SvxFrameDirection::Horizontal_RL_TB; | |||
1979 | ||||
1980 | return bR2L; | |||
1981 | } | |||
1982 | ||||
1983 | bool ImpEditEngine::HasDifferentRTLLevels( const ContentNode* pNode ) | |||
1984 | { | |||
1985 | bool bHasDifferentRTLLevels = false; | |||
1986 | ||||
1987 | sal_Int32 nPara = GetEditDoc().GetPos( pNode ); | |||
1988 | ParaPortion* pParaPortion = GetParaPortions().SafeGetObject( nPara ); | |||
1989 | if (pParaPortion) | |||
1990 | { | |||
1991 | sal_uInt16 nRTLLevel = IsRightToLeft( nPara ) ? 1 : 0; | |||
1992 | for ( sal_Int32 n = 0; n < pParaPortion->GetTextPortions().Count(); n++ ) | |||
1993 | { | |||
1994 | const TextPortion& rTextPortion = pParaPortion->GetTextPortions()[n]; | |||
1995 | if ( rTextPortion.GetRightToLeftLevel() != nRTLLevel ) | |||
1996 | { | |||
1997 | bHasDifferentRTLLevels = true; | |||
1998 | break; | |||
1999 | } | |||
2000 | } | |||
2001 | } | |||
2002 | return bHasDifferentRTLLevels; | |||
2003 | } | |||
2004 | ||||
2005 | ||||
2006 | sal_uInt8 ImpEditEngine::GetRightToLeft( sal_Int32 nPara, sal_Int32 nPos, sal_Int32* pStart, sal_Int32* pEnd ) | |||
2007 | { | |||
2008 | sal_uInt8 nRightToLeft = 0; | |||
2009 | ||||
2010 | ContentNode* pNode = aEditDoc.GetObject( nPara ); | |||
2011 | if ( pNode && pNode->Len() ) | |||
2012 | { | |||
2013 | ParaPortion* pParaPortion = GetParaPortions().SafeGetObject( nPara ); | |||
2014 | if (pParaPortion) | |||
2015 | { | |||
2016 | if ( pParaPortion->aWritingDirectionInfos.empty() ) | |||
2017 | InitWritingDirections( nPara ); | |||
2018 | ||||
2019 | WritingDirectionInfos& rDirInfos = pParaPortion->aWritingDirectionInfos; | |||
2020 | for (const WritingDirectionInfo & rDirInfo : rDirInfos) | |||
2021 | { | |||
2022 | if ( ( rDirInfo.nStartPos <= nPos ) && ( rDirInfo.nEndPos >= nPos ) ) | |||
2023 | { | |||
2024 | nRightToLeft = rDirInfo.nType; | |||
2025 | if ( pStart ) | |||
2026 | *pStart = rDirInfo.nStartPos; | |||
2027 | if ( pEnd ) | |||
2028 | *pEnd = rDirInfo.nEndPos; | |||
2029 | break; | |||
2030 | } | |||
2031 | } | |||
2032 | } | |||
2033 | } | |||
2034 | return nRightToLeft; | |||
2035 | } | |||
2036 | ||||
2037 | SvxAdjust ImpEditEngine::GetJustification( sal_Int32 nPara ) const | |||
2038 | { | |||
2039 | SvxAdjust eJustification = SvxAdjust::Left; | |||
2040 | ||||
2041 | if ( !aStatus.IsOutliner() ) | |||
2042 | { | |||
2043 | eJustification = GetParaAttrib( nPara, EE_PARA_JUST ).GetAdjust(); | |||
2044 | ||||
2045 | if ( IsRightToLeft( nPara ) ) | |||
2046 | { | |||
2047 | if ( eJustification == SvxAdjust::Left ) | |||
2048 | eJustification = SvxAdjust::Right; | |||
2049 | else if ( eJustification == SvxAdjust::Right ) | |||
2050 | eJustification = SvxAdjust::Left; | |||
2051 | } | |||
2052 | } | |||
2053 | return eJustification; | |||
2054 | } | |||
2055 | ||||
2056 | SvxCellJustifyMethod ImpEditEngine::GetJustifyMethod( sal_Int32 nPara ) const | |||
2057 | { | |||
2058 | const SvxJustifyMethodItem& rItem = GetParaAttrib(nPara, EE_PARA_JUST_METHOD); | |||
2059 | return static_cast<SvxCellJustifyMethod>(rItem.GetEnumValue()); | |||
2060 | } | |||
2061 | ||||
2062 | SvxCellVerJustify ImpEditEngine::GetVerJustification( sal_Int32 nPara ) const | |||
2063 | { | |||
2064 | const SvxVerJustifyItem& rItem = GetParaAttrib(nPara, EE_PARA_VER_JUST); | |||
2065 | return static_cast<SvxCellVerJustify>(rItem.GetEnumValue()); | |||
2066 | } | |||
2067 | ||||
2068 | // Text changes | |||
2069 | void ImpEditEngine::ImpRemoveChars( const EditPaM& rPaM, sal_Int32 nChars ) | |||
2070 | { | |||
2071 | if ( IsUndoEnabled() && !IsInUndo() ) | |||
2072 | { | |||
2073 | const OUString aStr( rPaM.GetNode()->Copy( rPaM.GetIndex(), nChars ) ); | |||
2074 | ||||
2075 | // Check whether attributes are deleted or changed: | |||
2076 | const sal_Int32 nStart = rPaM.GetIndex(); | |||
2077 | const sal_Int32 nEnd = nStart + nChars; | |||
2078 | const CharAttribList::AttribsType& rAttribs = rPaM.GetNode()->GetCharAttribs().GetAttribs(); | |||
2079 | for (const auto & rAttrib : rAttribs) | |||
2080 | { | |||
2081 | const EditCharAttrib& rAttr = *rAttrib; | |||
2082 | if (rAttr.GetEnd() >= nStart && rAttr.GetStart() < nEnd) | |||
2083 | { | |||
2084 | EditSelection aSel( rPaM ); | |||
2085 | aSel.Max().SetIndex( aSel.Max().GetIndex() + nChars ); | |||
2086 | InsertUndo( CreateAttribUndo( aSel, GetEmptyItemSet() ) ); | |||
2087 | break; // for | |||
2088 | } | |||
2089 | } | |||
2090 | InsertUndo(std::make_unique<EditUndoRemoveChars>(pEditEngine, CreateEPaM(rPaM), aStr)); | |||
2091 | } | |||
2092 | ||||
2093 | aEditDoc.RemoveChars( rPaM, nChars ); | |||
2094 | } | |||
2095 | ||||
2096 | EditSelection ImpEditEngine::ImpMoveParagraphs( Range aOldPositions, sal_Int32 nNewPos ) | |||
2097 | { | |||
2098 | aOldPositions.Justify(); | |||
2099 | bool bValidAction = ( static_cast<long>(nNewPos) < aOldPositions.Min() ) || ( static_cast<long>(nNewPos) > aOldPositions.Max() ); | |||
2100 | OSL_ENSURE( bValidAction, "Move in itself?" )do { if (true && (!(bValidAction))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2100" ": "), "%s", "Move in itself?"); } } while (false ); | |||
2101 | OSL_ENSURE( aOldPositions.Max() <= static_cast<long>(GetParaPortions().Count()), "totally over it: MoveParagraphs" )do { if (true && (!(aOldPositions.Max() <= static_cast <long>(GetParaPortions().Count())))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2101" ": "), "%s", "totally over it: MoveParagraphs"); } } while (false); | |||
2102 | ||||
2103 | EditSelection aSelection; | |||
2104 | ||||
2105 | if ( !bValidAction ) | |||
2106 | { | |||
2107 | aSelection = aEditDoc.GetStartPaM(); | |||
2108 | return aSelection; | |||
2109 | } | |||
2110 | ||||
2111 | sal_Int32 nParaCount = GetParaPortions().Count(); | |||
2112 | ||||
2113 | if ( nNewPos >= nParaCount ) | |||
2114 | nNewPos = nParaCount; | |||
2115 | ||||
2116 | // Height may change when moving first or last Paragraph | |||
2117 | ParaPortion* pRecalc1 = nullptr; | |||
2118 | ParaPortion* pRecalc2 = nullptr; | |||
2119 | ParaPortion* pRecalc3 = nullptr; | |||
2120 | ParaPortion* pRecalc4 = nullptr; | |||
2121 | ||||
2122 | if ( nNewPos == 0 ) // Move to Start | |||
2123 | { | |||
2124 | pRecalc1 = GetParaPortions()[0]; | |||
2125 | pRecalc2 = GetParaPortions()[aOldPositions.Min()]; | |||
2126 | ||||
2127 | } | |||
2128 | else if ( nNewPos == nParaCount ) | |||
2129 | { | |||
2130 | pRecalc1 = GetParaPortions()[nParaCount-1]; | |||
2131 | pRecalc2 = GetParaPortions()[aOldPositions.Max()]; | |||
2132 | } | |||
2133 | ||||
2134 | if ( aOldPositions.Min() == 0 ) // Move from Start | |||
2135 | { | |||
2136 | pRecalc3 = GetParaPortions()[0]; | |||
2137 | pRecalc4 = GetParaPortions()[aOldPositions.Max()+1]; | |||
2138 | } | |||
2139 | else if ( aOldPositions.Max() == (nParaCount-1) ) | |||
2140 | { | |||
2141 | pRecalc3 = GetParaPortions()[aOldPositions.Max()]; | |||
2142 | pRecalc4 = GetParaPortions()[aOldPositions.Min()-1]; | |||
2143 | } | |||
2144 | ||||
2145 | MoveParagraphsInfo aMoveParagraphsInfo( aOldPositions.Min(), aOldPositions.Max(), nNewPos ); | |||
2146 | aBeginMovingParagraphsHdl.Call( aMoveParagraphsInfo ); | |||
2147 | ||||
2148 | if ( IsUndoEnabled() && !IsInUndo()) | |||
2149 | InsertUndo(std::make_unique<EditUndoMoveParagraphs>(pEditEngine, aOldPositions, nNewPos)); | |||
2150 | ||||
2151 | // do not lose sight of the Position ! | |||
2152 | ParaPortion* pDestPortion = GetParaPortions().SafeGetObject( nNewPos ); | |||
2153 | ||||
2154 | ParaPortionList aTmpPortionList; | |||
2155 | for (long i = aOldPositions.Min(); i <= aOldPositions.Max(); i++ ) | |||
2156 | { | |||
2157 | // always aOldPositions.Min(), since Remove(). | |||
2158 | std::unique_ptr<ParaPortion> pTmpPortion = GetParaPortions().Release(aOldPositions.Min()); | |||
2159 | aEditDoc.Release( aOldPositions.Min() ); | |||
2160 | aTmpPortionList.Append(std::move(pTmpPortion)); | |||
2161 | } | |||
2162 | ||||
2163 | sal_Int32 nRealNewPos = pDestPortion ? GetParaPortions().GetPos( pDestPortion ) : GetParaPortions().Count(); | |||
2164 | OSL_ENSURE( nRealNewPos != EE_PARA_NOT_FOUND, "ImpMoveParagraphs: Invalid Position!" )do { if (true && (!(nRealNewPos != ((sal_Int32) 0x7FFFFFFF )))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2164" ": "), "%s", "ImpMoveParagraphs: Invalid Position!" ); } } while (false); | |||
2165 | ||||
2166 | sal_Int32 i = 0; | |||
2167 | while( aTmpPortionList.Count() > 0 ) | |||
2168 | { | |||
2169 | std::unique_ptr<ParaPortion> pTmpPortion = aTmpPortionList.Release(0); | |||
2170 | if ( i == 0 ) | |||
2171 | aSelection.Min().SetNode( pTmpPortion->GetNode() ); | |||
2172 | ||||
2173 | aSelection.Max().SetNode( pTmpPortion->GetNode() ); | |||
2174 | aSelection.Max().SetIndex( pTmpPortion->GetNode()->Len() ); | |||
2175 | ||||
2176 | ContentNode* pN = pTmpPortion->GetNode(); | |||
2177 | aEditDoc.Insert(nRealNewPos+i, pN); | |||
2178 | ||||
2179 | GetParaPortions().Insert(nRealNewPos+i, std::move(pTmpPortion)); | |||
2180 | ++i; | |||
2181 | } | |||
2182 | ||||
2183 | aEndMovingParagraphsHdl.Call( aMoveParagraphsInfo ); | |||
2184 | ||||
2185 | if ( GetNotifyHdl().IsSet() ) | |||
2186 | { | |||
2187 | EENotify aNotify( EE_NOTIFY_PARAGRAPHSMOVED ); | |||
2188 | aNotify.nParagraph = nNewPos; | |||
2189 | aNotify.nParam1 = aOldPositions.Min(); | |||
2190 | aNotify.nParam2 = aOldPositions.Max(); | |||
2191 | GetNotifyHdl().Call( aNotify ); | |||
2192 | } | |||
2193 | ||||
2194 | aEditDoc.SetModified( true ); | |||
2195 | ||||
2196 | if ( pRecalc1 ) | |||
2197 | CalcHeight( pRecalc1 ); | |||
2198 | if ( pRecalc2 ) | |||
2199 | CalcHeight( pRecalc2 ); | |||
2200 | if ( pRecalc3 ) | |||
2201 | CalcHeight( pRecalc3 ); | |||
2202 | if ( pRecalc4 ) | |||
2203 | CalcHeight( pRecalc4 ); | |||
2204 | ||||
2205 | #if OSL_DEBUG_LEVEL1 > 0 && !defined NDEBUG | |||
2206 | ParaPortionList::DbgCheck(GetParaPortions(), aEditDoc); | |||
2207 | #endif | |||
2208 | return aSelection; | |||
2209 | } | |||
2210 | ||||
2211 | ||||
2212 | EditPaM ImpEditEngine::ImpConnectParagraphs( ContentNode* pLeft, ContentNode* pRight, bool bBackward ) | |||
2213 | { | |||
2214 | OSL_ENSURE( pLeft != pRight, "Join together the same paragraph ?" )do { if (true && (!(pLeft != pRight))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2214" ": "), "%s", "Join together the same paragraph ?" ); } } while (false); | |||
2215 | OSL_ENSURE( aEditDoc.GetPos( pLeft ) != EE_PARA_NOT_FOUND, "Inserted node not found (1)" )do { if (true && (!(aEditDoc.GetPos( pLeft ) != ((sal_Int32 ) 0x7FFFFFFF)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2215" ": "), "%s", "Inserted node not found (1)"); } } while (false); | |||
2216 | OSL_ENSURE( aEditDoc.GetPos( pRight ) != EE_PARA_NOT_FOUND, "Inserted node not found (2)" )do { if (true && (!(aEditDoc.GetPos( pRight ) != ((sal_Int32 ) 0x7FFFFFFF)))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2216" ": "), "%s", "Inserted node not found (2)"); } } while (false); | |||
2217 | ||||
2218 | // #i120020# it is possible that left and right are *not* in the desired order (left/right) | |||
2219 | // so correct it. This correction is needed, else an invalid SfxLinkUndoAction will be | |||
2220 | // created from ConnectParagraphs below. Assert this situation, it should be corrected by the | |||
2221 | // caller. | |||
2222 | if(aEditDoc.GetPos( pLeft ) > aEditDoc.GetPos( pRight )) | |||
2223 | { | |||
2224 | OSL_ENSURE(false, "ImpConnectParagraphs with wrong order of pLeft/pRight nodes (!)")do { if (true && (!(false))) { sal_detail_logFormat(( SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2224" ": "), "%s", "ImpConnectParagraphs with wrong order of pLeft/pRight nodes (!)" ); } } while (false); | |||
2225 | std::swap(pLeft, pRight); | |||
2226 | } | |||
2227 | ||||
2228 | sal_Int32 nParagraphTobeDeleted = aEditDoc.GetPos( pRight ); | |||
2229 | aDeletedNodes.push_back(std::make_unique<DeletedNodeInfo>( pRight, nParagraphTobeDeleted )); | |||
2230 | ||||
2231 | GetEditEnginePtr()->ParagraphConnected( aEditDoc.GetPos( pLeft ), aEditDoc.GetPos( pRight ) ); | |||
2232 | ||||
2233 | if ( IsUndoEnabled() && !IsInUndo() ) | |||
2234 | { | |||
2235 | InsertUndo( std::make_unique<EditUndoConnectParas>(pEditEngine, | |||
2236 | aEditDoc.GetPos( pLeft ), pLeft->Len(), | |||
2237 | pLeft->GetContentAttribs().GetItems(), pRight->GetContentAttribs().GetItems(), | |||
2238 | pLeft->GetStyleSheet(), pRight->GetStyleSheet(), bBackward ) ); | |||
2239 | } | |||
2240 | ||||
2241 | if ( bBackward ) | |||
2242 | { | |||
2243 | pLeft->SetStyleSheet( pRight->GetStyleSheet() ); | |||
2244 | // it feels wrong to set pLeft's attribs if pRight is empty, tdf#128046 | |||
2245 | if ( pRight->Len() ) | |||
2246 | pLeft->GetContentAttribs().GetItems().Set( pRight->GetContentAttribs().GetItems() ); | |||
2247 | pLeft->GetCharAttribs().GetDefFont() = pRight->GetCharAttribs().GetDefFont(); | |||
2248 | } | |||
2249 | ||||
2250 | ParaAttribsChanged( pLeft, true ); | |||
2251 | ||||
2252 | // First search for Portions since pRight is gone after ConnectParagraphs. | |||
2253 | ParaPortion* pLeftPortion = FindParaPortion( pLeft ); | |||
2254 | OSL_ENSURE( pLeftPortion, "Blind Portion in ImpConnectParagraphs(1)" )do { if (true && (!(pLeftPortion))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2254" ": "), "%s", "Blind Portion in ImpConnectParagraphs(1)" ); } } while (false); | |||
2255 | ||||
2256 | if ( GetStatus().DoOnlineSpelling() ) | |||
2257 | { | |||
2258 | sal_Int32 nEnd = pLeft->Len(); | |||
2259 | sal_Int32 nInv = nEnd ? nEnd-1 : nEnd; | |||
2260 | pLeft->GetWrongList()->ClearWrongs( nInv, static_cast<size_t>(-1), pLeft ); // Possibly remove one | |||
2261 | pLeft->GetWrongList()->SetInvalidRange(nInv, nEnd+1); | |||
2262 | // Take over misspelled words | |||
2263 | WrongList* pRWrongs = pRight->GetWrongList(); | |||
2264 | for (auto & elem : *pRWrongs) | |||
2265 | { | |||
2266 | if (elem.mnStart != 0) // Not a subsequent | |||
2267 | { | |||
2268 | elem.mnStart = elem.mnStart + nEnd; | |||
2269 | elem.mnEnd = elem.mnEnd + nEnd; | |||
2270 | pLeft->GetWrongList()->push_back(elem); | |||
2271 | } | |||
2272 | } | |||
2273 | } | |||
2274 | ||||
2275 | if ( IsCallParaInsertedOrDeleted() ) | |||
2276 | GetEditEnginePtr()->ParagraphDeleted( nParagraphTobeDeleted ); | |||
2277 | ||||
2278 | EditPaM aPaM = aEditDoc.ConnectParagraphs( pLeft, pRight ); | |||
2279 | GetParaPortions().Remove( nParagraphTobeDeleted ); | |||
2280 | ||||
2281 | pLeftPortion->MarkSelectionInvalid( aPaM.GetIndex() ); | |||
2282 | ||||
2283 | // the right node is deleted by EditDoc:ConnectParagraphs(). | |||
2284 | if ( GetTextRanger() ) | |||
2285 | { | |||
2286 | // By joining together the two, the left is although reformatted, | |||
2287 | // however if its height does not change then the formatting receives | |||
2288 | // the change of the total text height too late... | |||
2289 | for ( sal_Int32 n = nParagraphTobeDeleted; n < GetParaPortions().Count(); n++ ) | |||
2290 | { | |||
2291 | ParaPortion* pPP = GetParaPortions()[n]; | |||
2292 | pPP->MarkSelectionInvalid( 0 ); | |||
2293 | pPP->GetLines().Reset(); | |||
2294 | } | |||
2295 | } | |||
2296 | ||||
2297 | TextModified(); | |||
2298 | ||||
2299 | return aPaM; | |||
2300 | } | |||
2301 | ||||
2302 | EditPaM ImpEditEngine::DeleteLeftOrRight( const EditSelection& rSel, sal_uInt8 nMode, DeleteMode nDelMode ) | |||
2303 | { | |||
2304 | OSL_ENSURE( !rSel.DbgIsBuggy( aEditDoc ), "Index out of range in DeleteLeftOrRight" )do { if (true && (!(!rSel.DbgIsBuggy( aEditDoc )))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2304" ": "), "%s", "Index out of range in DeleteLeftOrRight" ); } } while (false); | |||
2305 | ||||
2306 | if ( rSel.HasRange() ) // only then Delete Selection | |||
2307 | return ImpDeleteSelection( rSel ); | |||
2308 | ||||
2309 | EditPaM aCurPos( rSel.Max() ); | |||
2310 | EditPaM aDelStart( aCurPos ); | |||
2311 | EditPaM aDelEnd( aCurPos ); | |||
2312 | if ( nMode == DEL_LEFT1 ) | |||
2313 | { | |||
2314 | if ( nDelMode == DeleteMode::Simple ) | |||
2315 | { | |||
2316 | sal_uInt16 nCharMode = i18n::CharacterIteratorMode::SKIPCHARACTER; | |||
2317 | // Check if we are deleting a CJK ideograph variance sequence (IVS). | |||
2318 | sal_Int32 nIndex = aCurPos.GetIndex(); | |||
2319 | if (nIndex > 0) | |||
2320 | { | |||
2321 | const OUString& rString = aCurPos.GetNode()->GetString(); | |||
2322 | sal_Int32 nCode = rString.iterateCodePoints(&nIndex, -1); | |||
2323 | if (unicode::isIVSSelector(nCode) && nIndex > 0 && | |||
2324 | unicode::isCJKIVSCharacter(rString.iterateCodePoints(&nIndex, -1))) | |||
2325 | { | |||
2326 | nCharMode = i18n::CharacterIteratorMode::SKIPCELL; | |||
2327 | } | |||
2328 | } | |||
2329 | aDelStart = CursorLeft(aCurPos, nCharMode); | |||
2330 | } | |||
2331 | else if ( nDelMode == DeleteMode::RestOfWord ) | |||
2332 | { | |||
2333 | aDelStart = StartOfWord( aCurPos ); | |||
2334 | if ( aDelStart.GetIndex() == aCurPos.GetIndex() ) | |||
2335 | aDelStart = WordLeft( aCurPos ); | |||
2336 | } | |||
2337 | else // DELMODE_RESTOFCONTENT | |||
2338 | { | |||
2339 | aDelStart.SetIndex( 0 ); | |||
2340 | if ( aDelStart == aCurPos ) | |||
2341 | { | |||
2342 | // Complete paragraph previous | |||
2343 | ContentNode* pPrev = GetPrevVisNode( aCurPos.GetNode() ); | |||
2344 | if ( pPrev ) | |||
2345 | aDelStart = EditPaM( pPrev, 0 ); | |||
2346 | } | |||
2347 | } | |||
2348 | } | |||
2349 | else | |||
2350 | { | |||
2351 | if ( nDelMode == DeleteMode::Simple ) | |||
2352 | { | |||
2353 | aDelEnd = CursorRight( aCurPos ); | |||
2354 | } | |||
2355 | else if ( nDelMode == DeleteMode::RestOfWord ) | |||
2356 | { | |||
2357 | aDelEnd = EndOfWord( aCurPos ); | |||
2358 | ||||
2359 | if (aDelEnd.GetIndex() == aCurPos.GetIndex()) | |||
2360 | { | |||
2361 | const sal_Int32 nLen(aCurPos.GetNode()->Len()); | |||
2362 | ||||
2363 | // #i120020# when 0 == nLen, aDelStart needs to be adapted, not | |||
2364 | // aDelEnd. This would (and did) lead to a wrong order in the | |||
2365 | // ImpConnectParagraphs call later. | |||
2366 | if(nLen) | |||
2367 | { | |||
2368 | // end of para? | |||
2369 | if (aDelEnd.GetIndex() == nLen) | |||
2370 | { | |||
2371 | aDelEnd = WordLeft( aCurPos ); | |||
2372 | } | |||
2373 | else // there's still sth to delete on the right | |||
2374 | { | |||
2375 | aDelEnd = EndOfWord( WordRight( aCurPos ) ); | |||
2376 | // if there'n no next word... | |||
2377 | if (aDelEnd.GetIndex() == nLen ) | |||
2378 | { | |||
2379 | aDelEnd.SetIndex( nLen ); | |||
2380 | } | |||
2381 | } | |||
2382 | } | |||
2383 | else | |||
2384 | { | |||
2385 | aDelStart = WordLeft(aCurPos); | |||
2386 | } | |||
2387 | } | |||
2388 | } | |||
2389 | else // DELMODE_RESTOFCONTENT | |||
2390 | { | |||
2391 | aDelEnd.SetIndex( aCurPos.GetNode()->Len() ); | |||
2392 | if ( aDelEnd == aCurPos ) | |||
2393 | { | |||
2394 | // Complete paragraph next | |||
2395 | ContentNode* pNext = GetNextVisNode( aCurPos.GetNode() ); | |||
2396 | if ( pNext ) | |||
2397 | aDelEnd = EditPaM( pNext, pNext->Len() ); | |||
2398 | } | |||
2399 | } | |||
2400 | } | |||
2401 | ||||
2402 | // ConnectParagraphs not enough for different Nodes when | |||
2403 | // DeleteMode::RestOfContent. | |||
2404 | if ( ( nDelMode == DeleteMode::RestOfContent ) || ( aDelStart.GetNode() == aDelEnd.GetNode() ) ) | |||
2405 | return ImpDeleteSelection( EditSelection( aDelStart, aDelEnd ) ); | |||
2406 | ||||
2407 | return ImpConnectParagraphs(aDelStart.GetNode(), aDelEnd.GetNode()); | |||
2408 | } | |||
2409 | ||||
2410 | EditPaM ImpEditEngine::ImpDeleteSelection(const EditSelection& rCurSel) | |||
2411 | { | |||
2412 | if ( !rCurSel.HasRange() ) | |||
2413 | return rCurSel.Min(); | |||
2414 | ||||
2415 | EditSelection aCurSel(rCurSel); | |||
2416 | aCurSel.Adjust( aEditDoc ); | |||
2417 | EditPaM aStartPaM(aCurSel.Min()); | |||
2418 | EditPaM aEndPaM(aCurSel.Max()); | |||
2419 | ||||
2420 | CursorMoved( aStartPaM.GetNode() ); // only so that newly set Attributes disappear... | |||
2421 | CursorMoved( aEndPaM.GetNode() ); // only so that newly set Attributes disappear... | |||
2422 | ||||
2423 | OSL_ENSURE( aStartPaM.GetIndex() <= aStartPaM.GetNode()->Len(), "Index out of range in ImpDeleteSelection" )do { if (true && (!(aStartPaM.GetIndex() <= aStartPaM .GetNode()->Len()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2423" ": "), "%s", "Index out of range in ImpDeleteSelection" ); } } while (false); | |||
2424 | OSL_ENSURE( aEndPaM.GetIndex() <= aEndPaM.GetNode()->Len(), "Index out of range in ImpDeleteSelection" )do { if (true && (!(aEndPaM.GetIndex() <= aEndPaM. GetNode()->Len()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2424" ": "), "%s", "Index out of range in ImpDeleteSelection" ); } } while (false); | |||
2425 | ||||
2426 | sal_Int32 nStartNode = aEditDoc.GetPos( aStartPaM.GetNode() ); | |||
2427 | sal_Int32 nEndNode = aEditDoc.GetPos( aEndPaM.GetNode() ); | |||
2428 | ||||
2429 | OSL_ENSURE( nEndNode != EE_PARA_NOT_FOUND, "Start > End ?!" )do { if (true && (!(nEndNode != ((sal_Int32) 0x7FFFFFFF )))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2429" ": "), "%s", "Start > End ?!"); } } while (false ); | |||
2430 | OSL_ENSURE( nStartNode <= nEndNode, "Start > End ?!" )do { if (true && (!(nStartNode <= nEndNode))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2430" ": "), "%s", "Start > End ?!"); } } while (false ); | |||
2431 | ||||
2432 | // Remove all nodes in between... | |||
2433 | for ( sal_Int32 z = nStartNode+1; z < nEndNode; z++ ) | |||
2434 | { | |||
2435 | // Always nStartNode+1, due to Remove()! | |||
2436 | ImpRemoveParagraph( nStartNode+1 ); | |||
2437 | } | |||
2438 | ||||
2439 | if ( aStartPaM.GetNode() != aEndPaM.GetNode() ) | |||
2440 | { | |||
2441 | // The Rest of the StartNodes... | |||
2442 | ImpRemoveChars( aStartPaM, aStartPaM.GetNode()->Len() - aStartPaM.GetIndex() ); | |||
2443 | ParaPortion* pPortion = FindParaPortion( aStartPaM.GetNode() ); | |||
2444 | OSL_ENSURE( pPortion, "Blind Portion in ImpDeleteSelection(3)" )do { if (true && (!(pPortion))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2444" ": "), "%s", "Blind Portion in ImpDeleteSelection(3)" ); } } while (false); | |||
2445 | pPortion->MarkSelectionInvalid( aStartPaM.GetIndex() ); | |||
2446 | ||||
2447 | // The beginning of the EndNodes... | |||
2448 | const sal_Int32 nChars = aEndPaM.GetIndex(); | |||
2449 | aEndPaM.SetIndex( 0 ); | |||
2450 | ImpRemoveChars( aEndPaM, nChars ); | |||
2451 | pPortion = FindParaPortion( aEndPaM.GetNode() ); | |||
2452 | OSL_ENSURE( pPortion, "Blind Portion in ImpDeleteSelection(4)" )do { if (true && (!(pPortion))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2452" ": "), "%s", "Blind Portion in ImpDeleteSelection(4)" ); } } while (false); | |||
2453 | pPortion->MarkSelectionInvalid( 0 ); | |||
2454 | // Join together... | |||
2455 | aStartPaM = ImpConnectParagraphs( aStartPaM.GetNode(), aEndPaM.GetNode() ); | |||
2456 | } | |||
2457 | else | |||
2458 | { | |||
2459 | ImpRemoveChars( aStartPaM, aEndPaM.GetIndex() - aStartPaM.GetIndex() ); | |||
2460 | ParaPortion* pPortion = FindParaPortion( aStartPaM.GetNode() ); | |||
2461 | OSL_ENSURE( pPortion, "Blind Portion in ImpDeleteSelection(5)" )do { if (true && (!(pPortion))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2461" ": "), "%s", "Blind Portion in ImpDeleteSelection(5)" ); } } while (false); | |||
2462 | pPortion->MarkInvalid( aEndPaM.GetIndex(), aStartPaM.GetIndex() - aEndPaM.GetIndex() ); | |||
2463 | } | |||
2464 | ||||
2465 | UpdateSelections(); | |||
2466 | TextModified(); | |||
2467 | return aStartPaM; | |||
2468 | } | |||
2469 | ||||
2470 | void ImpEditEngine::ImpRemoveParagraph( sal_Int32 nPara ) | |||
2471 | { | |||
2472 | ContentNode* pNode = aEditDoc.GetObject( nPara ); | |||
2473 | ContentNode* pNextNode = aEditDoc.GetObject( nPara+1 ); | |||
2474 | ||||
2475 | OSL_ENSURE( pNode, "Blind Node in ImpRemoveParagraph" )do { if (true && (!(pNode))) { sal_detail_logFormat(( SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2475" ": "), "%s", "Blind Node in ImpRemoveParagraph"); } } while (false); | |||
2476 | ||||
2477 | aDeletedNodes.push_back(std::make_unique<DeletedNodeInfo>( pNode, nPara )); | |||
2478 | ||||
2479 | // The node is managed by the undo and possibly destroyed! | |||
2480 | aEditDoc.Release( nPara ); | |||
2481 | GetParaPortions().Remove( nPara ); | |||
2482 | ||||
2483 | if ( IsCallParaInsertedOrDeleted() ) | |||
2484 | { | |||
2485 | GetEditEnginePtr()->ParagraphDeleted( nPara ); | |||
2486 | } | |||
2487 | ||||
2488 | // Extra-Space may be determined again in the following. For | |||
2489 | // ParaAttribsChanged the paragraph is unfortunately formatted again, | |||
2490 | // however this method should not be time critical! | |||
2491 | if ( pNextNode ) | |||
2492 | ParaAttribsChanged( pNextNode ); | |||
2493 | ||||
2494 | if ( IsUndoEnabled() && !IsInUndo() ) | |||
2495 | InsertUndo(std::make_unique<EditUndoDelContent>(pEditEngine, pNode, nPara)); | |||
2496 | else | |||
2497 | { | |||
2498 | aEditDoc.RemoveItemsFromPool(*pNode); | |||
2499 | if ( pNode->GetStyleSheet() ) | |||
2500 | EndListening( *pNode->GetStyleSheet() ); | |||
2501 | delete pNode; | |||
2502 | } | |||
2503 | } | |||
2504 | ||||
2505 | EditPaM ImpEditEngine::AutoCorrect( const EditSelection& rCurSel, sal_Unicode c, | |||
2506 | bool bOverwrite, vcl::Window const * pFrameWin ) | |||
2507 | { | |||
2508 | // i.e. Calc has special needs regarding a leading single quotation mark | |||
2509 | // when starting cell input. | |||
2510 | if (c == '\'' && !IsReplaceLeadingSingleQuotationMark() && | |||
2511 | rCurSel.Min() == rCurSel.Max() && rCurSel.Max().GetIndex() == 0) | |||
2512 | { | |||
2513 | return InsertTextUserInput( rCurSel, c, bOverwrite ); | |||
2514 | } | |||
2515 | ||||
2516 | EditSelection aSel( rCurSel ); | |||
2517 | SvxAutoCorrect* pAutoCorrect = SvxAutoCorrCfg::Get().GetAutoCorrect(); | |||
2518 | if ( pAutoCorrect ) | |||
2519 | { | |||
2520 | if ( aSel.HasRange() ) | |||
2521 | aSel = ImpDeleteSelection( rCurSel ); | |||
2522 | ||||
2523 | // #i78661 allow application to turn off capitalization of | |||
2524 | // start sentence explicitly. | |||
2525 | // (This is done by setting IsFirstWordCapitalization to sal_False.) | |||
2526 | bool bOldCapitalStartSentence = pAutoCorrect->IsAutoCorrFlag( ACFlags::CapitalStartSentence ); | |||
2527 | if (!IsFirstWordCapitalization()) | |||
2528 | { | |||
2529 | ESelection aESel( CreateESel(aSel) ); | |||
2530 | EditSelection aFirstWordSel; | |||
2531 | EditSelection aSecondWordSel; | |||
2532 | if (aESel.nEndPara == 0) // is this the first para? | |||
2533 | { | |||
2534 | // select first word... | |||
2535 | // start by checking if para starts with word. | |||
2536 | aFirstWordSel = SelectWord( CreateSel(ESelection()) ); | |||
2537 | if (aFirstWordSel.Min().GetIndex() == 0 && aFirstWordSel.Max().GetIndex() == 0) | |||
2538 | { | |||
2539 | // para does not start with word -> select next/first word | |||
2540 | EditPaM aRightWord( WordRight( aFirstWordSel.Max() ) ); | |||
2541 | aFirstWordSel = SelectWord( EditSelection( aRightWord ) ); | |||
2542 | } | |||
2543 | ||||
2544 | // select second word | |||
2545 | // (sometimes aSel might not point to the end of the first word | |||
2546 | // but to some following char like '.'. ':', ... | |||
2547 | // In those cases we need aSecondWordSel to see if aSel | |||
2548 | // will actually effect the first word.) | |||
2549 | EditPaM aRight2Word( WordRight( aFirstWordSel.Max() ) ); | |||
2550 | aSecondWordSel = SelectWord( EditSelection( aRight2Word ) ); | |||
2551 | } | |||
2552 | bool bIsFirstWordInFirstPara = aESel.nEndPara == 0 && | |||
2553 | aFirstWordSel.Max().GetIndex() <= aSel.Max().GetIndex() && | |||
2554 | aSel.Max().GetIndex() <= aSecondWordSel.Min().GetIndex(); | |||
2555 | ||||
2556 | if (bIsFirstWordInFirstPara) | |||
2557 | pAutoCorrect->SetAutoCorrFlag( ACFlags::CapitalStartSentence, IsFirstWordCapitalization() ); | |||
2558 | } | |||
2559 | ||||
2560 | ContentNode* pNode = aSel.Max().GetNode(); | |||
2561 | const sal_Int32 nIndex = aSel.Max().GetIndex(); | |||
2562 | EdtAutoCorrDoc aAuto(pEditEngine, pNode, nIndex, c); | |||
2563 | // FIXME: this _must_ be called with reference to the actual node text! | |||
2564 | OUString const& rNodeString(pNode->GetString()); | |||
2565 | pAutoCorrect->DoAutoCorrect( | |||
2566 | aAuto, rNodeString, nIndex, c, !bOverwrite, mbNbspRunNext, pFrameWin ); | |||
2567 | aSel.Max().SetIndex( aAuto.GetCursor() ); | |||
2568 | ||||
2569 | // #i78661 since the SvxAutoCorrect object used here is | |||
2570 | // shared we need to reset the value to its original state. | |||
2571 | pAutoCorrect->SetAutoCorrFlag( ACFlags::CapitalStartSentence, bOldCapitalStartSentence ); | |||
2572 | } | |||
2573 | return aSel.Max(); | |||
2574 | } | |||
2575 | ||||
2576 | ||||
2577 | EditPaM ImpEditEngine::InsertTextUserInput( const EditSelection& rCurSel, | |||
2578 | sal_Unicode c, bool bOverwrite ) | |||
2579 | { | |||
2580 | OSL_ENSURE( c != '\t', "Tab for InsertText ?" )do { if (true && (!(c != '\t'))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2580" ": "), "%s", "Tab for InsertText ?"); } } while ( false); | |||
2581 | OSL_ENSURE( c != '\n', "Word wrapping for InsertText ?")do { if (true && (!(c != '\n'))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2581" ": "), "%s", "Word wrapping for InsertText ?"); } } while (false); | |||
2582 | ||||
2583 | EditPaM aPaM( rCurSel.Min() ); | |||
2584 | ||||
2585 | bool bDoOverwrite = bOverwrite && | |||
2586 | ( aPaM.GetIndex() < aPaM.GetNode()->Len() ); | |||
2587 | ||||
2588 | bool bUndoAction = ( rCurSel.HasRange() || bDoOverwrite ); | |||
2589 | ||||
2590 | if ( bUndoAction ) | |||
2591 | UndoActionStart( EDITUNDO_INSERT111 ); | |||
2592 | ||||
2593 | if ( rCurSel.HasRange() ) | |||
2594 | { | |||
2595 | aPaM = ImpDeleteSelection( rCurSel ); | |||
2596 | } | |||
2597 | else if ( bDoOverwrite ) | |||
2598 | { | |||
2599 | // If selected, then do not also overwrite a character! | |||
2600 | EditSelection aTmpSel( aPaM ); | |||
2601 | aTmpSel.Max().SetIndex( aTmpSel.Max().GetIndex()+1 ); | |||
2602 | OSL_ENSURE( !aTmpSel.DbgIsBuggy( aEditDoc ), "Overwrite: Wrong selection! ")do { if (true && (!(!aTmpSel.DbgIsBuggy( aEditDoc ))) ) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2602" ": "), "%s", "Overwrite: Wrong selection! "); } } while (false); | |||
2603 | ImpDeleteSelection( aTmpSel ); | |||
2604 | } | |||
2605 | ||||
2606 | if ( aPaM.GetNode()->Len() < MAXCHARSINPARA0x3FFF-16 ) | |||
2607 | { | |||
2608 | if (IsInputSequenceCheckingRequired( c, rCurSel )) | |||
2609 | { | |||
2610 | uno::Reference < i18n::XExtendedInputSequenceChecker > _xISC( ImplGetInputSequenceChecker() ); | |||
2611 | if (!pCTLOptions) | |||
2612 | pCTLOptions.reset( new SvtCTLOptions ); | |||
2613 | ||||
2614 | if (_xISC) | |||
2615 | { | |||
2616 | const sal_Int32 nTmpPos = aPaM.GetIndex(); | |||
2617 | sal_Int16 nCheckMode = pCTLOptions->IsCTLSequenceCheckingRestricted() ? | |||
2618 | i18n::InputSequenceCheckMode::STRICT : i18n::InputSequenceCheckMode::BASIC; | |||
2619 | ||||
2620 | // the text that needs to be checked is only the one | |||
2621 | // before the current cursor position | |||
2622 | const OUString aOldText( aPaM.GetNode()->Copy(0, nTmpPos) ); | |||
2623 | OUString aNewText( aOldText ); | |||
2624 | if (pCTLOptions->IsCTLSequenceCheckingTypeAndReplace()) | |||
2625 | { | |||
2626 | _xISC->correctInputSequence(aNewText, nTmpPos - 1, c, nCheckMode); | |||
2627 | ||||
2628 | // find position of first character that has changed | |||
2629 | sal_Int32 nOldLen = aOldText.getLength(); | |||
2630 | sal_Int32 nNewLen = aNewText.getLength(); | |||
2631 | const sal_Unicode *pOldTxt = aOldText.getStr(); | |||
2632 | const sal_Unicode *pNewTxt = aNewText.getStr(); | |||
2633 | sal_Int32 nChgPos = 0; | |||
2634 | while ( nChgPos < nOldLen && nChgPos < nNewLen && | |||
2635 | pOldTxt[nChgPos] == pNewTxt[nChgPos] ) | |||
2636 | ++nChgPos; | |||
2637 | ||||
2638 | const OUString aChgText( aNewText.copy( nChgPos ) ); | |||
2639 | ||||
2640 | // select text from first pos to be changed to current pos | |||
2641 | EditSelection aSel( EditPaM( aPaM.GetNode(), nChgPos ), aPaM ); | |||
2642 | ||||
2643 | if (!aChgText.isEmpty()) | |||
2644 | return InsertText( aSel, aChgText ); // implicitly handles undo | |||
2645 | else | |||
2646 | return aPaM; | |||
2647 | } | |||
2648 | else | |||
2649 | { | |||
2650 | // should the character be ignored (i.e. not get inserted) ? | |||
2651 | if (!_xISC->checkInputSequence( aOldText, nTmpPos - 1, c, nCheckMode )) | |||
2652 | return aPaM; // nothing to be done -> no need for undo | |||
2653 | } | |||
2654 | } | |||
2655 | ||||
2656 | // at this point now we will insert the character 'normally' some lines below... | |||
2657 | } | |||
2658 | ||||
2659 | if ( IsUndoEnabled() && !IsInUndo() ) | |||
2660 | { | |||
2661 | std::unique_ptr<EditUndoInsertChars> pNewUndo(new EditUndoInsertChars(pEditEngine, CreateEPaM(aPaM), OUString(c))); | |||
2662 | bool bTryMerge = !bDoOverwrite && ( c != ' ' ); | |||
2663 | InsertUndo( std::move(pNewUndo), bTryMerge ); | |||
2664 | } | |||
2665 | ||||
2666 | aEditDoc.InsertText( aPaM, OUString(c) ); | |||
2667 | ParaPortion* pPortion = FindParaPortion( aPaM.GetNode() ); | |||
2668 | OSL_ENSURE( pPortion, "Blind Portion in InsertText" )do { if (true && (!(pPortion))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2668" ": "), "%s", "Blind Portion in InsertText"); } } while (false); | |||
2669 | pPortion->MarkInvalid( aPaM.GetIndex(), 1 ); | |||
2670 | aPaM.SetIndex( aPaM.GetIndex()+1 ); // does not do EditDoc-Method anymore | |||
2671 | } | |||
2672 | ||||
2673 | TextModified(); | |||
2674 | ||||
2675 | if ( bUndoAction ) | |||
2676 | UndoActionEnd(); | |||
2677 | ||||
2678 | return aPaM; | |||
2679 | } | |||
2680 | ||||
2681 | EditPaM ImpEditEngine::ImpInsertText(const EditSelection& aCurSel, const OUString& rStr) | |||
2682 | { | |||
2683 | UndoActionStart( EDITUNDO_INSERT111 ); | |||
2684 | ||||
2685 | EditPaM aPaM; | |||
2686 | if ( aCurSel.HasRange() ) | |||
2687 | aPaM = ImpDeleteSelection( aCurSel ); | |||
2688 | else | |||
2689 | aPaM = aCurSel.Max(); | |||
2690 | ||||
2691 | EditPaM aCurPaM( aPaM ); // for the Invalidate | |||
2692 | ||||
2693 | // get word boundaries in order to clear possible WrongList entries | |||
2694 | // and invalidate all the necessary text (everything after and including the | |||
2695 | // start of the word) | |||
2696 | // #i107201# do the expensive SelectWord call only if online spelling is active | |||
2697 | EditSelection aCurWord; | |||
2698 | if ( GetStatus().DoOnlineSpelling() ) | |||
2699 | aCurWord = SelectWord( aCurPaM, i18n::WordType::DICTIONARY_WORD ); | |||
2700 | ||||
2701 | OUString aText(convertLineEnd(rStr, LINEEND_LF)); | |||
2702 | if (utl::ConfigManager::IsFuzzing()) //tab expansion performance in editeng is appalling | |||
2703 | aText = aText.replaceAll("\t","-"); | |||
2704 | SfxVoidItem aTabItem( EE_FEATURE_TAB ); | |||
2705 | ||||
2706 | // Converts to linesep = \n | |||
2707 | // Token LINE_SEP query, | |||
2708 | // since the MAC-Compiler makes something else from \n ! | |||
2709 | ||||
2710 | sal_Int32 nStart = 0; | |||
2711 | while ( nStart < aText.getLength() ) | |||
2712 | { | |||
2713 | sal_Int32 nEnd = aText.indexOf( LINE_SEP'\x0A', nStart ); | |||
2714 | if ( nEnd == -1 ) | |||
2715 | nEnd = aText.getLength(); // not dereference! | |||
2716 | ||||
2717 | // Start == End => empty line | |||
2718 | if ( nEnd > nStart ) | |||
2719 | { | |||
2720 | OUString aLine = aText.copy( nStart, nEnd-nStart ); | |||
2721 | sal_Int32 nExistingChars = aPaM.GetNode()->Len(); | |||
2722 | sal_Int32 nChars = nExistingChars + aLine.getLength(); | |||
2723 | if (nChars > MAXCHARSINPARA0x3FFF-16) | |||
2724 | { | |||
2725 | sal_Int32 nMaxNewChars = std::max<sal_Int32>(0, MAXCHARSINPARA0x3FFF-16 - nExistingChars); | |||
2726 | nEnd -= ( aLine.getLength() - nMaxNewChars ); // Then the characters end up in the next paragraph. | |||
2727 | aLine = aLine.copy( 0, nMaxNewChars ); // Delete the Rest... | |||
2728 | } | |||
2729 | if ( IsUndoEnabled() && !IsInUndo() ) | |||
2730 | InsertUndo(std::make_unique<EditUndoInsertChars>(pEditEngine, CreateEPaM(aPaM), aLine)); | |||
2731 | // Tabs ? | |||
2732 | if ( aLine.indexOf( '\t' ) == -1 ) | |||
2733 | aPaM = aEditDoc.InsertText( aPaM, aLine ); | |||
2734 | else | |||
2735 | { | |||
2736 | sal_Int32 nStart2 = 0; | |||
2737 | while ( nStart2 < aLine.getLength() ) | |||
2738 | { | |||
2739 | sal_Int32 nEnd2 = aLine.indexOf( "\t", nStart2 ); | |||
2740 | if ( nEnd2 == -1 ) | |||
2741 | nEnd2 = aLine.getLength(); // not dereference! | |||
2742 | ||||
2743 | if ( nEnd2 > nStart2 ) | |||
2744 | aPaM = aEditDoc.InsertText( aPaM, aLine.copy( nStart2, nEnd2-nStart2 ) ); | |||
2745 | if ( nEnd2 < aLine.getLength() ) | |||
2746 | { | |||
2747 | aPaM = aEditDoc.InsertFeature( aPaM, aTabItem ); | |||
2748 | } | |||
2749 | nStart2 = nEnd2+1; | |||
2750 | } | |||
2751 | } | |||
2752 | ParaPortion* pPortion = FindParaPortion( aPaM.GetNode() ); | |||
2753 | OSL_ENSURE( pPortion, "Blind Portion in InsertText" )do { if (true && (!(pPortion))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2753" ": "), "%s", "Blind Portion in InsertText"); } } while (false); | |||
2754 | ||||
2755 | if ( GetStatus().DoOnlineSpelling() ) | |||
2756 | { | |||
2757 | // now remove the Wrongs (red spell check marks) from both words... | |||
2758 | WrongList *pWrongs = aCurPaM.GetNode()->GetWrongList(); | |||
2759 | if (pWrongs && !pWrongs->empty()) | |||
2760 | pWrongs->ClearWrongs( aCurWord.Min().GetIndex(), aPaM.GetIndex(), aPaM.GetNode() ); | |||
2761 | // ... and mark both words as 'to be checked again' | |||
2762 | pPortion->MarkInvalid( aCurWord.Min().GetIndex(), aLine.getLength() ); | |||
2763 | } | |||
2764 | else | |||
2765 | pPortion->MarkInvalid( aCurPaM.GetIndex(), aLine.getLength() ); | |||
2766 | } | |||
2767 | if ( nEnd < aText.getLength() ) | |||
2768 | aPaM = ImpInsertParaBreak( aPaM ); | |||
2769 | ||||
2770 | nStart = nEnd+1; | |||
2771 | } | |||
2772 | ||||
2773 | UndoActionEnd(); | |||
2774 | ||||
2775 | TextModified(); | |||
2776 | return aPaM; | |||
2777 | } | |||
2778 | ||||
2779 | EditPaM ImpEditEngine::ImpFastInsertText( EditPaM aPaM, const OUString& rStr ) | |||
2780 | { | |||
2781 | OSL_ENSURE( rStr.indexOf( 0x0A ) == -1, "FastInsertText: Newline not allowed! ")do { if (true && (!(rStr.indexOf( 0x0A ) == -1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2781" ": "), "%s", "FastInsertText: Newline not allowed! " ); } } while (false); | |||
2782 | OSL_ENSURE( rStr.indexOf( 0x0D ) == -1, "FastInsertText: Newline not allowed! ")do { if (true && (!(rStr.indexOf( 0x0D ) == -1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2782" ": "), "%s", "FastInsertText: Newline not allowed! " ); } } while (false); | |||
2783 | OSL_ENSURE( rStr.indexOf( '\t' ) == -1, "FastInsertText: Newline not allowed! ")do { if (true && (!(rStr.indexOf( '\t' ) == -1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2783" ": "), "%s", "FastInsertText: Newline not allowed! " ); } } while (false); | |||
2784 | ||||
2785 | if ( ( aPaM.GetNode()->Len() + rStr.getLength() ) < MAXCHARSINPARA0x3FFF-16 ) | |||
2786 | { | |||
2787 | if ( IsUndoEnabled() && !IsInUndo() ) | |||
2788 | InsertUndo(std::make_unique<EditUndoInsertChars>(pEditEngine, CreateEPaM(aPaM), rStr)); | |||
2789 | ||||
2790 | aPaM = aEditDoc.InsertText( aPaM, rStr ); | |||
2791 | TextModified(); | |||
2792 | } | |||
2793 | else | |||
2794 | { | |||
2795 | aPaM = ImpInsertText( aPaM, rStr ); | |||
2796 | } | |||
2797 | ||||
2798 | return aPaM; | |||
2799 | } | |||
2800 | ||||
2801 | EditPaM ImpEditEngine::ImpInsertFeature(const EditSelection& rCurSel, const SfxPoolItem& rItem) | |||
2802 | { | |||
2803 | EditPaM aPaM; | |||
2804 | if ( rCurSel.HasRange() ) | |||
2805 | aPaM = ImpDeleteSelection( rCurSel ); | |||
2806 | else | |||
2807 | aPaM = rCurSel.Max(); | |||
2808 | ||||
2809 | if ( aPaM.GetIndex() >= SAL_MAX_INT32((sal_Int32) 0x7FFFFFFF)-1 ) | |||
2810 | return aPaM; | |||
2811 | ||||
2812 | if ( IsUndoEnabled() && !IsInUndo() ) | |||
2813 | InsertUndo(std::make_unique<EditUndoInsertFeature>(pEditEngine, CreateEPaM(aPaM), rItem)); | |||
2814 | aPaM = aEditDoc.InsertFeature( aPaM, rItem ); | |||
2815 | UpdateFields(); | |||
2816 | ||||
2817 | ParaPortion* pPortion = FindParaPortion( aPaM.GetNode() ); | |||
2818 | OSL_ENSURE( pPortion, "Blind Portion in InsertFeature" )do { if (true && (!(pPortion))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2818" ": "), "%s", "Blind Portion in InsertFeature"); } } while (false); | |||
2819 | pPortion->MarkInvalid( aPaM.GetIndex()-1, 1 ); | |||
2820 | ||||
2821 | TextModified(); | |||
2822 | ||||
2823 | return aPaM; | |||
2824 | } | |||
2825 | ||||
2826 | EditPaM ImpEditEngine::ImpInsertParaBreak( const EditSelection& rCurSel ) | |||
2827 | { | |||
2828 | EditPaM aPaM; | |||
2829 | if ( rCurSel.HasRange() ) | |||
2830 | aPaM = ImpDeleteSelection( rCurSel ); | |||
2831 | else | |||
2832 | aPaM = rCurSel.Max(); | |||
2833 | ||||
2834 | return ImpInsertParaBreak( aPaM ); | |||
2835 | } | |||
2836 | ||||
2837 | EditPaM ImpEditEngine::ImpInsertParaBreak( EditPaM& rPaM, bool bKeepEndingAttribs ) | |||
2838 | { | |||
2839 | if ( aEditDoc.Count() >= EE_PARA_MAX_COUNT((sal_Int32) 0x7FFFFFFF) ) | |||
2840 | { | |||
2841 | SAL_WARN( "editeng", "ImpEditEngine::ImpInsertParaBreak - can't process more than "do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "editeng")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "ImpEditEngine::ImpInsertParaBreak - can't process more than " << ((sal_Int32) 0x7FFFFFFF) << " paragraphs!") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng" ), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2842" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "ImpEditEngine::ImpInsertParaBreak - can't process more than " << ((sal_Int32) 0x7FFFFFFF) << " paragraphs!"), 0 ); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ImpEditEngine::ImpInsertParaBreak - can't process more than " << ((sal_Int32) 0x7FFFFFFF) << " paragraphs!"; :: sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2842" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "ImpEditEngine::ImpInsertParaBreak - can't process more than " << ((sal_Int32) 0x7FFFFFFF) << " paragraphs!") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng" ), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2842" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "ImpEditEngine::ImpInsertParaBreak - can't process more than " << ((sal_Int32) 0x7FFFFFFF) << " paragraphs!"), 0 ); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ImpEditEngine::ImpInsertParaBreak - can't process more than " << ((sal_Int32) 0x7FFFFFFF) << " paragraphs!"; :: sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2842" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false) | |||
2842 | << EE_PARA_MAX_COUNT << " paragraphs!")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "editeng")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "ImpEditEngine::ImpInsertParaBreak - can't process more than " << ((sal_Int32) 0x7FFFFFFF) << " paragraphs!") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng" ), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2842" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "ImpEditEngine::ImpInsertParaBreak - can't process more than " << ((sal_Int32) 0x7FFFFFFF) << " paragraphs!"), 0 ); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ImpEditEngine::ImpInsertParaBreak - can't process more than " << ((sal_Int32) 0x7FFFFFFF) << " paragraphs!"; :: sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2842" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "ImpEditEngine::ImpInsertParaBreak - can't process more than " << ((sal_Int32) 0x7FFFFFFF) << " paragraphs!") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng" ), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2842" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "ImpEditEngine::ImpInsertParaBreak - can't process more than " << ((sal_Int32) 0x7FFFFFFF) << " paragraphs!"), 0 ); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ImpEditEngine::ImpInsertParaBreak - can't process more than " << ((sal_Int32) 0x7FFFFFFF) << " paragraphs!"; :: sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2842" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
2843 | return rPaM; | |||
2844 | } | |||
2845 | ||||
2846 | if ( IsUndoEnabled() && !IsInUndo() ) | |||
2847 | InsertUndo(std::make_unique<EditUndoSplitPara>(pEditEngine, aEditDoc.GetPos(rPaM.GetNode()), rPaM.GetIndex())); | |||
2848 | ||||
2849 | EditPaM aPaM( aEditDoc.InsertParaBreak( rPaM, bKeepEndingAttribs ) ); | |||
2850 | ||||
2851 | if ( GetStatus().DoOnlineSpelling() ) | |||
2852 | { | |||
2853 | sal_Int32 nEnd = rPaM.GetNode()->Len(); | |||
2854 | aPaM.GetNode()->CreateWrongList(); | |||
2855 | WrongList* pLWrongs = rPaM.GetNode()->GetWrongList(); | |||
2856 | WrongList* pRWrongs = aPaM.GetNode()->GetWrongList(); | |||
2857 | // take over misspelled words: | |||
2858 | for (auto & elem : *pLWrongs) | |||
2859 | { | |||
2860 | // Correct only if really a word gets overlapped in the process of | |||
2861 | // Spell checking | |||
2862 | if (elem.mnStart > o3tl::make_unsigned(nEnd)) | |||
2863 | { | |||
2864 | pRWrongs->push_back(elem); | |||
2865 | editeng::MisspellRange& rRWrong = pRWrongs->back(); | |||
2866 | rRWrong.mnStart = rRWrong.mnStart - nEnd; | |||
2867 | rRWrong.mnEnd = rRWrong.mnEnd - nEnd; | |||
2868 | } | |||
2869 | else if (elem.mnStart < o3tl::make_unsigned(nEnd) && elem.mnEnd > o3tl::make_unsigned(nEnd)) | |||
2870 | elem.mnEnd = nEnd; | |||
2871 | } | |||
2872 | sal_Int32 nInv = nEnd ? nEnd-1 : nEnd; | |||
2873 | if ( nEnd ) | |||
2874 | pLWrongs->SetInvalidRange(nInv, nEnd); | |||
2875 | else | |||
2876 | pLWrongs->SetValid(); | |||
2877 | pRWrongs->SetValid(); | |||
2878 | pRWrongs->SetInvalidRange(0, 1); // Only test the first word | |||
2879 | } | |||
2880 | ||||
2881 | ParaPortion* pPortion = FindParaPortion( rPaM.GetNode() ); | |||
2882 | OSL_ENSURE( pPortion, "Blind Portion in ImpInsertParaBreak" )do { if (true && (!(pPortion))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2882" ": "), "%s", "Blind Portion in ImpInsertParaBreak" ); } } while (false); | |||
2883 | pPortion->MarkInvalid( rPaM.GetIndex(), 0 ); | |||
2884 | ||||
2885 | // Optimization: Do not place unnecessarily many getPos to Listen! | |||
2886 | // Here, as in undo, but also in all other methods. | |||
2887 | sal_Int32 nPos = GetParaPortions().GetPos( pPortion ); | |||
2888 | ParaPortion* pNewPortion = new ParaPortion( aPaM.GetNode() ); | |||
2889 | GetParaPortions().Insert(nPos+1, std::unique_ptr<ParaPortion>(pNewPortion)); | |||
2890 | ParaAttribsChanged( pNewPortion->GetNode() ); | |||
2891 | if ( IsCallParaInsertedOrDeleted() ) | |||
2892 | GetEditEnginePtr()->ParagraphInserted( nPos+1 ); | |||
2893 | ||||
2894 | CursorMoved( rPaM.GetNode() ); // if empty Attributes have emerged. | |||
2895 | TextModified(); | |||
2896 | return aPaM; | |||
2897 | } | |||
2898 | ||||
2899 | EditPaM ImpEditEngine::ImpFastInsertParagraph( sal_Int32 nPara ) | |||
2900 | { | |||
2901 | if ( IsUndoEnabled() && !IsInUndo() ) | |||
2902 | { | |||
2903 | if ( nPara ) | |||
2904 | { | |||
2905 | OSL_ENSURE( aEditDoc.GetObject( nPara-1 ), "FastInsertParagraph: Prev does not exist" )do { if (true && (!(aEditDoc.GetObject( nPara-1 )))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2905" ": "), "%s", "FastInsertParagraph: Prev does not exist" ); } } while (false); | |||
2906 | InsertUndo(std::make_unique<EditUndoSplitPara>(pEditEngine, nPara-1, aEditDoc.GetObject( nPara-1 )->Len())); | |||
2907 | } | |||
2908 | else | |||
2909 | InsertUndo(std::make_unique<EditUndoSplitPara>(pEditEngine, 0, 0)); | |||
2910 | } | |||
2911 | ||||
2912 | ContentNode* pNode = new ContentNode( aEditDoc.GetItemPool() ); | |||
2913 | // If flat mode, then later no Font is set: | |||
2914 | pNode->GetCharAttribs().GetDefFont() = aEditDoc.GetDefFont(); | |||
2915 | ||||
2916 | if ( GetStatus().DoOnlineSpelling() ) | |||
2917 | pNode->CreateWrongList(); | |||
2918 | ||||
2919 | aEditDoc.Insert(nPara, pNode); | |||
2920 | ||||
2921 | GetParaPortions().Insert(nPara, std::make_unique<ParaPortion>( pNode )); | |||
2922 | if ( IsCallParaInsertedOrDeleted() ) | |||
2923 | GetEditEnginePtr()->ParagraphInserted( nPara ); | |||
2924 | ||||
2925 | return EditPaM( pNode, 0 ); | |||
2926 | } | |||
2927 | ||||
2928 | EditPaM ImpEditEngine::InsertParaBreak(const EditSelection& rCurSel) | |||
2929 | { | |||
2930 | EditPaM aPaM(ImpInsertParaBreak(rCurSel)); | |||
2931 | if ( aStatus.DoAutoIndenting() ) | |||
2932 | { | |||
2933 | sal_Int32 nPara = aEditDoc.GetPos( aPaM.GetNode() ); | |||
2934 | OSL_ENSURE( nPara > 0, "AutoIndenting: Error!" )do { if (true && (!(nPara > 0))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2934" ": "), "%s", "AutoIndenting: Error!"); } } while ( false); | |||
2935 | const OUString aPrevParaText( GetEditDoc().GetParaAsString( nPara-1 ) ); | |||
2936 | sal_Int32 n = 0; | |||
2937 | while ( ( n < aPrevParaText.getLength() ) && | |||
2938 | ( ( aPrevParaText[n] == ' ' ) || ( aPrevParaText[n] == '\t' ) ) ) | |||
2939 | { | |||
2940 | if ( aPrevParaText[n] == '\t' ) | |||
2941 | aPaM = ImpInsertFeature( aPaM, SfxVoidItem( EE_FEATURE_TAB ) ); | |||
2942 | else | |||
2943 | aPaM = ImpInsertText( aPaM, OUString(aPrevParaText[n]) ); | |||
2944 | n++; | |||
2945 | } | |||
2946 | ||||
2947 | } | |||
2948 | return aPaM; | |||
2949 | } | |||
2950 | ||||
2951 | EditPaM ImpEditEngine::InsertTab(const EditSelection& rCurSel) | |||
2952 | { | |||
2953 | EditPaM aPaM( ImpInsertFeature(rCurSel, SfxVoidItem(EE_FEATURE_TAB ))); | |||
2954 | return aPaM; | |||
2955 | } | |||
2956 | ||||
2957 | EditPaM ImpEditEngine::InsertField(const EditSelection& rCurSel, const SvxFieldItem& rFld) | |||
2958 | { | |||
2959 | return ImpInsertFeature(rCurSel, rFld); | |||
2960 | } | |||
2961 | ||||
2962 | bool ImpEditEngine::UpdateFields() | |||
2963 | { | |||
2964 | bool bChanges = false; | |||
2965 | sal_Int32 nParas = GetEditDoc().Count(); | |||
2966 | for ( sal_Int32 nPara = 0; nPara < nParas; nPara++ ) | |||
2967 | { | |||
2968 | bool bChangesInPara = false; | |||
2969 | ContentNode* pNode = GetEditDoc().GetObject( nPara ); | |||
2970 | OSL_ENSURE( pNode, "NULL-Pointer in Doc" )do { if (true && (!(pNode))) { sal_detail_logFormat(( SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "2970" ": "), "%s", "NULL-Pointer in Doc"); } } while (false ); | |||
2971 | CharAttribList::AttribsType& rAttribs = pNode->GetCharAttribs().GetAttribs(); | |||
2972 | for (std::unique_ptr<EditCharAttrib> & rAttrib : rAttribs) | |||
2973 | { | |||
2974 | EditCharAttrib& rAttr = *rAttrib; | |||
2975 | if (rAttr.Which() == EE_FEATURE_FIELD) | |||
2976 | { | |||
2977 | EditCharAttribField& rField = static_cast<EditCharAttribField&>(rAttr); | |||
2978 | std::unique_ptr<EditCharAttribField> pCurrent(new EditCharAttribField(rField)); | |||
2979 | rField.Reset(); | |||
2980 | ||||
2981 | if (!aStatus.MarkNonUrlFields() && !aStatus.MarkUrlFields()) | |||
2982 | ; // nothing marked | |||
2983 | else if (aStatus.MarkNonUrlFields() && aStatus.MarkUrlFields()) | |||
2984 | rField.GetFieldColor() = GetColorConfig().GetColorValue( svtools::WRITERFIELDSHADINGS ).nColor; | |||
2985 | else | |||
2986 | { | |||
2987 | bool bURL = false; | |||
2988 | if (const SvxFieldItem* pFieldItem = dynamic_cast<const SvxFieldItem*>(rField.GetItem())) | |||
2989 | { | |||
2990 | if (const SvxFieldData* pFieldData = pFieldItem->GetField()) | |||
2991 | bURL = (dynamic_cast<const SvxURLField* >(pFieldData) != nullptr); | |||
2992 | } | |||
2993 | if ((bURL && aStatus.MarkUrlFields()) || (!bURL && aStatus.MarkNonUrlFields())) | |||
2994 | rField.GetFieldColor() = GetColorConfig().GetColorValue( svtools::WRITERFIELDSHADINGS ).nColor; | |||
2995 | } | |||
2996 | ||||
2997 | const OUString aFldValue = | |||
2998 | GetEditEnginePtr()->CalcFieldValue( | |||
2999 | static_cast<const SvxFieldItem&>(*rField.GetItem()), | |||
3000 | nPara, rField.GetStart(), rField.GetTextColor(), rField.GetFieldColor()); | |||
3001 | ||||
3002 | rField.SetFieldValue(aFldValue); | |||
3003 | if (rField != *pCurrent) | |||
3004 | { | |||
3005 | bChanges = true; | |||
3006 | bChangesInPara = true; | |||
3007 | } | |||
3008 | } | |||
3009 | } | |||
3010 | if ( bChangesInPara ) | |||
3011 | { | |||
3012 | // If possible be more precise when invalidate. | |||
3013 | ParaPortion* pPortion = GetParaPortions()[nPara]; | |||
3014 | OSL_ENSURE( pPortion, "NULL-Pointer in Doc" )do { if (true && (!(pPortion))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3014" ": "), "%s", "NULL-Pointer in Doc"); } } while (false ); | |||
3015 | pPortion->MarkSelectionInvalid( 0 ); | |||
3016 | } | |||
3017 | } | |||
3018 | return bChanges; | |||
3019 | } | |||
3020 | ||||
3021 | EditPaM ImpEditEngine::InsertLineBreak(const EditSelection& aCurSel) | |||
3022 | { | |||
3023 | EditPaM aPaM( ImpInsertFeature( aCurSel, SfxVoidItem( EE_FEATURE_LINEBR ) ) ); | |||
3024 | return aPaM; | |||
3025 | } | |||
3026 | ||||
3027 | ||||
3028 | // Helper functions | |||
3029 | ||||
3030 | tools::Rectangle ImpEditEngine::PaMtoEditCursor( EditPaM aPaM, GetCursorFlags nFlags ) | |||
3031 | { | |||
3032 | OSL_ENSURE( GetUpdateMode(), "Must not be reached when Update=FALSE: PaMtoEditCursor" )do { if (true && (!(GetUpdateMode()))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3032" ": "), "%s", "Must not be reached when Update=FALSE: PaMtoEditCursor" ); } } while (false); | |||
3033 | ||||
3034 | tools::Rectangle aEditCursor; | |||
3035 | long nY = 0; | |||
3036 | for ( sal_Int32 nPortion = 0; nPortion < GetParaPortions().Count(); nPortion++ ) | |||
3037 | { | |||
3038 | ParaPortion* pPortion = GetParaPortions()[nPortion]; | |||
3039 | ContentNode* pNode = pPortion->GetNode(); | |||
3040 | OSL_ENSURE( pNode, "Invalid Node in Portion!" )do { if (true && (!(pNode))) { sal_detail_logFormat(( SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3040" ": "), "%s", "Invalid Node in Portion!"); } } while (false); | |||
3041 | if ( pNode != aPaM.GetNode() ) | |||
3042 | { | |||
3043 | nY += pPortion->GetHeight(); | |||
3044 | } | |||
3045 | else | |||
3046 | { | |||
3047 | aEditCursor = GetEditCursor( pPortion, aPaM.GetIndex(), nFlags ); | |||
3048 | aEditCursor.AdjustTop(nY ); | |||
3049 | aEditCursor.AdjustBottom(nY ); | |||
3050 | return aEditCursor; | |||
3051 | } | |||
3052 | } | |||
3053 | OSL_FAIL( "Portion not found!" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3053" ": "), "%s", "Portion not found!"); } } while (false ); | |||
3054 | return aEditCursor; | |||
3055 | } | |||
3056 | ||||
3057 | EditPaM ImpEditEngine::GetPaM( Point aDocPos, bool bSmart ) | |||
3058 | { | |||
3059 | OSL_ENSURE( GetUpdateMode(), "Must not be reached when Update=FALSE: GetPaM" )do { if (true && (!(GetUpdateMode()))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3059" ": "), "%s", "Must not be reached when Update=FALSE: GetPaM" ); } } while (false); | |||
3060 | ||||
3061 | long nY = 0; | |||
3062 | EditPaM aPaM; | |||
3063 | sal_Int32 nPortion; | |||
3064 | for ( nPortion = 0; nPortion < GetParaPortions().Count(); nPortion++ ) | |||
3065 | { | |||
3066 | ParaPortion* pPortion = GetParaPortions()[nPortion]; | |||
3067 | const long nTmpHeight = pPortion->GetHeight(); // should also be correct for !bVisible! | |||
3068 | nY += nTmpHeight; | |||
3069 | if ( nY > aDocPos.Y() ) | |||
3070 | { | |||
3071 | nY -= nTmpHeight; | |||
3072 | aDocPos.AdjustY( -nY ); | |||
3073 | // Skip invisible Portions: | |||
3074 | while ( pPortion && !pPortion->IsVisible() ) | |||
3075 | { | |||
3076 | nPortion++; | |||
3077 | pPortion = GetParaPortions().SafeGetObject( nPortion ); | |||
3078 | } | |||
3079 | SAL_WARN_IF(!pPortion, "editeng", "worrying lack of any visible paragraph")do { if (true && (!pPortion)) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "editeng")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "worrying lack of any visible paragraph" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng" ), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3079" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "worrying lack of any visible paragraph" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "worrying lack of any visible paragraph"; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3079" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "worrying lack of any visible paragraph") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng") , ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3079" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "worrying lack of any visible paragraph" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "worrying lack of any visible paragraph"; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3079" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
3080 | if (!pPortion) | |||
3081 | return aPaM; | |||
3082 | return GetPaM(pPortion, aDocPos, bSmart); | |||
3083 | ||||
3084 | } | |||
3085 | } | |||
3086 | // Then search for the last visible: | |||
3087 | nPortion = GetParaPortions().Count()-1; | |||
3088 | while ( nPortion && !GetParaPortions()[nPortion]->IsVisible() ) | |||
3089 | nPortion--; | |||
3090 | ||||
3091 | OSL_ENSURE( GetParaPortions()[nPortion]->IsVisible(), "No visible paragraph found: GetPaM" )do { if (true && (!(GetParaPortions()[nPortion]->IsVisible ()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3091" ": "), "%s", "No visible paragraph found: GetPaM" ); } } while (false); | |||
3092 | aPaM.SetNode( GetParaPortions()[nPortion]->GetNode() ); | |||
3093 | aPaM.SetIndex( GetParaPortions()[nPortion]->GetNode()->Len() ); | |||
3094 | return aPaM; | |||
3095 | } | |||
3096 | ||||
3097 | sal_uInt32 ImpEditEngine::GetTextHeight() const | |||
3098 | { | |||
3099 | OSL_ENSURE( GetUpdateMode(), "Should not be used for Update=FALSE: GetTextHeight" )do { if (true && (!(GetUpdateMode()))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3099" ": "), "%s", "Should not be used for Update=FALSE: GetTextHeight" ); } } while (false); | |||
3100 | OSL_ENSURE( IsFormatted() || IsFormatting(), "GetTextHeight: Not formatted" )do { if (true && (!(IsFormatted() || IsFormatting())) ) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3100" ": "), "%s", "GetTextHeight: Not formatted"); } } while (false); | |||
3101 | return nCurTextHeight; | |||
3102 | } | |||
3103 | ||||
3104 | sal_uInt32 ImpEditEngine::CalcTextWidth( bool bIgnoreExtraSpace ) | |||
3105 | { | |||
3106 | // If still not formatted and not in the process. | |||
3107 | // Will be brought in the formatting for AutoPageSize. | |||
3108 | if ( !IsFormatted() && !IsFormatting() ) | |||
3109 | FormatDoc(); | |||
3110 | ||||
3111 | sal_uInt32 nMaxWidth = 0; | |||
3112 | ||||
3113 | // Over all the paragraphs ... | |||
3114 | ||||
3115 | sal_Int32 nParas = GetParaPortions().Count(); | |||
3116 | for ( sal_Int32 nPara = 0; nPara < nParas; nPara++ ) | |||
3117 | { | |||
3118 | nMaxWidth = std::max(nMaxWidth, CalcParaWidth(nPara, bIgnoreExtraSpace)); | |||
3119 | } | |||
3120 | ||||
3121 | return nMaxWidth; | |||
3122 | } | |||
3123 | ||||
3124 | sal_uInt32 ImpEditEngine::CalcParaWidth( sal_Int32 nPara, bool bIgnoreExtraSpace ) | |||
3125 | { | |||
3126 | // If still not formatted and not in the process. | |||
3127 | // Will be brought in the formatting for AutoPageSize. | |||
3128 | if ( !IsFormatted() && !IsFormatting() ) | |||
3129 | FormatDoc(); | |||
3130 | ||||
3131 | long nMaxWidth = 0; | |||
3132 | ||||
3133 | // Over all the paragraphs ... | |||
3134 | ||||
3135 | OSL_ENSURE( 0 <= nPara && nPara < GetParaPortions().Count(), "CalcParaWidth: Out of range" )do { if (true && (!(0 <= nPara && nPara < GetParaPortions().Count()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3135" ": "), "%s", "CalcParaWidth: Out of range"); } } while (false); | |||
3136 | ParaPortion* pPortion = GetParaPortions()[nPara]; | |||
3137 | if ( pPortion && pPortion->IsVisible() ) | |||
3138 | { | |||
3139 | const SvxLRSpaceItem& rLRItem = GetLRSpaceItem( pPortion->GetNode() ); | |||
3140 | sal_Int32 nSpaceBeforeAndMinLabelWidth = GetSpaceBeforeAndMinLabelWidth( pPortion->GetNode() ); | |||
3141 | ||||
3142 | ||||
3143 | // On the lines of the paragraph ... | |||
3144 | ||||
3145 | sal_Int32 nLines = pPortion->GetLines().Count(); | |||
3146 | for ( sal_Int32 nLine = 0; nLine < nLines; nLine++ ) | |||
3147 | { | |||
3148 | EditLine& rLine = pPortion->GetLines()[nLine]; | |||
3149 | // nCurWidth = pLine->GetStartPosX(); | |||
3150 | // For Center- or Right- alignment it depends on the paper | |||
3151 | // width, here not preferred. I general, it is best not leave it | |||
3152 | // to StartPosX, also the right indents have to be taken into | |||
3153 | // account! | |||
3154 | long nCurWidth = GetXValue( rLRItem.GetTextLeft() + nSpaceBeforeAndMinLabelWidth ); | |||
3155 | if ( nLine == 0 ) | |||
3156 | { | |||
3157 | long nFI = GetXValue( rLRItem.GetTextFirstLineOffset() ); | |||
3158 | nCurWidth -= nFI; | |||
3159 | if ( pPortion->GetBulletX() > nCurWidth ) | |||
3160 | { | |||
3161 | nCurWidth += nFI; // LI? | |||
3162 | if ( pPortion->GetBulletX() > nCurWidth ) | |||
3163 | nCurWidth = pPortion->GetBulletX(); | |||
3164 | } | |||
3165 | } | |||
3166 | nCurWidth += GetXValue( rLRItem.GetRight() ); | |||
3167 | nCurWidth += CalcLineWidth( pPortion, &rLine, bIgnoreExtraSpace ); | |||
3168 | if ( nCurWidth > nMaxWidth ) | |||
3169 | { | |||
3170 | nMaxWidth = nCurWidth; | |||
3171 | } | |||
3172 | } | |||
3173 | } | |||
3174 | ||||
3175 | nMaxWidth++; // widen it, because in CreateLines for >= is wrapped. | |||
3176 | return static_cast<sal_uInt32>(nMaxWidth); | |||
3177 | } | |||
3178 | ||||
3179 | sal_uInt32 ImpEditEngine::CalcLineWidth( ParaPortion* pPortion, EditLine* pLine, bool bIgnoreExtraSpace ) | |||
3180 | { | |||
3181 | sal_Int32 nPara = GetEditDoc().GetPos( pPortion->GetNode() ); | |||
3182 | ||||
3183 | // #114278# Saving both layout mode and language (since I'm | |||
3184 | // potentially changing both) | |||
3185 | GetRefDevice()->Push( PushFlags::TEXTLAYOUTMODE|PushFlags::TEXTLANGUAGE ); | |||
3186 | ||||
3187 | ImplInitLayoutMode( GetRefDevice(), nPara, -1 ); | |||
3188 | ||||
3189 | SvxAdjust eJustification = GetJustification( nPara ); | |||
3190 | ||||
3191 | // Calculation of the width without the Indents ... | |||
3192 | sal_uInt32 nWidth = 0; | |||
3193 | sal_Int32 nPos = pLine->GetStart(); | |||
3194 | for ( sal_Int32 nTP = pLine->GetStartPortion(); nTP <= pLine->GetEndPortion(); nTP++ ) | |||
3195 | { | |||
3196 | const TextPortion& rTextPortion = pPortion->GetTextPortions()[nTP]; | |||
3197 | switch ( rTextPortion.GetKind() ) | |||
3198 | { | |||
3199 | case PortionKind::FIELD: | |||
3200 | case PortionKind::HYPHENATOR: | |||
3201 | case PortionKind::TAB: | |||
3202 | { | |||
3203 | nWidth += rTextPortion.GetSize().Width(); | |||
3204 | } | |||
3205 | break; | |||
3206 | case PortionKind::TEXT: | |||
3207 | { | |||
3208 | if ( ( eJustification != SvxAdjust::Block ) || ( !bIgnoreExtraSpace ) ) | |||
3209 | { | |||
3210 | nWidth += rTextPortion.GetSize().Width(); | |||
3211 | } | |||
3212 | else | |||
3213 | { | |||
3214 | SvxFont aTmpFont( pPortion->GetNode()->GetCharAttribs().GetDefFont() ); | |||
3215 | SeekCursor( pPortion->GetNode(), nPos+1, aTmpFont ); | |||
3216 | aTmpFont.SetPhysFont( GetRefDevice() ); | |||
3217 | ImplInitDigitMode(GetRefDevice(), aTmpFont.GetLanguage()); | |||
3218 | nWidth += aTmpFont.QuickGetTextSize( GetRefDevice(), pPortion->GetNode()->GetString(), nPos, rTextPortion.GetLen() ).Width(); | |||
3219 | } | |||
3220 | } | |||
3221 | break; | |||
3222 | case PortionKind::LINEBREAK: break; | |||
3223 | } | |||
3224 | nPos = nPos + rTextPortion.GetLen(); | |||
3225 | } | |||
3226 | ||||
3227 | GetRefDevice()->Pop(); | |||
3228 | ||||
3229 | return nWidth; | |||
3230 | } | |||
3231 | ||||
3232 | sal_uInt32 ImpEditEngine::GetTextHeightNTP() const | |||
3233 | { | |||
3234 | DBG_ASSERT( GetUpdateMode(), "Should not be used for Update=FALSE: GetTextHeight" )do { if (true && (!(GetUpdateMode()))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3234" ": "), "%s", "Should not be used for Update=FALSE: GetTextHeight" ); } } while (false); | |||
3235 | DBG_ASSERT( IsFormatted() || IsFormatting(), "GetTextHeight: Not formatted" )do { if (true && (!(IsFormatted() || IsFormatting())) ) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools" ), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3235" ": "), "%s", "GetTextHeight: Not formatted"); } } while (false); | |||
3236 | return nCurTextHeightNTP; | |||
3237 | } | |||
3238 | ||||
3239 | sal_uInt32 ImpEditEngine::CalcTextHeight( sal_uInt32* pHeightNTP ) | |||
3240 | { | |||
3241 | OSL_ENSURE( GetUpdateMode(), "Should not be used when Update=FALSE: CalcTextHeight" )do { if (true && (!(GetUpdateMode()))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3241" ": "), "%s", "Should not be used when Update=FALSE: CalcTextHeight" ); } } while (false); | |||
3242 | sal_uInt32 nY = 0; | |||
3243 | sal_uInt32 nPH; | |||
3244 | sal_uInt32 nEmptyHeight = 0; | |||
3245 | for ( sal_Int32 nPortion = 0; nPortion < GetParaPortions().Count(); nPortion++ ) { | |||
3246 | ParaPortion* pPortion = GetParaPortions()[nPortion]; | |||
3247 | nPH = pPortion->GetHeight(); | |||
3248 | nY += nPH; | |||
3249 | if( pHeightNTP ) { | |||
3250 | if ( pPortion->IsEmpty() ) | |||
3251 | nEmptyHeight += nPH; | |||
3252 | else | |||
3253 | nEmptyHeight = 0; | |||
3254 | } | |||
3255 | } | |||
3256 | ||||
3257 | if ( pHeightNTP ) | |||
3258 | *pHeightNTP = nY - nEmptyHeight; | |||
3259 | ||||
3260 | return nY; | |||
3261 | } | |||
3262 | ||||
3263 | sal_Int32 ImpEditEngine::GetLineCount( sal_Int32 nParagraph ) const | |||
3264 | { | |||
3265 | OSL_ENSURE( 0 <= nParagraph && nParagraph < GetParaPortions().Count(), "GetLineCount: Out of range" )do { if (true && (!(0 <= nParagraph && nParagraph < GetParaPortions().Count()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3265" ": "), "%s", "GetLineCount: Out of range"); } } while (false); | |||
3266 | const ParaPortion* pPPortion = GetParaPortions().SafeGetObject( nParagraph ); | |||
3267 | OSL_ENSURE( pPPortion, "Paragraph not found: GetLineCount" )do { if (true && (!(pPPortion))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3267" ": "), "%s", "Paragraph not found: GetLineCount") ; } } while (false); | |||
3268 | if ( pPPortion ) | |||
3269 | return pPPortion->GetLines().Count(); | |||
3270 | ||||
3271 | return -1; | |||
3272 | } | |||
3273 | ||||
3274 | sal_Int32 ImpEditEngine::GetLineLen( sal_Int32 nParagraph, sal_Int32 nLine ) const | |||
3275 | { | |||
3276 | OSL_ENSURE( 0 <= nParagraph && nParagraph < GetParaPortions().Count(), "GetLineLen: Out of range" )do { if (true && (!(0 <= nParagraph && nParagraph < GetParaPortions().Count()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3276" ": "), "%s", "GetLineLen: Out of range"); } } while (false); | |||
3277 | const ParaPortion* pPPortion = GetParaPortions().SafeGetObject( nParagraph ); | |||
3278 | OSL_ENSURE( pPPortion, "Paragraph not found: GetLineLen" )do { if (true && (!(pPPortion))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3278" ": "), "%s", "Paragraph not found: GetLineLen"); } } while (false); | |||
3279 | if ( pPPortion && ( nLine < pPPortion->GetLines().Count() ) ) | |||
3280 | { | |||
3281 | const EditLine& rLine = pPPortion->GetLines()[nLine]; | |||
3282 | return rLine.GetLen(); | |||
3283 | } | |||
3284 | ||||
3285 | return -1; | |||
3286 | } | |||
3287 | ||||
3288 | void ImpEditEngine::GetLineBoundaries( /*out*/sal_Int32 &rStart, /*out*/sal_Int32 &rEnd, sal_Int32 nParagraph, sal_Int32 nLine ) const | |||
3289 | { | |||
3290 | OSL_ENSURE( 0 <= nParagraph && nParagraph < GetParaPortions().Count(), "GetLineCount: Out of range" )do { if (true && (!(0 <= nParagraph && nParagraph < GetParaPortions().Count()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3290" ": "), "%s", "GetLineCount: Out of range"); } } while (false); | |||
3291 | const ParaPortion* pPPortion = GetParaPortions().SafeGetObject( nParagraph ); | |||
3292 | OSL_ENSURE( pPPortion, "Paragraph not found: GetLineBoundaries" )do { if (true && (!(pPPortion))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3292" ": "), "%s", "Paragraph not found: GetLineBoundaries" ); } } while (false); | |||
3293 | rStart = rEnd = -1; // default values in case of error | |||
3294 | if ( pPPortion && ( nLine < pPPortion->GetLines().Count() ) ) | |||
3295 | { | |||
3296 | const EditLine& rLine = pPPortion->GetLines()[nLine]; | |||
3297 | rStart = rLine.GetStart(); | |||
3298 | rEnd = rLine.GetEnd(); | |||
3299 | } | |||
3300 | } | |||
3301 | ||||
3302 | sal_Int32 ImpEditEngine::GetLineNumberAtIndex( sal_Int32 nPara, sal_Int32 nIndex ) const | |||
3303 | { | |||
3304 | sal_Int32 nLineNo = -1; | |||
3305 | const ContentNode* pNode = GetEditDoc().GetObject( nPara ); | |||
3306 | OSL_ENSURE( pNode, "GetLineNumberAtIndex: invalid paragraph index" )do { if (true && (!(pNode))) { sal_detail_logFormat(( SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3306" ": "), "%s", "GetLineNumberAtIndex: invalid paragraph index" ); } } while (false); | |||
3307 | if (pNode) | |||
3308 | { | |||
3309 | // we explicitly allow for the index to point at the character right behind the text | |||
3310 | const bool bValidIndex = /*0 <= nIndex &&*/ nIndex <= pNode->Len(); | |||
3311 | OSL_ENSURE( bValidIndex, "GetLineNumberAtIndex: invalid index" )do { if (true && (!(bValidIndex))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3311" ": "), "%s", "GetLineNumberAtIndex: invalid index" ); } } while (false); | |||
3312 | const sal_Int32 nLineCount = GetLineCount( nPara ); | |||
3313 | if (nIndex == pNode->Len()) | |||
3314 | nLineNo = nLineCount > 0 ? nLineCount - 1 : 0; | |||
3315 | else if (bValidIndex) // nIndex < pNode->Len() | |||
3316 | { | |||
3317 | sal_Int32 nStart = -1, nEnd = -1; | |||
3318 | for (sal_Int32 i = 0; i < nLineCount && nLineNo == -1; ++i) | |||
3319 | { | |||
3320 | GetLineBoundaries( nStart, nEnd, nPara, i ); | |||
3321 | if (nStart >= 0 && nStart <= nIndex && nEnd >= 0 && nIndex < nEnd) | |||
3322 | nLineNo = i; | |||
3323 | } | |||
3324 | } | |||
3325 | } | |||
3326 | return nLineNo; | |||
3327 | } | |||
3328 | ||||
3329 | sal_uInt16 ImpEditEngine::GetLineHeight( sal_Int32 nParagraph, sal_Int32 nLine ) | |||
3330 | { | |||
3331 | OSL_ENSURE( 0 <= nParagraph && nParagraph < GetParaPortions().Count(), "GetLineCount: Out of range" )do { if (true && (!(0 <= nParagraph && nParagraph < GetParaPortions().Count()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3331" ": "), "%s", "GetLineCount: Out of range"); } } while (false); | |||
3332 | ParaPortion* pPPortion = GetParaPortions().SafeGetObject( nParagraph ); | |||
3333 | OSL_ENSURE( pPPortion, "Paragraph not found: GetLineHeight" )do { if (true && (!(pPPortion))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3333" ": "), "%s", "Paragraph not found: GetLineHeight" ); } } while (false); | |||
3334 | if ( pPPortion && ( nLine < pPPortion->GetLines().Count() ) ) | |||
3335 | { | |||
3336 | const EditLine& rLine = pPPortion->GetLines()[nLine]; | |||
3337 | return rLine.GetHeight(); | |||
3338 | } | |||
3339 | ||||
3340 | return 0xFFFF; | |||
3341 | } | |||
3342 | ||||
3343 | sal_uInt32 ImpEditEngine::GetParaHeight( sal_Int32 nParagraph ) | |||
3344 | { | |||
3345 | sal_uInt32 nHeight = 0; | |||
3346 | ||||
3347 | ParaPortion* pPPortion = GetParaPortions().SafeGetObject( nParagraph ); | |||
3348 | OSL_ENSURE( pPPortion, "Paragraph not found: GetParaHeight" )do { if (true && (!(pPPortion))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3348" ": "), "%s", "Paragraph not found: GetParaHeight" ); } } while (false); | |||
3349 | ||||
3350 | if ( pPPortion ) | |||
3351 | nHeight = pPPortion->GetHeight(); | |||
3352 | ||||
3353 | return nHeight; | |||
3354 | } | |||
3355 | ||||
3356 | void ImpEditEngine::UpdateSelections() | |||
3357 | { | |||
3358 | // Check whether one of the selections is at a deleted node... | |||
3359 | // If the node is valid, the index has yet to be examined! | |||
3360 | for (EditView* pView : aEditViews) | |||
3361 | { | |||
3362 | EditSelection aCurSel( pView->pImpEditView->GetEditSelection() ); | |||
3363 | bool bChanged = false; | |||
3364 | for (const std::unique_ptr<DeletedNodeInfo> & aDeletedNode : aDeletedNodes) | |||
3365 | { | |||
3366 | const DeletedNodeInfo& rInf = *aDeletedNode; | |||
3367 | if ( ( aCurSel.Min().GetNode() == rInf.GetNode() ) || | |||
3368 | ( aCurSel.Max().GetNode() == rInf.GetNode() ) ) | |||
3369 | { | |||
3370 | // Use ParaPortions, as now also hidden paragraphs have to be | |||
3371 | // taken into account! | |||
3372 | sal_Int32 nPara = rInf.GetPosition(); | |||
3373 | if (!GetParaPortions().SafeGetObject(nPara)) // Last paragraph | |||
3374 | { | |||
3375 | nPara = GetParaPortions().Count()-1; | |||
3376 | } | |||
3377 | assert(GetParaPortions()[nPara] && "Empty Document in UpdateSelections ?")(static_cast <bool> (GetParaPortions()[nPara] && "Empty Document in UpdateSelections ?") ? void (0) : __assert_fail ("GetParaPortions()[nPara] && \"Empty Document in UpdateSelections ?\"" , "/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" , 3377, __extension__ __PRETTY_FUNCTION__)); | |||
3378 | // Do not end up from a hidden paragraph: | |||
3379 | sal_Int32 nCurPara = nPara; | |||
3380 | sal_Int32 nLastPara = GetParaPortions().Count()-1; | |||
3381 | while ( nPara <= nLastPara && !GetParaPortions()[nPara]->IsVisible() ) | |||
3382 | nPara++; | |||
3383 | if ( nPara > nLastPara ) // then also backwards ... | |||
3384 | { | |||
3385 | nPara = nCurPara; | |||
3386 | while ( nPara && !GetParaPortions()[nPara]->IsVisible() ) | |||
3387 | nPara--; | |||
3388 | } | |||
3389 | OSL_ENSURE( GetParaPortions()[nPara]->IsVisible(), "No visible paragraph found: UpdateSelections" )do { if (true && (!(GetParaPortions()[nPara]->IsVisible ()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3389" ": "), "%s", "No visible paragraph found: UpdateSelections" ); } } while (false); | |||
3390 | ||||
3391 | ParaPortion* pParaPortion = GetParaPortions()[nPara]; | |||
3392 | EditSelection aTmpSelection( EditPaM( pParaPortion->GetNode(), 0 ) ); | |||
3393 | pView->pImpEditView->SetEditSelection( aTmpSelection ); | |||
3394 | bChanged=true; | |||
3395 | break; // for loop | |||
3396 | } | |||
3397 | } | |||
3398 | if ( !bChanged ) | |||
3399 | { | |||
3400 | // Check Index if node shrunk. | |||
3401 | if ( aCurSel.Min().GetIndex() > aCurSel.Min().GetNode()->Len() ) | |||
3402 | { | |||
3403 | aCurSel.Min().SetIndex( aCurSel.Min().GetNode()->Len() ); | |||
3404 | pView->pImpEditView->SetEditSelection( aCurSel ); | |||
3405 | } | |||
3406 | if ( aCurSel.Max().GetIndex() > aCurSel.Max().GetNode()->Len() ) | |||
3407 | { | |||
3408 | aCurSel.Max().SetIndex( aCurSel.Max().GetNode()->Len() ); | |||
3409 | pView->pImpEditView->SetEditSelection( aCurSel ); | |||
3410 | } | |||
3411 | } | |||
3412 | } | |||
3413 | aDeletedNodes.clear(); | |||
3414 | } | |||
3415 | ||||
3416 | EditSelection ImpEditEngine::ConvertSelection( | |||
3417 | sal_Int32 nStartPara, sal_Int32 nStartPos, sal_Int32 nEndPara, sal_Int32 nEndPos ) | |||
3418 | { | |||
3419 | EditSelection aNewSelection; | |||
3420 | ||||
3421 | // Start... | |||
3422 | ContentNode* pNode = aEditDoc.GetObject( nStartPara ); | |||
3423 | sal_Int32 nIndex = nStartPos; | |||
3424 | if ( !pNode ) | |||
3425 | { | |||
3426 | pNode = aEditDoc[ aEditDoc.Count()-1 ]; | |||
3427 | nIndex = pNode->Len(); | |||
3428 | } | |||
3429 | else if ( nIndex > pNode->Len() ) | |||
3430 | nIndex = pNode->Len(); | |||
3431 | ||||
3432 | aNewSelection.Min().SetNode( pNode ); | |||
3433 | aNewSelection.Min().SetIndex( nIndex ); | |||
3434 | ||||
3435 | // End... | |||
3436 | pNode = aEditDoc.GetObject( nEndPara ); | |||
3437 | nIndex = nEndPos; | |||
3438 | if ( !pNode ) | |||
3439 | { | |||
3440 | pNode = aEditDoc[ aEditDoc.Count()-1 ]; | |||
3441 | nIndex = pNode->Len(); | |||
3442 | } | |||
3443 | else if ( nIndex > pNode->Len() ) | |||
3444 | nIndex = pNode->Len(); | |||
3445 | ||||
3446 | aNewSelection.Max().SetNode( pNode ); | |||
3447 | aNewSelection.Max().SetIndex( nIndex ); | |||
3448 | ||||
3449 | return aNewSelection; | |||
3450 | } | |||
3451 | ||||
3452 | void ImpEditEngine::SetActiveView( EditView* pView ) | |||
3453 | { | |||
3454 | // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | |||
3455 | // Actually, now bHasVisSel and HideSelection would be necessary !!! | |||
3456 | ||||
3457 | if ( pView == pActiveView ) | |||
3458 | return; | |||
3459 | ||||
3460 | if ( pActiveView && pActiveView->HasSelection() ) | |||
3461 | pActiveView->pImpEditView->DrawSelectionXOR(); | |||
3462 | ||||
3463 | pActiveView = pView; | |||
3464 | ||||
3465 | if ( pActiveView && pActiveView->HasSelection() ) | |||
3466 | pActiveView->pImpEditView->DrawSelectionXOR(); | |||
3467 | ||||
3468 | // NN: Quick fix for #78668#: | |||
3469 | // When editing of a cell in Calc is ended, the edit engine is not deleted, | |||
3470 | // only the edit views are removed. If mpIMEInfos is still set in that case, | |||
3471 | // mpIMEInfos->aPos points to an invalid selection. | |||
3472 | // -> reset mpIMEInfos now | |||
3473 | // (probably something like this is necessary whenever the content is modified | |||
3474 | // from the outside) | |||
3475 | ||||
3476 | if ( !pView && mpIMEInfos ) | |||
3477 | { | |||
3478 | mpIMEInfos.reset(); | |||
3479 | } | |||
3480 | } | |||
3481 | ||||
3482 | uno::Reference< datatransfer::XTransferable > ImpEditEngine::CreateTransferable( const EditSelection& rSelection ) | |||
3483 | { | |||
3484 | EditSelection aSelection( rSelection ); | |||
3485 | aSelection.Adjust( GetEditDoc() ); | |||
3486 | ||||
3487 | EditDataObject* pDataObj = new EditDataObject; | |||
3488 | uno::Reference< datatransfer::XTransferable > xDataObj = pDataObj; | |||
3489 | ||||
3490 | pDataObj->GetString() = convertLineEnd(GetSelected(aSelection), GetSystemLineEnd()); // System specific | |||
3491 | ||||
3492 | WriteRTF( pDataObj->GetRTFStream(), aSelection ); | |||
3493 | pDataObj->GetRTFStream().Seek( 0 ); | |||
3494 | ||||
3495 | WriteXML( pDataObj->GetODFStream(), aSelection ); | |||
3496 | pDataObj->GetODFStream().Seek( 0 ); | |||
3497 | ||||
3498 | //Dumping the ODFStream to a XML file for testing purpose | |||
3499 | /* | |||
3500 | std::filebuf afilebuf; | |||
3501 | afilebuf.open ("gsoc17_clipboard_test.xml",std::ios::out); | |||
3502 | std::ostream os(&afilebuf); | |||
3503 | os.write((const char*)(pDataObj->GetODFStream().GetData()), pDataObj->GetODFStream().remainingSize()); | |||
3504 | afilebuf.close(); | |||
3505 | */ | |||
3506 | //dumping ends | |||
3507 | ||||
3508 | if ( ( aSelection.Min().GetNode() == aSelection.Max().GetNode() ) | |||
3509 | && ( aSelection.Max().GetIndex() == (aSelection.Min().GetIndex()+1) ) ) | |||
3510 | { | |||
3511 | const EditCharAttrib* pAttr = aSelection.Min().GetNode()->GetCharAttribs(). | |||
3512 | FindFeature( aSelection.Min().GetIndex() ); | |||
3513 | if ( pAttr && | |||
3514 | ( pAttr->GetStart() == aSelection.Min().GetIndex() ) && | |||
3515 | ( pAttr->Which() == EE_FEATURE_FIELD ) ) | |||
3516 | { | |||
3517 | const SvxFieldItem* pField = static_cast<const SvxFieldItem*>(pAttr->GetItem()); | |||
3518 | const SvxFieldData* pFld = pField->GetField(); | |||
3519 | if ( auto pUrlField = dynamic_cast<const SvxURLField* >(pFld) ) | |||
3520 | { | |||
3521 | // Office-Bookmark | |||
3522 | pDataObj->GetURL() = pUrlField->GetURL(); | |||
3523 | } | |||
3524 | } | |||
3525 | } | |||
3526 | ||||
3527 | return xDataObj; | |||
3528 | } | |||
3529 | ||||
3530 | EditSelection ImpEditEngine::PasteText( uno::Reference< datatransfer::XTransferable > const & rxDataObj, const OUString& rBaseURL, const EditPaM& rPaM, bool bUseSpecial ) | |||
3531 | { | |||
3532 | EditSelection aNewSelection( rPaM ); | |||
3533 | ||||
3534 | if ( !rxDataObj.is() ) | |||
3535 | return aNewSelection; | |||
3536 | ||||
3537 | datatransfer::DataFlavor aFlavor; | |||
3538 | bool bDone = false; | |||
3539 | ||||
3540 | if ( bUseSpecial ) | |||
3541 | { | |||
3542 | // XML | |||
3543 | SotExchange::GetFormatDataFlavor( SotClipboardFormatId::EDITENGINE_ODF_TEXT_FLAT, aFlavor ); | |||
3544 | if ( rxDataObj->isDataFlavorSupported( aFlavor ) ) | |||
3545 | { | |||
3546 | try | |||
3547 | { | |||
3548 | uno::Any aData = rxDataObj->getTransferData( aFlavor ); | |||
3549 | uno::Sequence< sal_Int8 > aSeq; | |||
3550 | aData >>= aSeq; | |||
3551 | { | |||
3552 | SvMemoryStream aODFStream( aSeq.getArray(), aSeq.getLength(), StreamMode::READ ); | |||
3553 | aNewSelection = Read( aODFStream, rBaseURL, EETextFormat::Xml, rPaM ); | |||
3554 | } | |||
3555 | bDone = true; | |||
3556 | } | |||
3557 | catch( const css::uno::Exception&) | |||
3558 | { | |||
3559 | TOOLS_WARN_EXCEPTION( "editeng", "Unable to paste EDITENGINE_ODF_TEXT_FLAT" )do { css::uno::Any tools_warn_exception( DbgGetCaughtException () ); do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "editeng")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult ( ::sal::detail::StreamStart() << "Unable to paste EDITENGINE_ODF_TEXT_FLAT" << " " << exceptionToString(tools_warn_exception )) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ( "editeng"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3559" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "Unable to paste EDITENGINE_ODF_TEXT_FLAT" << " " << exceptionToString(tools_warn_exception )), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "Unable to paste EDITENGINE_ODF_TEXT_FLAT" << " " << exceptionToString(tools_warn_exception); ::sal:: detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3559" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "Unable to paste EDITENGINE_ODF_TEXT_FLAT" << " " << exceptionToString(tools_warn_exception)) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng") , ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3559" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "Unable to paste EDITENGINE_ODF_TEXT_FLAT" << " " << exceptionToString(tools_warn_exception )), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "Unable to paste EDITENGINE_ODF_TEXT_FLAT" << " " << exceptionToString(tools_warn_exception); ::sal:: detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("editeng"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3559" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); } while (false); | |||
3560 | } | |||
3561 | } | |||
3562 | ||||
3563 | if ( !bDone ) | |||
3564 | { | |||
3565 | // RTF | |||
3566 | SotExchange::GetFormatDataFlavor( SotClipboardFormatId::RTF, aFlavor ); | |||
3567 | // RICHTEXT | |||
3568 | datatransfer::DataFlavor aFlavorRichtext; | |||
3569 | SotExchange::GetFormatDataFlavor( SotClipboardFormatId::RICHTEXT, aFlavorRichtext ); | |||
3570 | bool bRtfSupported = rxDataObj->isDataFlavorSupported( aFlavor ); | |||
3571 | bool bRichtextSupported = rxDataObj->isDataFlavorSupported( aFlavorRichtext ); | |||
3572 | if ( bRtfSupported || bRichtextSupported ) | |||
3573 | { | |||
3574 | if(bRichtextSupported) | |||
3575 | { | |||
3576 | aFlavor = aFlavorRichtext; | |||
3577 | } | |||
3578 | try | |||
3579 | { | |||
3580 | uno::Any aData = rxDataObj->getTransferData( aFlavor ); | |||
3581 | uno::Sequence< sal_Int8 > aSeq; | |||
3582 | aData >>= aSeq; | |||
3583 | { | |||
3584 | SvMemoryStream aRTFStream( aSeq.getArray(), aSeq.getLength(), StreamMode::READ ); | |||
3585 | aNewSelection = Read( aRTFStream, rBaseURL, EETextFormat::Rtf, rPaM ); | |||
3586 | } | |||
3587 | bDone = true; | |||
3588 | } | |||
3589 | catch( const css::uno::Exception& ) | |||
3590 | { | |||
3591 | } | |||
3592 | } | |||
3593 | } | |||
3594 | } | |||
3595 | if ( !bDone ) | |||
3596 | { | |||
3597 | SotExchange::GetFormatDataFlavor( SotClipboardFormatId::STRING, aFlavor ); | |||
3598 | if ( rxDataObj->isDataFlavorSupported( aFlavor ) ) | |||
3599 | { | |||
3600 | try | |||
3601 | { | |||
3602 | uno::Any aData = rxDataObj->getTransferData( aFlavor ); | |||
3603 | OUString aText; | |||
3604 | aData >>= aText; | |||
3605 | aNewSelection = ImpInsertText( rPaM, aText ); | |||
3606 | } | |||
3607 | catch( ... ) | |||
3608 | { | |||
3609 | ; // #i9286# can happen, even if isDataFlavorSupported returns true... | |||
3610 | } | |||
3611 | } | |||
3612 | } | |||
3613 | ||||
3614 | return aNewSelection; | |||
3615 | } | |||
3616 | ||||
3617 | Range ImpEditEngine::GetInvalidYOffsets( ParaPortion* pPortion ) | |||
3618 | { | |||
3619 | Range aRange( 0, 0 ); | |||
3620 | ||||
3621 | if ( pPortion->IsVisible() ) | |||
3622 | { | |||
3623 | const SvxULSpaceItem& rULSpace = pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE ); | |||
3624 | const SvxLineSpacingItem& rLSItem = pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL ); | |||
3625 | sal_uInt16 nSBL = ( rLSItem.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Fix ) | |||
3626 | ? GetYValue( rLSItem.GetInterLineSpace() ) : 0; | |||
3627 | ||||
3628 | // only from the top ... | |||
3629 | sal_Int32 nFirstInvalid = -1; | |||
3630 | sal_Int32 nLine; | |||
3631 | for ( nLine = 0; nLine < pPortion->GetLines().Count(); nLine++ ) | |||
3632 | { | |||
3633 | const EditLine& rL = pPortion->GetLines()[nLine]; | |||
3634 | if ( rL.IsInvalid() ) | |||
3635 | { | |||
3636 | nFirstInvalid = nLine; | |||
3637 | break; | |||
3638 | } | |||
3639 | if ( nLine && !aStatus.IsOutliner() ) // not the first line | |||
3640 | aRange.Min() += nSBL; | |||
3641 | aRange.Min() += rL.GetHeight(); | |||
3642 | } | |||
3643 | OSL_ENSURE( nFirstInvalid != -1, "No invalid line found in GetInvalidYOffset(1)" )do { if (true && (!(nFirstInvalid != -1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3643" ": "), "%s", "No invalid line found in GetInvalidYOffset(1)" ); } } while (false); | |||
3644 | ||||
3645 | ||||
3646 | // Syndicate and more ... | |||
3647 | aRange.Max() = aRange.Min(); | |||
3648 | aRange.Max() += pPortion->GetFirstLineOffset(); | |||
3649 | if (nFirstInvalid >= 0) // Only if the first line is invalid | |||
3650 | aRange.Min() = aRange.Max(); | |||
3651 | ||||
3652 | sal_Int32 nLastInvalid = pPortion->GetLines().Count()-1; | |||
3653 | if (nFirstInvalid >= 0) | |||
3654 | { | |||
3655 | for ( nLine = nFirstInvalid; nLine < pPortion->GetLines().Count(); nLine++ ) | |||
3656 | { | |||
3657 | const EditLine& rL = pPortion->GetLines()[nLine]; | |||
3658 | if ( rL.IsValid() ) | |||
3659 | { | |||
3660 | nLastInvalid = nLine; | |||
3661 | break; | |||
3662 | } | |||
3663 | if ( nLine && !aStatus.IsOutliner() ) | |||
3664 | aRange.Max() += nSBL; | |||
3665 | aRange.Max() += rL.GetHeight(); | |||
3666 | } | |||
3667 | ||||
3668 | sal_uInt16 nPropLineSpace = rLSItem.GetPropLineSpace(); | |||
3669 | if ( ( rLSItem.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Prop ) | |||
3670 | && nPropLineSpace && ( nPropLineSpace < 100 ) ) | |||
3671 | { | |||
3672 | const EditLine& rL = pPortion->GetLines()[nFirstInvalid]; | |||
3673 | auto n = rL.GetTxtHeight() * ( 100 - nPropLineSpace ); | |||
3674 | n /= 100; | |||
3675 | aRange.Min() -= n; | |||
3676 | aRange.Max() += n; | |||
3677 | } | |||
3678 | ||||
3679 | if ( ( nLastInvalid == pPortion->GetLines().Count()-1 ) && ( !aStatus.IsOutliner() ) ) | |||
3680 | aRange.Max() += GetYValue( rULSpace.GetLower() ); | |||
3681 | } | |||
3682 | } | |||
3683 | return aRange; | |||
3684 | } | |||
3685 | ||||
3686 | EditPaM ImpEditEngine::GetPaM( ParaPortion* pPortion, Point aDocPos, bool bSmart ) | |||
3687 | { | |||
3688 | OSL_ENSURE( pPortion->IsVisible(), "Why GetPaM() for an invisible paragraph?" )do { if (true && (!(pPortion->IsVisible()))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3688" ": "), "%s", "Why GetPaM() for an invisible paragraph?" ); } } while (false); | |||
3689 | OSL_ENSURE( IsFormatted(), "GetPaM: Not formatted" )do { if (true && (!(IsFormatted()))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3689" ": "), "%s", "GetPaM: Not formatted"); } } while ( false); | |||
3690 | ||||
3691 | sal_Int32 nCurIndex = 0; | |||
3692 | EditPaM aPaM; | |||
3693 | aPaM.SetNode( pPortion->GetNode() ); | |||
3694 | ||||
3695 | const SvxLineSpacingItem& rLSItem = pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL ); | |||
3696 | sal_uInt16 nSBL = ( rLSItem.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Fix ) | |||
3697 | ? GetYValue( rLSItem.GetInterLineSpace() ) : 0; | |||
3698 | ||||
3699 | long nY = pPortion->GetFirstLineOffset(); | |||
3700 | ||||
3701 | OSL_ENSURE( pPortion->GetLines().Count(), "Empty ParaPortion in GetPaM!" )do { if (true && (!(pPortion->GetLines().Count())) ) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3701" ": "), "%s", "Empty ParaPortion in GetPaM!"); } } while (false); | |||
3702 | ||||
3703 | const EditLine* pLine = nullptr; | |||
3704 | for ( sal_Int32 nLine = 0; nLine < pPortion->GetLines().Count(); nLine++ ) | |||
3705 | { | |||
3706 | const EditLine& rTmpLine = pPortion->GetLines()[nLine]; | |||
3707 | nY += rTmpLine.GetHeight(); | |||
3708 | if ( !aStatus.IsOutliner() ) | |||
3709 | nY += nSBL; | |||
3710 | if ( nY > aDocPos.Y() ) | |||
3711 | { | |||
3712 | pLine = &rTmpLine; | |||
3713 | break; // correct Y-position is not of interest | |||
3714 | } | |||
3715 | ||||
3716 | nCurIndex = nCurIndex + rTmpLine.GetLen(); | |||
3717 | } | |||
3718 | ||||
3719 | if ( !pLine ) // may happen only in the range of SA! | |||
3720 | { | |||
3721 | #if OSL_DEBUG_LEVEL1 > 0 | |||
3722 | const SvxULSpaceItem& rULSpace = pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE ); | |||
3723 | OSL_ENSURE( nY+GetYValue( rULSpace.GetLower() ) >= aDocPos.Y() , "Index in no line, GetPaM ?" )do { if (true && (!(nY+GetYValue( rULSpace.GetLower() ) >= aDocPos.Y()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3723" ": "), "%s", "Index in no line, GetPaM ?"); } } while (false); | |||
3724 | #endif | |||
3725 | aPaM.SetIndex( pPortion->GetNode()->Len() ); | |||
3726 | return aPaM; | |||
3727 | } | |||
3728 | ||||
3729 | // If no line found, only just X-Position => Index | |||
3730 | nCurIndex = GetChar( pPortion, pLine, aDocPos.X(), bSmart ); | |||
3731 | aPaM.SetIndex( nCurIndex ); | |||
3732 | ||||
3733 | if ( nCurIndex && ( nCurIndex == pLine->GetEnd() ) && | |||
3734 | ( pLine != &pPortion->GetLines()[pPortion->GetLines().Count()-1] ) ) | |||
3735 | { | |||
3736 | aPaM = CursorLeft( aPaM ); | |||
3737 | } | |||
3738 | ||||
3739 | return aPaM; | |||
3740 | } | |||
3741 | ||||
3742 | sal_Int32 ImpEditEngine::GetChar( | |||
3743 | const ParaPortion* pParaPortion, const EditLine* pLine, long nXPos, bool bSmart) | |||
3744 | { | |||
3745 | OSL_ENSURE( pLine, "No line received: GetChar" )do { if (true && (!(pLine))) { sal_detail_logFormat(( SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3745" ": "), "%s", "No line received: GetChar"); } } while (false); | |||
3746 | ||||
3747 | sal_Int32 nChar = -1; | |||
3748 | sal_Int32 nCurIndex = pLine->GetStart(); | |||
3749 | ||||
3750 | ||||
3751 | // Search best matching portion with GetPortionXOffset() | |||
3752 | for ( sal_Int32 i = pLine->GetStartPortion(); i <= pLine->GetEndPortion(); i++ ) | |||
3753 | { | |||
3754 | const TextPortion& rPortion = pParaPortion->GetTextPortions()[i]; | |||
3755 | long nXLeft = GetPortionXOffset( pParaPortion, pLine, i ); | |||
3756 | long nXRight = nXLeft + rPortion.GetSize().Width(); | |||
3757 | if ( ( nXLeft <= nXPos ) && ( nXRight >= nXPos ) ) | |||
3758 | { | |||
3759 | nChar = nCurIndex; | |||
3760 | ||||
3761 | // Search within Portion... | |||
3762 | ||||
3763 | // Don't search within special portions... | |||
3764 | if ( rPortion.GetKind() != PortionKind::TEXT ) | |||
3765 | { | |||
3766 | // ...but check on which side | |||
3767 | if ( bSmart ) | |||
3768 | { | |||
3769 | long nLeftDiff = nXPos-nXLeft; | |||
3770 | long nRightDiff = nXRight-nXPos; | |||
3771 | if ( nRightDiff < nLeftDiff ) | |||
3772 | nChar++; | |||
3773 | } | |||
3774 | } | |||
3775 | else | |||
3776 | { | |||
3777 | sal_Int32 nMax = rPortion.GetLen(); | |||
3778 | sal_Int32 nOffset = -1; | |||
3779 | sal_Int32 nTmpCurIndex = nChar - pLine->GetStart(); | |||
3780 | ||||
3781 | long nXInPortion = nXPos - nXLeft; | |||
3782 | if ( rPortion.IsRightToLeft() ) | |||
3783 | nXInPortion = nXRight - nXPos; | |||
3784 | ||||
3785 | // Search in Array... | |||
3786 | for ( sal_Int32 x = 0; x < nMax; x++ ) | |||
3787 | { | |||
3788 | long nTmpPosMax = pLine->GetCharPosArray()[nTmpCurIndex+x]; | |||
3789 | if ( nTmpPosMax > nXInPortion ) | |||
3790 | { | |||
3791 | // Check whether this or the previous... | |||
3792 | long nTmpPosMin = x ? pLine->GetCharPosArray()[nTmpCurIndex+x-1] : 0; | |||
3793 | long nDiffLeft = nXInPortion - nTmpPosMin; | |||
3794 | long nDiffRight = nTmpPosMax - nXInPortion; | |||
3795 | OSL_ENSURE( nDiffLeft >= 0, "DiffLeft negative" )do { if (true && (!(nDiffLeft >= 0))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3795" ": "), "%s", "DiffLeft negative"); } } while (false ); | |||
3796 | OSL_ENSURE( nDiffRight >= 0, "DiffRight negative" )do { if (true && (!(nDiffRight >= 0))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3796" ": "), "%s", "DiffRight negative"); } } while (false ); | |||
3797 | nOffset = ( bSmart && ( nDiffRight < nDiffLeft ) ) ? x+1 : x; | |||
3798 | // I18N: If there are character position with the length of 0, | |||
3799 | // they belong to the same character, we can not use this position as an index. | |||
3800 | // Skip all 0-positions, cheaper than using XBreakIterator: | |||
3801 | if ( nOffset < nMax ) | |||
3802 | { | |||
3803 | const long nX = pLine->GetCharPosArray()[nOffset]; | |||
3804 | while ( ( (nOffset+1) < nMax ) && ( pLine->GetCharPosArray()[nOffset+1] == nX ) ) | |||
3805 | nOffset++; | |||
3806 | } | |||
3807 | break; | |||
3808 | } | |||
3809 | } | |||
3810 | ||||
3811 | // There should not be any inaccuracies when using the | |||
3812 | // CharPosArray! Maybe for kerning? | |||
3813 | // 0xFFF happens for example for Outline-Font when at the very end. | |||
3814 | if ( nOffset < 0 ) | |||
3815 | nOffset = nMax; | |||
3816 | ||||
3817 | OSL_ENSURE( nOffset <= nMax, "nOffset > nMax" )do { if (true && (!(nOffset <= nMax))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3817" ": "), "%s", "nOffset > nMax"); } } while (false ); | |||
3818 | ||||
3819 | nChar = nChar + nOffset; | |||
3820 | ||||
3821 | // Check if index is within a cell: | |||
3822 | if ( nChar && ( nChar < pParaPortion->GetNode()->Len() ) ) | |||
3823 | { | |||
3824 | EditPaM aPaM( pParaPortion->GetNode(), nChar+1 ); | |||
3825 | sal_uInt16 nScriptType = GetI18NScriptType( aPaM ); | |||
3826 | if ( nScriptType == i18n::ScriptType::COMPLEX ) | |||
3827 | { | |||
3828 | uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() ); | |||
3829 | sal_Int32 nCount = 1; | |||
3830 | lang::Locale aLocale = GetLocale( aPaM ); | |||
3831 | sal_Int32 nRight = _xBI->nextCharacters( | |||
3832 | pParaPortion->GetNode()->GetString(), nChar, aLocale, css::i18n::CharacterIteratorMode::SKIPCELL, nCount, nCount ); | |||
3833 | sal_Int32 nLeft = _xBI->previousCharacters( | |||
3834 | pParaPortion->GetNode()->GetString(), nRight, aLocale, css::i18n::CharacterIteratorMode::SKIPCELL, nCount, nCount ); | |||
3835 | if ( ( nLeft != nChar ) && ( nRight != nChar ) ) | |||
3836 | { | |||
3837 | nChar = ( std::abs( nRight - nChar ) < std::abs( nLeft - nChar ) ) ? nRight : nLeft; | |||
3838 | } | |||
3839 | } | |||
3840 | else | |||
3841 | { | |||
3842 | OUString aStr(pParaPortion->GetNode()->GetString()); | |||
3843 | // tdf#102625: don't select middle of a pair of surrogates with mouse cursor | |||
3844 | if (rtl::isSurrogate(aStr[nChar])) | |||
3845 | --nChar; | |||
3846 | } | |||
3847 | } | |||
3848 | } | |||
3849 | } | |||
3850 | ||||
3851 | nCurIndex = nCurIndex + rPortion.GetLen(); | |||
3852 | } | |||
3853 | ||||
3854 | if ( nChar == -1 ) | |||
3855 | { | |||
3856 | nChar = ( nXPos <= pLine->GetStartPosX() ) ? pLine->GetStart() : pLine->GetEnd(); | |||
3857 | } | |||
3858 | ||||
3859 | return nChar; | |||
3860 | } | |||
3861 | ||||
3862 | Range ImpEditEngine::GetLineXPosStartEnd( const ParaPortion* pParaPortion, const EditLine* pLine ) const | |||
3863 | { | |||
3864 | Range aLineXPosStartEnd; | |||
3865 | ||||
3866 | sal_Int32 nPara = GetEditDoc().GetPos( pParaPortion->GetNode() ); | |||
3867 | if ( !IsRightToLeft( nPara ) ) | |||
3868 | { | |||
3869 | aLineXPosStartEnd.Min() = pLine->GetStartPosX(); | |||
3870 | aLineXPosStartEnd.Max() = pLine->GetStartPosX() + pLine->GetTextWidth(); | |||
3871 | } | |||
3872 | else | |||
3873 | { | |||
3874 | aLineXPosStartEnd.Min() = GetPaperSize().Width() - ( pLine->GetStartPosX() + pLine->GetTextWidth() ); | |||
3875 | aLineXPosStartEnd.Max() = GetPaperSize().Width() - pLine->GetStartPosX(); | |||
3876 | } | |||
3877 | ||||
3878 | ||||
3879 | return aLineXPosStartEnd; | |||
3880 | } | |||
3881 | ||||
3882 | long ImpEditEngine::GetPortionXOffset( | |||
3883 | const ParaPortion* pParaPortion, const EditLine* pLine, sal_Int32 nTextPortion) const | |||
3884 | { | |||
3885 | long nX = pLine->GetStartPosX(); | |||
3886 | ||||
3887 | for ( sal_Int32 i = pLine->GetStartPortion(); i < nTextPortion; i++ ) | |||
3888 | { | |||
3889 | const TextPortion& rPortion = pParaPortion->GetTextPortions()[i]; | |||
3890 | switch ( rPortion.GetKind() ) | |||
3891 | { | |||
3892 | case PortionKind::FIELD: | |||
3893 | case PortionKind::TEXT: | |||
3894 | case PortionKind::HYPHENATOR: | |||
3895 | case PortionKind::TAB: | |||
3896 | { | |||
3897 | nX += rPortion.GetSize().Width(); | |||
3898 | } | |||
3899 | break; | |||
3900 | case PortionKind::LINEBREAK: break; | |||
3901 | } | |||
3902 | } | |||
3903 | ||||
3904 | sal_Int32 nPara = GetEditDoc().GetPos( pParaPortion->GetNode() ); | |||
3905 | bool bR2LPara = IsRightToLeft( nPara ); | |||
3906 | ||||
3907 | const TextPortion& rDestPortion = pParaPortion->GetTextPortions()[nTextPortion]; | |||
3908 | if ( rDestPortion.GetKind() != PortionKind::TAB ) | |||
3909 | { | |||
3910 | if ( !bR2LPara && rDestPortion.GetRightToLeftLevel() ) | |||
3911 | { | |||
3912 | // Portions behind must be added, visual before this portion | |||
3913 | sal_Int32 nTmpPortion = nTextPortion+1; | |||
3914 | while ( nTmpPortion <= pLine->GetEndPortion() ) | |||
3915 | { | |||
3916 | const TextPortion& rNextTextPortion = pParaPortion->GetTextPortions()[nTmpPortion]; | |||
3917 | if ( rNextTextPortion.GetRightToLeftLevel() && ( rNextTextPortion.GetKind() != PortionKind::TAB ) ) | |||
3918 | nX += rNextTextPortion.GetSize().Width(); | |||
3919 | else | |||
3920 | break; | |||
3921 | nTmpPortion++; | |||
3922 | } | |||
3923 | // Portions before must be removed, visual behind this portion | |||
3924 | nTmpPortion = nTextPortion; | |||
3925 | while ( nTmpPortion > pLine->GetStartPortion() ) | |||
3926 | { | |||
3927 | --nTmpPortion; | |||
3928 | const TextPortion& rPrevTextPortion = pParaPortion->GetTextPortions()[nTmpPortion]; | |||
3929 | if ( rPrevTextPortion.GetRightToLeftLevel() && ( rPrevTextPortion.GetKind() != PortionKind::TAB ) ) | |||
3930 | nX -= rPrevTextPortion.GetSize().Width(); | |||
3931 | else | |||
3932 | break; | |||
3933 | } | |||
3934 | } | |||
3935 | else if ( bR2LPara && !rDestPortion.IsRightToLeft() ) | |||
3936 | { | |||
3937 | // Portions behind must be removed, visual behind this portion | |||
3938 | sal_Int32 nTmpPortion = nTextPortion+1; | |||
3939 | while ( nTmpPortion <= pLine->GetEndPortion() ) | |||
3940 | { | |||
3941 | const TextPortion& rNextTextPortion = pParaPortion->GetTextPortions()[nTmpPortion]; | |||
3942 | if ( !rNextTextPortion.IsRightToLeft() && ( rNextTextPortion.GetKind() != PortionKind::TAB ) ) | |||
3943 | nX += rNextTextPortion.GetSize().Width(); | |||
3944 | else | |||
3945 | break; | |||
3946 | nTmpPortion++; | |||
3947 | } | |||
3948 | // Portions before must be added, visual before this portion | |||
3949 | nTmpPortion = nTextPortion; | |||
3950 | while ( nTmpPortion > pLine->GetStartPortion() ) | |||
3951 | { | |||
3952 | --nTmpPortion; | |||
3953 | const TextPortion& rPrevTextPortion = pParaPortion->GetTextPortions()[nTmpPortion]; | |||
3954 | if ( !rPrevTextPortion.IsRightToLeft() && ( rPrevTextPortion.GetKind() != PortionKind::TAB ) ) | |||
3955 | nX -= rPrevTextPortion.GetSize().Width(); | |||
3956 | else | |||
3957 | break; | |||
3958 | } | |||
3959 | } | |||
3960 | } | |||
3961 | if ( bR2LPara ) | |||
3962 | { | |||
3963 | // Switch X positions... | |||
3964 | OSL_ENSURE( GetTextRanger() || GetPaperSize().Width(), "GetPortionXOffset - paper size?!" )do { if (true && (!(GetTextRanger() || GetPaperSize() .Width()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3964" ": "), "%s", "GetPortionXOffset - paper size?!"); } } while (false); | |||
3965 | OSL_ENSURE( GetTextRanger() || (nX <= GetPaperSize().Width()), "GetPortionXOffset - position out of paper size!" )do { if (true && (!(GetTextRanger() || (nX <= GetPaperSize ().Width())))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3965" ": "), "%s", "GetPortionXOffset - position out of paper size!" ); } } while (false); | |||
3966 | nX = GetPaperSize().Width() - nX; | |||
3967 | nX -= rDestPortion.GetSize().Width(); | |||
3968 | } | |||
3969 | ||||
3970 | return nX; | |||
3971 | } | |||
3972 | ||||
3973 | long ImpEditEngine::GetXPos( | |||
3974 | const ParaPortion* pParaPortion, const EditLine* pLine, sal_Int32 nIndex, bool bPreferPortionStart) const | |||
3975 | { | |||
3976 | OSL_ENSURE( pLine, "No line received: GetXPos" )do { if (true && (!(pLine))) { sal_detail_logFormat(( SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3976" ": "), "%s", "No line received: GetXPos"); } } while (false); | |||
3977 | OSL_ENSURE( ( nIndex >= pLine->GetStart() ) && ( nIndex <= pLine->GetEnd() ) , "GetXPos has to be called properly!" )do { if (true && (!(( nIndex >= pLine->GetStart () ) && ( nIndex <= pLine->GetEnd() )))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3977" ": "), "%s", "GetXPos has to be called properly!" ); } } while (false); | |||
3978 | ||||
3979 | bool bDoPreferPortionStart = bPreferPortionStart; | |||
3980 | // Assure that the portion belongs to this line: | |||
3981 | if ( nIndex == pLine->GetStart() ) | |||
3982 | bDoPreferPortionStart = true; | |||
3983 | else if ( nIndex == pLine->GetEnd() ) | |||
3984 | bDoPreferPortionStart = false; | |||
3985 | ||||
3986 | sal_Int32 nTextPortionStart = 0; | |||
3987 | sal_Int32 nTextPortion = pParaPortion->GetTextPortions().FindPortion( nIndex, nTextPortionStart, bDoPreferPortionStart ); | |||
3988 | ||||
3989 | OSL_ENSURE( ( nTextPortion >= pLine->GetStartPortion() ) && ( nTextPortion <= pLine->GetEndPortion() ), "GetXPos: Portion not in current line! " )do { if (true && (!(( nTextPortion >= pLine->GetStartPortion () ) && ( nTextPortion <= pLine->GetEndPortion( ) )))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "3989" ": "), "%s", "GetXPos: Portion not in current line! " ); } } while (false); | |||
3990 | ||||
3991 | const TextPortion& rPortion = pParaPortion->GetTextPortions()[nTextPortion]; | |||
3992 | ||||
3993 | long nX = GetPortionXOffset( pParaPortion, pLine, nTextPortion ); | |||
3994 | ||||
3995 | // calc text width, portion size may include CJK/CTL spacing... | |||
3996 | // But the array might not be init yet, if using text ranger this method is called within CreateLines()... | |||
3997 | long nPortionTextWidth = rPortion.GetSize().Width(); | |||
3998 | if ( ( rPortion.GetKind() == PortionKind::TEXT ) && rPortion.GetLen() && !GetTextRanger() ) | |||
3999 | nPortionTextWidth = pLine->GetCharPosArray()[nTextPortionStart + rPortion.GetLen() - 1 - pLine->GetStart()]; | |||
4000 | ||||
4001 | if ( nTextPortionStart != nIndex ) | |||
4002 | { | |||
4003 | // Search within portion... | |||
4004 | if ( nIndex == ( nTextPortionStart + rPortion.GetLen() ) ) | |||
4005 | { | |||
4006 | // End of Portion | |||
4007 | if ( rPortion.GetKind() == PortionKind::TAB ) | |||
4008 | { | |||
4009 | if ( nTextPortion+1 < pParaPortion->GetTextPortions().Count() ) | |||
4010 | { | |||
4011 | const TextPortion& rNextPortion = pParaPortion->GetTextPortions()[nTextPortion+1]; | |||
4012 | if ( rNextPortion.GetKind() != PortionKind::TAB ) | |||
4013 | { | |||
4014 | if ( !bPreferPortionStart ) | |||
4015 | nX = GetXPos( pParaPortion, pLine, nIndex, true ); | |||
4016 | else if ( !IsRightToLeft( GetEditDoc().GetPos( pParaPortion->GetNode() ) ) ) | |||
4017 | nX += nPortionTextWidth; | |||
4018 | } | |||
4019 | } | |||
4020 | else if ( !IsRightToLeft( GetEditDoc().GetPos( pParaPortion->GetNode() ) ) ) | |||
4021 | { | |||
4022 | nX += nPortionTextWidth; | |||
4023 | } | |||
4024 | } | |||
4025 | else if ( !rPortion.IsRightToLeft() ) | |||
4026 | { | |||
4027 | nX += nPortionTextWidth; | |||
4028 | } | |||
4029 | } | |||
4030 | else if ( rPortion.GetKind() == PortionKind::TEXT ) | |||
4031 | { | |||
4032 | OSL_ENSURE( nIndex != pLine->GetStart(), "Strange behavior in new GetXPos()" )do { if (true && (!(nIndex != pLine->GetStart()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "4032" ": "), "%s", "Strange behavior in new GetXPos()") ; } } while (false); | |||
4033 | OSL_ENSURE( pLine && !pLine->GetCharPosArray().empty(), "svx::ImpEditEngine::GetXPos(), portion in an empty line?" )do { if (true && (!(pLine && !pLine->GetCharPosArray ().empty()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "4033" ": "), "%s", "svx::ImpEditEngine::GetXPos(), portion in an empty line?" ); } } while (false); | |||
4034 | ||||
4035 | if( !pLine->GetCharPosArray().empty() ) | |||
4036 | { | |||
4037 | sal_Int32 nPos = nIndex - 1 - pLine->GetStart(); | |||
4038 | if (nPos < 0 || nPos >= static_cast<sal_Int32>(pLine->GetCharPosArray().size())) | |||
4039 | { | |||
4040 | nPos = pLine->GetCharPosArray().size()-1; | |||
4041 | OSL_FAIL("svx::ImpEditEngine::GetXPos(), index out of range!")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "4041" ": "), "%s", "svx::ImpEditEngine::GetXPos(), index out of range!" ); } } while (false); | |||
4042 | } | |||
4043 | ||||
4044 | // old code restored see #i112788 (which leaves #i74188 unfixed again) | |||
4045 | long nPosInPortion = pLine->GetCharPosArray()[nPos]; | |||
4046 | ||||
4047 | if ( !rPortion.IsRightToLeft() ) | |||
4048 | { | |||
4049 | nX += nPosInPortion; | |||
4050 | } | |||
4051 | else | |||
4052 | { | |||
4053 | nX += nPortionTextWidth - nPosInPortion; | |||
4054 | } | |||
4055 | ||||
4056 | if ( rPortion.GetExtraInfos() && rPortion.GetExtraInfos()->bCompressed ) | |||
4057 | { | |||
4058 | nX += rPortion.GetExtraInfos()->nPortionOffsetX; | |||
4059 | if ( rPortion.GetExtraInfos()->nAsianCompressionTypes & AsianCompressionFlags::PunctuationRight ) | |||
4060 | { | |||
4061 | AsianCompressionFlags nType = GetCharTypeForCompression( pParaPortion->GetNode()->GetChar( nIndex ) ); | |||
4062 | if ( nType == AsianCompressionFlags::PunctuationRight && !pLine->GetCharPosArray().empty() ) | |||
4063 | { | |||
4064 | sal_Int32 n = nIndex - nTextPortionStart; | |||
4065 | const long* pDXArray = pLine->GetCharPosArray().data()+( nTextPortionStart-pLine->GetStart() ); | |||
4066 | sal_Int32 nCharWidth = ( ( (n+1) < rPortion.GetLen() ) ? pDXArray[n] : rPortion.GetSize().Width() ) | |||
4067 | - ( n ? pDXArray[n-1] : 0 ); | |||
4068 | if ( (n+1) < rPortion.GetLen() ) | |||
4069 | { | |||
4070 | // smaller, when char behind is AsianCompressionFlags::PunctuationRight also | |||
4071 | nType = GetCharTypeForCompression( pParaPortion->GetNode()->GetChar( nIndex+1 ) ); | |||
4072 | if ( nType == AsianCompressionFlags::PunctuationRight ) | |||
4073 | { | |||
4074 | sal_Int32 nNextCharWidth = ( ( (n+2) < rPortion.GetLen() ) ? pDXArray[n+1] : rPortion.GetSize().Width() ) | |||
4075 | - pDXArray[n]; | |||
4076 | sal_Int32 nCompressed = nNextCharWidth/2; | |||
4077 | nCompressed *= rPortion.GetExtraInfos()->nMaxCompression100thPercent; | |||
4078 | nCompressed /= 10000; | |||
4079 | nCharWidth += nCompressed; | |||
4080 | } | |||
4081 | } | |||
4082 | else | |||
4083 | { | |||
4084 | nCharWidth *= 2; // last char pos to portion end is only compressed size | |||
4085 | } | |||
4086 | nX += nCharWidth/2; // 50% compression | |||
4087 | } | |||
4088 | } | |||
4089 | } | |||
4090 | } | |||
4091 | } | |||
4092 | } | |||
4093 | else // if ( nIndex == pLine->GetStart() ) | |||
4094 | { | |||
4095 | if ( rPortion.IsRightToLeft() ) | |||
4096 | { | |||
4097 | nX += nPortionTextWidth; | |||
4098 | } | |||
4099 | } | |||
4100 | ||||
4101 | return nX; | |||
4102 | } | |||
4103 | ||||
4104 | void ImpEditEngine::CalcHeight( ParaPortion* pPortion ) | |||
4105 | { | |||
4106 | pPortion->nHeight = 0; | |||
4107 | pPortion->nFirstLineOffset = 0; | |||
4108 | ||||
4109 | if ( !pPortion->IsVisible() ) | |||
4110 | return; | |||
4111 | ||||
4112 | OSL_ENSURE( pPortion->GetLines().Count(), "Paragraph with no lines in ParaPortion::CalcHeight" )do { if (true && (!(pPortion->GetLines().Count())) ) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "4112" ": "), "%s", "Paragraph with no lines in ParaPortion::CalcHeight" ); } } while (false); | |||
4113 | for (sal_Int32 nLine = 0; nLine < pPortion->GetLines().Count(); ++nLine) | |||
4114 | pPortion->nHeight += pPortion->GetLines()[nLine].GetHeight(); | |||
4115 | ||||
4116 | if ( aStatus.IsOutliner() ) | |||
4117 | return; | |||
4118 | ||||
4119 | const SvxULSpaceItem& rULItem = pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE ); | |||
4120 | const SvxLineSpacingItem& rLSItem = pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL ); | |||
4121 | sal_Int32 nSBL = ( rLSItem.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Fix ) ? GetYValue( rLSItem.GetInterLineSpace() ) : 0; | |||
4122 | ||||
4123 | if ( nSBL ) | |||
4124 | { | |||
4125 | if ( pPortion->GetLines().Count() > 1 ) | |||
4126 | pPortion->nHeight += ( pPortion->GetLines().Count() - 1 ) * nSBL; | |||
4127 | if ( aStatus.ULSpaceSummation() ) | |||
4128 | pPortion->nHeight += nSBL; | |||
4129 | } | |||
4130 | ||||
4131 | sal_Int32 nPortion = GetParaPortions().GetPos( pPortion ); | |||
4132 | if ( nPortion ) | |||
4133 | { | |||
4134 | sal_uInt16 nUpper = GetYValue( rULItem.GetUpper() ); | |||
4135 | pPortion->nHeight += nUpper; | |||
4136 | pPortion->nFirstLineOffset = nUpper; | |||
4137 | } | |||
4138 | ||||
4139 | if ( nPortion != (GetParaPortions().Count()-1) ) | |||
4140 | { | |||
4141 | pPortion->nHeight += GetYValue( rULItem.GetLower() ); // not in the last | |||
4142 | } | |||
4143 | ||||
4144 | ||||
4145 | if ( !nPortion || aStatus.ULSpaceSummation() ) | |||
4146 | return; | |||
4147 | ||||
4148 | ParaPortion* pPrev = GetParaPortions().SafeGetObject( nPortion-1 ); | |||
4149 | if (!pPrev) | |||
4150 | return; | |||
4151 | ||||
4152 | const SvxULSpaceItem& rPrevULItem = pPrev->GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE ); | |||
4153 | const SvxLineSpacingItem& rPrevLSItem = pPrev->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL ); | |||
4154 | ||||
4155 | // In relation between WinWord6/Writer3: | |||
4156 | // With a proportional line spacing the paragraph spacing is | |||
4157 | // also manipulated. | |||
4158 | // Only Writer3: Do not add up, but minimum distance. | |||
4159 | ||||
4160 | // check if distance by LineSpacing > Upper: | |||
4161 | sal_uInt16 nExtraSpace = GetYValue( lcl_CalcExtraSpace( rLSItem ) ); | |||
4162 | if ( nExtraSpace > pPortion->nFirstLineOffset ) | |||
4163 | { | |||
4164 | // Paragraph becomes 'bigger': | |||
4165 | pPortion->nHeight += ( nExtraSpace - pPortion->nFirstLineOffset ); | |||
4166 | pPortion->nFirstLineOffset = nExtraSpace; | |||
4167 | } | |||
4168 | ||||
4169 | // Determine nFirstLineOffset now f(pNode) => now f(pNode, pPrev): | |||
4170 | sal_uInt16 nPrevLower = GetYValue( rPrevULItem.GetLower() ); | |||
4171 | ||||
4172 | // This PrevLower is still in the height of PrevPortion ... | |||
4173 | if ( nPrevLower > pPortion->nFirstLineOffset ) | |||
4174 | { | |||
4175 | // Paragraph is 'small': | |||
4176 | pPortion->nHeight -= pPortion->nFirstLineOffset; | |||
4177 | pPortion->nFirstLineOffset = 0; | |||
4178 | } | |||
4179 | else if ( nPrevLower ) | |||
4180 | { | |||
4181 | // Paragraph becomes 'somewhat smaller': | |||
4182 | pPortion->nHeight -= nPrevLower; | |||
4183 | pPortion->nFirstLineOffset = | |||
4184 | pPortion->nFirstLineOffset - nPrevLower; | |||
4185 | } | |||
4186 | // I find it not so good, but Writer3 feature: | |||
4187 | // Check if distance by LineSpacing > Lower: this value is not | |||
4188 | // stuck in the height of PrevPortion. | |||
4189 | if ( pPrev->IsInvalid() ) | |||
4190 | return; | |||
4191 | ||||
4192 | nExtraSpace = GetYValue( lcl_CalcExtraSpace( rPrevLSItem ) ); | |||
4193 | if ( nExtraSpace > nPrevLower ) | |||
4194 | { | |||
4195 | sal_uInt16 nMoreLower = nExtraSpace - nPrevLower; | |||
4196 | // Paragraph becomes 'bigger', 'grows' downwards: | |||
4197 | if ( nMoreLower > pPortion->nFirstLineOffset ) | |||
4198 | { | |||
4199 | pPortion->nHeight += ( nMoreLower - pPortion->nFirstLineOffset ); | |||
4200 | pPortion->nFirstLineOffset = nMoreLower; | |||
4201 | } | |||
4202 | } | |||
4203 | } | |||
4204 | ||||
4205 | tools::Rectangle ImpEditEngine::GetEditCursor( ParaPortion* pPortion, sal_Int32 nIndex, GetCursorFlags nFlags ) | |||
4206 | { | |||
4207 | OSL_ENSURE( pPortion->IsVisible(), "Why GetEditCursor() for an invisible paragraph?" )do { if (true && (!(pPortion->IsVisible()))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "4207" ": "), "%s", "Why GetEditCursor() for an invisible paragraph?" ); } } while (false); | |||
4208 | OSL_ENSURE( IsFormatted() || GetTextRanger(), "GetEditCursor: Not formatted" )do { if (true && (!(IsFormatted() || GetTextRanger()) )) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "4208" ": "), "%s", "GetEditCursor: Not formatted"); } } while (false); | |||
4209 | ||||
4210 | /* | |||
4211 | GetCursorFlags::EndOfLine: If after the last character of a wrapped line, remaining | |||
4212 | at the end of the line, not the beginning of the next one. | |||
4213 | Purpose: - END => really after the last character | |||
4214 | - Selection... | |||
4215 | */ | |||
4216 | ||||
4217 | long nY = pPortion->GetFirstLineOffset(); | |||
4218 | ||||
4219 | const SvxLineSpacingItem& rLSItem = pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL ); | |||
4220 | sal_uInt16 nSBL = ( rLSItem.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Fix ) | |||
4221 | ? GetYValue( rLSItem.GetInterLineSpace() ) : 0; | |||
4222 | ||||
4223 | sal_Int32 nCurIndex = 0; | |||
4224 | sal_Int32 nLineCount = pPortion->GetLines().Count(); | |||
4225 | OSL_ENSURE( nLineCount, "Empty ParaPortion in GetEditCursor!" )do { if (true && (!(nLineCount))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "4225" ": "), "%s", "Empty ParaPortion in GetEditCursor!" ); } } while (false); | |||
4226 | if (nLineCount == 0) | |||
4227 | return tools::Rectangle(); | |||
4228 | const EditLine* pLine = nullptr; | |||
4229 | bool bEOL( nFlags & GetCursorFlags::EndOfLine ); | |||
4230 | for (sal_Int32 nLine = 0; nLine < nLineCount; ++nLine) | |||
4231 | { | |||
4232 | const EditLine& rTmpLine = pPortion->GetLines()[nLine]; | |||
4233 | if ( ( rTmpLine.GetStart() == nIndex ) || ( rTmpLine.IsIn( nIndex, bEOL ) ) ) | |||
4234 | { | |||
4235 | pLine = &rTmpLine; | |||
4236 | break; | |||
4237 | } | |||
4238 | ||||
4239 | nCurIndex = nCurIndex + rTmpLine.GetLen(); | |||
4240 | nY += rTmpLine.GetHeight(); | |||
4241 | if ( !aStatus.IsOutliner() ) | |||
4242 | nY += nSBL; | |||
4243 | } | |||
4244 | if ( !pLine ) | |||
4245 | { | |||
4246 | // Cursor at the End of the paragraph. | |||
4247 | OSL_ENSURE( nIndex == nCurIndex, "Index dead wrong in GetEditCursor!" )do { if (true && (!(nIndex == nCurIndex))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/editeng/source/editeng/impedit2.cxx" ":" "4247" ": "), "%s", "Index dead wrong in GetEditCursor!" ); } } while (false); | |||
4248 | ||||
4249 | pLine = &pPortion->GetLines()[nLineCount-1]; | |||
4250 | nY -= pLine->GetHeight(); | |||
4251 | if ( !aStatus.IsOutliner() ) | |||
4252 | nY -= nSBL; | |||
4253 | } | |||
4254 | ||||
4255 | tools::Rectangle aEditCursor; | |||
4256 | ||||
4257 | aEditCursor.SetTop( nY ); | |||
4258 | nY += pLine->GetHeight(); | |||
4259 | aEditCursor.SetBottom( nY-1 ); | |||
4260 | ||||
4261 | // Search within the line... | |||
4262 | long nX; | |||
4263 | ||||
4264 | if ( ( nIndex == pLine->GetStart() ) && ( nFlags & GetCursorFlags::StartOfLine ) ) | |||
4265 | { | |||
4266 | Range aXRange = GetLineXPosStartEnd( pPortion, pLine ); | |||
4267 | nX = !IsRightToLeft( GetEditDoc().GetPos( pPortion->GetNode() ) ) ? aXRange.Min() : aXRange.Max(); | |||
4268 | } | |||
4269 | else if ( ( nIndex == pLine->GetEnd() ) && ( nFlags & GetCursorFlags::EndOfLine ) ) | |||
4270 | { | |||
4271 | Range aXRange = GetLineXPosStartEnd( pPortion, pLine ); | |||
4272 | nX = !IsRightToLeft( GetEditDoc().GetPos( pPortion->GetNode() ) ) ? aXRange.Max() : aXRange.Min(); | |||
4273 | } | |||
4274 | else | |||
4275 | { | |||
4276 | nX = GetXPos( pPortion, pLine, nIndex, bool( nFlags & GetCursorFlags::PreferPortionStart ) ); | |||
4277 | } | |||
4278 | ||||
4279 | aEditCursor.SetLeft(nX); | |||
4280 | aEditCursor.SetRight(nX); | |||
4281 | ||||
4282 | if ( nFlags & GetCursorFlags::TextOnly ) | |||
4283 | aEditCursor.SetTop( aEditCursor.Bottom() - pLine->GetTxtHeight() + 1 ); | |||
4284 | else | |||
4285 | aEditCursor.SetTop( aEditCursor.Bottom() - std::min( pLine->GetTxtHeight(), pLine->GetHeight() ) + 1 ); | |||
4286 | ||||
4287 | return aEditCursor; | |||
4288 | } | |||
4289 | ||||
4290 | void ImpEditEngine::SetValidPaperSize( const Size& rNewSz ) | |||
4291 | { | |||
4292 | aPaperSize = rNewSz; | |||
4293 | ||||
4294 | long nMinWidth = aStatus.AutoPageWidth() ? aMinAutoPaperSize.Width() : 0; | |||
4295 | long nMaxWidth = aStatus.AutoPageWidth() ? aMaxAutoPaperSize.Width() : 0x7FFFFFFF; | |||
4296 | long nMinHeight = aStatus.AutoPageHeight() ? aMinAutoPaperSize.Height() : 0; | |||
4297 | long nMaxHeight = aStatus.AutoPageHeight() ? aMaxAutoPaperSize.Height() : 0x7FFFFFFF; | |||
4298 | ||||
4299 | // Minimum/Maximum width: | |||
4300 | if ( aPaperSize.Width() < nMinWidth ) | |||
4301 | aPaperSize.setWidth( nMinWidth ); | |||
4302 | else if ( aPaperSize.Width() > nMaxWidth ) | |||
4303 | aPaperSize.setWidth( nMaxWidth ); | |||
4304 | ||||
4305 | // Minimum/Maximum height: | |||
4306 | if ( aPaperSize.Height() < nMinHeight ) | |||
4307 | aPaperSize.setHeight( nMinHeight ); | |||
4308 | else if ( aPaperSize.Height() > nMaxHeight ) | |||
4309 | aPaperSize.setHeight( nMaxHeight ); | |||
4310 | } | |||
4311 | ||||
4312 | std::shared_ptr<SvxForbiddenCharactersTable> const & ImpEditEngine::GetForbiddenCharsTable() | |||
4313 | { | |||
4314 | return EditDLL::Get().GetGlobalData()->GetForbiddenCharsTable(); | |||
4315 | } | |||
4316 | ||||
4317 | void ImpEditEngine::SetForbiddenCharsTable(const std::shared_ptr<SvxForbiddenCharactersTable>& xForbiddenChars) | |||
4318 | { | |||
4319 | EditDLL::Get().GetGlobalData()->SetForbiddenCharsTable( xForbiddenChars ); | |||
4320 | } | |||
4321 | ||||
4322 | bool ImpEditEngine::IsVisualCursorTravelingEnabled() | |||
4323 | { | |||
4324 | bool bVisualCursorTravaling = false; | |||
4325 | ||||
4326 | if( !pCTLOptions ) | |||
4327 | pCTLOptions.reset( new SvtCTLOptions ); | |||
4328 | ||||
4329 | if ( pCTLOptions->IsCTLFontEnabled() && ( pCTLOptions->GetCTLCursorMovement() == SvtCTLOptions::MOVEMENT_VISUAL ) ) | |||
4330 | { | |||
4331 | bVisualCursorTravaling = true; | |||
4332 | } | |||
4333 | ||||
4334 | return bVisualCursorTravaling; | |||
4335 | ||||
4336 | } | |||
4337 | ||||
4338 | bool ImpEditEngine::DoVisualCursorTraveling() | |||
4339 | { | |||
4340 | // Don't check if it's necessary, because we also need it when leaving the paragraph | |||
4341 | return IsVisualCursorTravelingEnabled(); | |||
4342 | } | |||
4343 | ||||
4344 | IMPL_LINK_NOARG(ImpEditEngine, DocModified, LinkParamNone*, void)void ImpEditEngine::LinkStubDocModified(void * instance, LinkParamNone * data) { return static_cast<ImpEditEngine *>(instance) ->DocModified(data); } void ImpEditEngine::DocModified(__attribute__ ((unused)) LinkParamNone*) | |||
4345 | { | |||
4346 | aModifyHdl.Call( nullptr /*GetEditEnginePtr()*/ ); // NULL, because also used for Outliner | |||
4347 | } | |||
4348 | ||||
4349 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |
1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | /* |
3 | * This file is part of the LibreOffice project. |
4 | * |
5 | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | * |
9 | * This file incorporates work covered by the following license notice: |
10 | * |
11 | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | * contributor license agreements. See the NOTICE file distributed |
13 | * with this work for additional information regarding copyright |
14 | * ownership. The ASF licenses this file to you under the Apache |
15 | * License, Version 2.0 (the "License"); you may not use this file |
16 | * except in compliance with the License. You may obtain a copy of |
17 | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | */ |
19 | |
20 | #ifndef INCLUDED_VCL_PTR_HXX |
21 | #define INCLUDED_VCL_PTR_HXX |
22 | |
23 | #include <sal/config.h> |
24 | |
25 | #include <rtl/ref.hxx> |
26 | |
27 | #include <utility> |
28 | #include <type_traits> |
29 | |
30 | #ifdef DBG_UTIL |
31 | #ifndef _WIN32 |
32 | #include <vcl/vclmain.hxx> |
33 | #endif |
34 | #endif |
35 | |
36 | class VclReferenceBase; |
37 | |
38 | namespace vcl::detail { |
39 | |
40 | template<typename> |
41 | constexpr bool isIncompleteOrDerivedFromVclReferenceBase(...) { return true; } |
42 | |
43 | template<typename T> constexpr bool isIncompleteOrDerivedFromVclReferenceBase( |
44 | int (*)[sizeof(T)]) |
45 | { return std::is_base_of<VclReferenceBase, T>::value; } |
46 | |
47 | } // namespace vcl::detail |
48 | |
49 | /** |
50 | * A thin wrapper around rtl::Reference to implement the acquire and dispose semantics we want for references to vcl::Window subclasses. |
51 | * |
52 | * For more details on the design please see vcl/README.lifecycle |
53 | * |
54 | * @param reference_type must be a subclass of vcl::Window |
55 | */ |
56 | template <class reference_type> |
57 | class VclPtr |
58 | { |
59 | static_assert( |
60 | vcl::detail::isIncompleteOrDerivedFromVclReferenceBase<reference_type>( |
61 | nullptr), |
62 | "template argument type must be derived from VclReferenceBase"); |
63 | |
64 | ::rtl::Reference<reference_type> m_rInnerRef; |
65 | |
66 | public: |
67 | /** Constructor... |
68 | */ |
69 | VclPtr() |
70 | : m_rInnerRef() |
71 | {} |
72 | |
73 | /** Constructor... |
74 | */ |
75 | VclPtr (reference_type * pBody) |
76 | : m_rInnerRef(pBody) |
77 | {} |
78 | |
79 | /** Constructor... that doesn't take a ref. |
80 | */ |
81 | VclPtr (reference_type * pBody, __sal_NoAcquire) |
82 | : m_rInnerRef(pBody, SAL_NO_ACQUIRE) |
83 | {} |
84 | |
85 | /** Up-casting conversion constructor: Copies interface reference. |
86 | |
87 | Does not work for up-casts to ambiguous bases. For the special case of |
88 | up-casting to Reference< XInterface >, see the corresponding conversion |
89 | operator. |
90 | |
91 | @param rRef another reference |
92 | */ |
93 | template< class derived_type > |
94 | VclPtr( |
95 | const VclPtr< derived_type > & rRef, |
96 | typename std::enable_if< |
97 | std::is_base_of<reference_type, derived_type>::value, int>::type |
98 | = 0 ) |
99 | : m_rInnerRef( static_cast<reference_type*>(rRef) ) |
100 | { |
101 | } |
102 | |
103 | #if defined(DBG_UTIL) && !defined(_WIN32) |
104 | virtual ~VclPtr() |
105 | { |
106 | assert(m_rInnerRef.get() == nullptr || vclmain::isAlive())(static_cast <bool> (m_rInnerRef.get() == nullptr || vclmain ::isAlive()) ? void (0) : __assert_fail ("m_rInnerRef.get() == nullptr || vclmain::isAlive()" , "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx" , 106, __extension__ __PRETTY_FUNCTION__)); |
107 | // We can be one of the intermediate counts, but if we are the last |
108 | // VclPtr keeping this object alive, then something forgot to call dispose(). |
109 | assert((!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1)(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef ->isDisposed() || m_rInnerRef->getRefCount() > 1) && "someone forgot to call dispose()") ? void (0) : __assert_fail ("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\"" , "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx" , 110, __extension__ __PRETTY_FUNCTION__)) |
110 | && "someone forgot to call dispose()")(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef ->isDisposed() || m_rInnerRef->getRefCount() > 1) && "someone forgot to call dispose()") ? void (0) : __assert_fail ("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\"" , "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx" , 110, __extension__ __PRETTY_FUNCTION__)); |
111 | } |
112 | VclPtr(VclPtr const &) = default; |
113 | VclPtr(VclPtr &&) = default; |
114 | VclPtr & operator =(VclPtr const &) = default; |
115 | VclPtr & operator =(VclPtr &&) = default; |
116 | #endif |
117 | |
118 | /** |
119 | * A construction helper for VclPtr. Since VclPtr types are created |
120 | * with a reference-count of one - to help fit into the existing |
121 | * code-flow; this helps us to construct them easily. |
122 | * |
123 | * For more details on the design please see vcl/README.lifecycle |
124 | * |
125 | * @tparam reference_type must be a subclass of vcl::Window |
126 | */ |
127 | template<typename... Arg> [[nodiscard]] static VclPtr< reference_type > Create(Arg &&... arg) |
128 | { |
129 | return VclPtr< reference_type >( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE ); |
130 | } |
131 | |
132 | /** Probably most common used: handle->someBodyOp(). |
133 | */ |
134 | reference_type * operator->() const |
135 | { |
136 | return m_rInnerRef.get(); |
137 | } |
138 | |
139 | /** Get the body. Can be used instead of operator->(). |
140 | I.e. handle->someBodyOp() and handle.get()->someBodyOp() |
141 | are the same. |
142 | */ |
143 | reference_type * get() const |
144 | { |
145 | return m_rInnerRef.get(); |
146 | } |
147 | |
148 | void set(reference_type *pBody) |
149 | { |
150 | m_rInnerRef.set(pBody); |
151 | } |
152 | |
153 | void reset(reference_type *pBody) |
154 | { |
155 | m_rInnerRef.set(pBody); |
156 | } |
157 | |
158 | /** Up-casting copy assignment operator. |
159 | |
160 | Does not work for up-casts to ambiguous bases. |
161 | |
162 | @param rRef another reference |
163 | */ |
164 | template<typename derived_type> |
165 | typename std::enable_if< |
166 | std::is_base_of<reference_type, derived_type>::value, |
167 | VclPtr &>::type |
168 | operator =(VclPtr<derived_type> const & rRef) |
169 | { |
170 | m_rInnerRef.set(rRef.get()); |
171 | return *this; |
172 | } |
173 | |
174 | VclPtr & operator =(reference_type * pBody) |
175 | { |
176 | m_rInnerRef.set(pBody); |
177 | return *this; |
178 | } |
179 | |
180 | operator reference_type * () const |
181 | { |
182 | return m_rInnerRef.get(); |
183 | } |
184 | |
185 | explicit operator bool () const |
186 | { |
187 | return m_rInnerRef.get() != nullptr; |
188 | } |
189 | |
190 | void clear() |
191 | { |
192 | m_rInnerRef.clear(); |
193 | } |
194 | |
195 | void reset() |
196 | { |
197 | m_rInnerRef.clear(); |
198 | } |
199 | |
200 | void disposeAndClear() |
201 | { |
202 | // hold it alive for the lifetime of this method |
203 | ::rtl::Reference<reference_type> aTmp(m_rInnerRef); |
204 | m_rInnerRef.clear(); // we should use some 'swap' method ideally ;-) |
205 | if (aTmp.get()) { |
206 | aTmp->disposeOnce(); |
207 | } |
208 | } |
209 | |
210 | /** Needed to place VclPtr's into STL collection. |
211 | */ |
212 | bool operator< (const VclPtr<reference_type> & handle) const |
213 | { |
214 | return (m_rInnerRef < handle.m_rInnerRef); |
215 | } |
216 | }; // class VclPtr |
217 | |
218 | template<typename T1, typename T2> |
219 | inline bool operator ==(VclPtr<T1> const & p1, VclPtr<T2> const & p2) { |
220 | return p1.get() == p2.get(); |
221 | } |
222 | |
223 | template<typename T> inline bool operator ==(VclPtr<T> const & p1, T const * p2) |
224 | { |
225 | return p1.get() == p2; |
226 | } |
227 | |
228 | template<typename T> inline bool operator ==(VclPtr<T> const & p1, T * p2) { |
229 | return p1.get() == p2; |
230 | } |
231 | |
232 | template<typename T> inline bool operator ==(T const * p1, VclPtr<T> const & p2) |
233 | { |
234 | return p1 == p2.get(); |
235 | } |
236 | |
237 | template<typename T> inline bool operator ==(T * p1, VclPtr<T> const & p2) { |
238 | return p1 == p2.get(); |
239 | } |
240 | |
241 | template<typename T1, typename T2> |
242 | inline bool operator !=(VclPtr<T1> const & p1, VclPtr<T2> const & p2) { |
243 | return !(p1 == p2); |
244 | } |
245 | |
246 | template<typename T> inline bool operator !=(VclPtr<T> const & p1, T const * p2) |
247 | { |
248 | return !(p1 == p2); |
249 | } |
250 | |
251 | template<typename T> inline bool operator !=(VclPtr<T> const & p1, T * p2) { |
252 | return !(p1 == p2); |
253 | } |
254 | |
255 | template<typename T> inline bool operator !=(T const * p1, VclPtr<T> const & p2) |
256 | { |
257 | return !(p1 == p2); |
258 | } |
259 | |
260 | template<typename T> inline bool operator !=(T * p1, VclPtr<T> const & p2) { |
261 | return !(p1 == p2); |
262 | } |
263 | |
264 | /** |
265 | * A construction helper for a temporary VclPtr. Since VclPtr types |
266 | * are created with a reference-count of one - to help fit into |
267 | * the existing code-flow; this helps us to construct them easily. |
268 | * see also VclPtr::Create and ScopedVclPtr |
269 | * |
270 | * For more details on the design please see vcl/README.lifecycle |
271 | * |
272 | * @param reference_type must be a subclass of vcl::Window |
273 | */ |
274 | template <class reference_type> |
275 | class SAL_WARN_UNUSED__attribute__((warn_unused)) VclPtrInstance final : public VclPtr<reference_type> |
276 | { |
277 | public: |
278 | template<typename... Arg> VclPtrInstance(Arg &&... arg) |
279 | : VclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE ) |
280 | { |
281 | } |
282 | |
283 | /** |
284 | * Override and disallow this, to prevent people accidentally calling it and actually |
285 | * getting VclPtr::Create and getting a naked VclPtr<> instance |
286 | */ |
287 | template<typename... Arg> static VclPtrInstance< reference_type > Create(Arg &&... ) = delete; |
288 | }; |
289 | |
290 | template <class reference_type> |
291 | class ScopedVclPtr : public VclPtr<reference_type> |
292 | { |
293 | public: |
294 | /** Constructor... |
295 | */ |
296 | ScopedVclPtr() |
297 | : VclPtr<reference_type>() |
298 | {} |
299 | |
300 | /** Constructor |
301 | */ |
302 | ScopedVclPtr (reference_type * pBody) |
303 | : VclPtr<reference_type>(pBody) |
304 | {} |
305 | |
306 | /** Copy constructor... |
307 | */ |
308 | ScopedVclPtr (const VclPtr<reference_type> & handle) |
309 | : VclPtr<reference_type>(handle) |
310 | {} |
311 | |
312 | /** |
313 | Assignment that releases the last reference. |
314 | */ |
315 | void disposeAndReset(reference_type *pBody) |
316 | { |
317 | if (pBody != this->get()) { |
318 | VclPtr<reference_type>::disposeAndClear(); |
319 | VclPtr<reference_type>::set(pBody); |
320 | } |
321 | } |
322 | |
323 | /** |
324 | Assignment that releases the last reference. |
325 | */ |
326 | ScopedVclPtr<reference_type>& operator = (reference_type * pBody) |
327 | { |
328 | disposeAndReset(pBody); |
329 | return *this; |
330 | } |
331 | |
332 | /** Up-casting conversion constructor: Copies interface reference. |
333 | |
334 | Does not work for up-casts to ambiguous bases. For the special case of |
335 | up-casting to Reference< XInterface >, see the corresponding conversion |
336 | operator. |
337 | |
338 | @param rRef another reference |
339 | */ |
340 | template< class derived_type > |
341 | ScopedVclPtr( |
342 | const VclPtr< derived_type > & rRef, |
343 | typename std::enable_if< |
344 | std::is_base_of<reference_type, derived_type>::value, int>::type |
345 | = 0 ) |
346 | : VclPtr<reference_type>( rRef ) |
347 | { |
348 | } |
349 | |
350 | /** Up-casting assignment operator. |
351 | |
352 | Does not work for up-casts to ambiguous bases. |
353 | |
354 | @param rRef another VclPtr |
355 | */ |
356 | template<typename derived_type> |
357 | typename std::enable_if< |
358 | std::is_base_of<reference_type, derived_type>::value, |
359 | ScopedVclPtr &>::type |
360 | operator =(VclPtr<derived_type> const & rRef) |
361 | { |
362 | disposeAndReset(rRef.get()); |
363 | return *this; |
364 | } |
365 | |
366 | /** |
367 | * Override and disallow this, to prevent people accidentally calling it and actually |
368 | * getting VclPtr::Create and getting a naked VclPtr<> instance |
369 | */ |
370 | template<typename... Arg> static ScopedVclPtr< reference_type > Create(Arg &&... ) = delete; |
371 | |
372 | ~ScopedVclPtr() |
373 | { |
374 | VclPtr<reference_type>::disposeAndClear(); |
375 | assert(VclPtr<reference_type>::get() == nullptr)(static_cast <bool> (VclPtr<reference_type>::get( ) == nullptr) ? void (0) : __assert_fail ("VclPtr<reference_type>::get() == nullptr" , "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx" , 375, __extension__ __PRETTY_FUNCTION__)); // make sure there are no lingering references |
376 | } |
377 | |
378 | private: |
379 | // Most likely we don't want this default copy-constructor. |
380 | ScopedVclPtr (const ScopedVclPtr<reference_type> &) = delete; |
381 | // And certainly we don't want a default assignment operator. |
382 | ScopedVclPtr<reference_type>& operator = (const ScopedVclPtr<reference_type> &) = delete; |
383 | // And disallow reset as that doesn't call disposeAndClear on the original reference |
384 | void reset() = delete; |
385 | void reset(reference_type *pBody) = delete; |
386 | |
387 | protected: |
388 | ScopedVclPtr (reference_type * pBody, __sal_NoAcquire) |
389 | : VclPtr<reference_type>(pBody, SAL_NO_ACQUIRE) |
390 | {} |
391 | }; |
392 | |
393 | /** |
394 | * A construction helper for ScopedVclPtr. Since VclPtr types are created |
395 | * with a reference-count of one - to help fit into the existing |
396 | * code-flow; this helps us to construct them easily. |
397 | * |
398 | * For more details on the design please see vcl/README.lifecycle |
399 | * |
400 | * @param reference_type must be a subclass of vcl::Window |
401 | */ |
402 | #if defined _MSC_VER |
403 | #pragma warning(push) |
404 | #pragma warning(disable: 4521) // " multiple copy constructors specified" |
405 | #endif |
406 | template <class reference_type> |
407 | class SAL_WARN_UNUSED__attribute__((warn_unused)) ScopedVclPtrInstance final : public ScopedVclPtr<reference_type> |
408 | { |
409 | public: |
410 | template<typename... Arg> ScopedVclPtrInstance(Arg &&... arg) |
411 | : ScopedVclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE ) |
412 | { |
413 | } |
414 | |
415 | /** |
416 | * Override and disallow this, to prevent people accidentally calling it and actually |
417 | * getting VclPtr::Create and getting a naked VclPtr<> instance |
418 | */ |
419 | template<typename... Arg> static ScopedVclPtrInstance< reference_type > Create(Arg &&...) = delete; |
420 | |
421 | private: |
422 | // Prevent the above perfect forwarding ctor from hijacking (accidental) |
423 | // attempts at ScopedVclPtrInstance copy construction (where the hijacking |
424 | // would typically lead to somewhat obscure error messages); both non-const |
425 | // and const variants are needed here, as the ScopedVclPtr base class has a |
426 | // const--variant copy ctor, so the implicitly declared copy ctor for |
427 | // ScopedVclPtrInstance would also be the const variant, so non-const copy |
428 | // construction attempts would be hijacked by the perfect forwarding ctor; |
429 | // but if we only declared a non-const variant here, the const variant would |
430 | // no longer be implicitly declared (as there would already be an explicitly |
431 | // declared copy ctor), so const copy construction attempts would then be |
432 | // hijacked by the perfect forwarding ctor: |
433 | ScopedVclPtrInstance(ScopedVclPtrInstance &) = delete; |
434 | ScopedVclPtrInstance(ScopedVclPtrInstance const &) = delete; |
435 | }; |
436 | #if defined _MSC_VER |
437 | #pragma warning(pop) |
438 | #endif |
439 | |
440 | #endif // INCLUDED_VCL_PTR_HXX |
441 | |
442 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |
1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ | ||||||||
2 | /* | ||||||||
3 | * This file is part of the LibreOffice project. | ||||||||
4 | * | ||||||||
5 | * This Source Code Form is subject to the terms of the Mozilla Public | ||||||||
6 | * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||||
7 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||||
8 | * | ||||||||
9 | * This file incorporates work covered by the following license notice: | ||||||||
10 | * | ||||||||
11 | * Licensed to the Apache Software Foundation (ASF) under one or more | ||||||||
12 | * contributor license agreements. See the NOTICE file distributed | ||||||||
13 | * with this work for additional information regarding copyright | ||||||||
14 | * ownership. The ASF licenses this file to you under the Apache | ||||||||
15 | * License, Version 2.0 (the "License"); you may not use this file | ||||||||
16 | * except in compliance with the License. You may obtain a copy of | ||||||||
17 | * the License at http://www.apache.org/licenses/LICENSE-2.0 . | ||||||||
18 | */ | ||||||||
19 | |||||||||
20 | #ifndef INCLUDED_RTL_REF_HXX | ||||||||
21 | #define INCLUDED_RTL_REF_HXX | ||||||||
22 | |||||||||
23 | #include "sal/config.h" | ||||||||
24 | |||||||||
25 | #include <cassert> | ||||||||
26 | #include <cstddef> | ||||||||
27 | #include <functional> | ||||||||
28 | #ifdef LIBO_INTERNAL_ONLY1 | ||||||||
29 | #include <type_traits> | ||||||||
30 | #endif | ||||||||
31 | |||||||||
32 | #include "sal/types.h" | ||||||||
33 | |||||||||
34 | namespace rtl | ||||||||
35 | { | ||||||||
36 | |||||||||
37 | /** Template reference class for reference type. | ||||||||
38 | */ | ||||||||
39 | template <class reference_type> | ||||||||
40 | class Reference | ||||||||
41 | { | ||||||||
42 | /** The <b>reference_type</b> body pointer. | ||||||||
43 | */ | ||||||||
44 | reference_type * m_pBody; | ||||||||
45 | |||||||||
46 | |||||||||
47 | public: | ||||||||
48 | /** Constructor... | ||||||||
49 | */ | ||||||||
50 | Reference() | ||||||||
51 | : m_pBody (NULL__null) | ||||||||
52 | {} | ||||||||
53 | |||||||||
54 | |||||||||
55 | /** Constructor... | ||||||||
56 | */ | ||||||||
57 | Reference (reference_type * pBody, __sal_NoAcquire) | ||||||||
58 | : m_pBody (pBody) | ||||||||
59 | { | ||||||||
60 | } | ||||||||
61 | |||||||||
62 | /** Constructor... | ||||||||
63 | */ | ||||||||
64 | Reference (reference_type * pBody) | ||||||||
65 | : m_pBody (pBody) | ||||||||
66 | { | ||||||||
67 | if (m_pBody) | ||||||||
68 | m_pBody->acquire(); | ||||||||
69 | } | ||||||||
70 | |||||||||
71 | /** Copy constructor... | ||||||||
72 | */ | ||||||||
73 | Reference (const Reference<reference_type> & handle) | ||||||||
74 | : m_pBody (handle.m_pBody) | ||||||||
75 | { | ||||||||
76 | if (m_pBody) | ||||||||
77 | m_pBody->acquire(); | ||||||||
78 | } | ||||||||
79 | |||||||||
80 | #ifdef LIBO_INTERNAL_ONLY1 | ||||||||
81 | /** Move constructor... | ||||||||
82 | */ | ||||||||
83 | Reference (Reference<reference_type> && handle) noexcept | ||||||||
84 | : m_pBody (handle.m_pBody) | ||||||||
85 | { | ||||||||
86 | handle.m_pBody = nullptr; | ||||||||
87 | } | ||||||||
88 | #endif | ||||||||
89 | |||||||||
90 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
91 | /** Up-casting conversion constructor: Copies interface reference. | ||||||||
92 | |||||||||
93 | Does not work for up-casts to ambiguous bases. | ||||||||
94 | |||||||||
95 | @param rRef another reference | ||||||||
96 | */ | ||||||||
97 | template< class derived_type > | ||||||||
98 | inline Reference( | ||||||||
99 | const Reference< derived_type > & rRef, | ||||||||
100 | std::enable_if_t<std::is_base_of_v<reference_type, derived_type>, int> = 0 ) | ||||||||
101 | : m_pBody (rRef.get()) | ||||||||
102 | { | ||||||||
103 | if (m_pBody) | ||||||||
104 | m_pBody->acquire(); | ||||||||
105 | } | ||||||||
106 | #endif | ||||||||
107 | |||||||||
108 | /** Destructor... | ||||||||
109 | */ | ||||||||
110 | ~Reference() COVERITY_NOEXCEPT_FALSE | ||||||||
111 | { | ||||||||
112 | if (m_pBody) | ||||||||
113 | m_pBody->release(); | ||||||||
114 | } | ||||||||
115 | |||||||||
116 | /** Set... | ||||||||
117 | Similar to assignment. | ||||||||
118 | */ | ||||||||
119 | Reference<reference_type> & | ||||||||
120 | SAL_CALL set (reference_type * pBody) | ||||||||
121 | { | ||||||||
122 | if (pBody) | ||||||||
123 | pBody->acquire(); | ||||||||
124 | reference_type * const pOld = m_pBody; | ||||||||
125 | m_pBody = pBody; | ||||||||
126 | if (pOld) | ||||||||
127 | pOld->release(); | ||||||||
128 | return *this; | ||||||||
129 | } | ||||||||
130 | |||||||||
131 | /** Assignment. | ||||||||
132 | Unbinds this instance from its body (if bound) and | ||||||||
133 | bind it to the body represented by the handle. | ||||||||
134 | */ | ||||||||
135 | Reference<reference_type> & | ||||||||
136 | SAL_CALL operator= (const Reference<reference_type> & handle) | ||||||||
137 | { | ||||||||
138 | return set( handle.m_pBody ); | ||||||||
139 | } | ||||||||
140 | |||||||||
141 | #ifdef LIBO_INTERNAL_ONLY1 | ||||||||
142 | /** Assignment. | ||||||||
143 | * Unbinds this instance from its body (if bound), | ||||||||
144 | * bind it to the body represented by the handle, and | ||||||||
145 | * set the body represented by the handle to nullptr. | ||||||||
146 | */ | ||||||||
147 | Reference<reference_type> & | ||||||||
148 | operator= (Reference<reference_type> && handle) | ||||||||
149 | { | ||||||||
150 | // self-movement guts ourself | ||||||||
151 | if (m_pBody) | ||||||||
152 | m_pBody->release(); | ||||||||
153 | m_pBody = handle.m_pBody; | ||||||||
154 | handle.m_pBody = nullptr; | ||||||||
155 | return *this; | ||||||||
156 | } | ||||||||
157 | #endif | ||||||||
158 | |||||||||
159 | /** Assignment... | ||||||||
160 | */ | ||||||||
161 | Reference<reference_type> & | ||||||||
162 | SAL_CALL operator= (reference_type * pBody) | ||||||||
163 | { | ||||||||
164 | return set( pBody ); | ||||||||
165 | } | ||||||||
166 | |||||||||
167 | /** Unbind the body from this handle. | ||||||||
168 | Note that for a handle representing a large body, | ||||||||
169 | "handle.clear().set(new body());" _might_ | ||||||||
170 | perform a little bit better than "handle.set(new body());", | ||||||||
171 | since in the second case two large objects exist in memory | ||||||||
172 | (the old body and the new body). | ||||||||
173 | */ | ||||||||
174 | Reference<reference_type> & SAL_CALL clear() | ||||||||
175 | { | ||||||||
176 | if (m_pBody
| ||||||||
177 | { | ||||||||
178 | reference_type * const pOld = m_pBody; | ||||||||
179 | m_pBody = NULL__null; | ||||||||
180 | pOld->release(); | ||||||||
181 | } | ||||||||
182 | return *this; | ||||||||
183 | } | ||||||||
184 | |||||||||
185 | |||||||||
186 | /** Get the body. Can be used instead of operator->(). | ||||||||
187 | I.e. handle->someBodyOp() and handle.get()->someBodyOp() | ||||||||
188 | are the same. | ||||||||
189 | */ | ||||||||
190 | reference_type * SAL_CALL get() const | ||||||||
191 | { | ||||||||
192 | return m_pBody; | ||||||||
| |||||||||
193 | } | ||||||||
194 | |||||||||
195 | |||||||||
196 | /** Probably most common used: handle->someBodyOp(). | ||||||||
197 | */ | ||||||||
198 | reference_type * SAL_CALL operator->() const | ||||||||
199 | { | ||||||||
200 | assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail ("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx" , 200, __extension__ __PRETTY_FUNCTION__)); | ||||||||
201 | return m_pBody; | ||||||||
202 | } | ||||||||
203 | |||||||||
204 | |||||||||
205 | /** Allows (*handle).someBodyOp(). | ||||||||
206 | */ | ||||||||
207 | reference_type & SAL_CALL operator*() const | ||||||||
208 | { | ||||||||
209 | assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail ("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx" , 209, __extension__ __PRETTY_FUNCTION__)); | ||||||||
210 | return *m_pBody; | ||||||||
211 | } | ||||||||
212 | |||||||||
213 | |||||||||
214 | /** Returns True if the handle does point to a valid body. | ||||||||
215 | */ | ||||||||
216 | bool SAL_CALL is() const | ||||||||
217 | { | ||||||||
218 | return (m_pBody != NULL__null); | ||||||||
219 | } | ||||||||
220 | |||||||||
221 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
222 | /** Returns True if the handle does point to a valid body. | ||||||||
223 | */ | ||||||||
224 | explicit operator bool() const | ||||||||
225 | { | ||||||||
226 | return is(); | ||||||||
227 | } | ||||||||
228 | #endif | ||||||||
229 | |||||||||
230 | /** Returns True if this points to pBody. | ||||||||
231 | */ | ||||||||
232 | bool SAL_CALL operator== (const reference_type * pBody) const | ||||||||
233 | { | ||||||||
234 | return (m_pBody == pBody); | ||||||||
235 | } | ||||||||
236 | |||||||||
237 | |||||||||
238 | /** Returns True if handle points to the same body. | ||||||||
239 | */ | ||||||||
240 | bool | ||||||||
241 | SAL_CALL operator== (const Reference<reference_type> & handle) const | ||||||||
242 | { | ||||||||
243 | return (m_pBody == handle.m_pBody); | ||||||||
244 | } | ||||||||
245 | |||||||||
246 | |||||||||
247 | /** Needed to place References into STL collection. | ||||||||
248 | */ | ||||||||
249 | bool | ||||||||
250 | SAL_CALL operator!= (const Reference<reference_type> & handle) const | ||||||||
251 | { | ||||||||
252 | return (m_pBody != handle.m_pBody); | ||||||||
253 | } | ||||||||
254 | |||||||||
255 | |||||||||
256 | /** Needed to place References into STL collection. | ||||||||
257 | */ | ||||||||
258 | bool | ||||||||
259 | SAL_CALL operator< (const Reference<reference_type> & handle) const | ||||||||
260 | { | ||||||||
261 | return (m_pBody < handle.m_pBody); | ||||||||
262 | } | ||||||||
263 | |||||||||
264 | |||||||||
265 | /** Needed to place References into STL collection. | ||||||||
266 | */ | ||||||||
267 | bool | ||||||||
268 | SAL_CALL operator> (const Reference<reference_type> & handle) const | ||||||||
269 | { | ||||||||
270 | return (m_pBody > handle.m_pBody); | ||||||||
271 | } | ||||||||
272 | }; | ||||||||
273 | |||||||||
274 | } // namespace rtl | ||||||||
275 | |||||||||
276 | #if defined LIBO_INTERNAL_ONLY1 | ||||||||
277 | namespace std | ||||||||
278 | { | ||||||||
279 | |||||||||
280 | /// @cond INTERNAL | ||||||||
281 | /** | ||||||||
282 | Make rtl::Reference hashable by default for use in STL containers. | ||||||||
283 | |||||||||
284 | @since LibreOffice 6.3 | ||||||||
285 | */ | ||||||||
286 | template<typename T> | ||||||||
287 | struct hash<::rtl::Reference<T>> | ||||||||
288 | { | ||||||||
289 | std::size_t operator()(::rtl::Reference<T> const & s) const | ||||||||
290 | { return std::size_t(s.get()); } | ||||||||
291 | }; | ||||||||
292 | /// @endcond | ||||||||
293 | |||||||||
294 | } | ||||||||
295 | |||||||||
296 | #endif | ||||||||
297 | |||||||||
298 | #endif /* ! INCLUDED_RTL_REF_HXX */ | ||||||||
299 | |||||||||
300 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |
1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | /* |
3 | * This file is part of the LibreOffice project. |
4 | * |
5 | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | * |
9 | * This file incorporates work covered by the following license notice: |
10 | * |
11 | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | * contributor license agreements. See the NOTICE file distributed |
13 | * with this work for additional information regarding copyright |
14 | * ownership. The ASF licenses this file to you under the Apache |
15 | * License, Version 2.0 (the "License"); you may not use this file |
16 | * except in compliance with the License. You may obtain a copy of |
17 | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | */ |
19 | #ifndef INCLUDED_VCL_Reference_HXX |
20 | #define INCLUDED_VCL_Reference_HXX |
21 | |
22 | #include <vcl/dllapi.h> |
23 | #include <osl/interlck.h> |
24 | |
25 | class VCL_DLLPUBLIC__attribute__ ((visibility("default"))) VclReferenceBase |
26 | { |
27 | mutable oslInterlockedCount mnRefCnt; |
28 | |
29 | template<typename T> friend class VclPtr; |
30 | |
31 | public: |
32 | void acquire() const |
33 | { |
34 | osl_atomic_increment(&mnRefCnt)__sync_add_and_fetch((&mnRefCnt), 1); |
35 | } |
36 | |
37 | void release() const |
38 | { |
39 | if (osl_atomic_decrement(&mnRefCnt)__sync_sub_and_fetch((&mnRefCnt), 1) == 0) |
40 | delete this; |
41 | } |
42 | #ifdef DBG_UTIL |
43 | #ifndef _WIN32 |
44 | sal_Int32 getRefCount() const { return mnRefCnt; } |
45 | #endif |
46 | #endif |
47 | |
48 | |
49 | private: |
50 | VclReferenceBase(const VclReferenceBase&) = delete; |
51 | VclReferenceBase& operator=(const VclReferenceBase&) = delete; |
52 | |
53 | bool mbDisposed : 1; |
54 | |
55 | protected: |
56 | VclReferenceBase(); |
57 | protected: |
58 | virtual ~VclReferenceBase(); |
59 | |
60 | protected: |
61 | virtual void dispose(); |
62 | |
63 | public: |
64 | void disposeOnce(); |
65 | bool isDisposed() const { return mbDisposed; } |
66 | |
67 | }; |
68 | #endif |