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