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