File: | home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx |
Warning: | line 1859, column 47 Called C++ object pointer is null |
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 <tools/stream.hxx> | |||
21 | ||||
22 | #include <vcl/texteng.hxx> | |||
23 | #include <vcl/textview.hxx> | |||
24 | #include <vcl/commandevent.hxx> | |||
25 | #include <vcl/inputctx.hxx> | |||
26 | #include "textdoc.hxx" | |||
27 | #include "textdat2.hxx" | |||
28 | #include "textundo.hxx" | |||
29 | #include "textund2.hxx" | |||
30 | #include <svl/ctloptions.hxx> | |||
31 | #include <vcl/window.hxx> | |||
32 | #include <vcl/settings.hxx> | |||
33 | #include <vcl/toolkit/edit.hxx> | |||
34 | #include <vcl/virdev.hxx> | |||
35 | #include <sal/log.hxx> | |||
36 | #include <osl/diagnose.h> | |||
37 | ||||
38 | #include <com/sun/star/i18n/XBreakIterator.hpp> | |||
39 | ||||
40 | #include <com/sun/star/i18n/CharacterIteratorMode.hpp> | |||
41 | ||||
42 | #include <com/sun/star/i18n/WordType.hpp> | |||
43 | ||||
44 | #include <com/sun/star/i18n/InputSequenceChecker.hpp> | |||
45 | #include <com/sun/star/i18n/InputSequenceCheckMode.hpp> | |||
46 | #include <com/sun/star/i18n/ScriptType.hpp> | |||
47 | ||||
48 | #include <comphelper/processfactory.hxx> | |||
49 | ||||
50 | #include <unotools/localedatawrapper.hxx> | |||
51 | #include <vcl/unohelp.hxx> | |||
52 | ||||
53 | #include <vcl/svapp.hxx> | |||
54 | ||||
55 | #include <unicode/ubidi.h> | |||
56 | ||||
57 | #include <algorithm> | |||
58 | #include <cstddef> | |||
59 | #include <cstdlib> | |||
60 | #include <memory> | |||
61 | #include <set> | |||
62 | #include <string_view> | |||
63 | #include <vector> | |||
64 | ||||
65 | using namespace ::com::sun::star; | |||
66 | using namespace ::com::sun::star::uno; | |||
67 | ||||
68 | TextEngine::TextEngine() | |||
69 | : mpActiveView {nullptr} | |||
70 | , maTextColor {COL_BLACK} | |||
71 | , mnMaxTextLen {0} | |||
72 | , mnMaxTextWidth {0} | |||
73 | , mnCharHeight {0} | |||
74 | , mnCurTextWidth {-1} | |||
75 | , mnCurTextHeight {0} | |||
76 | , mnDefTab {0} | |||
77 | , meAlign {TxtAlign::Left} | |||
78 | , mbIsFormatting {false} | |||
79 | , mbFormatted {false} | |||
80 | , mbUpdate {true} | |||
81 | , mbModified {false} | |||
82 | , mbUndoEnabled {false} | |||
83 | , mbIsInUndo {false} | |||
84 | , mbDowning {false} | |||
85 | , mbRightToLeft {false} | |||
86 | , mbHasMultiLineParas {false} | |||
87 | { | |||
88 | mpViews.reset( new TextViews ); | |||
89 | ||||
90 | mpIdleFormatter.reset( new IdleFormatter ); | |||
91 | mpIdleFormatter->SetInvokeHandler( LINK( this, TextEngine, IdleFormatHdl )::tools::detail::makeLink( ::tools::detail::castTo<TextEngine *>(this), &TextEngine::LinkStubIdleFormatHdl) ); | |||
92 | mpIdleFormatter->SetDebugName( "vcl::TextEngine mpIdleFormatter" ); | |||
93 | ||||
94 | mpRefDev = VclPtr<VirtualDevice>::Create(); | |||
95 | ||||
96 | ImpInitLayoutMode( mpRefDev ); | |||
97 | ||||
98 | ImpInitDoc(); | |||
99 | ||||
100 | vcl::Font aFont; | |||
101 | aFont.SetTransparent( false ); | |||
102 | Color aFillColor( aFont.GetFillColor() ); | |||
103 | aFillColor.SetTransparency( 0 ); | |||
104 | aFont.SetFillColor( aFillColor ); | |||
105 | SetFont( aFont ); | |||
106 | } | |||
107 | ||||
108 | TextEngine::~TextEngine() | |||
109 | { | |||
110 | mbDowning = true; | |||
111 | ||||
112 | mpIdleFormatter.reset(); | |||
113 | mpDoc.reset(); | |||
114 | mpTEParaPortions.reset(); | |||
115 | mpViews.reset(); // only the list, not the Views | |||
116 | mpRefDev.disposeAndClear(); | |||
117 | mpUndoManager.reset(); | |||
118 | mpIMEInfos.reset(); | |||
119 | mpLocaleDataWrapper.reset(); | |||
120 | } | |||
121 | ||||
122 | void TextEngine::InsertView( TextView* pTextView ) | |||
123 | { | |||
124 | mpViews->push_back( pTextView ); | |||
125 | pTextView->SetSelection( TextSelection() ); | |||
126 | ||||
127 | if ( !GetActiveView() ) | |||
128 | SetActiveView( pTextView ); | |||
129 | } | |||
130 | ||||
131 | void TextEngine::RemoveView( TextView* pTextView ) | |||
132 | { | |||
133 | TextViews::iterator it = std::find( mpViews->begin(), mpViews->end(), pTextView ); | |||
134 | if( it != mpViews->end() ) | |||
135 | { | |||
136 | pTextView->HideCursor(); | |||
137 | mpViews->erase( it ); | |||
138 | if ( pTextView == GetActiveView() ) | |||
139 | SetActiveView( nullptr ); | |||
140 | } | |||
141 | } | |||
142 | ||||
143 | sal_uInt16 TextEngine::GetViewCount() const | |||
144 | { | |||
145 | return mpViews->size(); | |||
146 | } | |||
147 | ||||
148 | TextView* TextEngine::GetView( sal_uInt16 nView ) const | |||
149 | { | |||
150 | return (*mpViews)[ nView ]; | |||
151 | } | |||
152 | ||||
153 | ||||
154 | void TextEngine::SetActiveView( TextView* pTextView ) | |||
155 | { | |||
156 | if ( pTextView != mpActiveView ) | |||
157 | { | |||
158 | if ( mpActiveView ) | |||
159 | mpActiveView->HideSelection(); | |||
160 | ||||
161 | mpActiveView = pTextView; | |||
162 | ||||
163 | if ( mpActiveView ) | |||
164 | mpActiveView->ShowSelection(); | |||
165 | } | |||
166 | } | |||
167 | ||||
168 | void TextEngine::SetFont( const vcl::Font& rFont ) | |||
169 | { | |||
170 | if ( rFont == maFont ) | |||
171 | return; | |||
172 | ||||
173 | maFont = rFont; | |||
174 | // #i40221# As the font's color now defaults to transparent (since i35764) | |||
175 | // we have to choose a useful textcolor in this case. | |||
176 | // Otherwise maTextColor and maFont.GetColor() are both transparent... | |||
177 | if( rFont.GetColor() == COL_TRANSPARENT ) | |||
178 | maTextColor = COL_BLACK; | |||
179 | else | |||
180 | maTextColor = rFont.GetColor(); | |||
181 | ||||
182 | // Do not allow transparent fonts because of selection | |||
183 | // (otherwise delete the background in ImplPaint later differently) | |||
184 | maFont.SetTransparent( false ); | |||
185 | // Tell VCL not to use the font color, use text color from OutputDevice | |||
186 | maFont.SetColor( COL_TRANSPARENT ); | |||
187 | Color aFillColor( maFont.GetFillColor() ); | |||
188 | aFillColor.SetTransparency( 0 ); | |||
189 | maFont.SetFillColor( aFillColor ); | |||
190 | ||||
191 | maFont.SetAlignment( ALIGN_TOP ); | |||
192 | mpRefDev->SetFont( maFont ); | |||
193 | mnDefTab = mpRefDev->GetTextWidth(" "); | |||
194 | if ( !mnDefTab ) | |||
195 | mnDefTab = mpRefDev->GetTextWidth("XXXX"); | |||
196 | if ( !mnDefTab ) | |||
197 | mnDefTab = 1; | |||
198 | mnCharHeight = mpRefDev->GetTextHeight(); | |||
199 | ||||
200 | FormatFullDoc(); | |||
201 | UpdateViews(); | |||
202 | ||||
203 | for ( auto nView = mpViews->size(); nView; ) | |||
204 | { | |||
205 | TextView* pView = (*mpViews)[ --nView ]; | |||
206 | pView->GetWindow()->SetInputContext( InputContext( GetFont(), !pView->IsReadOnly() ? InputContextFlags::Text|InputContextFlags::ExtText : InputContextFlags::NONE ) ); | |||
207 | } | |||
208 | ||||
209 | } | |||
210 | ||||
211 | void TextEngine::SetMaxTextLen( sal_Int32 nLen ) | |||
212 | { | |||
213 | mnMaxTextLen = nLen>=0 ? nLen : EDIT_NOLIMIT((sal_Int32) 0x7FFFFFFF); | |||
214 | } | |||
215 | ||||
216 | void TextEngine::SetMaxTextWidth( long nMaxWidth ) | |||
217 | { | |||
218 | if ( nMaxWidth>=0 && nMaxWidth != mnMaxTextWidth ) | |||
219 | { | |||
220 | mnMaxTextWidth = nMaxWidth; | |||
221 | FormatFullDoc(); | |||
222 | UpdateViews(); | |||
223 | } | |||
224 | } | |||
225 | ||||
226 | const sal_Unicode static_aLFText[] = { '\n', 0 }; | |||
227 | const sal_Unicode static_aCRText[] = { '\r', 0 }; | |||
228 | const sal_Unicode static_aCRLFText[] = { '\r', '\n', 0 }; | |||
229 | ||||
230 | static const sal_Unicode* static_getLineEndText( LineEnd aLineEnd ) | |||
231 | { | |||
232 | const sal_Unicode* pRet = nullptr; | |||
233 | ||||
234 | switch( aLineEnd ) | |||
235 | { | |||
236 | case LINEEND_LF: | |||
237 | pRet = static_aLFText; | |||
238 | break; | |||
239 | case LINEEND_CR: | |||
240 | pRet = static_aCRText; | |||
241 | break; | |||
242 | case LINEEND_CRLF: | |||
243 | pRet = static_aCRLFText; | |||
244 | break; | |||
245 | } | |||
246 | return pRet; | |||
247 | } | |||
248 | ||||
249 | void TextEngine::ReplaceText(const TextSelection& rSel, const OUString& rText) | |||
250 | { | |||
251 | ImpInsertText( rSel, rText ); | |||
252 | } | |||
253 | ||||
254 | OUString TextEngine::GetText( LineEnd aSeparator ) const | |||
255 | { | |||
256 | return mpDoc->GetText( static_getLineEndText( aSeparator ) ); | |||
257 | } | |||
258 | ||||
259 | OUString TextEngine::GetTextLines( LineEnd aSeparator ) const | |||
260 | { | |||
261 | OUStringBuffer aText; | |||
262 | const sal_uInt32 nParas = mpTEParaPortions->Count(); | |||
263 | const sal_Unicode* pSep = static_getLineEndText( aSeparator ); | |||
264 | for ( sal_uInt32 nP = 0; nP < nParas; ++nP ) | |||
265 | { | |||
266 | TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nP ); | |||
267 | ||||
268 | const size_t nLines = pTEParaPortion->GetLines().size(); | |||
269 | for ( size_t nL = 0; nL < nLines; ++nL ) | |||
270 | { | |||
271 | TextLine& rLine = pTEParaPortion->GetLines()[nL]; | |||
272 | aText.append( std::u16string_view(pTEParaPortion->GetNode()->GetText()).substr(rLine.GetStart(), rLine.GetEnd() - rLine.GetStart()) ); | |||
273 | if ( pSep && ( ( (nP+1) < nParas ) || ( (nL+1) < nLines ) ) ) | |||
274 | aText.append(pSep); | |||
275 | } | |||
276 | } | |||
277 | return aText.makeStringAndClear(); | |||
278 | } | |||
279 | ||||
280 | OUString TextEngine::GetText( sal_uInt32 nPara ) const | |||
281 | { | |||
282 | return mpDoc->GetText( nPara ); | |||
283 | } | |||
284 | ||||
285 | sal_Int32 TextEngine::GetTextLen() const | |||
286 | { | |||
287 | return mpDoc->GetTextLen( static_getLineEndText( LINEEND_LF ) ); | |||
288 | } | |||
289 | ||||
290 | sal_Int32 TextEngine::GetTextLen( const TextSelection& rSel ) const | |||
291 | { | |||
292 | TextSelection aSel( rSel ); | |||
293 | aSel.Justify(); | |||
294 | ValidateSelection( aSel ); | |||
295 | return mpDoc->GetTextLen( static_getLineEndText( LINEEND_LF ), &aSel ); | |||
296 | } | |||
297 | ||||
298 | sal_Int32 TextEngine::GetTextLen( const sal_uInt32 nPara ) const | |||
299 | { | |||
300 | return mpDoc->GetNodes()[ nPara ]->GetText().getLength(); | |||
301 | } | |||
302 | ||||
303 | void TextEngine::SetUpdateMode( bool bUpdate ) | |||
304 | { | |||
305 | if ( bUpdate != mbUpdate ) | |||
306 | { | |||
307 | mbUpdate = bUpdate; | |||
308 | if ( mbUpdate ) | |||
309 | { | |||
310 | FormatAndUpdate( GetActiveView() ); | |||
311 | if ( GetActiveView() ) | |||
312 | GetActiveView()->ShowCursor(); | |||
313 | } | |||
314 | } | |||
315 | } | |||
316 | ||||
317 | bool TextEngine::DoesKeyChangeText( const KeyEvent& rKeyEvent ) | |||
318 | { | |||
319 | bool bDoesChange = false; | |||
320 | ||||
321 | KeyFuncType eFunc = rKeyEvent.GetKeyCode().GetFunction(); | |||
322 | if ( eFunc != KeyFuncType::DONTKNOW ) | |||
323 | { | |||
324 | switch ( eFunc ) | |||
325 | { | |||
326 | case KeyFuncType::UNDO: | |||
327 | case KeyFuncType::REDO: | |||
328 | case KeyFuncType::CUT: | |||
329 | case KeyFuncType::PASTE: | |||
330 | bDoesChange = true; | |||
331 | break; | |||
332 | default: | |||
333 | // might get handled below | |||
334 | eFunc = KeyFuncType::DONTKNOW; | |||
335 | } | |||
336 | } | |||
337 | if ( eFunc == KeyFuncType::DONTKNOW ) | |||
338 | { | |||
339 | switch ( rKeyEvent.GetKeyCode().GetCode() ) | |||
340 | { | |||
341 | case KEY_DELETE: | |||
342 | case KEY_BACKSPACE: | |||
343 | if ( !rKeyEvent.GetKeyCode().IsMod2() ) | |||
344 | bDoesChange = true; | |||
345 | break; | |||
346 | case KEY_RETURN: | |||
347 | case KEY_TAB: | |||
348 | if ( !rKeyEvent.GetKeyCode().IsMod1() && !rKeyEvent.GetKeyCode().IsMod2() ) | |||
349 | bDoesChange = true; | |||
350 | break; | |||
351 | default: | |||
352 | bDoesChange = TextEngine::IsSimpleCharInput( rKeyEvent ); | |||
353 | } | |||
354 | } | |||
355 | return bDoesChange; | |||
356 | } | |||
357 | ||||
358 | bool TextEngine::IsSimpleCharInput( const KeyEvent& rKeyEvent ) | |||
359 | { | |||
360 | return rKeyEvent.GetCharCode() >= 32 && rKeyEvent.GetCharCode() != 127 && | |||
361 | KEY_MOD1 != (rKeyEvent.GetKeyCode().GetModifier() & ~KEY_SHIFT) && // (ssa) #i45714#: | |||
362 | KEY_MOD2 != (rKeyEvent.GetKeyCode().GetModifier() & ~KEY_SHIFT); // check for Ctrl and Alt separately | |||
363 | } | |||
364 | ||||
365 | void TextEngine::ImpInitDoc() | |||
366 | { | |||
367 | if ( mpDoc ) | |||
368 | mpDoc->Clear(); | |||
369 | else | |||
370 | mpDoc.reset( new TextDoc ); | |||
371 | ||||
372 | mpTEParaPortions.reset(new TEParaPortions); | |||
373 | ||||
374 | std::unique_ptr<TextNode> pNode(new TextNode( OUString() )); | |||
375 | mpDoc->GetNodes().insert( mpDoc->GetNodes().begin(), std::move(pNode) ); | |||
376 | ||||
377 | TEParaPortion* pIniPortion = new TEParaPortion( mpDoc->GetNodes().begin()->get() ); | |||
378 | mpTEParaPortions->Insert( pIniPortion, 0 ); | |||
379 | ||||
380 | mbFormatted = false; | |||
381 | ||||
382 | ImpParagraphRemoved( TEXT_PARA_ALL((sal_uInt32) 0xFFFFFFFF) ); | |||
383 | ImpParagraphInserted( 0 ); | |||
384 | } | |||
385 | ||||
386 | OUString TextEngine::GetText( const TextSelection& rSel, LineEnd aSeparator ) const | |||
387 | { | |||
388 | if ( !rSel.HasRange() ) | |||
389 | return OUString(); | |||
390 | ||||
391 | TextSelection aSel( rSel ); | |||
392 | aSel.Justify(); | |||
393 | ||||
394 | OUStringBuffer aText; | |||
395 | const sal_uInt32 nStartPara = aSel.GetStart().GetPara(); | |||
396 | const sal_uInt32 nEndPara = aSel.GetEnd().GetPara(); | |||
397 | const sal_Unicode* pSep = static_getLineEndText( aSeparator ); | |||
398 | for ( sal_uInt32 nNode = aSel.GetStart().GetPara(); nNode <= nEndPara; ++nNode ) | |||
399 | { | |||
400 | TextNode* pNode = mpDoc->GetNodes()[ nNode ].get(); | |||
401 | ||||
402 | sal_Int32 nStartPos = 0; | |||
403 | sal_Int32 nEndPos = pNode->GetText().getLength(); | |||
404 | if ( nNode == nStartPara ) | |||
405 | nStartPos = aSel.GetStart().GetIndex(); | |||
406 | if ( nNode == nEndPara ) // may also be == nStart! | |||
407 | nEndPos = aSel.GetEnd().GetIndex(); | |||
408 | ||||
409 | aText.append(std::u16string_view(pNode->GetText()).substr(nStartPos, nEndPos-nStartPos)); | |||
410 | if ( nNode < nEndPara ) | |||
411 | aText.append(pSep); | |||
412 | } | |||
413 | return aText.makeStringAndClear(); | |||
414 | } | |||
415 | ||||
416 | void TextEngine::ImpRemoveText() | |||
417 | { | |||
418 | ImpInitDoc(); | |||
419 | ||||
420 | const TextSelection aEmptySel; | |||
421 | for (TextView* pView : *mpViews) | |||
422 | { | |||
423 | pView->ImpSetSelection( aEmptySel ); | |||
424 | } | |||
425 | ResetUndo(); | |||
426 | } | |||
427 | ||||
428 | void TextEngine::SetText( const OUString& rText ) | |||
429 | { | |||
430 | ImpRemoveText(); | |||
431 | ||||
432 | const bool bUndoCurrentlyEnabled = IsUndoEnabled(); | |||
433 | // the manually inserted text cannot be reversed by the user | |||
434 | EnableUndo( false ); | |||
435 | ||||
436 | const TextSelection aEmptySel; | |||
437 | ||||
438 | TextPaM aPaM; | |||
439 | if ( !rText.isEmpty() ) | |||
440 | aPaM = ImpInsertText( aEmptySel, rText ); | |||
441 | ||||
442 | for (TextView* pView : *mpViews) | |||
443 | { | |||
444 | pView->ImpSetSelection( aEmptySel ); | |||
445 | ||||
446 | // if no text, then no Format&Update => the text remains | |||
447 | if ( rText.isEmpty() && GetUpdateMode() ) | |||
448 | pView->Invalidate(); | |||
449 | } | |||
450 | ||||
451 | if( rText.isEmpty() ) // otherwise needs invalidation later; !bFormatted is sufficient | |||
452 | mnCurTextHeight = 0; | |||
453 | ||||
454 | FormatAndUpdate(); | |||
455 | ||||
456 | EnableUndo( bUndoCurrentlyEnabled ); | |||
457 | SAL_WARN_IF( HasUndoManager() && GetUndoManager().GetUndoActionCount(), "vcl", "SetText: Undo!" )do { if (true && (HasUndoManager() && GetUndoManager ().GetUndoActionCount())) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "SetText: Undo!") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "457" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "SetText: Undo!"), 0); } else { ::std:: ostringstream sal_detail_stream; sal_detail_stream << "SetText: Undo!" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "457" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "SetText: Undo!") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "457" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "SetText: Undo!"), 0); } else { ::std:: ostringstream sal_detail_stream; sal_detail_stream << "SetText: Undo!" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "457" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
458 | } | |||
459 | ||||
460 | void TextEngine::CursorMoved( sal_uInt32 nNode ) | |||
461 | { | |||
462 | // delete empty attribute; but only if paragraph is not empty! | |||
463 | TextNode* pNode = mpDoc->GetNodes()[ nNode ].get(); | |||
464 | if ( pNode && pNode->GetCharAttribs().HasEmptyAttribs() && !pNode->GetText().isEmpty() ) | |||
465 | pNode->GetCharAttribs().DeleteEmptyAttribs(); | |||
466 | } | |||
467 | ||||
468 | void TextEngine::ImpRemoveChars( const TextPaM& rPaM, sal_Int32 nChars ) | |||
469 | { | |||
470 | SAL_WARN_IF( !nChars, "vcl", "ImpRemoveChars: 0 Chars?!" )do { if (true && (!nChars)) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "ImpRemoveChars: 0 Chars?!" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "470" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "ImpRemoveChars: 0 Chars?!"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ImpRemoveChars: 0 Chars?!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "470" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "ImpRemoveChars: 0 Chars?!") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "470" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "ImpRemoveChars: 0 Chars?!"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ImpRemoveChars: 0 Chars?!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "470" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
471 | if ( IsUndoEnabled() && !IsInUndo() ) | |||
472 | { | |||
473 | // attributes have to be saved for UNDO before RemoveChars! | |||
474 | TextNode* pNode = mpDoc->GetNodes()[ rPaM.GetPara() ].get(); | |||
475 | OUString aStr( pNode->GetText().copy( rPaM.GetIndex(), nChars ) ); | |||
476 | ||||
477 | // check if attributes are being deleted or changed | |||
478 | const sal_Int32 nStart = rPaM.GetIndex(); | |||
479 | const sal_Int32 nEnd = nStart + nChars; | |||
480 | for ( sal_uInt16 nAttr = pNode->GetCharAttribs().Count(); nAttr; ) | |||
481 | { | |||
482 | TextCharAttrib& rAttr = pNode->GetCharAttribs().GetAttrib( --nAttr ); | |||
483 | if ( ( rAttr.GetEnd() >= nStart ) && ( rAttr.GetStart() < nEnd ) ) | |||
484 | { | |||
485 | break; // for | |||
486 | } | |||
487 | } | |||
488 | InsertUndo( std::make_unique<TextUndoRemoveChars>( this, rPaM, aStr ) ); | |||
489 | } | |||
490 | ||||
491 | mpDoc->RemoveChars( rPaM, nChars ); | |||
492 | ImpCharsRemoved( rPaM.GetPara(), rPaM.GetIndex(), nChars ); | |||
493 | } | |||
494 | ||||
495 | TextPaM TextEngine::ImpConnectParagraphs( sal_uInt32 nLeft, sal_uInt32 nRight ) | |||
496 | { | |||
497 | SAL_WARN_IF( nLeft == nRight, "vcl", "ImpConnectParagraphs: connect the very same paragraph ?" )do { if (true && (nLeft == nRight)) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "ImpConnectParagraphs: connect the very same paragraph ?" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "497" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "ImpConnectParagraphs: connect the very same paragraph ?" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ImpConnectParagraphs: connect the very same paragraph ?" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "497" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "ImpConnectParagraphs: connect the very same paragraph ?" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "497" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "ImpConnectParagraphs: connect the very same paragraph ?" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ImpConnectParagraphs: connect the very same paragraph ?" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "497" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
498 | ||||
499 | TextNode* pLeft = mpDoc->GetNodes()[ nLeft ].get(); | |||
500 | TextNode* pRight = mpDoc->GetNodes()[ nRight ].get(); | |||
501 | ||||
502 | if ( IsUndoEnabled() && !IsInUndo() ) | |||
503 | InsertUndo( std::make_unique<TextUndoConnectParas>( this, nLeft, pLeft->GetText().getLength() ) ); | |||
504 | ||||
505 | // first lookup Portions, as pRight is gone after ConnectParagraphs | |||
506 | TEParaPortion* pLeftPortion = mpTEParaPortions->GetObject( nLeft ); | |||
507 | TEParaPortion* pRightPortion = mpTEParaPortions->GetObject( nRight ); | |||
508 | SAL_WARN_IF( !pLeft || !pLeftPortion, "vcl", "ImpConnectParagraphs(1): Hidden Portion" )do { if (true && (!pLeft || !pLeftPortion)) { switch ( sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "ImpConnectParagraphs(1): Hidden Portion") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "508" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "ImpConnectParagraphs(1): Hidden Portion" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ImpConnectParagraphs(1): Hidden Portion"; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "508" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "ImpConnectParagraphs(1): Hidden Portion") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "508" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "ImpConnectParagraphs(1): Hidden Portion" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ImpConnectParagraphs(1): Hidden Portion"; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "508" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
509 | SAL_WARN_IF( !pRight || !pRightPortion, "vcl", "ImpConnectParagraphs(2): Hidden Portion" )do { if (true && (!pRight || !pRightPortion)) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "ImpConnectParagraphs(2): Hidden Portion") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "509" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "ImpConnectParagraphs(2): Hidden Portion" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ImpConnectParagraphs(2): Hidden Portion"; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "509" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "ImpConnectParagraphs(2): Hidden Portion") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "509" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "ImpConnectParagraphs(2): Hidden Portion" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ImpConnectParagraphs(2): Hidden Portion"; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "509" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
510 | ||||
511 | TextPaM aPaM = mpDoc->ConnectParagraphs( pLeft, pRight ); | |||
512 | ImpParagraphRemoved( nRight ); | |||
513 | ||||
514 | pLeftPortion->MarkSelectionInvalid( aPaM.GetIndex() ); | |||
515 | ||||
516 | mpTEParaPortions->Remove( nRight ); | |||
517 | // the right Node is deleted by EditDoc::ConnectParagraphs() | |||
518 | ||||
519 | return aPaM; | |||
520 | } | |||
521 | ||||
522 | TextPaM TextEngine::ImpDeleteText( const TextSelection& rSel ) | |||
523 | { | |||
524 | if ( !rSel.HasRange() ) | |||
525 | return rSel.GetStart(); | |||
526 | ||||
527 | TextSelection aSel( rSel ); | |||
528 | aSel.Justify(); | |||
529 | TextPaM aStartPaM( aSel.GetStart() ); | |||
530 | TextPaM aEndPaM( aSel.GetEnd() ); | |||
531 | ||||
532 | CursorMoved( aStartPaM.GetPara() ); // so that newly-adjusted attributes vanish | |||
533 | CursorMoved( aEndPaM.GetPara() ); // so that newly-adjusted attributes vanish | |||
534 | ||||
535 | SAL_WARN_IF( !mpDoc->IsValidPaM( aStartPaM ), "vcl", "ImpDeleteText(1): bad Index" )do { if (true && (!mpDoc->IsValidPaM( aStartPaM )) ) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "ImpDeleteText(1): bad Index") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "535" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "ImpDeleteText(1): bad Index"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ImpDeleteText(1): bad Index"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "535" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "ImpDeleteText(1): bad Index") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "535" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "ImpDeleteText(1): bad Index"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ImpDeleteText(1): bad Index"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "535" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
536 | SAL_WARN_IF( !mpDoc->IsValidPaM( aEndPaM ), "vcl", "ImpDeleteText(2): bad Index" )do { if (true && (!mpDoc->IsValidPaM( aEndPaM ))) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl" )) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "ImpDeleteText(2): bad Index") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "536" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "ImpDeleteText(2): bad Index"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ImpDeleteText(2): bad Index"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "536" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "ImpDeleteText(2): bad Index") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "536" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "ImpDeleteText(2): bad Index"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ImpDeleteText(2): bad Index"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "536" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
537 | ||||
538 | const sal_uInt32 nStartNode = aStartPaM.GetPara(); | |||
539 | sal_uInt32 nEndNode = aEndPaM.GetPara(); | |||
540 | ||||
541 | // remove all Nodes inbetween | |||
542 | for ( sal_uInt32 z = nStartNode+1; z < nEndNode; ++z ) | |||
543 | { | |||
544 | // always nStartNode+1, because of Remove()! | |||
545 | ImpRemoveParagraph( nStartNode+1 ); | |||
546 | } | |||
547 | ||||
548 | if ( nStartNode != nEndNode ) | |||
549 | { | |||
550 | // the remainder of StartNodes... | |||
551 | TextNode* pLeft = mpDoc->GetNodes()[ nStartNode ].get(); | |||
552 | sal_Int32 nChars = pLeft->GetText().getLength() - aStartPaM.GetIndex(); | |||
553 | if ( nChars ) | |||
554 | { | |||
555 | ImpRemoveChars( aStartPaM, nChars ); | |||
556 | TEParaPortion* pPortion = mpTEParaPortions->GetObject( nStartNode ); | |||
557 | SAL_WARN_IF( !pPortion, "vcl", "ImpDeleteText(3): bad Index" )do { if (true && (!pPortion)) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "ImpDeleteText(3): bad Index" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "557" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "ImpDeleteText(3): bad Index"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ImpDeleteText(3): bad Index"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "557" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "ImpDeleteText(3): bad Index") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "557" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "ImpDeleteText(3): bad Index"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ImpDeleteText(3): bad Index"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "557" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
558 | pPortion->MarkSelectionInvalid( aStartPaM.GetIndex() ); | |||
559 | } | |||
560 | ||||
561 | // the beginning of EndNodes... | |||
562 | nEndNode = nStartNode+1; // the other paragraphs were deleted | |||
563 | nChars = aEndPaM.GetIndex(); | |||
564 | if ( nChars ) | |||
565 | { | |||
566 | aEndPaM.GetPara() = nEndNode; | |||
567 | aEndPaM.GetIndex() = 0; | |||
568 | ImpRemoveChars( aEndPaM, nChars ); | |||
569 | TEParaPortion* pPortion = mpTEParaPortions->GetObject( nEndNode ); | |||
570 | SAL_WARN_IF( !pPortion, "vcl", "ImpDeleteText(4): bad Index" )do { if (true && (!pPortion)) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "ImpDeleteText(4): bad Index" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "570" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "ImpDeleteText(4): bad Index"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ImpDeleteText(4): bad Index"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "570" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "ImpDeleteText(4): bad Index") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "570" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "ImpDeleteText(4): bad Index"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ImpDeleteText(4): bad Index"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "570" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
571 | pPortion->MarkSelectionInvalid( 0 ); | |||
572 | } | |||
573 | ||||
574 | // connect... | |||
575 | aStartPaM = ImpConnectParagraphs( nStartNode, nEndNode ); | |||
576 | } | |||
577 | else | |||
578 | { | |||
579 | const sal_Int32 nChars = aEndPaM.GetIndex() - aStartPaM.GetIndex(); | |||
580 | ImpRemoveChars( aStartPaM, nChars ); | |||
581 | TEParaPortion* pPortion = mpTEParaPortions->GetObject( nStartNode ); | |||
582 | SAL_WARN_IF( !pPortion, "vcl", "ImpDeleteText(5): bad Index" )do { if (true && (!pPortion)) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "ImpDeleteText(5): bad Index" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "582" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "ImpDeleteText(5): bad Index"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ImpDeleteText(5): bad Index"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "582" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "ImpDeleteText(5): bad Index") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "582" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "ImpDeleteText(5): bad Index"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ImpDeleteText(5): bad Index"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "582" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
583 | pPortion->MarkInvalid( aEndPaM.GetIndex(), aStartPaM.GetIndex() - aEndPaM.GetIndex() ); | |||
584 | } | |||
585 | ||||
586 | // UpdateSelections(); | |||
587 | TextModified(); | |||
588 | return aStartPaM; | |||
589 | } | |||
590 | ||||
591 | void TextEngine::ImpRemoveParagraph( sal_uInt32 nPara ) | |||
592 | { | |||
593 | std::unique_ptr<TextNode> pNode = std::move(mpDoc->GetNodes()[ nPara ]); | |||
594 | ||||
595 | // the Node is handled by Undo and is deleted if appropriate | |||
596 | mpDoc->GetNodes().erase( mpDoc->GetNodes().begin() + nPara ); | |||
597 | if ( IsUndoEnabled() && !IsInUndo() ) | |||
598 | InsertUndo( std::make_unique<TextUndoDelPara>( this, pNode.release(), nPara ) ); | |||
599 | ||||
600 | mpTEParaPortions->Remove( nPara ); | |||
601 | ||||
602 | ImpParagraphRemoved( nPara ); | |||
603 | } | |||
604 | ||||
605 | uno::Reference < i18n::XExtendedInputSequenceChecker > const & TextEngine::GetInputSequenceChecker() | |||
606 | { | |||
607 | if ( !mxISC.is() ) | |||
608 | { | |||
609 | mxISC = i18n::InputSequenceChecker::create( ::comphelper::getProcessComponentContext() ); | |||
610 | } | |||
611 | return mxISC; | |||
612 | } | |||
613 | ||||
614 | bool TextEngine::IsInputSequenceCheckingRequired( sal_Unicode c, const TextSelection& rCurSel ) const | |||
615 | { | |||
616 | SvtCTLOptions aCTLOptions; | |||
617 | ||||
618 | // get the index that really is first | |||
619 | const sal_Int32 nFirstPos = std::min(rCurSel.GetStart().GetIndex(), rCurSel.GetEnd().GetIndex()); | |||
620 | ||||
621 | bool bIsSequenceChecking = | |||
622 | aCTLOptions.IsCTLFontEnabled() && | |||
623 | aCTLOptions.IsCTLSequenceChecking() && | |||
624 | nFirstPos != 0; /* first char needs not to be checked */ | |||
625 | ||||
626 | if (bIsSequenceChecking) | |||
627 | { | |||
628 | uno::Reference< i18n::XBreakIterator > xBI = const_cast<TextEngine *>(this)->GetBreakIterator(); | |||
629 | bIsSequenceChecking = xBI.is() && i18n::ScriptType::COMPLEX == xBI->getScriptType( OUString( c ), 0 ); | |||
630 | } | |||
631 | ||||
632 | return bIsSequenceChecking; | |||
633 | } | |||
634 | ||||
635 | TextPaM TextEngine::ImpInsertText( const TextSelection& rCurSel, sal_Unicode c, bool bOverwrite ) | |||
636 | { | |||
637 | return ImpInsertText( c, rCurSel, bOverwrite ); | |||
638 | } | |||
639 | ||||
640 | TextPaM TextEngine::ImpInsertText( sal_Unicode c, const TextSelection& rCurSel, bool bOverwrite, bool bIsUserInput ) | |||
641 | { | |||
642 | SAL_WARN_IF( c == '\n', "vcl", "InsertText: NewLine!" )do { if (true && (c == '\n')) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "InsertText: NewLine!" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "642" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "InsertText: NewLine!"), 0); } else { :: std::ostringstream sal_detail_stream; sal_detail_stream << "InsertText: NewLine!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "642" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "InsertText: NewLine!") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "642" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "InsertText: NewLine!"), 0); } else { :: std::ostringstream sal_detail_stream; sal_detail_stream << "InsertText: NewLine!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "642" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
643 | SAL_WARN_IF( c == '\r', "vcl", "InsertText: NewLine!" )do { if (true && (c == '\r')) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "InsertText: NewLine!" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "643" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "InsertText: NewLine!"), 0); } else { :: std::ostringstream sal_detail_stream; sal_detail_stream << "InsertText: NewLine!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "643" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "InsertText: NewLine!") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "643" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "InsertText: NewLine!"), 0); } else { :: std::ostringstream sal_detail_stream; sal_detail_stream << "InsertText: NewLine!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "643" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
644 | ||||
645 | TextPaM aPaM( rCurSel.GetStart() ); | |||
646 | TextNode* pNode = mpDoc->GetNodes()[ aPaM.GetPara() ].get(); | |||
647 | ||||
648 | bool bDoOverwrite = bOverwrite && ( aPaM.GetIndex() < pNode->GetText().getLength() ); | |||
649 | ||||
650 | bool bUndoAction = rCurSel.HasRange() || bDoOverwrite; | |||
651 | ||||
652 | if ( bUndoAction ) | |||
653 | UndoActionStart(); | |||
654 | ||||
655 | if ( rCurSel.HasRange() ) | |||
656 | { | |||
657 | aPaM = ImpDeleteText( rCurSel ); | |||
658 | } | |||
659 | else if ( bDoOverwrite ) | |||
660 | { | |||
661 | // if selection, then don't overwrite a character | |||
662 | TextSelection aTmpSel( aPaM ); | |||
663 | ++aTmpSel.GetEnd().GetIndex(); | |||
664 | ImpDeleteText( aTmpSel ); | |||
665 | } | |||
666 | ||||
667 | if (bIsUserInput && IsInputSequenceCheckingRequired( c, rCurSel )) | |||
668 | { | |||
669 | uno::Reference < i18n::XExtendedInputSequenceChecker > xISC = GetInputSequenceChecker(); | |||
670 | SvtCTLOptions aCTLOptions; | |||
671 | ||||
672 | if (xISC.is()) | |||
673 | { | |||
674 | sal_Int32 nTmpPos = aPaM.GetIndex(); | |||
675 | sal_Int16 nCheckMode = aCTLOptions.IsCTLSequenceCheckingRestricted() ? | |||
676 | i18n::InputSequenceCheckMode::STRICT : i18n::InputSequenceCheckMode::BASIC; | |||
677 | ||||
678 | // the text that needs to be checked is only the one | |||
679 | // before the current cursor position | |||
680 | OUString aOldText( mpDoc->GetText( aPaM.GetPara() ).copy(0, nTmpPos) ); | |||
681 | if (aCTLOptions.IsCTLSequenceCheckingTypeAndReplace()) | |||
682 | { | |||
683 | OUString aNewText( aOldText ); | |||
684 | xISC->correctInputSequence( aNewText, nTmpPos - 1, c, nCheckMode ); | |||
685 | ||||
686 | // find position of first character that has changed | |||
687 | const sal_Int32 nOldLen = aOldText.getLength(); | |||
688 | const sal_Int32 nNewLen = aNewText.getLength(); | |||
689 | const sal_Unicode *pOldTxt = aOldText.getStr(); | |||
690 | const sal_Unicode *pNewTxt = aNewText.getStr(); | |||
691 | sal_Int32 nChgPos = 0; | |||
692 | while ( nChgPos < nOldLen && nChgPos < nNewLen && | |||
693 | pOldTxt[nChgPos] == pNewTxt[nChgPos] ) | |||
694 | ++nChgPos; | |||
695 | ||||
696 | OUString aChgText( aNewText.copy( nChgPos ) ); | |||
697 | ||||
698 | // select text from first pos to be changed to current pos | |||
699 | TextSelection aSel( TextPaM( aPaM.GetPara(), nChgPos ), aPaM ); | |||
700 | ||||
701 | if (!aChgText.isEmpty()) | |||
702 | // ImpInsertText implicitly handles undo... | |||
703 | return ImpInsertText( aSel, aChgText ); | |||
704 | else | |||
705 | return aPaM; | |||
706 | } | |||
707 | else | |||
708 | { | |||
709 | // should the character be ignored (i.e. not get inserted) ? | |||
710 | if (!xISC->checkInputSequence( aOldText, nTmpPos - 1, c, nCheckMode )) | |||
711 | return aPaM; // nothing to be done -> no need for undo | |||
712 | } | |||
713 | } | |||
714 | ||||
715 | // at this point now we will insert the character 'normally' some lines below... | |||
716 | } | |||
717 | ||||
718 | if ( IsUndoEnabled() && !IsInUndo() ) | |||
719 | { | |||
720 | std::unique_ptr<TextUndoInsertChars> pNewUndo(new TextUndoInsertChars( this, aPaM, OUString(c) )); | |||
721 | bool bTryMerge = !bDoOverwrite && ( c != ' ' ); | |||
722 | InsertUndo( std::move(pNewUndo), bTryMerge ); | |||
723 | } | |||
724 | ||||
725 | TEParaPortion* pPortion = mpTEParaPortions->GetObject( aPaM.GetPara() ); | |||
726 | pPortion->MarkInvalid( aPaM.GetIndex(), 1 ); | |||
727 | if ( c == '\t' ) | |||
728 | pPortion->SetNotSimpleInvalid(); | |||
729 | aPaM = mpDoc->InsertText( aPaM, c ); | |||
730 | ImpCharsInserted( aPaM.GetPara(), aPaM.GetIndex()-1, 1 ); | |||
731 | ||||
732 | TextModified(); | |||
733 | ||||
734 | if ( bUndoAction ) | |||
735 | UndoActionEnd(); | |||
736 | ||||
737 | return aPaM; | |||
738 | } | |||
739 | ||||
740 | TextPaM TextEngine::ImpInsertText( const TextSelection& rCurSel, const OUString& rStr ) | |||
741 | { | |||
742 | UndoActionStart(); | |||
743 | ||||
744 | TextPaM aPaM; | |||
745 | ||||
746 | if ( rCurSel.HasRange() ) | |||
747 | aPaM = ImpDeleteText( rCurSel ); | |||
748 | else | |||
749 | aPaM = rCurSel.GetEnd(); | |||
750 | ||||
751 | OUString aText(convertLineEnd(rStr, LINEEND_LF)); | |||
752 | ||||
753 | sal_Int32 nStart = 0; | |||
754 | while ( nStart < aText.getLength() ) | |||
755 | { | |||
756 | sal_Int32 nEnd = aText.indexOf( LINE_SEP0x0A, nStart ); | |||
757 | if (nEnd == -1) | |||
758 | nEnd = aText.getLength(); // do not dereference! | |||
759 | ||||
760 | // Start == End => empty line | |||
761 | if ( nEnd > nStart ) | |||
762 | { | |||
763 | OUString aLine(aText.copy(nStart, nEnd-nStart)); | |||
764 | if ( IsUndoEnabled() && !IsInUndo() ) | |||
765 | InsertUndo( std::make_unique<TextUndoInsertChars>( this, aPaM, aLine ) ); | |||
766 | ||||
767 | TEParaPortion* pPortion = mpTEParaPortions->GetObject( aPaM.GetPara() ); | |||
768 | pPortion->MarkInvalid( aPaM.GetIndex(), aLine.getLength() ); | |||
769 | if (aLine.indexOf( '\t' ) != -1) | |||
770 | pPortion->SetNotSimpleInvalid(); | |||
771 | ||||
772 | aPaM = mpDoc->InsertText( aPaM, aLine ); | |||
773 | ImpCharsInserted( aPaM.GetPara(), aPaM.GetIndex()-aLine.getLength(), aLine.getLength() ); | |||
774 | ||||
775 | } | |||
776 | if ( nEnd < aText.getLength() ) | |||
777 | aPaM = ImpInsertParaBreak( aPaM ); | |||
778 | ||||
779 | if ( nEnd == aText.getLength() ) // #108611# prevent overflow in "nStart = nEnd+1" calculation | |||
780 | break; | |||
781 | ||||
782 | nStart = nEnd+1; | |||
783 | } | |||
784 | ||||
785 | UndoActionEnd(); | |||
786 | ||||
787 | TextModified(); | |||
788 | return aPaM; | |||
789 | } | |||
790 | ||||
791 | TextPaM TextEngine::ImpInsertParaBreak( const TextSelection& rCurSel ) | |||
792 | { | |||
793 | TextPaM aPaM; | |||
794 | if ( rCurSel.HasRange() ) | |||
795 | aPaM = ImpDeleteText( rCurSel ); | |||
796 | else | |||
797 | aPaM = rCurSel.GetEnd(); | |||
798 | ||||
799 | return ImpInsertParaBreak( aPaM ); | |||
800 | } | |||
801 | ||||
802 | TextPaM TextEngine::ImpInsertParaBreak( const TextPaM& rPaM ) | |||
803 | { | |||
804 | if ( IsUndoEnabled() && !IsInUndo() ) | |||
805 | InsertUndo( std::make_unique<TextUndoSplitPara>( this, rPaM.GetPara(), rPaM.GetIndex() ) ); | |||
806 | ||||
807 | TextNode* pNode = mpDoc->GetNodes()[ rPaM.GetPara() ].get(); | |||
808 | bool bFirstParaContentChanged = rPaM.GetIndex() < pNode->GetText().getLength(); | |||
809 | ||||
810 | TextPaM aPaM( mpDoc->InsertParaBreak( rPaM ) ); | |||
811 | ||||
812 | TEParaPortion* pPortion = mpTEParaPortions->GetObject( rPaM.GetPara() ); | |||
813 | SAL_WARN_IF( !pPortion, "vcl", "ImpInsertParaBreak: Hidden Portion" )do { if (true && (!pPortion)) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "ImpInsertParaBreak: Hidden Portion" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "813" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "ImpInsertParaBreak: Hidden Portion"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ImpInsertParaBreak: Hidden Portion"; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "813" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "ImpInsertParaBreak: Hidden Portion") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "813" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "ImpInsertParaBreak: Hidden Portion"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ImpInsertParaBreak: Hidden Portion"; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "813" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
814 | pPortion->MarkInvalid( rPaM.GetIndex(), 0 ); | |||
815 | ||||
816 | TextNode* pNewNode = mpDoc->GetNodes()[ aPaM.GetPara() ].get(); | |||
817 | TEParaPortion* pNewPortion = new TEParaPortion( pNewNode ); | |||
818 | mpTEParaPortions->Insert( pNewPortion, aPaM.GetPara() ); | |||
819 | ImpParagraphInserted( aPaM.GetPara() ); | |||
820 | ||||
821 | CursorMoved( rPaM.GetPara() ); // if empty attribute created | |||
822 | TextModified(); | |||
823 | ||||
824 | if ( bFirstParaContentChanged ) | |||
825 | Broadcast( TextHint( SfxHintId::TextParaContentChanged, rPaM.GetPara() ) ); | |||
826 | ||||
827 | return aPaM; | |||
828 | } | |||
829 | ||||
830 | tools::Rectangle TextEngine::PaMtoEditCursor( const TextPaM& rPaM, bool bSpecial ) | |||
831 | { | |||
832 | SAL_WARN_IF( !GetUpdateMode(), "vcl", "PaMtoEditCursor: GetUpdateMode()" )do { if (true && (!GetUpdateMode())) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "PaMtoEditCursor: GetUpdateMode()" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "832" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "PaMtoEditCursor: GetUpdateMode()"), 0 ); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "PaMtoEditCursor: GetUpdateMode()"; ::sal::detail:: log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "832" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "PaMtoEditCursor: GetUpdateMode()") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "832" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "PaMtoEditCursor: GetUpdateMode()"), 0 ); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "PaMtoEditCursor: GetUpdateMode()"; ::sal::detail:: log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "832" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
833 | ||||
834 | tools::Rectangle aEditCursor; | |||
835 | long nY = 0; | |||
836 | ||||
837 | if ( !mbHasMultiLineParas ) | |||
838 | { | |||
839 | nY = rPaM.GetPara() * mnCharHeight; | |||
840 | } | |||
841 | else | |||
842 | { | |||
843 | for ( sal_uInt32 nPortion = 0; nPortion < rPaM.GetPara(); ++nPortion ) | |||
844 | { | |||
845 | TEParaPortion* pPortion = mpTEParaPortions->GetObject(nPortion); | |||
846 | nY += pPortion->GetLines().size() * mnCharHeight; | |||
847 | } | |||
848 | } | |||
849 | ||||
850 | aEditCursor = GetEditCursor( rPaM, bSpecial ); | |||
851 | aEditCursor.AdjustTop(nY ); | |||
852 | aEditCursor.AdjustBottom(nY ); | |||
853 | return aEditCursor; | |||
854 | } | |||
855 | ||||
856 | tools::Rectangle TextEngine::GetEditCursor( const TextPaM& rPaM, bool bSpecial, bool bPreferPortionStart ) | |||
857 | { | |||
858 | if ( !IsFormatted() && !IsFormatting() ) | |||
859 | FormatAndUpdate(); | |||
860 | ||||
861 | TEParaPortion* pPortion = mpTEParaPortions->GetObject( rPaM.GetPara() ); | |||
862 | //TextNode* pNode = mpDoc->GetNodes().GetObject( rPaM.GetPara() ); | |||
863 | ||||
864 | /* | |||
865 | bSpecial: If behind the last character of a made up line, stay at the | |||
866 | end of the line, not at the start of the next line. | |||
867 | Purpose: - really END = > behind the last character | |||
868 | - to selection... | |||
869 | ||||
870 | */ | |||
871 | ||||
872 | long nY = 0; | |||
873 | sal_Int32 nCurIndex = 0; | |||
874 | TextLine* pLine = nullptr; | |||
875 | for (TextLine & rTmpLine : pPortion->GetLines()) | |||
876 | { | |||
877 | if ( ( rTmpLine.GetStart() == rPaM.GetIndex() ) || ( rTmpLine.IsIn( rPaM.GetIndex(), bSpecial ) ) ) | |||
878 | { | |||
879 | pLine = &rTmpLine; | |||
880 | break; | |||
881 | } | |||
882 | ||||
883 | nCurIndex = nCurIndex + rTmpLine.GetLen(); | |||
884 | nY += mnCharHeight; | |||
885 | } | |||
886 | if ( !pLine ) | |||
887 | { | |||
888 | // Cursor at end of paragraph | |||
889 | SAL_WARN_IF( rPaM.GetIndex() != nCurIndex, "vcl", "GetEditCursor: Bad Index!" )do { if (true && (rPaM.GetIndex() != nCurIndex)) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "GetEditCursor: Bad Index!") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "889" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "GetEditCursor: Bad Index!"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "GetEditCursor: Bad Index!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "889" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "GetEditCursor: Bad Index!") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "889" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "GetEditCursor: Bad Index!"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "GetEditCursor: Bad Index!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "889" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
890 | ||||
891 | pLine = & ( pPortion->GetLines().back() ); | |||
892 | nY -= mnCharHeight; | |||
893 | } | |||
894 | ||||
895 | tools::Rectangle aEditCursor; | |||
896 | ||||
897 | aEditCursor.SetTop( nY ); | |||
898 | nY += mnCharHeight; | |||
899 | aEditCursor.SetBottom( nY-1 ); | |||
900 | ||||
901 | // search within the line | |||
902 | long nX = ImpGetXPos( rPaM.GetPara(), pLine, rPaM.GetIndex(), bPreferPortionStart ); | |||
903 | aEditCursor.SetLeft(nX); | |||
904 | aEditCursor.SetRight(nX); | |||
905 | return aEditCursor; | |||
906 | } | |||
907 | ||||
908 | long TextEngine::ImpGetXPos( sal_uInt32 nPara, TextLine* pLine, sal_Int32 nIndex, bool bPreferPortionStart ) | |||
909 | { | |||
910 | SAL_WARN_IF( ( nIndex < pLine->GetStart() ) || ( nIndex > pLine->GetEnd() ) , "vcl", "ImpGetXPos: Bad parameters!" )do { if (true && (( nIndex < pLine->GetStart() ) || ( nIndex > pLine->GetEnd() ))) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "ImpGetXPos: Bad parameters!" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "910" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "ImpGetXPos: Bad parameters!"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ImpGetXPos: Bad parameters!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "910" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "ImpGetXPos: Bad parameters!") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "910" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "ImpGetXPos: Bad parameters!"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ImpGetXPos: Bad parameters!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "910" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
911 | ||||
912 | bool bDoPreferPortionStart = bPreferPortionStart; | |||
913 | // Assure that the portion belongs to this line | |||
914 | if ( nIndex == pLine->GetStart() ) | |||
915 | bDoPreferPortionStart = true; | |||
916 | else if ( nIndex == pLine->GetEnd() ) | |||
917 | bDoPreferPortionStart = false; | |||
918 | ||||
919 | TEParaPortion* pParaPortion = mpTEParaPortions->GetObject( nPara ); | |||
920 | ||||
921 | sal_Int32 nTextPortionStart = 0; | |||
922 | std::size_t nTextPortion = pParaPortion->GetTextPortions().FindPortion( nIndex, nTextPortionStart, bDoPreferPortionStart ); | |||
923 | ||||
924 | SAL_WARN_IF( ( nTextPortion < pLine->GetStartPortion() ) || ( nTextPortion > pLine->GetEndPortion() ), "vcl", "GetXPos: Portion not in current line!" )do { if (true && (( nTextPortion < pLine->GetStartPortion () ) || ( nTextPortion > pLine->GetEndPortion() ))) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "GetXPos: Portion not in current line!") == 1) { :: sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "924" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "GetXPos: Portion not in current line!" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "GetXPos: Portion not in current line!"; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "924" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "GetXPos: Portion not in current line!") == 1) { :: sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "924" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "GetXPos: Portion not in current line!" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "GetXPos: Portion not in current line!"; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "924" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
925 | ||||
926 | TETextPortion* pPortion = pParaPortion->GetTextPortions()[ nTextPortion ]; | |||
927 | ||||
928 | long nX = ImpGetPortionXOffset( nPara, pLine, nTextPortion ); | |||
929 | ||||
930 | long nPortionTextWidth = pPortion->GetWidth(); | |||
931 | ||||
932 | if ( nTextPortionStart != nIndex ) | |||
933 | { | |||
934 | // Search within portion... | |||
935 | if ( nIndex == ( nTextPortionStart + pPortion->GetLen() ) ) | |||
936 | { | |||
937 | // End of Portion | |||
938 | if ( ( pPortion->GetKind() == PORTIONKIND_TAB1 ) || | |||
939 | ( !IsRightToLeft() && !pPortion->IsRightToLeft() ) || | |||
940 | ( IsRightToLeft() && pPortion->IsRightToLeft() ) ) | |||
941 | { | |||
942 | nX += nPortionTextWidth; | |||
943 | if ( ( pPortion->GetKind() == PORTIONKIND_TAB1 ) && ( (nTextPortion+1) < pParaPortion->GetTextPortions().size() ) ) | |||
944 | { | |||
945 | TETextPortion* pNextPortion = pParaPortion->GetTextPortions()[ nTextPortion+1 ]; | |||
946 | if (pNextPortion->GetKind() != PORTIONKIND_TAB1 && IsRightToLeft() != pNextPortion->IsRightToLeft()) | |||
947 | { | |||
948 | // End of the tab portion, use start of next for cursor pos | |||
949 | SAL_WARN_IF( bPreferPortionStart, "vcl", "ImpGetXPos: How can we get here!" )do { if (true && (bPreferPortionStart)) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "ImpGetXPos: How can we get here!" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "949" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "ImpGetXPos: How can we get here!"), 0 ); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ImpGetXPos: How can we get here!"; ::sal::detail:: log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "949" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "ImpGetXPos: How can we get here!") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "949" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "ImpGetXPos: How can we get here!"), 0 ); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ImpGetXPos: How can we get here!"; ::sal::detail:: log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "949" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
950 | nX = ImpGetXPos( nPara, pLine, nIndex, true ); | |||
951 | } | |||
952 | ||||
953 | } | |||
954 | } | |||
955 | } | |||
956 | else if ( pPortion->GetKind() == PORTIONKIND_TEXT0 ) | |||
957 | { | |||
958 | SAL_WARN_IF( nIndex == pLine->GetStart(), "vcl", "ImpGetXPos: Strange behavior" )do { if (true && (nIndex == pLine->GetStart())) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "ImpGetXPos: Strange behavior") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "958" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "ImpGetXPos: Strange behavior"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ImpGetXPos: Strange behavior"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "958" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "ImpGetXPos: Strange behavior") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "958" ": "), ::sal::detail::unwrapStream( ::sal::detail:: StreamStart() << "ImpGetXPos: Strange behavior"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ImpGetXPos: Strange behavior"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "958" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
959 | ||||
960 | long nPosInPortion = CalcTextWidth( nPara, nTextPortionStart, nIndex-nTextPortionStart ); | |||
961 | ||||
962 | if (IsRightToLeft() == pPortion->IsRightToLeft()) | |||
963 | { | |||
964 | nX += nPosInPortion; | |||
965 | } | |||
966 | else | |||
967 | { | |||
968 | nX += nPortionTextWidth - nPosInPortion; | |||
969 | } | |||
970 | } | |||
971 | } | |||
972 | else // if ( nIndex == pLine->GetStart() ) | |||
973 | { | |||
974 | if (pPortion->GetKind() != PORTIONKIND_TAB1 && IsRightToLeft() != pPortion->IsRightToLeft()) | |||
975 | { | |||
976 | nX += nPortionTextWidth; | |||
977 | } | |||
978 | } | |||
979 | ||||
980 | return nX; | |||
981 | } | |||
982 | ||||
983 | const TextAttrib* TextEngine::FindAttrib( const TextPaM& rPaM, sal_uInt16 nWhich ) const | |||
984 | { | |||
985 | const TextAttrib* pAttr = nullptr; | |||
986 | const TextCharAttrib* pCharAttr = FindCharAttrib( rPaM, nWhich ); | |||
987 | if ( pCharAttr ) | |||
988 | pAttr = &pCharAttr->GetAttr(); | |||
989 | return pAttr; | |||
990 | } | |||
991 | ||||
992 | const TextCharAttrib* TextEngine::FindCharAttrib( const TextPaM& rPaM, sal_uInt16 nWhich ) const | |||
993 | { | |||
994 | const TextCharAttrib* pAttr = nullptr; | |||
995 | TextNode* pNode = mpDoc->GetNodes()[ rPaM.GetPara() ].get(); | |||
996 | if (pNode && (rPaM.GetIndex() <= pNode->GetText().getLength())) | |||
997 | pAttr = pNode->GetCharAttribs().FindAttrib( nWhich, rPaM.GetIndex() ); | |||
998 | return pAttr; | |||
999 | } | |||
1000 | ||||
1001 | TextPaM TextEngine::GetPaM( const Point& rDocPos ) | |||
1002 | { | |||
1003 | SAL_WARN_IF( !GetUpdateMode(), "vcl", "GetPaM: GetUpdateMode()" )do { if (true && (!GetUpdateMode())) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "GetPaM: GetUpdateMode()" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1003" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "GetPaM: GetUpdateMode()"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "GetPaM: GetUpdateMode()"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1003" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "GetPaM: GetUpdateMode()") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1003" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "GetPaM: GetUpdateMode()"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "GetPaM: GetUpdateMode()"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1003" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1004 | ||||
1005 | long nY = 0; | |||
1006 | for ( sal_uInt32 nPortion = 0; nPortion < mpTEParaPortions->Count(); ++nPortion ) | |||
1007 | { | |||
1008 | TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPortion ); | |||
1009 | long nTmpHeight = pPortion->GetLines().size() * mnCharHeight; | |||
1010 | nY += nTmpHeight; | |||
1011 | if ( nY > rDocPos.Y() ) | |||
1012 | { | |||
1013 | nY -= nTmpHeight; | |||
1014 | Point aPosInPara( rDocPos ); | |||
1015 | aPosInPara.AdjustY( -nY ); | |||
1016 | ||||
1017 | TextPaM aPaM( nPortion, 0 ); | |||
1018 | aPaM.GetIndex() = ImpFindIndex( nPortion, aPosInPara ); | |||
1019 | return aPaM; | |||
1020 | } | |||
1021 | } | |||
1022 | ||||
1023 | // not found - go to last visible | |||
1024 | const sal_uInt32 nLastNode = static_cast<sal_uInt32>(mpDoc->GetNodes().size() - 1); | |||
1025 | TextNode* pLast = mpDoc->GetNodes()[ nLastNode ].get(); | |||
1026 | return TextPaM( nLastNode, pLast->GetText().getLength() ); | |||
1027 | } | |||
1028 | ||||
1029 | sal_Int32 TextEngine::ImpFindIndex( sal_uInt32 nPortion, const Point& rPosInPara ) | |||
1030 | { | |||
1031 | SAL_WARN_IF( !IsFormatted(), "vcl", "GetPaM: Not formatted" )do { if (true && (!IsFormatted())) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "GetPaM: Not formatted" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1031" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "GetPaM: Not formatted"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "GetPaM: Not formatted"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1031" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "GetPaM: Not formatted") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1031" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "GetPaM: Not formatted"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "GetPaM: Not formatted"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1031" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1032 | TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPortion ); | |||
1033 | ||||
1034 | sal_Int32 nCurIndex = 0; | |||
1035 | ||||
1036 | long nY = 0; | |||
1037 | TextLine* pLine = nullptr; | |||
1038 | std::vector<TextLine>::size_type nLine; | |||
1039 | for ( nLine = 0; nLine < pPortion->GetLines().size(); nLine++ ) | |||
1040 | { | |||
1041 | TextLine& rmpLine = pPortion->GetLines()[ nLine ]; | |||
1042 | nY += mnCharHeight; | |||
1043 | if ( nY > rPosInPara.Y() ) // that's it | |||
1044 | { | |||
1045 | pLine = &rmpLine; | |||
1046 | break; // correct Y-Position not needed | |||
1047 | } | |||
1048 | } | |||
1049 | ||||
1050 | assert(pLine && "ImpFindIndex: pLine ?")(static_cast <bool> (pLine && "ImpFindIndex: pLine ?" ) ? void (0) : __assert_fail ("pLine && \"ImpFindIndex: pLine ?\"" , "/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" , 1050, __extension__ __PRETTY_FUNCTION__)); | |||
1051 | ||||
1052 | nCurIndex = GetCharPos( nPortion, nLine, rPosInPara.X() ); | |||
1053 | ||||
1054 | if ( nCurIndex && ( nCurIndex == pLine->GetEnd() ) && | |||
1055 | ( pLine != &( pPortion->GetLines().back() ) ) ) | |||
1056 | { | |||
1057 | uno::Reference < i18n::XBreakIterator > xBI = GetBreakIterator(); | |||
1058 | sal_Int32 nCount = 1; | |||
1059 | nCurIndex = xBI->previousCharacters( pPortion->GetNode()->GetText(), nCurIndex, GetLocale(), i18n::CharacterIteratorMode::SKIPCELL, nCount, nCount ); | |||
1060 | } | |||
1061 | return nCurIndex; | |||
1062 | } | |||
1063 | ||||
1064 | sal_Int32 TextEngine::GetCharPos( sal_uInt32 nPortion, std::vector<TextLine>::size_type nLine, long nXPos ) | |||
1065 | { | |||
1066 | ||||
1067 | TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPortion ); | |||
1068 | TextLine& rLine = pPortion->GetLines()[ nLine ]; | |||
1069 | ||||
1070 | sal_Int32 nCurIndex = rLine.GetStart(); | |||
1071 | ||||
1072 | long nTmpX = rLine.GetStartX(); | |||
1073 | if ( nXPos <= nTmpX ) | |||
1074 | return nCurIndex; | |||
1075 | ||||
1076 | for ( std::size_t i = rLine.GetStartPortion(); i <= rLine.GetEndPortion(); i++ ) | |||
1077 | { | |||
1078 | TETextPortion* pTextPortion = pPortion->GetTextPortions()[ i ]; | |||
1079 | nTmpX += pTextPortion->GetWidth(); | |||
1080 | ||||
1081 | if ( nTmpX > nXPos ) | |||
1082 | { | |||
1083 | if( pTextPortion->GetLen() > 1 ) | |||
1084 | { | |||
1085 | nTmpX -= pTextPortion->GetWidth(); // position before Portion | |||
1086 | // TODO: Optimize: no GetTextBreak if fixed-width Font | |||
1087 | vcl::Font aFont; | |||
1088 | SeekCursor( nPortion, nCurIndex+1, aFont, nullptr ); | |||
1089 | mpRefDev->SetFont( aFont); | |||
1090 | long nPosInPortion = nXPos-nTmpX; | |||
1091 | if ( IsRightToLeft() != pTextPortion->IsRightToLeft() ) | |||
1092 | nPosInPortion = pTextPortion->GetWidth() - nPosInPortion; | |||
1093 | nCurIndex = mpRefDev->GetTextBreak( pPortion->GetNode()->GetText(), nPosInPortion, nCurIndex ); | |||
1094 | // MT: GetTextBreak should assure that we are not within a CTL cell... | |||
1095 | } | |||
1096 | return nCurIndex; | |||
1097 | } | |||
1098 | nCurIndex += pTextPortion->GetLen(); | |||
1099 | } | |||
1100 | return nCurIndex; | |||
1101 | } | |||
1102 | ||||
1103 | long TextEngine::GetTextHeight() const | |||
1104 | { | |||
1105 | SAL_WARN_IF( !GetUpdateMode(), "vcl", "GetTextHeight: GetUpdateMode()" )do { if (true && (!GetUpdateMode())) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "GetTextHeight: GetUpdateMode()" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1105" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "GetTextHeight: GetUpdateMode()"), 0 ); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "GetTextHeight: GetUpdateMode()"; ::sal::detail::log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1105" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "GetTextHeight: GetUpdateMode()") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1105" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "GetTextHeight: GetUpdateMode()"), 0 ); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "GetTextHeight: GetUpdateMode()"; ::sal::detail::log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1105" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1106 | ||||
1107 | if ( !IsFormatted() && !IsFormatting() ) | |||
1108 | const_cast<TextEngine*>(this)->FormatAndUpdate(); | |||
1109 | ||||
1110 | return mnCurTextHeight; | |||
1111 | } | |||
1112 | ||||
1113 | long TextEngine::GetTextHeight( sal_uInt32 nParagraph ) const | |||
1114 | { | |||
1115 | SAL_WARN_IF( !GetUpdateMode(), "vcl", "GetTextHeight: GetUpdateMode()" )do { if (true && (!GetUpdateMode())) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "GetTextHeight: GetUpdateMode()" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1115" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "GetTextHeight: GetUpdateMode()"), 0 ); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "GetTextHeight: GetUpdateMode()"; ::sal::detail::log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1115" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "GetTextHeight: GetUpdateMode()") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1115" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "GetTextHeight: GetUpdateMode()"), 0 ); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "GetTextHeight: GetUpdateMode()"; ::sal::detail::log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1115" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1116 | ||||
1117 | if ( !IsFormatted() && !IsFormatting() ) | |||
1118 | const_cast<TextEngine*>(this)->FormatAndUpdate(); | |||
1119 | ||||
1120 | return CalcParaHeight( nParagraph ); | |||
1121 | } | |||
1122 | ||||
1123 | long TextEngine::CalcTextWidth( sal_uInt32 nPara ) | |||
1124 | { | |||
1125 | long nParaWidth = 0; | |||
1126 | TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPara ); | |||
1127 | for ( auto nLine = pPortion->GetLines().size(); nLine; ) | |||
1128 | { | |||
1129 | long nLineWidth = 0; | |||
1130 | TextLine& rLine = pPortion->GetLines()[ --nLine ]; | |||
1131 | for ( std::size_t nTP = rLine.GetStartPortion(); nTP <= rLine.GetEndPortion(); nTP++ ) | |||
1132 | { | |||
1133 | TETextPortion* pTextPortion = pPortion->GetTextPortions()[ nTP ]; | |||
1134 | nLineWidth += pTextPortion->GetWidth(); | |||
1135 | } | |||
1136 | if ( nLineWidth > nParaWidth ) | |||
1137 | nParaWidth = nLineWidth; | |||
1138 | } | |||
1139 | return nParaWidth; | |||
1140 | } | |||
1141 | ||||
1142 | long TextEngine::CalcTextWidth() | |||
1143 | { | |||
1144 | if ( !IsFormatted() && !IsFormatting() ) | |||
1145 | FormatAndUpdate(); | |||
1146 | ||||
1147 | if ( mnCurTextWidth < 0 ) | |||
1148 | { | |||
1149 | mnCurTextWidth = 0; | |||
1150 | for ( sal_uInt32 nPara = mpTEParaPortions->Count(); nPara; ) | |||
1151 | { | |||
1152 | const long nParaWidth = CalcTextWidth( --nPara ); | |||
1153 | if ( nParaWidth > mnCurTextWidth ) | |||
1154 | mnCurTextWidth = nParaWidth; | |||
1155 | } | |||
1156 | } | |||
1157 | return mnCurTextWidth+1;// wider by 1, as CreateLines breaks at >= | |||
1158 | } | |||
1159 | ||||
1160 | long TextEngine::CalcTextHeight() | |||
1161 | { | |||
1162 | SAL_WARN_IF( !GetUpdateMode(), "vcl", "CalcTextHeight: GetUpdateMode()" )do { if (true && (!GetUpdateMode())) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "CalcTextHeight: GetUpdateMode()" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1162" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "CalcTextHeight: GetUpdateMode()"), 0 ); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "CalcTextHeight: GetUpdateMode()"; ::sal::detail::log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1162" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "CalcTextHeight: GetUpdateMode()") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1162" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "CalcTextHeight: GetUpdateMode()"), 0 ); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "CalcTextHeight: GetUpdateMode()"; ::sal::detail::log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1162" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1163 | ||||
1164 | long nY = 0; | |||
1165 | for ( auto nPortion = mpTEParaPortions->Count(); nPortion; ) | |||
1166 | nY += CalcParaHeight( --nPortion ); | |||
1167 | return nY; | |||
1168 | } | |||
1169 | ||||
1170 | long TextEngine::CalcTextWidth( sal_uInt32 nPara, sal_Int32 nPortionStart, sal_Int32 nLen ) | |||
1171 | { | |||
1172 | #ifdef DBG_UTIL | |||
1173 | // within the text there must not be a Portion change (attribute/tab)! | |||
1174 | sal_Int32 nTabPos = mpDoc->GetNodes()[ nPara ]->GetText().indexOf( '\t', nPortionStart ); | |||
1175 | SAL_WARN_IF( nTabPos != -1 && nTabPos < (nPortionStart+nLen), "vcl", "CalcTextWidth: Tab!" )do { if (true && (nTabPos != -1 && nTabPos < (nPortionStart+nLen))) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "CalcTextWidth: Tab!") == 1) { ::sal_detail_log( ( ::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1175" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "CalcTextWidth: Tab!"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "CalcTextWidth: Tab!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1175" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "CalcTextWidth: Tab!") == 1) { ::sal_detail_log( ( ::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1175" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "CalcTextWidth: Tab!"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "CalcTextWidth: Tab!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1175" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1176 | #endif | |||
1177 | ||||
1178 | vcl::Font aFont; | |||
1179 | SeekCursor( nPara, nPortionStart+1, aFont, nullptr ); | |||
1180 | mpRefDev->SetFont( aFont ); | |||
1181 | TextNode* pNode = mpDoc->GetNodes()[ nPara ].get(); | |||
1182 | long nWidth = mpRefDev->GetTextWidth( pNode->GetText(), nPortionStart, nLen ); | |||
1183 | return nWidth; | |||
1184 | } | |||
1185 | ||||
1186 | void TextEngine::GetTextPortionRange(const TextPaM& rPaM, sal_Int32& nStart, sal_Int32& nEnd) | |||
1187 | { | |||
1188 | nStart = 0; | |||
1189 | nEnd = 0; | |||
1190 | TEParaPortion* pParaPortion = mpTEParaPortions->GetObject( rPaM.GetPara() ); | |||
1191 | for ( std::size_t i = 0; i < pParaPortion->GetTextPortions().size(); ++i ) | |||
1192 | { | |||
1193 | TETextPortion* pTextPortion = pParaPortion->GetTextPortions()[ i ]; | |||
1194 | if (nStart + pTextPortion->GetLen() > rPaM.GetIndex()) | |||
1195 | { | |||
1196 | nEnd = nStart + pTextPortion->GetLen(); | |||
1197 | return; | |||
1198 | } | |||
1199 | else | |||
1200 | { | |||
1201 | nStart += pTextPortion->GetLen(); | |||
1202 | } | |||
1203 | } | |||
1204 | } | |||
1205 | ||||
1206 | sal_uInt16 TextEngine::GetLineCount( sal_uInt32 nParagraph ) const | |||
1207 | { | |||
1208 | SAL_WARN_IF( nParagraph >= mpTEParaPortions->Count(), "vcl", "GetLineCount: Out of range" )do { if (true && (nParagraph >= mpTEParaPortions-> Count())) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "GetLineCount: Out of range") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1208" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "GetLineCount: Out of range"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "GetLineCount: Out of range"; ::sal::detail::log( ( ::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1208" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "GetLineCount: Out of range") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1208" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "GetLineCount: Out of range"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "GetLineCount: Out of range"; ::sal::detail::log( ( ::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1208" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1209 | ||||
1210 | TEParaPortion* pPPortion = mpTEParaPortions->GetObject( nParagraph ); | |||
1211 | if ( pPPortion ) | |||
1212 | return pPPortion->GetLines().size(); | |||
1213 | ||||
1214 | return 0; | |||
1215 | } | |||
1216 | ||||
1217 | sal_Int32 TextEngine::GetLineLen( sal_uInt32 nParagraph, sal_uInt16 nLine ) const | |||
1218 | { | |||
1219 | SAL_WARN_IF( nParagraph >= mpTEParaPortions->Count(), "vcl", "GetLineCount: Out of range" )do { if (true && (nParagraph >= mpTEParaPortions-> Count())) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "GetLineCount: Out of range") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1219" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "GetLineCount: Out of range"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "GetLineCount: Out of range"; ::sal::detail::log( ( ::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1219" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "GetLineCount: Out of range") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1219" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "GetLineCount: Out of range"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "GetLineCount: Out of range"; ::sal::detail::log( ( ::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1219" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1220 | ||||
1221 | TEParaPortion* pPPortion = mpTEParaPortions->GetObject( nParagraph ); | |||
1222 | if ( pPPortion && ( nLine < pPPortion->GetLines().size() ) ) | |||
1223 | { | |||
1224 | return pPPortion->GetLines()[ nLine ].GetLen(); | |||
1225 | } | |||
1226 | ||||
1227 | return 0; | |||
1228 | } | |||
1229 | ||||
1230 | long TextEngine::CalcParaHeight( sal_uInt32 nParagraph ) const | |||
1231 | { | |||
1232 | long nHeight = 0; | |||
1233 | ||||
1234 | TEParaPortion* pPPortion = mpTEParaPortions->GetObject( nParagraph ); | |||
1235 | SAL_WARN_IF( !pPPortion, "vcl", "GetParaHeight: paragraph not found" )do { if (true && (!pPPortion)) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "GetParaHeight: paragraph not found" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1235" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "GetParaHeight: paragraph not found" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "GetParaHeight: paragraph not found"; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1235" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "GetParaHeight: paragraph not found") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1235" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "GetParaHeight: paragraph not found" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "GetParaHeight: paragraph not found"; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1235" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1236 | if ( pPPortion ) | |||
1237 | nHeight = pPPortion->GetLines().size() * mnCharHeight; | |||
1238 | ||||
1239 | return nHeight; | |||
1240 | } | |||
1241 | ||||
1242 | Range TextEngine::GetInvalidYOffsets( sal_uInt32 nPortion ) | |||
1243 | { | |||
1244 | TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPortion ); | |||
1245 | sal_uInt16 nLines = pTEParaPortion->GetLines().size(); | |||
1246 | sal_uInt16 nLastInvalid, nFirstInvalid = 0; | |||
1247 | sal_uInt16 nLine; | |||
1248 | for ( nLine = 0; nLine < nLines; nLine++ ) | |||
1249 | { | |||
1250 | TextLine& rL = pTEParaPortion->GetLines()[ nLine ]; | |||
1251 | if ( rL.IsInvalid() ) | |||
1252 | { | |||
1253 | nFirstInvalid = nLine; | |||
1254 | break; | |||
1255 | } | |||
1256 | } | |||
1257 | ||||
1258 | for ( nLastInvalid = nFirstInvalid; nLastInvalid < nLines; nLastInvalid++ ) | |||
1259 | { | |||
1260 | TextLine& rL = pTEParaPortion->GetLines()[ nLine ]; | |||
1261 | if ( rL.IsValid() ) | |||
1262 | break; | |||
1263 | } | |||
1264 | ||||
1265 | if ( nLastInvalid >= nLines ) | |||
1266 | nLastInvalid = nLines-1; | |||
1267 | ||||
1268 | return Range( nFirstInvalid*mnCharHeight, ((nLastInvalid+1)*mnCharHeight)-1 ); | |||
1269 | } | |||
1270 | ||||
1271 | sal_uInt32 TextEngine::GetParagraphCount() const | |||
1272 | { | |||
1273 | return static_cast<sal_uInt32>(mpDoc->GetNodes().size()); | |||
1274 | } | |||
1275 | ||||
1276 | void TextEngine::EnableUndo( bool bEnable ) | |||
1277 | { | |||
1278 | // delete list when switching mode | |||
1279 | if ( bEnable != IsUndoEnabled() ) | |||
1280 | ResetUndo(); | |||
1281 | ||||
1282 | mbUndoEnabled = bEnable; | |||
1283 | } | |||
1284 | ||||
1285 | SfxUndoManager& TextEngine::GetUndoManager() | |||
1286 | { | |||
1287 | if ( !mpUndoManager ) | |||
1288 | mpUndoManager.reset( new TextUndoManager( this ) ); | |||
1289 | return *mpUndoManager; | |||
1290 | } | |||
1291 | ||||
1292 | void TextEngine::UndoActionStart( sal_uInt16 nId ) | |||
1293 | { | |||
1294 | if ( IsUndoEnabled() && !IsInUndo() ) | |||
1295 | { | |||
1296 | GetUndoManager().EnterListAction( OUString(), OUString(), nId, ViewShellId(-1) ); | |||
1297 | } | |||
1298 | } | |||
1299 | ||||
1300 | void TextEngine::UndoActionEnd() | |||
1301 | { | |||
1302 | if ( IsUndoEnabled() && !IsInUndo() ) | |||
1303 | GetUndoManager().LeaveListAction(); | |||
1304 | } | |||
1305 | ||||
1306 | void TextEngine::InsertUndo( std::unique_ptr<TextUndo> pUndo, bool bTryMerge ) | |||
1307 | { | |||
1308 | SAL_WARN_IF( IsInUndo(), "vcl", "InsertUndo: in Undo mode!" )do { if (true && (IsInUndo())) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "InsertUndo: in Undo mode!" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1308" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "InsertUndo: in Undo mode!"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "InsertUndo: in Undo mode!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1308" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "InsertUndo: in Undo mode!") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1308" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "InsertUndo: in Undo mode!"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "InsertUndo: in Undo mode!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1308" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1309 | GetUndoManager().AddUndoAction( std::move(pUndo), bTryMerge ); | |||
1310 | } | |||
1311 | ||||
1312 | void TextEngine::ResetUndo() | |||
1313 | { | |||
1314 | if ( mpUndoManager ) | |||
1315 | mpUndoManager->Clear(); | |||
1316 | } | |||
1317 | ||||
1318 | void TextEngine::InsertContent( std::unique_ptr<TextNode> pNode, sal_uInt32 nPara ) | |||
1319 | { | |||
1320 | SAL_WARN_IF( !pNode, "vcl", "InsertContent: NULL-Pointer!" )do { if (true && (!pNode)) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "InsertContent: NULL-Pointer!" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1320" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "InsertContent: NULL-Pointer!"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "InsertContent: NULL-Pointer!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1320" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "InsertContent: NULL-Pointer!") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1320" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "InsertContent: NULL-Pointer!"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "InsertContent: NULL-Pointer!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1320" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1321 | SAL_WARN_IF( !IsInUndo(), "vcl", "InsertContent: only in Undo()!" )do { if (true && (!IsInUndo())) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "InsertContent: only in Undo()!" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1321" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "InsertContent: only in Undo()!"), 0 ); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "InsertContent: only in Undo()!"; ::sal::detail::log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1321" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "InsertContent: only in Undo()!") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1321" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "InsertContent: only in Undo()!"), 0 ); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "InsertContent: only in Undo()!"; ::sal::detail::log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1321" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1322 | TEParaPortion* pNew = new TEParaPortion( pNode.get() ); | |||
1323 | mpTEParaPortions->Insert( pNew, nPara ); | |||
1324 | mpDoc->GetNodes().insert( mpDoc->GetNodes().begin() + nPara, std::move(pNode) ); | |||
1325 | ImpParagraphInserted( nPara ); | |||
1326 | } | |||
1327 | ||||
1328 | TextPaM TextEngine::SplitContent( sal_uInt32 nNode, sal_Int32 nSepPos ) | |||
1329 | { | |||
1330 | #ifdef DBG_UTIL | |||
1331 | TextNode* pNode = mpDoc->GetNodes()[ nNode ].get(); | |||
1332 | SAL_WARN_IF( !pNode, "vcl", "SplitContent: Invalid Node!" )do { if (true && (!pNode)) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "SplitContent: Invalid Node!" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1332" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "SplitContent: Invalid Node!"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "SplitContent: Invalid Node!"; ::sal::detail::log( ( ::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1332" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "SplitContent: Invalid Node!") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1332" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "SplitContent: Invalid Node!"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "SplitContent: Invalid Node!"; ::sal::detail::log( ( ::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1332" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1333 | SAL_WARN_IF( !IsInUndo(), "vcl", "SplitContent: only in Undo()!" )do { if (true && (!IsInUndo())) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "SplitContent: only in Undo()!" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1333" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "SplitContent: only in Undo()!"), 0) ; } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "SplitContent: only in Undo()!"; ::sal::detail::log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1333" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "SplitContent: only in Undo()!") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1333" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "SplitContent: only in Undo()!"), 0) ; } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "SplitContent: only in Undo()!"; ::sal::detail::log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1333" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1334 | SAL_WARN_IF( nSepPos > pNode->GetText().getLength(), "vcl", "SplitContent: Bad index" )do { if (true && (nSepPos > pNode->GetText().getLength ())) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "SplitContent: Bad index") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1334" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "SplitContent: Bad index"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "SplitContent: Bad index"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1334" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "SplitContent: Bad index") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1334" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "SplitContent: Bad index"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "SplitContent: Bad index"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1334" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1335 | #endif | |||
1336 | TextPaM aPaM( nNode, nSepPos ); | |||
1337 | return ImpInsertParaBreak( aPaM ); | |||
1338 | } | |||
1339 | ||||
1340 | TextPaM TextEngine::ConnectContents( sal_uInt32 nLeftNode ) | |||
1341 | { | |||
1342 | SAL_WARN_IF( !IsInUndo(), "vcl", "ConnectContent: only in Undo()!" )do { if (true && (!IsInUndo())) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "ConnectContent: only in Undo()!" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1342" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "ConnectContent: only in Undo()!"), 0 ); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ConnectContent: only in Undo()!"; ::sal::detail::log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1342" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "ConnectContent: only in Undo()!") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1342" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "ConnectContent: only in Undo()!"), 0 ); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ConnectContent: only in Undo()!"; ::sal::detail::log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1342" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1343 | return ImpConnectParagraphs( nLeftNode, nLeftNode+1 ); | |||
1344 | } | |||
1345 | ||||
1346 | void TextEngine::SeekCursor( sal_uInt32 nPara, sal_Int32 nPos, vcl::Font& rFont, OutputDevice* pOutDev ) | |||
1347 | { | |||
1348 | rFont = maFont; | |||
1349 | if ( pOutDev ) | |||
1350 | pOutDev->SetTextColor( maTextColor ); | |||
1351 | ||||
1352 | TextNode* pNode = mpDoc->GetNodes()[ nPara ].get(); | |||
1353 | sal_uInt16 nAttribs = pNode->GetCharAttribs().Count(); | |||
1354 | for ( sal_uInt16 nAttr = 0; nAttr < nAttribs; nAttr++ ) | |||
1355 | { | |||
1356 | TextCharAttrib& rAttrib = pNode->GetCharAttribs().GetAttrib( nAttr ); | |||
1357 | if ( rAttrib.GetStart() > nPos ) | |||
1358 | break; | |||
1359 | ||||
1360 | // When seeking don't use Attr that start there! | |||
1361 | // Do not use empty attributes: | |||
1362 | // - If just being setup and empty => no effect on Font | |||
1363 | // - Characters that are setup in an empty paragraph become visible right away. | |||
1364 | if ( ( ( rAttrib.GetStart() < nPos ) && ( rAttrib.GetEnd() >= nPos ) ) | |||
1365 | || pNode->GetText().isEmpty() ) | |||
1366 | { | |||
1367 | if ( rAttrib.Which() != TEXTATTR_FONTCOLOR1 ) | |||
1368 | { | |||
1369 | rAttrib.GetAttr().SetFont(rFont); | |||
1370 | } | |||
1371 | else | |||
1372 | { | |||
1373 | if ( pOutDev ) | |||
1374 | pOutDev->SetTextColor( static_cast<const TextAttribFontColor&>(rAttrib.GetAttr()).GetColor() ); | |||
1375 | } | |||
1376 | } | |||
1377 | } | |||
1378 | ||||
1379 | if ( !(mpIMEInfos && mpIMEInfos->pAttribs && ( mpIMEInfos->aPos.GetPara() == nPara ) && | |||
1380 | ( nPos > mpIMEInfos->aPos.GetIndex() ) && ( nPos <= ( mpIMEInfos->aPos.GetIndex() + mpIMEInfos->nLen ) )) ) | |||
1381 | return; | |||
1382 | ||||
1383 | ExtTextInputAttr nAttr = mpIMEInfos->pAttribs[ nPos - mpIMEInfos->aPos.GetIndex() - 1 ]; | |||
1384 | if ( nAttr & ExtTextInputAttr::Underline ) | |||
1385 | rFont.SetUnderline( LINESTYLE_SINGLE ); | |||
1386 | else if ( nAttr & ExtTextInputAttr::BoldUnderline ) | |||
1387 | rFont.SetUnderline( LINESTYLE_BOLD ); | |||
1388 | else if ( nAttr & ExtTextInputAttr::DottedUnderline ) | |||
1389 | rFont.SetUnderline( LINESTYLE_DOTTED ); | |||
1390 | else if ( nAttr & ExtTextInputAttr::DashDotUnderline ) | |||
1391 | rFont.SetUnderline( LINESTYLE_DOTTED ); | |||
1392 | if ( nAttr & ExtTextInputAttr::RedText ) | |||
1393 | rFont.SetColor( COL_RED ); | |||
1394 | else if ( nAttr & ExtTextInputAttr::HalfToneText ) | |||
1395 | rFont.SetColor( COL_LIGHTGRAY ); | |||
1396 | if ( nAttr & ExtTextInputAttr::Highlight ) | |||
1397 | { | |||
1398 | const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); | |||
1399 | rFont.SetColor( rStyleSettings.GetHighlightTextColor() ); | |||
1400 | rFont.SetFillColor( rStyleSettings.GetHighlightColor() ); | |||
1401 | rFont.SetTransparent( false ); | |||
1402 | } | |||
1403 | else if ( nAttr & ExtTextInputAttr::GrayWaveline ) | |||
1404 | { | |||
1405 | rFont.SetUnderline( LINESTYLE_WAVE ); | |||
1406 | // if( pOut ) | |||
1407 | // pOut->SetTextLineColor( COL_LIGHTGRAY ); | |||
1408 | } | |||
1409 | } | |||
1410 | ||||
1411 | void TextEngine::FormatAndUpdate( TextView* pCurView ) | |||
1412 | { | |||
1413 | if ( mbDowning ) | |||
1414 | return; | |||
1415 | ||||
1416 | if ( IsInUndo() ) | |||
1417 | IdleFormatAndUpdate( pCurView ); | |||
1418 | else | |||
1419 | { | |||
1420 | FormatDoc(); | |||
1421 | UpdateViews( pCurView ); | |||
1422 | } | |||
1423 | } | |||
1424 | ||||
1425 | void TextEngine::IdleFormatAndUpdate( TextView* pCurView, sal_uInt16 nMaxTimerRestarts ) | |||
1426 | { | |||
1427 | mpIdleFormatter->DoIdleFormat( pCurView, nMaxTimerRestarts ); | |||
1428 | } | |||
1429 | ||||
1430 | void TextEngine::TextModified() | |||
1431 | { | |||
1432 | mbFormatted = false; | |||
1433 | mbModified = true; | |||
1434 | } | |||
1435 | ||||
1436 | void TextEngine::UpdateViews( TextView* pCurView ) | |||
1437 | { | |||
1438 | if ( !GetUpdateMode() || IsFormatting() || maInvalidRect.IsEmpty() ) | |||
1439 | return; | |||
1440 | ||||
1441 | SAL_WARN_IF( !IsFormatted(), "vcl", "UpdateViews: Doc not formatted!" )do { if (true && (!IsFormatted())) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "UpdateViews: Doc not formatted!" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1441" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "UpdateViews: Doc not formatted!"), 0 ); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "UpdateViews: Doc not formatted!"; ::sal::detail::log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1441" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "UpdateViews: Doc not formatted!") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1441" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "UpdateViews: Doc not formatted!"), 0 ); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "UpdateViews: Doc not formatted!"; ::sal::detail::log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1441" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1442 | ||||
1443 | for (TextView* pView : *mpViews) | |||
1444 | { | |||
1445 | pView->HideCursor(); | |||
1446 | ||||
1447 | tools::Rectangle aClipRect( maInvalidRect ); | |||
1448 | const Size aOutSz = pView->GetWindow()->GetOutputSizePixel(); | |||
1449 | const tools::Rectangle aVisArea( pView->GetStartDocPos(), aOutSz ); | |||
1450 | aClipRect.Intersection( aVisArea ); | |||
1451 | if ( !aClipRect.IsEmpty() ) | |||
1452 | { | |||
1453 | // translate into window coordinates | |||
1454 | Point aNewPos = pView->GetWindowPos( aClipRect.TopLeft() ); | |||
1455 | if ( IsRightToLeft() ) | |||
1456 | aNewPos.AdjustX( -(aOutSz.Width() - 1) ); | |||
1457 | aClipRect.SetPos( aNewPos ); | |||
1458 | ||||
1459 | pView->GetWindow()->Invalidate( aClipRect ); | |||
1460 | } | |||
1461 | } | |||
1462 | ||||
1463 | if ( pCurView ) | |||
1464 | { | |||
1465 | pCurView->ShowCursor( pCurView->IsAutoScroll() ); | |||
1466 | } | |||
1467 | ||||
1468 | maInvalidRect = tools::Rectangle(); | |||
1469 | } | |||
1470 | ||||
1471 | IMPL_LINK_NOARG(TextEngine, IdleFormatHdl, Timer *, void)void TextEngine::LinkStubIdleFormatHdl(void * instance, Timer * data) { return static_cast<TextEngine *>(instance)-> IdleFormatHdl(data); } void TextEngine::IdleFormatHdl(__attribute__ ((unused)) Timer *) | |||
1472 | { | |||
1473 | FormatAndUpdate( mpIdleFormatter->GetView() ); | |||
1474 | } | |||
1475 | ||||
1476 | void TextEngine::CheckIdleFormatter() | |||
1477 | { | |||
1478 | mpIdleFormatter->ForceTimeout(); | |||
1479 | } | |||
1480 | ||||
1481 | void TextEngine::FormatFullDoc() | |||
1482 | { | |||
1483 | for ( sal_uInt32 nPortion = 0; nPortion < mpTEParaPortions->Count(); ++nPortion ) | |||
1484 | { | |||
1485 | TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPortion ); | |||
1486 | pTEParaPortion->MarkSelectionInvalid( 0 ); | |||
1487 | } | |||
1488 | mbFormatted = false; | |||
1489 | FormatDoc(); | |||
1490 | } | |||
1491 | ||||
1492 | void TextEngine::FormatDoc() | |||
1493 | { | |||
1494 | if ( IsFormatted() || !GetUpdateMode() || IsFormatting() ) | |||
1495 | return; | |||
1496 | ||||
1497 | mbIsFormatting = true; | |||
1498 | mbHasMultiLineParas = false; | |||
1499 | ||||
1500 | long nY = 0; | |||
1501 | bool bGrow = false; | |||
1502 | ||||
1503 | maInvalidRect = tools::Rectangle(); // clear | |||
1504 | for ( sal_uInt32 nPara = 0; nPara < mpTEParaPortions->Count(); ++nPara ) | |||
1505 | { | |||
1506 | TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); | |||
1507 | if ( pTEParaPortion->IsInvalid() ) | |||
1508 | { | |||
1509 | const long nOldParaWidth = mnCurTextWidth >= 0 ? CalcTextWidth( nPara ) : -1; | |||
1510 | ||||
1511 | Broadcast( TextHint( SfxHintId::TextFormatPara, nPara ) ); | |||
1512 | ||||
1513 | if ( CreateLines( nPara ) ) | |||
1514 | bGrow = true; | |||
1515 | ||||
1516 | // set InvalidRect only once | |||
1517 | if ( maInvalidRect.IsEmpty() ) | |||
1518 | { | |||
1519 | // otherwise remains Empty() for Paperwidth 0 (AutoPageSize) | |||
1520 | const long nWidth = mnMaxTextWidth | |||
1521 | ? mnMaxTextWidth | |||
1522 | : std::numeric_limits<long>::max(); | |||
1523 | const Range aInvRange( GetInvalidYOffsets( nPara ) ); | |||
1524 | maInvalidRect = tools::Rectangle( Point( 0, nY+aInvRange.Min() ), | |||
1525 | Size( nWidth, aInvRange.Len() ) ); | |||
1526 | } | |||
1527 | else | |||
1528 | { | |||
1529 | maInvalidRect.SetBottom( nY + CalcParaHeight( nPara ) ); | |||
1530 | } | |||
1531 | ||||
1532 | if ( mnCurTextWidth >= 0 ) | |||
1533 | { | |||
1534 | const long nNewParaWidth = CalcTextWidth( nPara ); | |||
1535 | if ( nNewParaWidth >= mnCurTextWidth ) | |||
1536 | mnCurTextWidth = nNewParaWidth; | |||
1537 | else if ( nOldParaWidth >= mnCurTextWidth ) | |||
1538 | mnCurTextWidth = -1; | |||
1539 | } | |||
1540 | } | |||
1541 | else if ( bGrow ) | |||
1542 | { | |||
1543 | maInvalidRect.SetBottom( nY + CalcParaHeight( nPara ) ); | |||
1544 | } | |||
1545 | nY += CalcParaHeight( nPara ); | |||
1546 | if ( !mbHasMultiLineParas && pTEParaPortion->GetLines().size() > 1 ) | |||
1547 | mbHasMultiLineParas = true; | |||
1548 | } | |||
1549 | ||||
1550 | if ( !maInvalidRect.IsEmpty() ) | |||
1551 | { | |||
1552 | const long nNewHeight = CalcTextHeight(); | |||
1553 | const long nDiff = nNewHeight - mnCurTextHeight; | |||
1554 | if ( nNewHeight < mnCurTextHeight ) | |||
1555 | { | |||
1556 | maInvalidRect.SetBottom( std::max( nNewHeight, mnCurTextHeight ) ); | |||
1557 | if ( maInvalidRect.IsEmpty() ) | |||
1558 | { | |||
1559 | maInvalidRect.SetTop( 0 ); | |||
1560 | // Left and Right are not evaluated, but set because of IsEmpty | |||
1561 | maInvalidRect.SetLeft( 0 ); | |||
1562 | maInvalidRect.SetRight( mnMaxTextWidth ); | |||
1563 | } | |||
1564 | } | |||
1565 | ||||
1566 | mnCurTextHeight = nNewHeight; | |||
1567 | if ( nDiff ) | |||
1568 | { | |||
1569 | mbFormatted = true; | |||
1570 | Broadcast( TextHint( SfxHintId::TextHeightChanged ) ); | |||
1571 | } | |||
1572 | } | |||
1573 | ||||
1574 | mbIsFormatting = false; | |||
1575 | mbFormatted = true; | |||
1576 | ||||
1577 | Broadcast( TextHint( SfxHintId::TextFormatted ) ); | |||
1578 | } | |||
1579 | ||||
1580 | void TextEngine::CreateAndInsertEmptyLine( sal_uInt32 nPara ) | |||
1581 | { | |||
1582 | TextNode* pNode = mpDoc->GetNodes()[ nPara ].get(); | |||
1583 | TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); | |||
1584 | ||||
1585 | TextLine aTmpLine; | |||
1586 | aTmpLine.SetStart( pNode->GetText().getLength() ); | |||
1587 | aTmpLine.SetEnd( aTmpLine.GetStart() ); | |||
1588 | ||||
1589 | if ( ImpGetAlign() == TxtAlign::Center ) | |||
1590 | aTmpLine.SetStartX( static_cast<short>(mnMaxTextWidth / 2) ); | |||
1591 | else if ( ImpGetAlign() == TxtAlign::Right ) | |||
1592 | aTmpLine.SetStartX( static_cast<short>(mnMaxTextWidth) ); | |||
1593 | else | |||
1594 | aTmpLine.SetStartX( mpDoc->GetLeftMargin() ); | |||
1595 | ||||
1596 | bool bLineBreak = !pNode->GetText().isEmpty(); | |||
1597 | ||||
1598 | std::unique_ptr<TETextPortion> pDummyPortion(new TETextPortion( 0 )); | |||
1599 | pDummyPortion->GetWidth() = 0; | |||
1600 | pTEParaPortion->GetTextPortions().push_back( std::move(pDummyPortion) ); | |||
1601 | ||||
1602 | if ( bLineBreak ) | |||
1603 | { | |||
1604 | // -2: The new one is already inserted. | |||
1605 | const std::size_t nPos = pTEParaPortion->GetTextPortions().size() - 1; | |||
1606 | aTmpLine.SetStartPortion( nPos ); | |||
1607 | aTmpLine.SetEndPortion( nPos ); | |||
1608 | } | |||
1609 | pTEParaPortion->GetLines().push_back( aTmpLine ); | |||
1610 | } | |||
1611 | ||||
1612 | void TextEngine::ImpBreakLine( sal_uInt32 nPara, TextLine* pLine, sal_Int32 nPortionStart, long nRemainingWidth ) | |||
1613 | { | |||
1614 | TextNode* pNode = mpDoc->GetNodes()[ nPara ].get(); | |||
1615 | ||||
1616 | // Font still should be adjusted | |||
1617 | sal_Int32 nMaxBreakPos = mpRefDev->GetTextBreak( pNode->GetText(), nRemainingWidth, nPortionStart ); | |||
1618 | ||||
1619 | SAL_WARN_IF( nMaxBreakPos >= pNode->GetText().getLength(), "vcl", "ImpBreakLine: Break?!" )do { if (true && (nMaxBreakPos >= pNode->GetText ().getLength())) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "ImpBreakLine: Break?!") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1619" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "ImpBreakLine: Break?!"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ImpBreakLine: Break?!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1619" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "ImpBreakLine: Break?!") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1619" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "ImpBreakLine: Break?!"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ImpBreakLine: Break?!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1619" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1620 | ||||
1621 | if ( nMaxBreakPos == -1 ) // GetTextBreak() != GetTextSize() | |||
1622 | nMaxBreakPos = pNode->GetText().getLength() - 1; | |||
1623 | ||||
1624 | uno::Reference < i18n::XBreakIterator > xBI = GetBreakIterator(); | |||
1625 | i18n::LineBreakHyphenationOptions aHyphOptions( nullptr, uno::Sequence< beans::PropertyValue >(), 1 ); | |||
1626 | ||||
1627 | i18n::LineBreakUserOptions aUserOptions; | |||
1628 | aUserOptions.forbiddenBeginCharacters = ImpGetLocaleDataWrapper()->getForbiddenCharacters().beginLine; | |||
1629 | aUserOptions.forbiddenEndCharacters = ImpGetLocaleDataWrapper()->getForbiddenCharacters().endLine; | |||
1630 | aUserOptions.applyForbiddenRules = true; | |||
1631 | aUserOptions.allowPunctuationOutsideMargin = false; | |||
1632 | aUserOptions.allowHyphenateEnglish = false; | |||
1633 | ||||
1634 | static const css::lang::Locale aDefLocale; | |||
1635 | i18n::LineBreakResults aLBR = xBI->getLineBreak( pNode->GetText(), nMaxBreakPos, aDefLocale, pLine->GetStart(), aHyphOptions, aUserOptions ); | |||
1636 | sal_Int32 nBreakPos = aLBR.breakIndex; | |||
1637 | if ( nBreakPos <= pLine->GetStart() ) | |||
1638 | { | |||
1639 | nBreakPos = nMaxBreakPos; | |||
1640 | if ( nBreakPos <= pLine->GetStart() ) | |||
1641 | nBreakPos = pLine->GetStart() + 1; // infinite loop otherwise! | |||
1642 | } | |||
1643 | ||||
1644 | // the damaged Portion is the End Portion | |||
1645 | pLine->SetEnd( nBreakPos ); | |||
1646 | const std::size_t nEndPortion = SplitTextPortion( nPara, nBreakPos ); | |||
1647 | ||||
1648 | if ( nBreakPos >= pLine->GetStart() && | |||
1649 | nBreakPos < pNode->GetText().getLength() && | |||
1650 | pNode->GetText()[ nBreakPos ] == ' ' ) | |||
1651 | { | |||
1652 | // generally suppress blanks at the end of line | |||
1653 | TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); | |||
1654 | TETextPortion* pTP = pTEParaPortion->GetTextPortions()[ nEndPortion ]; | |||
1655 | SAL_WARN_IF( nBreakPos <= pLine->GetStart(), "vcl", "ImpBreakLine: SplitTextPortion at beginning of line?" )do { if (true && (nBreakPos <= pLine->GetStart( ))) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "ImpBreakLine: SplitTextPortion at beginning of line?" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1655" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "ImpBreakLine: SplitTextPortion at beginning of line?" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ImpBreakLine: SplitTextPortion at beginning of line?" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1655" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "ImpBreakLine: SplitTextPortion at beginning of line?" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1655" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "ImpBreakLine: SplitTextPortion at beginning of line?" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ImpBreakLine: SplitTextPortion at beginning of line?" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1655" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1656 | pTP->GetWidth() = CalcTextWidth( nPara, nBreakPos-pTP->GetLen(), pTP->GetLen()-1 ); | |||
1657 | } | |||
1658 | pLine->SetEndPortion( nEndPortion ); | |||
1659 | } | |||
1660 | ||||
1661 | std::size_t TextEngine::SplitTextPortion( sal_uInt32 nPara, sal_Int32 nPos ) | |||
1662 | { | |||
1663 | ||||
1664 | // the Portion at nPos is being split, unless there is already a switch at nPos | |||
1665 | if ( nPos == 0 ) | |||
1666 | return 0; | |||
1667 | ||||
1668 | std::size_t nSplitPortion; | |||
1669 | sal_Int32 nTmpPos = 0; | |||
1670 | TETextPortion* pTextPortion = nullptr; | |||
1671 | TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); | |||
1672 | const std::size_t nPortions = pTEParaPortion->GetTextPortions().size(); | |||
1673 | for ( nSplitPortion = 0; nSplitPortion < nPortions; nSplitPortion++ ) | |||
1674 | { | |||
1675 | TETextPortion* pTP = pTEParaPortion->GetTextPortions()[nSplitPortion]; | |||
1676 | nTmpPos += pTP->GetLen(); | |||
1677 | if ( nTmpPos >= nPos ) | |||
1678 | { | |||
1679 | if ( nTmpPos == nPos ) // nothing needs splitting | |||
1680 | return nSplitPortion; | |||
1681 | pTextPortion = pTP; | |||
1682 | break; | |||
1683 | } | |||
1684 | } | |||
1685 | ||||
1686 | SAL_WARN_IF( !pTextPortion, "vcl", "SplitTextPortion: position outside of region!" )do { if (true && (!pTextPortion)) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "SplitTextPortion: position outside of region!" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1686" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "SplitTextPortion: position outside of region!" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "SplitTextPortion: position outside of region!"; :: sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1686" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "SplitTextPortion: position outside of region!") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1686" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "SplitTextPortion: position outside of region!" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "SplitTextPortion: position outside of region!"; :: sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1686" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1687 | ||||
1688 | const sal_Int32 nOverlapp = nTmpPos - nPos; | |||
1689 | pTextPortion->GetLen() -= nOverlapp; | |||
1690 | std::unique_ptr<TETextPortion> pNewPortion( new TETextPortion( nOverlapp ) ); | |||
1691 | pTEParaPortion->GetTextPortions().insert( pTEParaPortion->GetTextPortions().begin() + nSplitPortion + 1, std::move(pNewPortion) ); | |||
1692 | pTextPortion->GetWidth() = CalcTextWidth( nPara, nPos-pTextPortion->GetLen(), pTextPortion->GetLen() ); | |||
1693 | ||||
1694 | return nSplitPortion; | |||
1695 | } | |||
1696 | ||||
1697 | void TextEngine::CreateTextPortions( sal_uInt32 nPara, sal_Int32 nStartPos ) | |||
1698 | { | |||
1699 | TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); | |||
1700 | TextNode* pNode = pTEParaPortion->GetNode(); | |||
1701 | SAL_WARN_IF( pNode->GetText().isEmpty(), "vcl", "CreateTextPortions: should not be used for empty paragraphs!" )do { if (true && (pNode->GetText().isEmpty())) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "CreateTextPortions: should not be used for empty paragraphs!" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1701" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "CreateTextPortions: should not be used for empty paragraphs!" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "CreateTextPortions: should not be used for empty paragraphs!" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1701" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "CreateTextPortions: should not be used for empty paragraphs!" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1701" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "CreateTextPortions: should not be used for empty paragraphs!" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "CreateTextPortions: should not be used for empty paragraphs!" ; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1701" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1702 | ||||
1703 | std::set<sal_Int32> aPositions; | |||
1704 | std::set<sal_Int32>::iterator aPositionsIt; | |||
1705 | aPositions.insert(0); | |||
1706 | ||||
1707 | const sal_uInt16 nAttribs = pNode->GetCharAttribs().Count(); | |||
1708 | for ( sal_uInt16 nAttr = 0; nAttr < nAttribs; nAttr++ ) | |||
1709 | { | |||
1710 | TextCharAttrib& rAttrib = pNode->GetCharAttribs().GetAttrib( nAttr ); | |||
1711 | ||||
1712 | aPositions.insert( rAttrib.GetStart() ); | |||
1713 | aPositions.insert( rAttrib.GetEnd() ); | |||
1714 | } | |||
1715 | aPositions.insert( pNode->GetText().getLength() ); | |||
1716 | ||||
1717 | const std::vector<TEWritingDirectionInfo>& rWritingDirections = pTEParaPortion->GetWritingDirectionInfos(); | |||
1718 | for ( const auto& rWritingDirection : rWritingDirections ) | |||
1719 | aPositions.insert( rWritingDirection.nStartPos ); | |||
1720 | ||||
1721 | if ( mpIMEInfos && mpIMEInfos->pAttribs && ( mpIMEInfos->aPos.GetPara() == nPara ) ) | |||
1722 | { | |||
1723 | ExtTextInputAttr nLastAttr = ExtTextInputAttr(0xffff); | |||
1724 | for( sal_Int32 n = 0; n < mpIMEInfos->nLen; n++ ) | |||
1725 | { | |||
1726 | if ( mpIMEInfos->pAttribs[n] != nLastAttr ) | |||
1727 | { | |||
1728 | aPositions.insert( mpIMEInfos->aPos.GetIndex() + n ); | |||
1729 | nLastAttr = mpIMEInfos->pAttribs[n]; | |||
1730 | } | |||
1731 | } | |||
1732 | } | |||
1733 | ||||
1734 | sal_Int32 nTabPos = pNode->GetText().indexOf( '\t' ); | |||
1735 | while ( nTabPos != -1 ) | |||
1736 | { | |||
1737 | aPositions.insert( nTabPos ); | |||
1738 | aPositions.insert( nTabPos + 1 ); | |||
1739 | nTabPos = pNode->GetText().indexOf( '\t', nTabPos+1 ); | |||
1740 | } | |||
1741 | ||||
1742 | // Delete starting with... | |||
1743 | // Unfortunately, the number of TextPortions does not have to be | |||
1744 | // equal to aPositions.Count(), because of linebreaks | |||
1745 | sal_Int32 nPortionStart = 0; | |||
1746 | std::size_t nInvPortion = 0; | |||
1747 | std::size_t nP; | |||
1748 | for ( nP = 0; nP < pTEParaPortion->GetTextPortions().size(); nP++ ) | |||
1749 | { | |||
1750 | TETextPortion* pTmpPortion = pTEParaPortion->GetTextPortions()[nP]; | |||
1751 | nPortionStart += pTmpPortion->GetLen(); | |||
1752 | if ( nPortionStart >= nStartPos ) | |||
1753 | { | |||
1754 | nPortionStart -= pTmpPortion->GetLen(); | |||
1755 | nInvPortion = nP; | |||
1756 | break; | |||
1757 | } | |||
1758 | } | |||
1759 | OSL_ENSURE(nP < pTEParaPortion->GetTextPortions().size()do { if (true && (!(nP < pTEParaPortion->GetTextPortions ().size() || pTEParaPortion->GetTextPortions().empty()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1761" ": "), "%s", "CreateTextPortions: Nothing to delete!" ); } } while (false) | |||
1760 | || pTEParaPortion->GetTextPortions().empty(),do { if (true && (!(nP < pTEParaPortion->GetTextPortions ().size() || pTEParaPortion->GetTextPortions().empty()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1761" ": "), "%s", "CreateTextPortions: Nothing to delete!" ); } } while (false) | |||
1761 | "CreateTextPortions: Nothing to delete!")do { if (true && (!(nP < pTEParaPortion->GetTextPortions ().size() || pTEParaPortion->GetTextPortions().empty()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1761" ": "), "%s", "CreateTextPortions: Nothing to delete!" ); } } while (false); | |||
1762 | if ( nInvPortion && ( nPortionStart+pTEParaPortion->GetTextPortions()[nInvPortion]->GetLen() > nStartPos ) ) | |||
1763 | { | |||
1764 | // better one before... | |||
1765 | // But only if it was within the Portion; otherwise it might be | |||
1766 | // the only one in the previous line! | |||
1767 | nInvPortion--; | |||
1768 | nPortionStart -= pTEParaPortion->GetTextPortions()[nInvPortion]->GetLen(); | |||
1769 | } | |||
1770 | pTEParaPortion->GetTextPortions().DeleteFromPortion( nInvPortion ); | |||
1771 | ||||
1772 | // a Portion might have been created by a line break | |||
1773 | aPositions.insert( nPortionStart ); | |||
1774 | ||||
1775 | aPositionsIt = aPositions.find( nPortionStart ); | |||
1776 | SAL_WARN_IF( aPositionsIt == aPositions.end(), "vcl", "CreateTextPortions: nPortionStart not found" )do { if (true && (aPositionsIt == aPositions.end())) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl" )) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "CreateTextPortions: nPortionStart not found") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1776" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "CreateTextPortions: nPortionStart not found" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "CreateTextPortions: nPortionStart not found"; ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1776" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "CreateTextPortions: nPortionStart not found") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1776" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "CreateTextPortions: nPortionStart not found" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "CreateTextPortions: nPortionStart not found"; ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1776" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1777 | ||||
1778 | if ( aPositionsIt != aPositions.end() ) | |||
1779 | { | |||
1780 | std::set<sal_Int32>::iterator nextIt = aPositionsIt; | |||
1781 | for ( ++nextIt; nextIt != aPositions.end(); ++aPositionsIt, ++nextIt ) | |||
1782 | { | |||
1783 | std::unique_ptr<TETextPortion> pNew( new TETextPortion( *nextIt - *aPositionsIt ) ); | |||
1784 | pTEParaPortion->GetTextPortions().push_back( std::move(pNew) ); | |||
1785 | } | |||
1786 | } | |||
1787 | OSL_ENSURE(pTEParaPortion->GetTextPortions().size(), "CreateTextPortions: No Portions?!")do { if (true && (!(pTEParaPortion->GetTextPortions ().size()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1787" ": "), "%s", "CreateTextPortions: No Portions?!") ; } } while (false); | |||
1788 | } | |||
1789 | ||||
1790 | void TextEngine::RecalcTextPortion( sal_uInt32 nPara, sal_Int32 nStartPos, sal_Int32 nNewChars ) | |||
1791 | { | |||
1792 | TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); | |||
1793 | OSL_ENSURE(pTEParaPortion->GetTextPortions().size(), "RecalcTextPortion: no Portions!")do { if (true && (!(pTEParaPortion->GetTextPortions ().size()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1793" ": "), "%s", "RecalcTextPortion: no Portions!"); } } while (false); | |||
| ||||
1794 | OSL_ENSURE(nNewChars, "RecalcTextPortion: Diff == 0")do { if (true && (!(nNewChars))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1794" ": "), "%s", "RecalcTextPortion: Diff == 0"); } } while (false); | |||
1795 | ||||
1796 | TextNode* const pNode = pTEParaPortion->GetNode(); | |||
1797 | if ( nNewChars > 0 ) | |||
1798 | { | |||
1799 | // If an Attribute is starting/ending at nStartPos, or there is a tab | |||
1800 | // before nStartPos => a new Portion starts. | |||
1801 | // Otherwise the Portion is extended at nStartPos. | |||
1802 | // Or if at the very beginning ( StartPos 0 ) followed by a tab... | |||
1803 | if ( ( pNode->GetCharAttribs().HasBoundingAttrib( nStartPos ) ) || | |||
1804 | ( nStartPos && ( pNode->GetText()[ nStartPos - 1 ] == '\t' ) ) || | |||
1805 | ( !nStartPos && ( nNewChars < pNode->GetText().getLength() ) && pNode->GetText()[ nNewChars ] == '\t' ) ) | |||
1806 | { | |||
1807 | std::size_t nNewPortionPos = 0; | |||
1808 | if ( nStartPos ) | |||
1809 | nNewPortionPos = SplitTextPortion( nPara, nStartPos ) + 1; | |||
1810 | ||||
1811 | // Here could be an empty Portion if the paragraph was empty, | |||
1812 | // or a new line was created by a hard line-break. | |||
1813 | if ( ( nNewPortionPos < pTEParaPortion->GetTextPortions().size() ) && | |||
1814 | !pTEParaPortion->GetTextPortions()[nNewPortionPos]->GetLen() ) | |||
1815 | { | |||
1816 | // use the empty Portion | |||
1817 | pTEParaPortion->GetTextPortions()[nNewPortionPos]->GetLen() = nNewChars; | |||
1818 | } | |||
1819 | else | |||
1820 | { | |||
1821 | std::unique_ptr<TETextPortion> pNewPortion(new TETextPortion( nNewChars )); | |||
1822 | pTEParaPortion->GetTextPortions().insert( pTEParaPortion->GetTextPortions().begin() + nNewPortionPos, std::move(pNewPortion) ); | |||
1823 | } | |||
1824 | } | |||
1825 | else | |||
1826 | { | |||
1827 | sal_Int32 nPortionStart {0}; | |||
1828 | const std::size_t nTP = pTEParaPortion->GetTextPortions().FindPortion( nStartPos, nPortionStart ); | |||
1829 | TETextPortion* const pTP = pTEParaPortion->GetTextPortions()[ nTP ]; | |||
1830 | SAL_WARN_IF( !pTP, "vcl", "RecalcTextPortion: Portion not found!" )do { if (true && (!pTP)) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "RecalcTextPortion: Portion not found!" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1830" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "RecalcTextPortion: Portion not found!" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "RecalcTextPortion: Portion not found!"; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1830" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "RecalcTextPortion: Portion not found!") == 1) { :: sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1830" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "RecalcTextPortion: Portion not found!" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "RecalcTextPortion: Portion not found!"; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1830" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1831 | pTP->GetLen() += nNewChars; | |||
1832 | pTP->GetWidth() = -1; | |||
1833 | } | |||
1834 | } | |||
1835 | else | |||
1836 | { | |||
1837 | // Shrink or remove Portion | |||
1838 | // Before calling this function, ensure that no Portions were in the deleted range! | |||
1839 | ||||
1840 | // There must be no Portion reaching into or starting within, | |||
1841 | // thus: nStartPos <= nPos <= nStartPos - nNewChars(neg.) | |||
1842 | std::size_t nPortion = 0; | |||
1843 | sal_Int32 nPos = 0; | |||
1844 | const sal_Int32 nEnd = nStartPos-nNewChars; | |||
1845 | const std::size_t nPortions = pTEParaPortion->GetTextPortions().size(); | |||
1846 | TETextPortion* pTP = nullptr; | |||
1847 | for ( nPortion = 0; nPortion < nPortions; nPortion++ ) | |||
1848 | { | |||
1849 | pTP = pTEParaPortion->GetTextPortions()[ nPortion ]; | |||
1850 | if ( ( nPos+pTP->GetLen() ) > nStartPos ) | |||
1851 | { | |||
1852 | SAL_WARN_IF( nPos > nStartPos, "vcl", "RecalcTextPortion: Bad Start!" )do { if (true && (nPos > nStartPos)) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "RecalcTextPortion: Bad Start!" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1852" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "RecalcTextPortion: Bad Start!"), 0) ; } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "RecalcTextPortion: Bad Start!"; ::sal::detail::log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1852" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "RecalcTextPortion: Bad Start!") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1852" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "RecalcTextPortion: Bad Start!"), 0) ; } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "RecalcTextPortion: Bad Start!"; ::sal::detail::log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1852" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1853 | SAL_WARN_IF( nPos+pTP->GetLen() < nEnd, "vcl", "RecalcTextPortion: Bad End!" )do { if (true && (nPos+pTP->GetLen() < nEnd)) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl" )) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "RecalcTextPortion: Bad End!") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1853" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "RecalcTextPortion: Bad End!"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "RecalcTextPortion: Bad End!"; ::sal::detail::log( ( ::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1853" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "RecalcTextPortion: Bad End!") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1853" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "RecalcTextPortion: Bad End!"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "RecalcTextPortion: Bad End!"; ::sal::detail::log( ( ::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1853" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1854 | break; | |||
1855 | } | |||
1856 | nPos += pTP->GetLen(); | |||
1857 | } | |||
1858 | SAL_WARN_IF( !pTP, "vcl", "RecalcTextPortion: Portion not found!" )do { if (true && (!pTP)) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "RecalcTextPortion: Portion not found!" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1858" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "RecalcTextPortion: Portion not found!" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "RecalcTextPortion: Portion not found!"; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1858" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "RecalcTextPortion: Portion not found!") == 1) { :: sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1858" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "RecalcTextPortion: Portion not found!" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "RecalcTextPortion: Portion not found!"; ::sal::detail ::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1858" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1859 | if ( ( nPos == nStartPos ) && ( (nPos+pTP->GetLen()) == nEnd ) ) | |||
| ||||
1860 | { | |||
1861 | // remove Portion | |||
1862 | pTEParaPortion->GetTextPortions().erase( pTEParaPortion->GetTextPortions().begin() + nPortion ); | |||
1863 | } | |||
1864 | else | |||
1865 | { | |||
1866 | SAL_WARN_IF( pTP->GetLen() <= (-nNewChars), "vcl", "RecalcTextPortion: Portion too small to shrink!" )do { if (true && (pTP->GetLen() <= (-nNewChars) )) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "RecalcTextPortion: Portion too small to shrink!" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1866" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "RecalcTextPortion: Portion too small to shrink!" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "RecalcTextPortion: Portion too small to shrink!"; :: sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1866" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "RecalcTextPortion: Portion too small to shrink!" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1866" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "RecalcTextPortion: Portion too small to shrink!" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "RecalcTextPortion: Portion too small to shrink!"; :: sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1866" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1867 | pTP->GetLen() += nNewChars; | |||
1868 | } | |||
1869 | OSL_ENSURE( pTEParaPortion->GetTextPortions().size(),do { if (true && (!(pTEParaPortion->GetTextPortions ().size()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1870" ": "), "%s", "RecalcTextPortion: none are left!") ; } } while (false) | |||
1870 | "RecalcTextPortion: none are left!" )do { if (true && (!(pTEParaPortion->GetTextPortions ().size()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1870" ": "), "%s", "RecalcTextPortion: none are left!") ; } } while (false); | |||
1871 | } | |||
1872 | } | |||
1873 | ||||
1874 | void TextEngine::ImpPaint( OutputDevice* pOutDev, const Point& rStartPos, tools::Rectangle const* pPaintArea, TextSelection const* pSelection ) | |||
1875 | { | |||
1876 | if ( !GetUpdateMode() ) | |||
1877 | return; | |||
1878 | ||||
1879 | if ( !IsFormatted() ) | |||
1880 | FormatDoc(); | |||
1881 | ||||
1882 | vcl::Window* const pOutWin = dynamic_cast<vcl::Window*>(pOutDev); | |||
1883 | const bool bTransparent = (pOutWin && pOutWin->IsPaintTransparent()); | |||
1884 | ||||
1885 | long nY = rStartPos.Y(); | |||
1886 | ||||
1887 | TextPaM const* pSelStart = nullptr; | |||
1888 | TextPaM const* pSelEnd = nullptr; | |||
1889 | if ( pSelection && pSelection->HasRange() ) | |||
1890 | { | |||
1891 | const bool bInvers = pSelection->GetEnd() < pSelection->GetStart(); | |||
1892 | pSelStart = !bInvers ? &pSelection->GetStart() : &pSelection->GetEnd(); | |||
1893 | pSelEnd = bInvers ? &pSelection->GetStart() : &pSelection->GetEnd(); | |||
1894 | } | |||
1895 | ||||
1896 | const StyleSettings& rStyleSettings = pOutDev->GetSettings().GetStyleSettings(); | |||
1897 | ||||
1898 | // for all paragraphs | |||
1899 | for ( sal_uInt32 nPara = 0; nPara < mpTEParaPortions->Count(); ++nPara ) | |||
1900 | { | |||
1901 | TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPara ); | |||
1902 | // in case while typing Idle-Formatting, asynchronous Paint | |||
1903 | if ( pPortion->IsInvalid() ) | |||
1904 | return; | |||
1905 | ||||
1906 | const long nParaHeight = CalcParaHeight( nPara ); | |||
1907 | if ( !pPaintArea || ( ( nY + nParaHeight ) > pPaintArea->Top() ) ) | |||
1908 | { | |||
1909 | // for all lines of the paragraph | |||
1910 | sal_Int32 nIndex = 0; | |||
1911 | for ( auto & rLine : pPortion->GetLines() ) | |||
1912 | { | |||
1913 | Point aTmpPos( rStartPos.X() + rLine.GetStartX(), nY ); | |||
1914 | ||||
1915 | if ( !pPaintArea || ( ( nY + mnCharHeight ) > pPaintArea->Top() ) ) | |||
1916 | { | |||
1917 | // for all Portions of the line | |||
1918 | nIndex = rLine.GetStart(); | |||
1919 | for ( std::size_t y = rLine.GetStartPortion(); y <= rLine.GetEndPortion(); y++ ) | |||
1920 | { | |||
1921 | OSL_ENSURE(pPortion->GetTextPortions().size(),do { if (true && (!(pPortion->GetTextPortions().size ()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1922" ": "), "%s", "ImpPaint: Line without Textportion!" ); } } while (false) | |||
1922 | "ImpPaint: Line without Textportion!")do { if (true && (!(pPortion->GetTextPortions().size ()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1922" ": "), "%s", "ImpPaint: Line without Textportion!" ); } } while (false); | |||
1923 | TETextPortion* pTextPortion = pPortion->GetTextPortions()[ y ]; | |||
1924 | SAL_WARN_IF( !pTextPortion, "vcl", "ImpPaint: Bad pTextPortion!" )do { if (true && (!pTextPortion)) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "ImpPaint: Bad pTextPortion!" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1924" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "ImpPaint: Bad pTextPortion!"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ImpPaint: Bad pTextPortion!"; ::sal::detail::log( ( ::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1924" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "ImpPaint: Bad pTextPortion!") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1924" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "ImpPaint: Bad pTextPortion!"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "ImpPaint: Bad pTextPortion!"; ::sal::detail::log( ( ::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "1924" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
1925 | ||||
1926 | ImpInitLayoutMode( pOutDev /*, pTextPortion->IsRightToLeft() */); | |||
1927 | ||||
1928 | const long nTxtWidth = pTextPortion->GetWidth(); | |||
1929 | aTmpPos.setX( rStartPos.X() + ImpGetOutputOffset( nPara, &rLine, nIndex, nIndex ) ); | |||
1930 | ||||
1931 | // only print if starting in the visible region | |||
1932 | if ( ( aTmpPos.X() + nTxtWidth ) >= 0 ) | |||
1933 | { | |||
1934 | switch ( pTextPortion->GetKind() ) | |||
1935 | { | |||
1936 | case PORTIONKIND_TEXT0: | |||
1937 | { | |||
1938 | vcl::Font aFont; | |||
1939 | SeekCursor( nPara, nIndex+1, aFont, pOutDev ); | |||
1940 | if( bTransparent ) | |||
1941 | aFont.SetTransparent( true ); | |||
1942 | else if ( pSelection ) | |||
1943 | aFont.SetTransparent( false ); | |||
1944 | pOutDev->SetFont( aFont ); | |||
1945 | ||||
1946 | sal_Int32 nTmpIndex = nIndex; | |||
1947 | sal_Int32 nEnd = nTmpIndex + pTextPortion->GetLen(); | |||
1948 | Point aPos = aTmpPos; | |||
1949 | ||||
1950 | bool bDone = false; | |||
1951 | if ( pSelStart ) | |||
1952 | { | |||
1953 | // is a part of it in the selection? | |||
1954 | const TextPaM aTextStart( nPara, nTmpIndex ); | |||
1955 | const TextPaM aTextEnd( nPara, nEnd ); | |||
1956 | if ( ( aTextStart < *pSelEnd ) && ( aTextEnd > *pSelStart ) ) | |||
1957 | { | |||
1958 | // 1) vcl::Region before Selection | |||
1959 | if ( aTextStart < *pSelStart ) | |||
1960 | { | |||
1961 | const sal_Int32 nL = pSelStart->GetIndex() - nTmpIndex; | |||
1962 | pOutDev->SetFont( aFont); | |||
1963 | pOutDev->SetTextFillColor(); | |||
1964 | aPos.setX( rStartPos.X() + ImpGetOutputOffset( nPara, &rLine, nTmpIndex, nTmpIndex+nL ) ); | |||
1965 | pOutDev->DrawText( aPos, pPortion->GetNode()->GetText(), nTmpIndex, nL ); | |||
1966 | nTmpIndex = nTmpIndex + nL; | |||
1967 | ||||
1968 | } | |||
1969 | // 2) vcl::Region with Selection | |||
1970 | sal_Int32 nL = nEnd - nTmpIndex; | |||
1971 | if ( aTextEnd > *pSelEnd ) | |||
1972 | nL = pSelEnd->GetIndex() - nTmpIndex; | |||
1973 | if ( nL ) | |||
1974 | { | |||
1975 | const Color aOldTextColor = pOutDev->GetTextColor(); | |||
1976 | pOutDev->SetTextColor( rStyleSettings.GetHighlightTextColor() ); | |||
1977 | pOutDev->SetTextFillColor( rStyleSettings.GetHighlightColor() ); | |||
1978 | aPos.setX( rStartPos.X() + ImpGetOutputOffset( nPara, &rLine, nTmpIndex, nTmpIndex+nL ) ); | |||
1979 | pOutDev->DrawText( aPos, pPortion->GetNode()->GetText(), nTmpIndex, nL ); | |||
1980 | pOutDev->SetTextColor( aOldTextColor ); | |||
1981 | pOutDev->SetTextFillColor(); | |||
1982 | nTmpIndex = nTmpIndex + nL; | |||
1983 | } | |||
1984 | ||||
1985 | // 3) vcl::Region after Selection | |||
1986 | if ( nTmpIndex < nEnd ) | |||
1987 | { | |||
1988 | nL = nEnd-nTmpIndex; | |||
1989 | pOutDev->SetTextFillColor(); | |||
1990 | aPos.setX( rStartPos.X() + ImpGetOutputOffset( nPara, &rLine, nTmpIndex, nTmpIndex+nL ) ); | |||
1991 | pOutDev->DrawText( aPos, pPortion->GetNode()->GetText(), nTmpIndex, nEnd-nTmpIndex ); | |||
1992 | } | |||
1993 | bDone = true; | |||
1994 | } | |||
1995 | } | |||
1996 | if ( !bDone ) | |||
1997 | { | |||
1998 | pOutDev->SetTextFillColor(); | |||
1999 | aPos.setX( rStartPos.X() + ImpGetOutputOffset( nPara, &rLine, nTmpIndex, nEnd ) ); | |||
2000 | pOutDev->DrawText( aPos, pPortion->GetNode()->GetText(), nTmpIndex, nEnd-nTmpIndex ); | |||
2001 | } | |||
2002 | } | |||
2003 | break; | |||
2004 | case PORTIONKIND_TAB1: | |||
2005 | // for HideSelection() only Range, pSelection = 0. | |||
2006 | if ( pSelStart ) // also implies pSelEnd | |||
2007 | { | |||
2008 | const tools::Rectangle aTabArea( aTmpPos, Point( aTmpPos.X()+nTxtWidth, aTmpPos.Y()+mnCharHeight-1 ) ); | |||
2009 | // is the Tab in the Selection??? | |||
2010 | const TextPaM aTextStart(nPara, nIndex); | |||
2011 | const TextPaM aTextEnd(nPara, nIndex + 1); | |||
2012 | if ((aTextStart < *pSelEnd) && (aTextEnd > *pSelStart)) | |||
2013 | { | |||
2014 | const Color aOldColor = pOutDev->GetFillColor(); | |||
2015 | pOutDev->SetFillColor( | |||
2016 | rStyleSettings.GetHighlightColor()); | |||
2017 | pOutDev->DrawRect(aTabArea); | |||
2018 | pOutDev->SetFillColor(aOldColor); | |||
2019 | } | |||
2020 | else | |||
2021 | { | |||
2022 | pOutDev->Erase( aTabArea ); | |||
2023 | } | |||
2024 | } | |||
2025 | break; | |||
2026 | default: | |||
2027 | OSL_FAIL( "ImpPaint: Unknown Portion-Type !" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "2027" ": "), "%s", "ImpPaint: Unknown Portion-Type !"); } } while (false); | |||
2028 | } | |||
2029 | } | |||
2030 | ||||
2031 | nIndex += pTextPortion->GetLen(); | |||
2032 | } | |||
2033 | } | |||
2034 | ||||
2035 | nY += mnCharHeight; | |||
2036 | ||||
2037 | if ( pPaintArea && ( nY >= pPaintArea->Bottom() ) ) | |||
2038 | break; // no more visible actions | |||
2039 | } | |||
2040 | } | |||
2041 | else | |||
2042 | { | |||
2043 | nY += nParaHeight; | |||
2044 | } | |||
2045 | ||||
2046 | if ( pPaintArea && ( nY > pPaintArea->Bottom() ) ) | |||
2047 | break; // no more visible actions | |||
2048 | } | |||
2049 | } | |||
2050 | ||||
2051 | bool TextEngine::CreateLines( sal_uInt32 nPara ) | |||
2052 | { | |||
2053 | // bool: changing Height of Paragraph Yes/No - true/false | |||
2054 | ||||
2055 | TextNode* pNode = mpDoc->GetNodes()[ nPara ].get(); | |||
2056 | TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); | |||
2057 | SAL_WARN_IF( !pTEParaPortion->IsInvalid(), "vcl", "CreateLines: Portion not invalid!" )do { if (true && (!pTEParaPortion->IsInvalid())) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl" )) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "CreateLines: Portion not invalid!") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "2057" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "CreateLines: Portion not invalid!") , 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "CreateLines: Portion not invalid!"; ::sal::detail:: log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "2057" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "CreateLines: Portion not invalid!") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "2057" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "CreateLines: Portion not invalid!") , 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "CreateLines: Portion not invalid!"; ::sal::detail:: log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "2057" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
2058 | ||||
2059 | const auto nOldLineCount = pTEParaPortion->GetLines().size(); | |||
2060 | ||||
2061 | // fast special case for empty paragraphs | |||
2062 | if ( pTEParaPortion->GetNode()->GetText().isEmpty() ) | |||
2063 | { | |||
2064 | if ( !pTEParaPortion->GetTextPortions().empty() ) | |||
2065 | pTEParaPortion->GetTextPortions().Reset(); | |||
2066 | pTEParaPortion->GetLines().clear(); | |||
2067 | CreateAndInsertEmptyLine( nPara ); | |||
2068 | pTEParaPortion->SetValid(); | |||
2069 | return nOldLineCount != pTEParaPortion->GetLines().size(); | |||
2070 | } | |||
2071 | ||||
2072 | // initialization | |||
2073 | if ( pTEParaPortion->GetLines().empty() ) | |||
2074 | { | |||
2075 | pTEParaPortion->GetLines().emplace_back( ); | |||
2076 | } | |||
2077 | ||||
2078 | const sal_Int32 nInvalidDiff = pTEParaPortion->GetInvalidDiff(); | |||
2079 | const sal_Int32 nInvalidStart = pTEParaPortion->GetInvalidPosStart(); | |||
2080 | const sal_Int32 nInvalidEnd = nInvalidStart + std::abs( nInvalidDiff ); | |||
2081 | bool bQuickFormat = false; | |||
2082 | ||||
2083 | if ( pTEParaPortion->GetWritingDirectionInfos().empty() ) | |||
2084 | ImpInitWritingDirections( nPara ); | |||
2085 | ||||
2086 | if ( pTEParaPortion->GetWritingDirectionInfos().size() == 1 && pTEParaPortion->IsSimpleInvalid() ) | |||
2087 | { | |||
2088 | bQuickFormat = nInvalidDiff != 0; | |||
2089 | if ( nInvalidDiff < 0 ) | |||
2090 | { | |||
2091 | // check if deleting across Portion border | |||
2092 | sal_Int32 nPos = 0; | |||
2093 | for ( const auto & pTP : pTEParaPortion->GetTextPortions() ) | |||
2094 | { | |||
2095 | // there must be no Start/End in the deleted region | |||
2096 | nPos += pTP->GetLen(); | |||
2097 | if ( nPos > nInvalidStart && nPos < nInvalidEnd ) | |||
2098 | { | |||
2099 | bQuickFormat = false; | |||
2100 | break; | |||
2101 | } | |||
2102 | } | |||
2103 | } | |||
2104 | } | |||
2105 | ||||
2106 | if ( bQuickFormat ) | |||
2107 | RecalcTextPortion( nPara, nInvalidStart, nInvalidDiff ); | |||
2108 | else | |||
2109 | CreateTextPortions( nPara, nInvalidStart ); | |||
2110 | ||||
2111 | // search for line with InvalidPos; start a line prior | |||
2112 | // flag lines => do not remove! | |||
2113 | ||||
2114 | sal_uInt16 nLine = pTEParaPortion->GetLines().size()-1; | |||
2115 | for ( sal_uInt16 nL = 0; nL <= nLine; nL++ ) | |||
2116 | { | |||
2117 | TextLine& rLine = pTEParaPortion->GetLines()[ nL ]; | |||
2118 | if ( rLine.GetEnd() > nInvalidStart ) | |||
2119 | { | |||
2120 | nLine = nL; | |||
2121 | break; | |||
2122 | } | |||
2123 | rLine.SetValid(); | |||
2124 | } | |||
2125 | // start a line before... | |||
2126 | // if typing at the end, the line before cannot change | |||
2127 | if ( nLine && ( !pTEParaPortion->IsSimpleInvalid() || ( nInvalidEnd < pNode->GetText().getLength() ) || ( nInvalidDiff <= 0 ) ) ) | |||
2128 | nLine--; | |||
2129 | ||||
2130 | TextLine* pLine = &( pTEParaPortion->GetLines()[ nLine ] ); | |||
2131 | ||||
2132 | // format all lines starting here | |||
2133 | std::size_t nDelFromLine = TETextPortionList::npos; | |||
2134 | ||||
2135 | sal_Int32 nIndex = pLine->GetStart(); | |||
2136 | TextLine aSaveLine( *pLine ); | |||
2137 | ||||
2138 | while ( nIndex < pNode->GetText().getLength() ) | |||
2139 | { | |||
2140 | bool bEOL = false; | |||
2141 | sal_Int32 nPortionStart = 0; | |||
2142 | sal_Int32 nPortionEnd = 0; | |||
2143 | ||||
2144 | sal_Int32 nTmpPos = nIndex; | |||
2145 | std::size_t nTmpPortion = pLine->GetStartPortion(); | |||
2146 | long nTmpWidth = mpDoc->GetLeftMargin(); | |||
2147 | // do not subtract margin; it is included in TmpWidth | |||
2148 | long nXWidth = std::max( | |||
2149 | mnMaxTextWidth ? mnMaxTextWidth : std::numeric_limits<long>::max(), nTmpWidth); | |||
2150 | ||||
2151 | // search for Portion that does not fit anymore into line | |||
2152 | TETextPortion* pPortion = nullptr; | |||
2153 | bool bBrokenLine = false; | |||
2154 | ||||
2155 | while ( ( nTmpWidth <= nXWidth ) && !bEOL && ( nTmpPortion < pTEParaPortion->GetTextPortions().size() ) ) | |||
2156 | { | |||
2157 | nPortionStart = nTmpPos; | |||
2158 | pPortion = pTEParaPortion->GetTextPortions()[ nTmpPortion ]; | |||
2159 | SAL_WARN_IF( !pPortion->GetLen(), "vcl", "CreateLines: Empty Portion!" )do { if (true && (!pPortion->GetLen())) { switch ( sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "CreateLines: Empty Portion!") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "2159" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "CreateLines: Empty Portion!"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "CreateLines: Empty Portion!"; ::sal::detail::log( ( ::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "2159" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "CreateLines: Empty Portion!") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "2159" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "CreateLines: Empty Portion!"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "CreateLines: Empty Portion!"; ::sal::detail::log( ( ::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "2159" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
2160 | if ( pNode->GetText()[ nTmpPos ] == '\t' ) | |||
2161 | { | |||
2162 | long nCurPos = nTmpWidth-mpDoc->GetLeftMargin(); | |||
2163 | nTmpWidth = ((nCurPos/mnDefTab)+1)*mnDefTab+mpDoc->GetLeftMargin(); | |||
2164 | pPortion->GetWidth() = nTmpWidth - nCurPos - mpDoc->GetLeftMargin(); | |||
2165 | // infinite loop, if this is the first token of the line and nTmpWidth > aPaperSize.Width !!! | |||
2166 | if ( ( nTmpWidth >= nXWidth ) && ( nTmpPortion == pLine->GetStartPortion() ) ) | |||
2167 | { | |||
2168 | // adjust Tab | |||
2169 | pPortion->GetWidth() = nXWidth-1; | |||
2170 | nTmpWidth = pPortion->GetWidth(); | |||
2171 | bEOL = true; | |||
2172 | bBrokenLine = true; | |||
2173 | } | |||
2174 | pPortion->GetKind() = PORTIONKIND_TAB1; | |||
2175 | } | |||
2176 | else | |||
2177 | { | |||
2178 | ||||
2179 | pPortion->GetWidth() = CalcTextWidth( nPara, nTmpPos, pPortion->GetLen() ); | |||
2180 | nTmpWidth += pPortion->GetWidth(); | |||
2181 | ||||
2182 | pPortion->SetRightToLeft( ImpGetRightToLeft( nPara, nTmpPos+1 ) ); | |||
2183 | pPortion->GetKind() = PORTIONKIND_TEXT0; | |||
2184 | } | |||
2185 | ||||
2186 | nTmpPos += pPortion->GetLen(); | |||
2187 | nPortionEnd = nTmpPos; | |||
2188 | nTmpPortion++; | |||
2189 | } | |||
2190 | ||||
2191 | // this was perhaps one Portion too far | |||
2192 | bool bFixedEnd = false; | |||
2193 | if ( nTmpWidth > nXWidth ) | |||
2194 | { | |||
2195 | nPortionEnd = nTmpPos; | |||
2196 | nTmpPos -= pPortion->GetLen(); | |||
2197 | nPortionStart = nTmpPos; | |||
2198 | nTmpPortion--; | |||
2199 | bEOL = false; | |||
2200 | ||||
2201 | nTmpWidth -= pPortion->GetWidth(); | |||
2202 | if ( pPortion->GetKind() == PORTIONKIND_TAB1 ) | |||
2203 | { | |||
2204 | bEOL = true; | |||
2205 | bFixedEnd = true; | |||
2206 | } | |||
2207 | } | |||
2208 | else | |||
2209 | { | |||
2210 | bEOL = true; | |||
2211 | pLine->SetEnd( nPortionEnd ); | |||
2212 | OSL_ENSURE(pTEParaPortion->GetTextPortions().size(),do { if (true && (!(pTEParaPortion->GetTextPortions ().size()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "2213" ": "), "%s", "CreateLines: No TextPortions?"); } } while (false) | |||
2213 | "CreateLines: No TextPortions?")do { if (true && (!(pTEParaPortion->GetTextPortions ().size()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "2213" ": "), "%s", "CreateLines: No TextPortions?"); } } while (false); | |||
2214 | pLine->SetEndPortion( pTEParaPortion->GetTextPortions().size() - 1 ); | |||
2215 | } | |||
2216 | ||||
2217 | if ( bFixedEnd ) | |||
2218 | { | |||
2219 | pLine->SetEnd( nPortionStart ); | |||
2220 | pLine->SetEndPortion( nTmpPortion-1 ); | |||
2221 | } | |||
2222 | else if ( bBrokenLine ) | |||
2223 | { | |||
2224 | pLine->SetEnd( nPortionStart+1 ); | |||
2225 | pLine->SetEndPortion( nTmpPortion-1 ); | |||
2226 | } | |||
2227 | else if ( !bEOL ) | |||
2228 | { | |||
2229 | SAL_WARN_IF( (nPortionEnd-nPortionStart) != pPortion->GetLen(), "vcl", "CreateLines: There is a Portion after all?!" )do { if (true && ((nPortionEnd-nPortionStart) != pPortion ->GetLen())) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "CreateLines: There is a Portion after all?!") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "2229" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "CreateLines: There is a Portion after all?!" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "CreateLines: There is a Portion after all?!"; ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "2229" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "CreateLines: There is a Portion after all?!") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "2229" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "CreateLines: There is a Portion after all?!" ), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "CreateLines: There is a Portion after all?!"; ::sal ::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "2229" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
2230 | const long nRemainingWidth = mnMaxTextWidth - nTmpWidth; | |||
2231 | ImpBreakLine( nPara, pLine, nPortionStart, nRemainingWidth ); | |||
2232 | } | |||
2233 | ||||
2234 | if ( ( ImpGetAlign() == TxtAlign::Center ) || ( ImpGetAlign() == TxtAlign::Right ) ) | |||
2235 | { | |||
2236 | // adjust | |||
2237 | long nTextWidth = 0; | |||
2238 | for ( std::size_t nTP = pLine->GetStartPortion(); nTP <= pLine->GetEndPortion(); nTP++ ) | |||
2239 | { | |||
2240 | TETextPortion* pTextPortion = pTEParaPortion->GetTextPortions()[ nTP ]; | |||
2241 | nTextWidth += pTextPortion->GetWidth(); | |||
2242 | } | |||
2243 | const long nSpace = mnMaxTextWidth - nTextWidth; | |||
2244 | if ( nSpace > 0 ) | |||
2245 | { | |||
2246 | if ( ImpGetAlign() == TxtAlign::Center ) | |||
2247 | pLine->SetStartX( static_cast<sal_uInt16>(nSpace / 2) ); | |||
2248 | else // TxtAlign::Right | |||
2249 | pLine->SetStartX( static_cast<sal_uInt16>(nSpace) ); | |||
2250 | } | |||
2251 | } | |||
2252 | else | |||
2253 | { | |||
2254 | pLine->SetStartX( mpDoc->GetLeftMargin() ); | |||
2255 | } | |||
2256 | ||||
2257 | // check if the line has to be printed again | |||
2258 | pLine->SetInvalid(); | |||
2259 | ||||
2260 | if ( pTEParaPortion->IsSimpleInvalid() ) | |||
2261 | { | |||
2262 | // Change due to simple TextChange... | |||
2263 | // Do not abort formatting, as Portions might have to be split! | |||
2264 | // Once it is ok to abort, then validate the following lines! | |||
2265 | // But mark as valid, thus reduce printing... | |||
2266 | if ( pLine->GetEnd() < nInvalidStart ) | |||
2267 | { | |||
2268 | if ( *pLine == aSaveLine ) | |||
2269 | { | |||
2270 | pLine->SetValid(); | |||
2271 | } | |||
2272 | } | |||
2273 | else | |||
2274 | { | |||
2275 | const sal_Int32 nStart = pLine->GetStart(); | |||
2276 | const sal_Int32 nEnd = pLine->GetEnd(); | |||
2277 | ||||
2278 | if ( nStart > nInvalidEnd ) | |||
2279 | { | |||
2280 | if ( ( ( nStart-nInvalidDiff ) == aSaveLine.GetStart() ) && | |||
2281 | ( ( nEnd-nInvalidDiff ) == aSaveLine.GetEnd() ) ) | |||
2282 | { | |||
2283 | pLine->SetValid(); | |||
2284 | if ( bQuickFormat ) | |||
2285 | { | |||
2286 | pTEParaPortion->CorrectValuesBehindLastFormattedLine( nLine ); | |||
2287 | break; | |||
2288 | } | |||
2289 | } | |||
2290 | } | |||
2291 | else if ( bQuickFormat && ( nEnd > nInvalidEnd) ) | |||
2292 | { | |||
2293 | // If the invalid line ends such that the next line starts | |||
2294 | // at the 'same' position as before (no change in line breaks), | |||
2295 | // the text width does not have to be recalculated. | |||
2296 | if ( nEnd == ( aSaveLine.GetEnd() + nInvalidDiff ) ) | |||
2297 | { | |||
2298 | pTEParaPortion->CorrectValuesBehindLastFormattedLine( nLine ); | |||
2299 | break; | |||
2300 | } | |||
2301 | } | |||
2302 | } | |||
2303 | } | |||
2304 | ||||
2305 | nIndex = pLine->GetEnd(); // next line Start = previous line End | |||
2306 | // because nEnd is past the last char! | |||
2307 | ||||
2308 | const std::size_t nEndPortion = pLine->GetEndPortion(); | |||
2309 | ||||
2310 | // next line or new line | |||
2311 | pLine = nullptr; | |||
2312 | if ( nLine < pTEParaPortion->GetLines().size()-1 ) | |||
2313 | pLine = &( pTEParaPortion->GetLines()[ ++nLine ] ); | |||
2314 | if ( pLine && ( nIndex >= pNode->GetText().getLength() ) ) | |||
2315 | { | |||
2316 | nDelFromLine = nLine; | |||
2317 | break; | |||
2318 | } | |||
2319 | if ( !pLine ) | |||
2320 | { | |||
2321 | if ( nIndex < pNode->GetText().getLength() ) | |||
2322 | { | |||
2323 | ++nLine; | |||
2324 | pTEParaPortion->GetLines().insert( pTEParaPortion->GetLines().begin() + nLine, TextLine() ); | |||
2325 | pLine = &pTEParaPortion->GetLines()[nLine]; | |||
2326 | } | |||
2327 | else | |||
2328 | { | |||
2329 | break; | |||
2330 | } | |||
2331 | } | |||
2332 | aSaveLine = *pLine; | |||
2333 | pLine->SetStart( nIndex ); | |||
2334 | pLine->SetEnd( nIndex ); | |||
2335 | pLine->SetStartPortion( nEndPortion+1 ); | |||
2336 | pLine->SetEndPortion( nEndPortion+1 ); | |||
2337 | ||||
2338 | } // while ( Index < Len ) | |||
2339 | ||||
2340 | if (nDelFromLine != TETextPortionList::npos) | |||
2341 | { | |||
2342 | pTEParaPortion->GetLines().erase( pTEParaPortion->GetLines().begin() + nDelFromLine, | |||
2343 | pTEParaPortion->GetLines().end() ); | |||
2344 | } | |||
2345 | ||||
2346 | SAL_WARN_IF( pTEParaPortion->GetLines().empty(), "vcl", "CreateLines: No Line!" )do { if (true && (pTEParaPortion->GetLines().empty ())) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN , "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "CreateLines: No Line!") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "2346" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "CreateLines: No Line!"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "CreateLines: No Line!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "2346" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "CreateLines: No Line!") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "2346" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "CreateLines: No Line!"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "CreateLines: No Line!"; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN ), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "2346" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
2347 | ||||
2348 | pTEParaPortion->SetValid(); | |||
2349 | ||||
2350 | return nOldLineCount != pTEParaPortion->GetLines().size(); | |||
2351 | } | |||
2352 | ||||
2353 | OUString TextEngine::GetWord( const TextPaM& rCursorPos, TextPaM* pStartOfWord, TextPaM* pEndOfWord ) | |||
2354 | { | |||
2355 | OUString aWord; | |||
2356 | if ( rCursorPos.GetPara() < mpDoc->GetNodes().size() ) | |||
2357 | { | |||
2358 | TextSelection aSel( rCursorPos ); | |||
2359 | TextNode* pNode = mpDoc->GetNodes()[ rCursorPos.GetPara() ].get(); | |||
2360 | uno::Reference < i18n::XBreakIterator > xBI = GetBreakIterator(); | |||
2361 | i18n::Boundary aBoundary = xBI->getWordBoundary( pNode->GetText(), rCursorPos.GetIndex(), GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, true ); | |||
2362 | // tdf#57879 - expand selection to the left to include connector punctuations and search for additional word boundaries | |||
2363 | if (aBoundary.startPos > 0 && aBoundary.startPos < pNode->GetText().getLength() && u_charTypeu_charType_67(pNode->GetText()[aBoundary.startPos]) == U_CONNECTOR_PUNCTUATION) | |||
2364 | { | |||
2365 | aBoundary.startPos = xBI->getWordBoundary(pNode->GetText(), aBoundary.startPos - 1, | |||
2366 | GetLocale(), css::i18n::WordType::ANYWORD_IGNOREWHITESPACES, true).startPos; | |||
2367 | } | |||
2368 | while (aBoundary.startPos > 0 && u_charTypeu_charType_67(pNode->GetText()[aBoundary.startPos - 1]) == U_CONNECTOR_PUNCTUATION) | |||
2369 | { | |||
2370 | aBoundary.startPos = std::min(aBoundary.startPos, | |||
2371 | xBI->getWordBoundary( pNode->GetText(), aBoundary.startPos - 2, | |||
2372 | GetLocale(), css::i18n::WordType::ANYWORD_IGNOREWHITESPACES, true).startPos); | |||
2373 | } | |||
2374 | // tdf#57879 - expand selection to the right to include connector punctuations and search for additional word boundaries | |||
2375 | if (aBoundary.endPos < pNode->GetText().getLength() && u_charTypeu_charType_67(pNode->GetText()[aBoundary.endPos - 1]) == U_CONNECTOR_PUNCTUATION) | |||
2376 | { | |||
2377 | aBoundary.endPos = xBI->getWordBoundary(pNode->GetText(), aBoundary.endPos, | |||
2378 | GetLocale(), css::i18n::WordType::ANYWORD_IGNOREWHITESPACES, true).endPos; | |||
2379 | } | |||
2380 | while (aBoundary.endPos < pNode->GetText().getLength() && u_charTypeu_charType_67(pNode->GetText()[aBoundary.endPos]) == U_CONNECTOR_PUNCTUATION) | |||
2381 | { | |||
2382 | aBoundary.endPos = xBI->getWordBoundary(pNode->GetText(), aBoundary.endPos + 1, | |||
2383 | GetLocale(), css::i18n::WordType::ANYWORD_IGNOREWHITESPACES, true).endPos; | |||
2384 | } | |||
2385 | aSel.GetStart().GetIndex() = aBoundary.startPos; | |||
2386 | aSel.GetEnd().GetIndex() = aBoundary.endPos; | |||
2387 | aWord = pNode->GetText().copy( aSel.GetStart().GetIndex(), aSel.GetEnd().GetIndex() - aSel.GetStart().GetIndex() ); | |||
2388 | if ( pStartOfWord ) | |||
2389 | *pStartOfWord = aSel.GetStart(); | |||
2390 | if (pEndOfWord) | |||
2391 | *pEndOfWord = aSel.GetEnd(); | |||
2392 | } | |||
2393 | return aWord; | |||
2394 | } | |||
2395 | ||||
2396 | bool TextEngine::Read( SvStream& rInput, const TextSelection* pSel ) | |||
2397 | { | |||
2398 | const bool bUpdate = GetUpdateMode(); | |||
2399 | SetUpdateMode( false ); | |||
2400 | ||||
2401 | UndoActionStart(); | |||
2402 | TextSelection aSel; | |||
2403 | if ( pSel ) | |||
2404 | aSel = *pSel; | |||
2405 | else | |||
2406 | { | |||
2407 | const sal_uInt32 nParas = static_cast<sal_uInt32>(mpDoc->GetNodes().size()); | |||
2408 | TextNode* pNode = mpDoc->GetNodes()[ nParas - 1 ].get(); | |||
2409 | aSel = TextPaM( nParas-1 , pNode->GetText().getLength() ); | |||
2410 | } | |||
2411 | ||||
2412 | if ( aSel.HasRange() ) | |||
2413 | aSel = ImpDeleteText( aSel ); | |||
2414 | ||||
2415 | OString aLine; | |||
2416 | bool bDone = rInput.ReadLine( aLine ); | |||
2417 | OUString aTmpStr(OStringToOUString(aLine, rInput.GetStreamCharSet())); | |||
2418 | while ( bDone ) | |||
2419 | { | |||
2420 | aSel = ImpInsertText( aSel, aTmpStr ); | |||
2421 | bDone = rInput.ReadLine( aLine ); | |||
2422 | aTmpStr = OStringToOUString(aLine, rInput.GetStreamCharSet()); | |||
2423 | if ( bDone ) | |||
2424 | aSel = ImpInsertParaBreak( aSel.GetEnd() ); | |||
2425 | } | |||
2426 | ||||
2427 | UndoActionEnd(); | |||
2428 | ||||
2429 | const TextSelection aNewSel( aSel.GetEnd(), aSel.GetEnd() ); | |||
2430 | ||||
2431 | // so that FormatAndUpdate does not access the invalid selection | |||
2432 | if ( GetActiveView() ) | |||
2433 | GetActiveView()->ImpSetSelection( aNewSel ); | |||
2434 | ||||
2435 | SetUpdateMode( bUpdate ); | |||
2436 | FormatAndUpdate( GetActiveView() ); | |||
2437 | ||||
2438 | return rInput.GetError() == ERRCODE_NONEErrCode(0); | |||
2439 | } | |||
2440 | ||||
2441 | void TextEngine::Write( SvStream& rOutput ) | |||
2442 | { | |||
2443 | TextSelection aSel; | |||
2444 | const sal_uInt32 nParas = static_cast<sal_uInt32>(mpDoc->GetNodes().size()); | |||
2445 | TextNode* pSelNode = mpDoc->GetNodes()[ nParas - 1 ].get(); | |||
2446 | aSel.GetStart() = TextPaM( 0, 0 ); | |||
2447 | aSel.GetEnd() = TextPaM( nParas-1, pSelNode->GetText().getLength() ); | |||
2448 | ||||
2449 | for ( sal_uInt32 nPara = aSel.GetStart().GetPara(); nPara <= aSel.GetEnd().GetPara(); ++nPara ) | |||
2450 | { | |||
2451 | TextNode* pNode = mpDoc->GetNodes()[ nPara ].get(); | |||
2452 | ||||
2453 | const sal_Int32 nStartPos = nPara == aSel.GetStart().GetPara() | |||
2454 | ? aSel.GetStart().GetIndex() : 0; | |||
2455 | const sal_Int32 nEndPos = nPara == aSel.GetEnd().GetPara() | |||
2456 | ? aSel.GetEnd().GetIndex() : pNode->GetText().getLength(); | |||
2457 | ||||
2458 | const OUString aText = pNode->GetText().copy( nStartPos, nEndPos-nStartPos ); | |||
2459 | rOutput.WriteLine(OUStringToOString(aText, rOutput.GetStreamCharSet())); | |||
2460 | } | |||
2461 | } | |||
2462 | ||||
2463 | void TextEngine::RemoveAttribs( sal_uInt32 nPara ) | |||
2464 | { | |||
2465 | if ( nPara >= mpDoc->GetNodes().size() ) | |||
2466 | return; | |||
2467 | ||||
2468 | TextNode* pNode = mpDoc->GetNodes()[ nPara ].get(); | |||
2469 | if ( pNode->GetCharAttribs().Count() ) | |||
2470 | { | |||
2471 | pNode->GetCharAttribs().Clear(); | |||
2472 | ||||
2473 | TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); | |||
2474 | pTEParaPortion->MarkSelectionInvalid( 0 ); | |||
2475 | ||||
2476 | mbFormatted = false; | |||
2477 | ||||
2478 | IdleFormatAndUpdate( nullptr, 0xFFFF ); | |||
2479 | } | |||
2480 | } | |||
2481 | ||||
2482 | void TextEngine::SetAttrib( const TextAttrib& rAttr, sal_uInt32 nPara, sal_Int32 nStart, sal_Int32 nEnd ) | |||
2483 | { | |||
2484 | ||||
2485 | // For now do not check if Attributes overlap! | |||
2486 | // This function is for TextEditors that want to _quickly_ generate the Syntax-Highlight | |||
2487 | ||||
2488 | // As TextEngine is currently intended only for TextEditors, there is no Undo for Attributes! | |||
2489 | ||||
2490 | if ( nPara >= mpDoc->GetNodes().size() ) | |||
2491 | return; | |||
2492 | ||||
2493 | TextNode* pNode = mpDoc->GetNodes()[ nPara ].get(); | |||
2494 | TEParaPortion* pTEParaPortion = mpTEParaPortions->GetObject( nPara ); | |||
2495 | ||||
2496 | const sal_Int32 nMax = pNode->GetText().getLength(); | |||
2497 | if ( nStart > nMax ) | |||
2498 | nStart = nMax; | |||
2499 | if ( nEnd > nMax ) | |||
2500 | nEnd = nMax; | |||
2501 | ||||
2502 | pNode->GetCharAttribs().InsertAttrib( std::make_unique<TextCharAttrib>( rAttr, nStart, nEnd ) ); | |||
2503 | pTEParaPortion->MarkSelectionInvalid( nStart ); | |||
2504 | ||||
2505 | mbFormatted = false; | |||
2506 | IdleFormatAndUpdate( nullptr, 0xFFFF ); | |||
2507 | } | |||
2508 | ||||
2509 | void TextEngine::SetTextAlign( TxtAlign eAlign ) | |||
2510 | { | |||
2511 | if ( eAlign != meAlign ) | |||
2512 | { | |||
2513 | meAlign = eAlign; | |||
2514 | FormatFullDoc(); | |||
2515 | UpdateViews(); | |||
2516 | } | |||
2517 | } | |||
2518 | ||||
2519 | void TextEngine::ValidateSelection( TextSelection& rSel ) const | |||
2520 | { | |||
2521 | ValidatePaM( rSel.GetStart() ); | |||
2522 | ValidatePaM( rSel.GetEnd() ); | |||
2523 | } | |||
2524 | ||||
2525 | void TextEngine::ValidatePaM( TextPaM& rPaM ) const | |||
2526 | { | |||
2527 | const sal_uInt32 nParas = static_cast<sal_uInt32>(mpDoc->GetNodes().size()); | |||
2528 | if ( rPaM.GetPara() >= nParas ) | |||
2529 | { | |||
2530 | rPaM.GetPara() = nParas ? nParas-1 : 0; | |||
2531 | rPaM.GetIndex() = TEXT_INDEX_ALL((sal_Int32) 0x7FFFFFFF); | |||
2532 | } | |||
2533 | ||||
2534 | const sal_Int32 nMaxIndex = GetTextLen( rPaM.GetPara() ); | |||
2535 | if ( rPaM.GetIndex() > nMaxIndex ) | |||
2536 | rPaM.GetIndex() = nMaxIndex; | |||
2537 | } | |||
2538 | ||||
2539 | // adjust State & Selection | |||
2540 | ||||
2541 | void TextEngine::ImpParagraphInserted( sal_uInt32 nPara ) | |||
2542 | { | |||
2543 | // No adjustment needed for the active View; | |||
2544 | // but for all passive Views the Selection needs adjusting. | |||
2545 | if ( mpViews->size() > 1 ) | |||
2546 | { | |||
2547 | for ( auto nView = mpViews->size(); nView; ) | |||
2548 | { | |||
2549 | TextView* pView = (*mpViews)[ --nView ]; | |||
2550 | if ( pView != GetActiveView() ) | |||
2551 | { | |||
2552 | for ( int n = 0; n <= 1; n++ ) | |||
2553 | { | |||
2554 | TextPaM& rPaM = n ? pView->GetSelection().GetStart(): pView->GetSelection().GetEnd(); | |||
2555 | if ( rPaM.GetPara() >= nPara ) | |||
2556 | rPaM.GetPara()++; | |||
2557 | } | |||
2558 | } | |||
2559 | } | |||
2560 | } | |||
2561 | Broadcast( TextHint( SfxHintId::TextParaInserted, nPara ) ); | |||
2562 | } | |||
2563 | ||||
2564 | void TextEngine::ImpParagraphRemoved( sal_uInt32 nPara ) | |||
2565 | { | |||
2566 | if ( mpViews->size() > 1 ) | |||
2567 | { | |||
2568 | for ( auto nView = mpViews->size(); nView; ) | |||
2569 | { | |||
2570 | TextView* pView = (*mpViews)[ --nView ]; | |||
2571 | if ( pView != GetActiveView() ) | |||
2572 | { | |||
2573 | const sal_uInt32 nParas = static_cast<sal_uInt32>(mpDoc->GetNodes().size()); | |||
2574 | for ( int n = 0; n <= 1; n++ ) | |||
2575 | { | |||
2576 | TextPaM& rPaM = n ? pView->GetSelection().GetStart(): pView->GetSelection().GetEnd(); | |||
2577 | if ( rPaM.GetPara() > nPara ) | |||
2578 | rPaM.GetPara()--; | |||
2579 | else if ( rPaM.GetPara() == nPara ) | |||
2580 | { | |||
2581 | rPaM.GetIndex() = 0; | |||
2582 | if ( rPaM.GetPara() >= nParas ) | |||
2583 | rPaM.GetPara()--; | |||
2584 | } | |||
2585 | } | |||
2586 | } | |||
2587 | } | |||
2588 | } | |||
2589 | Broadcast( TextHint( SfxHintId::TextParaRemoved, nPara ) ); | |||
2590 | } | |||
2591 | ||||
2592 | void TextEngine::ImpCharsRemoved( sal_uInt32 nPara, sal_Int32 nPos, sal_Int32 nChars ) | |||
2593 | { | |||
2594 | if ( mpViews->size() > 1 ) | |||
2595 | { | |||
2596 | for ( auto nView = mpViews->size(); nView; ) | |||
2597 | { | |||
2598 | TextView* pView = (*mpViews)[ --nView ]; | |||
2599 | if ( pView != GetActiveView() ) | |||
2600 | { | |||
2601 | const sal_Int32 nEnd = nPos + nChars; | |||
2602 | for ( int n = 0; n <= 1; n++ ) | |||
2603 | { | |||
2604 | TextPaM& rPaM = n ? pView->GetSelection().GetStart(): pView->GetSelection().GetEnd(); | |||
2605 | if ( rPaM.GetPara() == nPara ) | |||
2606 | { | |||
2607 | if ( rPaM.GetIndex() > nEnd ) | |||
2608 | rPaM.GetIndex() = rPaM.GetIndex() - nChars; | |||
2609 | else if ( rPaM.GetIndex() > nPos ) | |||
2610 | rPaM.GetIndex() = nPos; | |||
2611 | } | |||
2612 | } | |||
2613 | } | |||
2614 | } | |||
2615 | } | |||
2616 | Broadcast( TextHint( SfxHintId::TextParaContentChanged, nPara ) ); | |||
2617 | } | |||
2618 | ||||
2619 | void TextEngine::ImpCharsInserted( sal_uInt32 nPara, sal_Int32 nPos, sal_Int32 nChars ) | |||
2620 | { | |||
2621 | if ( mpViews->size() > 1 ) | |||
2622 | { | |||
2623 | for ( auto nView = mpViews->size(); nView; ) | |||
2624 | { | |||
2625 | TextView* pView = (*mpViews)[ --nView ]; | |||
2626 | if ( pView != GetActiveView() ) | |||
2627 | { | |||
2628 | for ( int n = 0; n <= 1; n++ ) | |||
2629 | { | |||
2630 | TextPaM& rPaM = n ? pView->GetSelection().GetStart(): pView->GetSelection().GetEnd(); | |||
2631 | if ( rPaM.GetPara() == nPara ) | |||
2632 | { | |||
2633 | if ( rPaM.GetIndex() >= nPos ) | |||
2634 | rPaM.GetIndex() += nChars; | |||
2635 | } | |||
2636 | } | |||
2637 | } | |||
2638 | } | |||
2639 | } | |||
2640 | Broadcast( TextHint( SfxHintId::TextParaContentChanged, nPara ) ); | |||
2641 | } | |||
2642 | ||||
2643 | void TextEngine::Draw( OutputDevice* pDev, const Point& rPos ) | |||
2644 | { | |||
2645 | ImpPaint( pDev, rPos, nullptr ); | |||
2646 | } | |||
2647 | ||||
2648 | void TextEngine::SetLeftMargin( sal_uInt16 n ) | |||
2649 | { | |||
2650 | mpDoc->SetLeftMargin( n ); | |||
2651 | } | |||
2652 | ||||
2653 | uno::Reference< i18n::XBreakIterator > const & TextEngine::GetBreakIterator() | |||
2654 | { | |||
2655 | if ( !mxBreakIterator.is() ) | |||
2656 | mxBreakIterator = vcl::unohelper::CreateBreakIterator(); | |||
2657 | SAL_WARN_IF( !mxBreakIterator.is(), "vcl", "BreakIterator: Failed to create!" )do { if (true && (!mxBreakIterator.is())) { switch (sal_detail_log_report (::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) { case SAL_DETAIL_LOG_ACTION_IGNORE : break; case SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail ::getResult( ::sal::detail::StreamStart() << "BreakIterator: Failed to create!" ) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl" ), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "2657" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "BreakIterator: Failed to create!"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "BreakIterator: Failed to create!"; ::sal::detail:: log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "2657" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL : if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart () << "BreakIterator: Failed to create!") == 1) { ::sal_detail_log ( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "2657" ": "), ::sal::detail::unwrapStream( ::sal::detail ::StreamStart() << "BreakIterator: Failed to create!"), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream << "BreakIterator: Failed to create!"; ::sal::detail:: log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/edit/texteng.cxx" ":" "2657" ": "), sal_detail_stream, 0); }; std::abort(); break ; } } } while (false); | |||
2658 | return mxBreakIterator; | |||
2659 | } | |||
2660 | ||||
2661 | void TextEngine::SetLocale( const css::lang::Locale& rLocale ) | |||
2662 | { | |||
2663 | maLocale = rLocale; | |||
2664 | mpLocaleDataWrapper.reset(); | |||
2665 | } | |||
2666 | ||||
2667 | css::lang::Locale const & TextEngine::GetLocale() | |||
2668 | { | |||
2669 | if ( maLocale.Language.isEmpty() ) | |||
2670 | { | |||
2671 | maLocale = Application::GetSettings().GetUILanguageTag().getLocale(); // TODO: why UI locale? | |||
2672 | } | |||
2673 | return maLocale; | |||
2674 | } | |||
2675 | ||||
2676 | LocaleDataWrapper* TextEngine::ImpGetLocaleDataWrapper() | |||
2677 | { | |||
2678 | if ( !mpLocaleDataWrapper ) | |||
2679 | mpLocaleDataWrapper.reset( new LocaleDataWrapper( LanguageTag( GetLocale()) ) ); | |||
2680 | ||||
2681 | return mpLocaleDataWrapper.get(); | |||
2682 | } | |||
2683 | ||||
2684 | void TextEngine::SetRightToLeft( bool bR2L ) | |||
2685 | { | |||
2686 | if ( mbRightToLeft != bR2L ) | |||
2687 | { | |||
2688 | mbRightToLeft = bR2L; | |||
2689 | meAlign = bR2L ? TxtAlign::Right : TxtAlign::Left; | |||
2690 | FormatFullDoc(); | |||
2691 | UpdateViews(); | |||
2692 | } | |||
2693 | } | |||
2694 | ||||
2695 | void TextEngine::ImpInitWritingDirections( sal_uInt32 nPara ) | |||
2696 | { | |||
2697 | TEParaPortion* pParaPortion = mpTEParaPortions->GetObject( nPara ); | |||
2698 | std::vector<TEWritingDirectionInfo>& rInfos = pParaPortion->GetWritingDirectionInfos(); | |||
2699 | rInfos.clear(); | |||
2700 | ||||
2701 | if ( !pParaPortion->GetNode()->GetText().isEmpty() ) | |||
2702 | { | |||
2703 | const UBiDiLevel nBidiLevel = IsRightToLeft() ? 1 /*RTL*/ : 0 /*LTR*/; | |||
2704 | OUString aText( pParaPortion->GetNode()->GetText() ); | |||
2705 | ||||
2706 | // Bidi functions from icu 2.0 | |||
2707 | ||||
2708 | UErrorCode nError = U_ZERO_ERROR; | |||
2709 | UBiDi* pBidi = ubidi_openSizedubidi_openSized_67( aText.getLength(), 0, &nError ); | |||
2710 | nError = U_ZERO_ERROR; | |||
2711 | ||||
2712 | ubidi_setParaubidi_setPara_67( pBidi, reinterpret_cast<const UChar *>(aText.getStr()), aText.getLength(), nBidiLevel, nullptr, &nError ); | |||
2713 | nError = U_ZERO_ERROR; | |||
2714 | ||||
2715 | long nCount = ubidi_countRunsubidi_countRuns_67( pBidi, &nError ); | |||
2716 | ||||
2717 | int32_t nStart = 0; | |||
2718 | int32_t nEnd; | |||
2719 | UBiDiLevel nCurrDir; | |||
2720 | ||||
2721 | for ( long nIdx = 0; nIdx < nCount; ++nIdx ) | |||
2722 | { | |||
2723 | ubidi_getLogicalRunubidi_getLogicalRun_67( pBidi, nStart, &nEnd, &nCurrDir ); | |||
2724 | // bit 0 of nCurrDir indicates direction | |||
2725 | rInfos.emplace_back( /*bLeftToRight*/ nCurrDir % 2 == 0, nStart, nEnd ); | |||
2726 | nStart = nEnd; | |||
2727 | } | |||
2728 | ||||
2729 | ubidi_closeubidi_close_67( pBidi ); | |||
2730 | } | |||
2731 | ||||
2732 | // No infos mean no CTL and default dir is L2R... | |||
2733 | if ( rInfos.empty() ) | |||
2734 | rInfos.emplace_back( 0, 0, pParaPortion->GetNode()->GetText().getLength() ); | |||
2735 | ||||
2736 | } | |||
2737 | ||||
2738 | bool TextEngine::ImpGetRightToLeft( sal_uInt32 nPara, sal_Int32 nPos ) | |||
2739 | { | |||
2740 | bool bRightToLeft = false; | |||
2741 | ||||
2742 | TextNode* pNode = mpDoc->GetNodes()[ nPara ].get(); | |||
2743 | if ( pNode && !pNode->GetText().isEmpty() ) | |||
2744 | { | |||
2745 | TEParaPortion* pParaPortion = mpTEParaPortions->GetObject( nPara ); | |||
2746 | if ( pParaPortion->GetWritingDirectionInfos().empty() ) | |||
2747 | ImpInitWritingDirections( nPara ); | |||
2748 | ||||
2749 | std::vector<TEWritingDirectionInfo>& rDirInfos = pParaPortion->GetWritingDirectionInfos(); | |||
2750 | for ( const auto& rWritingDirectionInfo : rDirInfos ) | |||
2751 | { | |||
2752 | if ( rWritingDirectionInfo.nStartPos <= nPos && rWritingDirectionInfo.nEndPos >= nPos ) | |||
2753 | { | |||
2754 | bRightToLeft = !rWritingDirectionInfo.bLeftToRight; | |||
2755 | break; | |||
2756 | } | |||
2757 | } | |||
2758 | } | |||
2759 | return bRightToLeft; | |||
2760 | } | |||
2761 | ||||
2762 | long TextEngine::ImpGetPortionXOffset( sal_uInt32 nPara, TextLine const * pLine, std::size_t nTextPortion ) | |||
2763 | { | |||
2764 | long nX = pLine->GetStartX(); | |||
2765 | ||||
2766 | TEParaPortion* pParaPortion = mpTEParaPortions->GetObject( nPara ); | |||
2767 | ||||
2768 | for ( std::size_t i = pLine->GetStartPortion(); i < nTextPortion; i++ ) | |||
2769 | { | |||
2770 | TETextPortion* pPortion = pParaPortion->GetTextPortions()[ i ]; | |||
2771 | nX += pPortion->GetWidth(); | |||
2772 | } | |||
2773 | ||||
2774 | TETextPortion* pDestPortion = pParaPortion->GetTextPortions()[ nTextPortion ]; | |||
2775 | if ( pDestPortion->GetKind() != PORTIONKIND_TAB1 ) | |||
2776 | { | |||
2777 | if ( !IsRightToLeft() && pDestPortion->IsRightToLeft() ) | |||
2778 | { | |||
2779 | // Portions behind must be added, visual before this portion | |||
2780 | std::size_t nTmpPortion = nTextPortion+1; | |||
2781 | while ( nTmpPortion <= pLine->GetEndPortion() ) | |||
2782 | { | |||
2783 | TETextPortion* pNextTextPortion = pParaPortion->GetTextPortions()[ nTmpPortion ]; | |||
2784 | if ( pNextTextPortion->IsRightToLeft() && ( pNextTextPortion->GetKind() != PORTIONKIND_TAB1 ) ) | |||
2785 | nX += pNextTextPortion->GetWidth(); | |||
2786 | else | |||
2787 | break; | |||
2788 | nTmpPortion++; | |||
2789 | } | |||
2790 | // Portions before must be removed, visual behind this portion | |||
2791 | nTmpPortion = nTextPortion; | |||
2792 | while ( nTmpPortion > pLine->GetStartPortion() ) | |||
2793 | { | |||
2794 | --nTmpPortion; | |||
2795 | TETextPortion* pPrevTextPortion = pParaPortion->GetTextPortions()[ nTmpPortion ]; | |||
2796 | if ( pPrevTextPortion->IsRightToLeft() && ( pPrevTextPortion->GetKind() != PORTIONKIND_TAB1 ) ) | |||
2797 | nX -= pPrevTextPortion->GetWidth(); | |||
2798 | else | |||
2799 | break; | |||
2800 | } | |||
2801 | } | |||
2802 | else if ( IsRightToLeft() && !pDestPortion->IsRightToLeft() ) | |||
2803 | { | |||
2804 | // Portions behind must be removed, visual behind this portion | |||
2805 | std::size_t nTmpPortion = nTextPortion+1; | |||
2806 | while ( nTmpPortion <= pLine->GetEndPortion() ) | |||
2807 | { | |||
2808 | TETextPortion* pNextTextPortion = pParaPortion->GetTextPortions()[ nTmpPortion ]; | |||
2809 | if ( !pNextTextPortion->IsRightToLeft() && ( pNextTextPortion->GetKind() != PORTIONKIND_TAB1 ) ) | |||
2810 | nX += pNextTextPortion->GetWidth(); | |||
2811 | else | |||
2812 | break; | |||
2813 | nTmpPortion++; | |||
2814 | } | |||
2815 | // Portions before must be added, visual before this portion | |||
2816 | nTmpPortion = nTextPortion; | |||
2817 | while ( nTmpPortion > pLine->GetStartPortion() ) | |||
2818 | { | |||
2819 | --nTmpPortion; | |||
2820 | TETextPortion* pPrevTextPortion = pParaPortion->GetTextPortions()[ nTmpPortion ]; | |||
2821 | if ( !pPrevTextPortion->IsRightToLeft() && ( pPrevTextPortion->GetKind() != PORTIONKIND_TAB1 ) ) | |||
2822 | nX -= pPrevTextPortion->GetWidth(); | |||
2823 | else | |||
2824 | break; | |||
2825 | } | |||
2826 | } | |||
2827 | } | |||
2828 | ||||
2829 | return nX; | |||
2830 | } | |||
2831 | ||||
2832 | void TextEngine::ImpInitLayoutMode( OutputDevice* pOutDev ) | |||
2833 | { | |||
2834 | ComplexTextLayoutFlags nLayoutMode = pOutDev->GetLayoutMode(); | |||
2835 | ||||
2836 | nLayoutMode &= ~ComplexTextLayoutFlags(ComplexTextLayoutFlags::BiDiRtl | ComplexTextLayoutFlags::BiDiStrong ); | |||
2837 | ||||
2838 | pOutDev->SetLayoutMode( nLayoutMode ); | |||
2839 | } | |||
2840 | ||||
2841 | TxtAlign TextEngine::ImpGetAlign() const | |||
2842 | { | |||
2843 | TxtAlign eAlign = meAlign; | |||
2844 | if ( IsRightToLeft() ) | |||
2845 | { | |||
2846 | if ( eAlign == TxtAlign::Left ) | |||
2847 | eAlign = TxtAlign::Right; | |||
2848 | else if ( eAlign == TxtAlign::Right ) | |||
2849 | eAlign = TxtAlign::Left; | |||
2850 | } | |||
2851 | return eAlign; | |||
2852 | } | |||
2853 | ||||
2854 | long TextEngine::ImpGetOutputOffset( sal_uInt32 nPara, TextLine* pLine, sal_Int32 nIndex, sal_Int32 nIndex2 ) | |||
2855 | { | |||
2856 | TEParaPortion* pPortion = mpTEParaPortions->GetObject( nPara ); | |||
2857 | ||||
2858 | sal_Int32 nPortionStart {0}; | |||
2859 | const std::size_t nPortion = pPortion->GetTextPortions().FindPortion( nIndex, nPortionStart, true ); | |||
2860 | ||||
2861 | TETextPortion* pTextPortion = pPortion->GetTextPortions()[ nPortion ]; | |||
2862 | ||||
2863 | long nX; | |||
2864 | ||||
2865 | if ( ( nIndex == nPortionStart ) && ( nIndex == nIndex2 ) ) | |||
2866 | { | |||
2867 | // Output of full portion, so we need portion x offset. | |||
2868 | // Use ImpGetPortionXOffset, because GetXPos may deliver left or right position from portion, depending on R2L, L2R | |||
2869 | nX = ImpGetPortionXOffset( nPara, pLine, nPortion ); | |||
2870 | if ( IsRightToLeft() ) | |||
2871 | { | |||
2872 | nX = -nX -pTextPortion->GetWidth(); | |||
2873 | } | |||
2874 | } | |||
2875 | else | |||
2876 | { | |||
2877 | nX = ImpGetXPos( nPara, pLine, nIndex, nIndex == nPortionStart ); | |||
2878 | if ( nIndex2 != nIndex ) | |||
2879 | { | |||
2880 | const long nX2 = ImpGetXPos( nPara, pLine, nIndex2 ); | |||
2881 | if ( ( !IsRightToLeft() && ( nX2 < nX ) ) || | |||
2882 | ( IsRightToLeft() && ( nX2 > nX ) ) ) | |||
2883 | { | |||
2884 | nX = nX2; | |||
2885 | } | |||
2886 | } | |||
2887 | if ( IsRightToLeft() ) | |||
2888 | { | |||
2889 | nX = -nX; | |||
2890 | } | |||
2891 | } | |||
2892 | ||||
2893 | return nX; | |||
2894 | } | |||
2895 | ||||
2896 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |