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