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