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