1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: impedit2.cxx,v $
10 * $Revision: 1.124.40.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svx.hxx"
34 #include <eeng_pch.hxx>
36 #include <svx/lspcitem.hxx>
37 #include <svx/flditem.hxx>
38 #include <impedit.hxx>
39 #include <svx/editeng.hxx>
40 #include <svx/editview.hxx>
41 #include <editdbg.hxx>
42 #include <eerdll2.hxx>
44 #include <edtspell.hxx>
46 #include <txtrange.hxx>
47 #include <svtools/urlbmk.hxx>
48 #include <svtools/colorcfg.hxx>
49 #include <svtools/ctloptions.hxx>
50 #include <acorrcfg.hxx>
52 #include <svx/fhgtitem.hxx>
53 #include <svx/lrspitem.hxx>
54 #include <svx/ulspitem.hxx>
55 #include <svx/wghtitem.hxx>
56 #include <svx/postitem.hxx>
57 #include <svx/udlnitem.hxx>
58 #include <svx/adjitem.hxx>
59 #include <svx/scripttypeitem.hxx>
60 #include <svx/frmdiritem.hxx>
61 #include <fontitem.hxx>
62 #include <sfx2/viewfrm.hxx>
63 #include <sfx2/fcontnr.hxx>
64 #include <sfx2/dispatch.hxx>
65 #include <vcl/cmdevt.h>
68 #ifndef _SFXFRAME_HXX //autogen
69 #include <sfx2/frame.hxx>
72 #include <com/sun/star/i18n/CharacterIteratorMode.hpp>
73 #include <com/sun/star/i18n/WordType.hpp>
74 #include <com/sun/star/i18n/ScriptType.hpp>
75 #include <com/sun/star/lang/Locale.hpp>
76 #include <com/sun/star/text/CharacterCompressionType.hpp>
77 #include <com/sun/star/i18n/InputSequenceCheckMode.hpp>
79 #include <comphelper/processfactory.hxx>
81 #include <sot/formats.hxx>
83 #include <unicode/ubidi.h>
85 using namespace ::com::sun::star
;
87 USHORT
lcl_CalcExtraSpace( ParaPortion
*, const SvxLineSpacingItem
& rLSItem
)
90 /* if ( ( rLSItem.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_PROP )
91 && ( rLSItem.GetPropLineSpace() != 100 ) )
93 // ULONG nH = pPortion->GetNode()->GetCharAttribs().GetDefFont().GetSize().Height();
94 ULONG nH = pPortion->GetLines().GetObject( 0 )->GetHeight();
95 long n = nH * rLSItem.GetPropLineSpace();
97 n -= nH; // nur den Abstand
102 if ( rLSItem
.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_FIX
)
104 nExtra
= rLSItem
.GetInterLineSpace();
110 \f// ----------------------------------------------------------------------
111 // class ImpEditEngine
112 // ----------------------------------------------------------------------
114 ImpEditEngine::ImpEditEngine( EditEngine
* pEE
, SfxItemPool
* pItemPool
) :
115 aPaperSize( 0x7FFFFFFF, 0x7FFFFFFF ),
116 aMinAutoPaperSize( 0x0, 0x0 ),
117 aMaxAutoPaperSize( 0x7FFFFFFF, 0x7FFFFFFF ),
118 aEditDoc( pItemPool
),
119 aWordDelimiters( RTL_CONSTASCII_USTRINGPARAM( " .,;:-'`'?!_=\"{}()[]\0xFF" ) ),
120 aGroupChars( RTL_CONSTASCII_USTRINGPARAM( "{}()[]" ) )
125 pEmptyItemSet
= NULL
;
129 pTextObjectPool
= NULL
;
133 pUndoMarkSelection
= NULL
;
139 nBlockNotifications
= 0;
140 nBigTextObjectStart
= 20;
145 bInSelection
= FALSE
;
146 bOwnerOfRefDev
= FALSE
;
149 bIsFormatting
= FALSE
;
152 bUseAutoColor
= TRUE
;
153 bForceAutoColor
= FALSE
;
154 bAddExtLeading
= FALSE
;
156 bCallParaInsertedOrDeleted
= FALSE
;
157 bImpConvertFirstCall
= FALSE
;
158 bFirstWordCapitalization
= TRUE
;
160 eDefLanguage
= LANGUAGE_DONTKNOW
;
161 maBackgroundColor
= COL_AUTO
;
163 nAsianCompressionMode
= text::CharacterCompressionType::NONE
;
164 bKernAsianPunctuation
= FALSE
;
166 eDefaultHorizontalTextDirection
= EE_HTEXTDIR_DEFAULT
;
169 aStatus
.GetControlWord() = EE_CNTRL_USECHARATTRIBS
| EE_CNTRL_DOIDLEFORMAT
|
170 EE_CNTRL_PASTESPECIAL
| EE_CNTRL_UNDOATTRIBS
|
171 EE_CNTRL_ALLOWBIGOBJS
| EE_CNTRL_RTFSTYLESHEETS
|
174 aSelEngine
.SetFunctionSet( &aSelFuncSet
);
176 aStatusTimer
.SetTimeout( 200 );
177 aStatusTimer
.SetTimeoutHdl( LINK( this, ImpEditEngine
, StatusTimerHdl
) );
179 aIdleFormatter
.SetTimeout( 5 );
180 aIdleFormatter
.SetTimeoutHdl( LINK( this, ImpEditEngine
, IdleFormatHdl
) );
182 aOnlineSpellTimer
.SetTimeout( 100 );
183 aOnlineSpellTimer
.SetTimeoutHdl( LINK( this, ImpEditEngine
, OnlineSpellHdl
) );
185 pRefDev
= EE_DLL()->GetGlobalData()->GetStdRefDevice();
187 // Ab hier wird schon auf Daten zugegriffen!
188 SetRefDevice( pRefDev
);
191 bCallParaInsertedOrDeleted
= TRUE
;
193 aEditDoc
.SetModifyHdl( LINK( this, ImpEditEngine
, DocModified
) );
195 mbLastTryMerge
= FALSE
;
198 ImpEditEngine::~ImpEditEngine()
201 aOnlineSpellTimer
.Stop();
202 aIdleFormatter
.Stop();
204 // das Zerstoeren von Vorlagen kann sonst unnoetiges Formatieren ausloesen,
205 // wenn eine Parent-Vorlage zerstoert wird.
206 // Und das nach dem Zerstoeren der Daten!
208 SetUpdateMode( FALSE
);
211 delete pEmptyItemSet
;
217 if ( bOwnerOfRefDev
)
222 void ImpEditEngine::SetRefDevice( OutputDevice
* pRef
)
224 if ( bOwnerOfRefDev
)
228 bOwnerOfRefDev
= FALSE
;
231 pRefDev
= EE_DLL()->GetGlobalData()->GetStdRefDevice();
233 nOnePixelInRef
= (USHORT
)pRefDev
->PixelToLogic( Size( 1, 0 ) ).Width();
238 UpdateViews( (EditView
*) 0);
242 void ImpEditEngine::SetRefMapMode( const MapMode
& rMapMode
)
244 if ( GetRefDevice()->GetMapMode() == rMapMode
)
247 // Wenn RefDev == GlobalRefDev => eigenes anlegen!
248 if ( !bOwnerOfRefDev
&& ( pRefDev
== EE_DLL()->GetGlobalData()->GetStdRefDevice() ) )
250 pRefDev
= new VirtualDevice
;
251 pRefDev
->SetMapMode( MAP_TWIP
);
252 SetRefDevice( pRefDev
);
253 bOwnerOfRefDev
= TRUE
;
255 pRefDev
->SetMapMode( rMapMode
);
256 nOnePixelInRef
= (USHORT
)pRefDev
->PixelToLogic( Size( 1, 0 ) ).Width();
260 UpdateViews( (EditView
*) 0);
264 void ImpEditEngine::InitDoc( BOOL bKeepParaAttribs
)
266 USHORT nParas
= aEditDoc
.Count();
267 for ( USHORT n
= bKeepParaAttribs
? 1 : 0; n
< nParas
; n
++ )
269 if ( aEditDoc
[n
]->GetStyleSheet() )
270 EndListening( *aEditDoc
[n
]->GetStyleSheet(), FALSE
);
273 if ( bKeepParaAttribs
)
274 aEditDoc
.RemoveText();
278 GetParaPortions().Reset();
280 ParaPortion
* pIniPortion
= new ParaPortion( aEditDoc
[0] );
281 GetParaPortions().Insert( pIniPortion
, 0 );
285 if ( IsCallParaInsertedOrDeleted() )
287 GetEditEnginePtr()->ParagraphDeleted( EE_PARA_ALL
);
288 GetEditEnginePtr()->ParagraphInserted( 0 );
292 if ( GetStatus().DoOnlineSpelling() )
293 aEditDoc
.GetObject( 0 )->CreateWrongList();
297 EditPaM
ImpEditEngine::DeleteSelected( EditSelection aSel
)
299 EditPaM
aPaM ( ImpDeleteSelection( aSel
) );
303 XubString
ImpEditEngine::GetSelected( const EditSelection
& rSel
, const LineEnd eEnd
) const
306 if ( !rSel
.HasRange() )
309 String aSep
= EditDoc::GetSepStr( eEnd
);
311 EditSelection
aSel( rSel
);
312 aSel
.Adjust( aEditDoc
);
314 ContentNode
* pStartNode
= aSel
.Min().GetNode();
315 ContentNode
* pEndNode
= aSel
.Max().GetNode();
316 USHORT nStartNode
= aEditDoc
.GetPos( pStartNode
);
317 USHORT nEndNode
= aEditDoc
.GetPos( pEndNode
);
319 DBG_ASSERT( nStartNode
<= nEndNode
, "Selektion nicht sortiert ?" );
321 // ueber die Absaetze iterieren...
322 for ( USHORT nNode
= nStartNode
; nNode
<= nEndNode
; nNode
++ )
324 DBG_ASSERT( aEditDoc
.SaveGetObject( nNode
), "Node nicht gefunden: GetSelected" );
325 ContentNode
* pNode
= aEditDoc
.GetObject( nNode
);
327 xub_StrLen nStartPos
= 0;
328 xub_StrLen nEndPos
= pNode
->Len();
329 if ( nNode
== nStartNode
)
330 nStartPos
= aSel
.Min().GetIndex();
331 if ( nNode
== nEndNode
) // kann auch == nStart sein!
332 nEndPos
= aSel
.Max().GetIndex();
334 aText
+= aEditDoc
.GetParaAsString( pNode
, nStartPos
, nEndPos
);
335 if ( nNode
< nEndNode
)
341 BOOL
ImpEditEngine::MouseButtonDown( const MouseEvent
& rMEvt
, EditView
* pView
)
343 GetSelEngine().SetCurView( pView
);
344 SetActiveView( pView
);
346 if ( GetAutoCompleteText().Len() )
347 SetAutoCompleteText( String(), TRUE
);
349 GetSelEngine().SelMouseButtonDown( rMEvt
);
350 // Sonderbehandlungen
351 EditSelection
aCurSel( pView
->pImpEditView
->GetEditSelection() );
352 if ( !rMEvt
.IsShift() )
354 if ( rMEvt
.GetClicks() == 2 )
356 // damit die SelectionEngine weiss, dass Anker.
357 aSelEngine
.CursorPosChanging( TRUE
, FALSE
);
359 EditSelection
aNewSelection( SelectWord( aCurSel
) );
360 pView
->pImpEditView
->DrawSelection();
361 pView
->pImpEditView
->SetEditSelection( aNewSelection
);
362 pView
->pImpEditView
->DrawSelection();
363 pView
->ShowCursor( TRUE
, TRUE
);
365 else if ( rMEvt
.GetClicks() == 3 )
367 // damit die SelectionEngine weiss, dass Anker.
368 aSelEngine
.CursorPosChanging( TRUE
, FALSE
);
370 EditSelection
aNewSelection( aCurSel
);
371 aNewSelection
.Min().SetIndex( 0 );
372 aNewSelection
.Max().SetIndex( aCurSel
.Min().GetNode()->Len() );
373 pView
->pImpEditView
->DrawSelection();
374 pView
->pImpEditView
->SetEditSelection( aNewSelection
);
375 pView
->pImpEditView
->DrawSelection();
376 pView
->ShowCursor( TRUE
, TRUE
);
382 void ImpEditEngine::Command( const CommandEvent
& rCEvt
, EditView
* pView
)
384 GetSelEngine().SetCurView( pView
);
385 SetActiveView( pView
);
386 if ( rCEvt
.GetCommand() == COMMAND_VOICE
)
388 const CommandVoiceData
* pData
= rCEvt
.GetVoiceData();
389 if ( pData
->GetType() == VOICECOMMANDTYPE_DICTATION
)
391 // Funktionen auf KeyEvents umbiegen, wenn keine entsprechende
392 // Methode an EditView/EditEngine, damit Undo konsistent bleibt.
394 SfxPoolItem
* pNewAttr
= NULL
;
396 switch ( pData
->GetCommand() )
398 case DICTATIONCOMMAND_UNKNOWN
:
400 pView
->InsertText( pData
->GetText() );
403 case DICTATIONCOMMAND_NEWPARAGRAPH
:
405 pView
->PostKeyEvent( KeyEvent( 0, KeyCode( KEY_RETURN
, 0 ) ) );
408 case DICTATIONCOMMAND_NEWLINE
:
410 pView
->PostKeyEvent( KeyEvent( 0, KeyCode( KEY_RETURN
, KEY_SHIFT
) ) );
413 case DICTATIONCOMMAND_TAB
:
415 pView
->PostKeyEvent( KeyEvent( 0, KeyCode( KEY_TAB
, 0 ) ) );
418 case DICTATIONCOMMAND_LEFT
:
420 pView
->PostKeyEvent( KeyEvent( 0, KeyCode( KEY_LEFT
, KEY_MOD1
) ) );
423 case DICTATIONCOMMAND_RIGHT
:
425 pView
->PostKeyEvent( KeyEvent( 0, KeyCode( KEY_RIGHT
, KEY_MOD1
) ) );
428 case DICTATIONCOMMAND_UP
:
430 pView
->PostKeyEvent( KeyEvent( 0, KeyCode( KEY_UP
, 0 ) ) );
433 case DICTATIONCOMMAND_DOWN
:
435 pView
->PostKeyEvent( KeyEvent( 0, KeyCode( KEY_UP
, 0 ) ) );
438 case DICTATIONCOMMAND_UNDO
:
443 case DICTATIONCOMMAND_DEL
:
445 pView
->PostKeyEvent( KeyEvent( 0, KeyCode( KEY_LEFT
, KEY_MOD1
|KEY_SHIFT
) ) );
446 pView
->DeleteSelected();
449 case DICTATIONCOMMAND_BOLD_ON
:
451 pNewAttr
= new SvxWeightItem( WEIGHT_BOLD
, EE_CHAR_WEIGHT
);
454 case DICTATIONCOMMAND_BOLD_OFF
:
456 pNewAttr
= new SvxWeightItem( WEIGHT_NORMAL
, EE_CHAR_WEIGHT
);
459 case DICTATIONCOMMAND_ITALIC_ON
:
461 pNewAttr
= new SvxPostureItem( ITALIC_NORMAL
, EE_CHAR_ITALIC
);
464 case DICTATIONCOMMAND_ITALIC_OFF
:
466 pNewAttr
= new SvxPostureItem( ITALIC_NORMAL
, EE_CHAR_ITALIC
);
469 case DICTATIONCOMMAND_UNDERLINE_ON
:
471 pNewAttr
= new SvxUnderlineItem( UNDERLINE_SINGLE
, EE_CHAR_UNDERLINE
);
474 case DICTATIONCOMMAND_UNDERLINE_OFF
:
476 pNewAttr
= new SvxUnderlineItem( UNDERLINE_NONE
, EE_CHAR_UNDERLINE
);
483 SfxItemSet
aSet( GetEmptyItemSet() );
484 aSet
.Put( *pNewAttr
);
485 pView
->SetAttribs( aSet
);
490 else if ( rCEvt
.GetCommand() == COMMAND_STARTEXTTEXTINPUT
)
492 pView
->DeleteSelected();
494 EditPaM aPaM
= pView
->GetImpEditView()->GetEditSelection().Max();
495 String aOldTextAfterStartPos
= aPaM
.GetNode()->Copy( aPaM
.GetIndex() );
496 USHORT nMax
= aOldTextAfterStartPos
.Search( CH_FEATURE
);
497 if ( nMax
!= STRING_NOTFOUND
) // don't overwrite features!
498 aOldTextAfterStartPos
.Erase( nMax
);
499 mpIMEInfos
= new ImplIMEInfos( aPaM
, aOldTextAfterStartPos
);
500 mpIMEInfos
->bWasCursorOverwrite
= !pView
->IsInsertMode();
501 UndoActionStart( EDITUNDO_INSERT
);
503 else if ( rCEvt
.GetCommand() == COMMAND_ENDEXTTEXTINPUT
)
505 DBG_ASSERT( mpIMEInfos
, "COMMAND_ENDEXTTEXTINPUT => Kein Start ?" );
508 // #102812# convert quotes in IME text
509 // works on the last input character, this is escpecially in Korean text often done
510 // quotes that are inside of the string are not replaced!
511 // Borrowed from sw: edtwin.cxx
512 if ( mpIMEInfos
->nLen
)
514 EditSelection
aSel( mpIMEInfos
->aPos
);
515 aSel
.Min().GetIndex() += mpIMEInfos
->nLen
-1;
516 aSel
.Max().GetIndex() =
517 aSel
.Max().GetIndex() + mpIMEInfos
->nLen
;
518 // #102812# convert quotes in IME text
519 // works on the last input character, this is escpecially in Korean text often done
520 // quotes that are inside of the string are not replaced!
521 const sal_Unicode nCharCode
= aSel
.Min().GetNode()->GetChar( aSel
.Min().GetIndex() );
522 if ( ( GetStatus().DoAutoCorrect() ) && ( ( nCharCode
== '\"' ) || ( nCharCode
== '\'' ) ) )
524 aSel
= DeleteSelected( aSel
);
525 aSel
= AutoCorrect( aSel
, nCharCode
, mpIMEInfos
->bWasCursorOverwrite
);
526 pView
->pImpEditView
->SetEditSelection( aSel
);
530 ParaPortion
* pPortion
= FindParaPortion( mpIMEInfos
->aPos
.GetNode() );
531 pPortion
->MarkSelectionInvalid( mpIMEInfos
->aPos
.GetIndex(), 0 );
533 BOOL bWasCursorOverwrite
= mpIMEInfos
->bWasCursorOverwrite
;
538 FormatAndUpdate( pView
);
540 pView
->SetInsertMode( !bWasCursorOverwrite
);
542 UndoActionEnd( EDITUNDO_INSERT
);
544 else if ( rCEvt
.GetCommand() == COMMAND_EXTTEXTINPUT
)
546 DBG_ASSERT( mpIMEInfos
, "COMMAND_EXTTEXTINPUT => Kein Start ?" );
549 const CommandExtTextInputData
* pData
= rCEvt
.GetExtTextInputData();
551 if ( !pData
->IsOnlyCursorChanged() )
553 EditSelection
aSel( mpIMEInfos
->aPos
);
554 aSel
.Max().GetIndex() =
555 aSel
.Max().GetIndex() + mpIMEInfos
->nLen
;
556 aSel
= DeleteSelected( aSel
);
557 aSel
= ImpInsertText( aSel
, pData
->GetText() );
559 if ( mpIMEInfos
->bWasCursorOverwrite
)
561 USHORT nOldIMETextLen
= mpIMEInfos
->nLen
;
562 USHORT nNewIMETextLen
= pData
->GetText().Len();
564 if ( ( nOldIMETextLen
> nNewIMETextLen
) &&
565 ( nNewIMETextLen
< mpIMEInfos
->aOldTextAfterStartPos
.Len() ) )
567 // restore old characters
568 USHORT nRestore
= nOldIMETextLen
- nNewIMETextLen
;
569 EditPaM
aPaM( mpIMEInfos
->aPos
);
570 aPaM
.GetIndex() = aPaM
.GetIndex() + nNewIMETextLen
;
571 ImpInsertText( aPaM
, mpIMEInfos
->aOldTextAfterStartPos
.Copy( nNewIMETextLen
, nRestore
) );
573 else if ( ( nOldIMETextLen
< nNewIMETextLen
) &&
574 ( nOldIMETextLen
< mpIMEInfos
->aOldTextAfterStartPos
.Len() ) )
577 USHORT nOverwrite
= nNewIMETextLen
- nOldIMETextLen
;
578 if ( ( nOldIMETextLen
+ nOverwrite
) > mpIMEInfos
->aOldTextAfterStartPos
.Len() )
579 nOverwrite
= mpIMEInfos
->aOldTextAfterStartPos
.Len() - nOldIMETextLen
;
580 DBG_ASSERT( nOverwrite
&& (nOverwrite
< 0xFF00), "IME Overwrite?!" );
581 EditPaM
aPaM( mpIMEInfos
->aPos
);
582 aPaM
.GetIndex() = aPaM
.GetIndex() + nNewIMETextLen
;
583 EditSelection
_aSel( aPaM
);
584 _aSel
.Max().GetIndex() =
585 _aSel
.Max().GetIndex() + nOverwrite
;
586 DeleteSelected( _aSel
);
589 if ( pData
->GetTextAttr() )
591 mpIMEInfos
->CopyAttribs( pData
->GetTextAttr(), pData
->GetText().Len() );
592 mpIMEInfos
->bCursor
= pData
->IsCursorVisible();
596 mpIMEInfos
->DestroyAttribs();
597 mpIMEInfos
->nLen
= pData
->GetText().Len();
600 ParaPortion
* pPortion
= FindParaPortion( mpIMEInfos
->aPos
.GetNode() );
601 pPortion
->MarkSelectionInvalid( mpIMEInfos
->aPos
.GetIndex(), 0 );
602 FormatAndUpdate( pView
);
605 EditSelection aNewSel
= EditPaM( mpIMEInfos
->aPos
.GetNode(), mpIMEInfos
->aPos
.GetIndex()+pData
->GetCursorPos() );
606 pView
->SetSelection( CreateESel( aNewSel
) );
607 pView
->SetInsertMode( !pData
->IsCursorOverwrite() );
609 if ( pData
->IsCursorVisible() )
615 else if ( rCEvt
.GetCommand() == COMMAND_INPUTCONTEXTCHANGE
)
618 else if ( rCEvt
.GetCommand() == COMMAND_CURSORPOS
)
620 if ( mpIMEInfos
&& mpIMEInfos
->nLen
)
622 EditPaM
aPaM( pView
->pImpEditView
->GetEditSelection().Max() );
623 Rectangle aR1
= PaMtoEditCursor( aPaM
, 0 );
625 USHORT nInputEnd
= mpIMEInfos
->aPos
.GetIndex() + mpIMEInfos
->nLen
;
627 if ( !IsFormatted() )
630 ParaPortion
* pParaPortion
= GetParaPortions().SaveGetObject( GetEditDoc().GetPos( aPaM
.GetNode() ) );
631 USHORT nLine
= pParaPortion
->GetLines().FindLine( aPaM
.GetIndex(), sal_True
);
632 EditLine
* pLine
= pParaPortion
->GetLines().GetObject( nLine
);
633 if ( pLine
&& ( nInputEnd
> pLine
->GetEnd() ) )
634 nInputEnd
= pLine
->GetEnd();
635 Rectangle aR2
= PaMtoEditCursor( EditPaM( aPaM
.GetNode(), nInputEnd
), GETCRSR_ENDOFLINE
);
636 Rectangle aRect
= pView
->GetImpEditView()->GetWindowPos( aR1
);
637 pView
->GetWindow()->SetCursorRect( &aRect
, aR2
.Left()-aR1
.Right() );
641 pView
->GetWindow()->SetCursorRect();
644 else if ( rCEvt
.GetCommand() == COMMAND_SELECTIONCHANGE
)
646 const CommandSelectionChangeData
*pData
= rCEvt
.GetSelectionChangeData();
648 ESelection aSelection
= pView
->GetSelection();
651 if( pView
->HasSelection() )
653 aSelection
.nEndPos
= aSelection
.nStartPos
;
654 aSelection
.nStartPos
+= pData
->GetStart();
655 aSelection
.nEndPos
+= pData
->GetEnd();
659 aSelection
.nStartPos
= pData
->GetStart();
660 aSelection
.nEndPos
= pData
->GetEnd();
662 pView
->SetSelection( aSelection
);
664 else if ( rCEvt
.GetCommand() == COMMAND_PREPARERECONVERSION
)
666 if ( pView
->HasSelection() )
668 ESelection aSelection
= pView
->GetSelection();
671 if ( aSelection
.nStartPara
!= aSelection
.nEndPara
)
673 xub_StrLen aParaLen
= pEditEngine
->GetTextLen( aSelection
.nStartPara
);
674 aSelection
.nEndPara
= aSelection
.nStartPara
;
675 aSelection
.nEndPos
= aParaLen
;
676 pView
->SetSelection( aSelection
);
681 GetSelEngine().Command( rCEvt
);
684 BOOL
ImpEditEngine::MouseButtonUp( const MouseEvent
& rMEvt
, EditView
* pView
)
686 GetSelEngine().SetCurView( pView
);
687 GetSelEngine().SelMouseButtonUp( rMEvt
);
688 bInSelection
= FALSE
;
689 // Sonderbehandlungen
690 EditSelection
aCurSel( pView
->pImpEditView
->GetEditSelection() );
691 if ( !aCurSel
.HasRange() )
693 if ( ( rMEvt
.GetClicks() == 1 ) && rMEvt
.IsLeft() && !rMEvt
.IsMod2() )
695 const SvxFieldItem
* pFld
= pView
->GetFieldUnderMousePointer();
698 EditPaM
aPaM( aCurSel
.Max() );
699 USHORT nPara
= GetEditDoc().GetPos( aPaM
.GetNode() );
700 GetEditEnginePtr()->FieldClicked( *pFld
, nPara
, aPaM
.GetIndex() );
707 BOOL
ImpEditEngine::MouseMove( const MouseEvent
& rMEvt
, EditView
* pView
)
709 // MouseMove wird sofort nach ShowQuickHelp() gerufen!
710 // if ( GetAutoCompleteText().Len() )
711 // SetAutoCompleteText( String(), TRUE );
712 GetSelEngine().SetCurView( pView
);
713 GetSelEngine().SelMouseMove( rMEvt
);
717 EditPaM
ImpEditEngine::InsertText( EditSelection aSel
, const XubString
& rStr
)
719 EditPaM aPaM
= ImpInsertText( aSel
, rStr
);
723 EditPaM
ImpEditEngine::Clear()
727 EditPaM aPaM
= aEditDoc
.GetStartPaM();
728 EditSelection
aSel( aPaM
);
734 for ( USHORT nView
= aEditViews
.Count(); nView
; )
736 EditView
* pView
= aEditViews
[--nView
];
737 DBG_CHKOBJ( pView
, EditView
, 0 );
738 pView
->pImpEditView
->SetEditSelection( aSel
);
744 EditPaM
ImpEditEngine::RemoveText()
748 EditPaM aStartPaM
= aEditDoc
.GetStartPaM();
749 EditSelection
aEmptySel( aStartPaM
, aStartPaM
);
750 for ( USHORT nView
= 0; nView
< aEditViews
.Count(); nView
++ )
752 EditView
* pView
= aEditViews
.GetObject(nView
);
753 DBG_CHKOBJ( pView
, EditView
, 0 );
754 pView
->pImpEditView
->SetEditSelection( aEmptySel
);
757 return aEditDoc
.GetStartPaM();
761 void ImpEditEngine::SetText( const XubString
& rText
)
763 // RemoveText loescht die Undo-Liste!
764 EditPaM aStartPaM
= RemoveText();
765 BOOL bUndoCurrentlyEnabled
= IsUndoEnabled();
766 // Der von Hand reingesteckte Text kann nicht vom Anwender rueckgaengig gemacht werden.
769 EditSelection
aEmptySel( aStartPaM
, aStartPaM
);
770 EditPaM aPaM
= aStartPaM
;
772 aPaM
= ImpInsertText( aEmptySel
, rText
);
774 for ( USHORT nView
= 0; nView
< aEditViews
.Count(); nView
++ )
776 EditView
* pView
= aEditViews
[nView
];
777 DBG_CHKOBJ( pView
, EditView
, 0 );
778 pView
->pImpEditView
->SetEditSelection( EditSelection( aPaM
, aPaM
) );
779 // Wenn kein Text, dann auch Kein Format&Update
780 // => Der Text bleibt stehen.
781 if ( !rText
.Len() && GetUpdateMode() )
783 Rectangle
aTmpRec( pView
->GetOutputArea().TopLeft(),
784 Size( aPaperSize
.Width(), nCurTextHeight
) );
785 aTmpRec
.Intersection( pView
->GetOutputArea() );
786 pView
->GetWindow()->Invalidate( aTmpRec
);
789 if( !rText
.Len() ) // sonst muss spaeter noch invalidiert werden, !bFormatted reicht.
791 EnableUndo( bUndoCurrentlyEnabled
);
793 DBG_ASSERT( !HasUndoManager() || !GetUndoManager().GetUndoActionCount(), "Undo nach SetText?" );
798 const SfxItemSet
& ImpEditEngine::GetEmptyItemSet()
800 if ( !pEmptyItemSet
)
802 pEmptyItemSet
= new SfxItemSet( aEditDoc
.GetItemPool(), EE_ITEMS_START
, EE_ITEMS_END
);
803 for ( USHORT nWhich
= EE_ITEMS_START
; nWhich
<= EE_CHAR_END
; nWhich
++)
805 pEmptyItemSet
->ClearItem( nWhich
);
808 return *pEmptyItemSet
;
811 // ----------------------------------------------------------------------
813 // ----------------------------------------------------------------------
814 void ImpEditEngine::CursorMoved( ContentNode
* pPrevNode
)
816 // Leere Attribute loeschen, aber nur, wenn Absatz nicht leer!
817 if ( pPrevNode
->GetCharAttribs().HasEmptyAttribs() && pPrevNode
->Len() )
818 pPrevNode
->GetCharAttribs().DeleteEmptyAttribs( aEditDoc
.GetItemPool() );
821 void ImpEditEngine::TextModified()
825 if ( GetNotifyHdl().IsSet() )
827 EENotify
aNotify( EE_NOTIFY_TEXTMODIFIED
);
828 aNotify
.pEditEngine
= GetEditEnginePtr();
829 CallNotify( aNotify
);
834 void ImpEditEngine::ParaAttribsChanged( ContentNode
* pNode
)
836 DBG_ASSERT( pNode
, "ParaAttribsChanged: Welcher?" );
838 aEditDoc
.SetModified( TRUE
);
841 ParaPortion
* pPortion
= FindParaPortion( pNode
);
842 DBG_ASSERT( pPortion
, "ParaAttribsChanged: Portion?" );
843 pPortion
->MarkSelectionInvalid( 0, pNode
->Len() );
845 USHORT nPara
= aEditDoc
.GetPos( pNode
);
846 pEditEngine
->ParaAttribsChanged( nPara
);
848 ParaPortion
* pNextPortion
= GetParaPortions().SaveGetObject( nPara
+1 );
849 // => wird sowieso noch formatiert, wenn Invalid.
850 if ( pNextPortion
&& !pNextPortion
->IsInvalid() )
851 CalcHeight( pNextPortion
);
854 // ----------------------------------------------------------------------
856 // ----------------------------------------------------------------------
858 EditSelection
ImpEditEngine::MoveCursor( const KeyEvent
& rKeyEvent
, EditView
* pEditView
)
860 // Eigentlich nur bei Up/Down noetig, aber was solls.
861 CheckIdleFormatter();
863 EditPaM
aPaM( pEditView
->pImpEditView
->GetEditSelection().Max() );
865 EditPaM
aOldPaM( aPaM
);
867 TextDirectionality eTextDirection
= TextDirectionality_LeftToRight_TopToBottom
;
869 eTextDirection
= TextDirectionality_TopToBottom_RightToLeft
;
870 else if ( IsRightToLeft( GetEditDoc().GetPos( aPaM
.GetNode() ) ) )
871 eTextDirection
= TextDirectionality_RightToLeft_TopToBottom
;
873 KeyEvent aTranslatedKeyEvent
= rKeyEvent
.LogicalTextDirectionality( eTextDirection
);
875 BOOL bCtrl
= aTranslatedKeyEvent
.GetKeyCode().IsMod1() ? TRUE
: FALSE
;
876 USHORT nCode
= aTranslatedKeyEvent
.GetKeyCode().GetCode();
878 if ( DoVisualCursorTraveling( aPaM
.GetNode() ) )
880 // Only for simple cursor movement...
881 if ( !bCtrl
&& ( ( nCode
== KEY_LEFT
) || ( nCode
== KEY_RIGHT
) ) )
883 aPaM
= CursorVisualLeftRight( pEditView
, aPaM
, rKeyEvent
.GetKeyCode().IsMod2() ? i18n::CharacterIteratorMode::SKIPCHARACTER
: i18n::CharacterIteratorMode::SKIPCELL
, rKeyEvent
.GetKeyCode().GetCode() == KEY_LEFT
);
884 nCode
= 0; // skip switch statement
887 else if ( !bCtrl && ( ( nCode == KEY_HOME ) || ( nCode == KEY_END ) ) )
889 aPaM = CursorVisualStartEnd( pEditView, aPaM, nCode == KEY_HOME );
890 nCode = 0; // skip switch statement
895 bool bKeyModifySelection
= aTranslatedKeyEvent
.GetKeyCode().IsShift();
898 case KEY_UP
: aPaM
= CursorUp( aPaM
, pEditView
);
900 case KEY_DOWN
: aPaM
= CursorDown( aPaM
, pEditView
);
902 case KEY_LEFT
: aPaM
= bCtrl
? WordLeft( aPaM
) : CursorLeft( aPaM
, aTranslatedKeyEvent
.GetKeyCode().IsMod2() ? i18n::CharacterIteratorMode::SKIPCHARACTER
: i18n::CharacterIteratorMode::SKIPCELL
);
904 case KEY_RIGHT
: aPaM
= bCtrl
? WordRight( aPaM
) : CursorRight( aPaM
, aTranslatedKeyEvent
.GetKeyCode().IsMod2() ? i18n::CharacterIteratorMode::SKIPCHARACTER
: i18n::CharacterIteratorMode::SKIPCELL
);
906 case KEY_HOME
: aPaM
= bCtrl
? CursorStartOfDoc() : CursorStartOfLine( aPaM
);
908 case KEY_END
: aPaM
= bCtrl
? CursorEndOfDoc() : CursorEndOfLine( aPaM
);
910 case KEY_PAGEUP
: aPaM
= bCtrl
? CursorStartOfDoc() : PageUp( aPaM
, pEditView
);
912 case KEY_PAGEDOWN
: aPaM
= bCtrl
? CursorEndOfDoc() : PageDown( aPaM
, pEditView
);
914 case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE
:
915 aPaM
= CursorStartOfLine( aPaM
);
916 bKeyModifySelection
= false;
918 case com::sun::star::awt::Key::MOVE_TO_END_OF_LINE
:
919 aPaM
= CursorEndOfLine( aPaM
);
920 bKeyModifySelection
= false;
922 case com::sun::star::awt::Key::MOVE_WORD_BACKWARD
:
923 aPaM
= WordLeft( aPaM
);
924 bKeyModifySelection
= false;
926 case com::sun::star::awt::Key::MOVE_WORD_FORWARD
:
927 aPaM
= WordRight( aPaM
);
928 bKeyModifySelection
= false;
930 case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH
:
931 aPaM
= CursorStartOfParagraph( aPaM
);
932 if( aPaM
== aOldPaM
)
934 aPaM
= CursorLeft( aPaM
, i18n::CharacterIteratorMode::SKIPCELL
);
935 aPaM
= CursorStartOfParagraph( aPaM
);
937 bKeyModifySelection
= false;
939 case com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH
:
940 aPaM
= CursorEndOfParagraph( aPaM
);
941 if( aPaM
== aOldPaM
)
943 aPaM
= CursorRight( aPaM
, i18n::CharacterIteratorMode::SKIPCELL
);
944 aPaM
= CursorEndOfParagraph( aPaM
);
946 bKeyModifySelection
= false;
948 case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT
:
949 aPaM
= CursorStartOfDoc();
950 bKeyModifySelection
= false;
952 case com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT
:
953 aPaM
= CursorEndOfDoc();
954 bKeyModifySelection
= false;
956 case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE
:
957 aPaM
= CursorStartOfLine( aPaM
);
958 bKeyModifySelection
= true;
960 case com::sun::star::awt::Key::SELECT_TO_END_OF_LINE
:
961 aPaM
= CursorEndOfLine( aPaM
);
962 bKeyModifySelection
= true;
964 case com::sun::star::awt::Key::SELECT_BACKWARD
:
965 aPaM
= CursorLeft( aPaM
, i18n::CharacterIteratorMode::SKIPCELL
);
966 bKeyModifySelection
= true;
968 case com::sun::star::awt::Key::SELECT_FORWARD
:
969 aPaM
= CursorRight( aPaM
, i18n::CharacterIteratorMode::SKIPCELL
);
970 bKeyModifySelection
= true;
972 case com::sun::star::awt::Key::SELECT_WORD_BACKWARD
:
973 aPaM
= WordLeft( aPaM
);
974 bKeyModifySelection
= true;
976 case com::sun::star::awt::Key::SELECT_WORD_FORWARD
:
977 aPaM
= WordRight( aPaM
);
978 bKeyModifySelection
= true;
980 case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH
:
981 aPaM
= CursorStartOfParagraph( aPaM
);
982 if( aPaM
== aOldPaM
)
984 aPaM
= CursorLeft( aPaM
, i18n::CharacterIteratorMode::SKIPCELL
);
985 aPaM
= CursorStartOfParagraph( aPaM
);
987 bKeyModifySelection
= true;
989 case com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH
:
990 aPaM
= CursorEndOfParagraph( aPaM
);
991 if( aPaM
== aOldPaM
)
993 aPaM
= CursorRight( aPaM
, i18n::CharacterIteratorMode::SKIPCELL
);
994 aPaM
= CursorEndOfParagraph( aPaM
);
996 bKeyModifySelection
= true;
998 case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT
:
999 aPaM
= CursorStartOfDoc();
1000 bKeyModifySelection
= true;
1002 case com::sun::star::awt::Key::SELECT_TO_END_OF_DOCUMENT
:
1003 aPaM
= CursorEndOfDoc();
1004 bKeyModifySelection
= true;
1008 if ( aOldPaM
!= aPaM
)
1010 CursorMoved( aOldPaM
.GetNode() );
1011 if ( aStatus
.NotifyCursorMovements() && ( aOldPaM
.GetNode() != aPaM
.GetNode() ) )
1013 aStatus
.GetStatusWord() = aStatus
.GetStatusWord() | EE_STAT_CRSRLEFTPARA
;
1014 aStatus
.GetPrevParagraph() = aEditDoc
.GetPos( aOldPaM
.GetNode() );
1018 aStatus
.GetStatusWord() = aStatus
.GetStatusWord() | EE_STAT_CRSRMOVEFAIL
;
1020 // Bewirkt evtl. ein CreateAnchor oder Deselection all
1021 aSelEngine
.SetCurView( pEditView
);
1022 aSelEngine
.CursorPosChanging( bKeyModifySelection
, aTranslatedKeyEvent
.GetKeyCode().IsMod1() );
1023 EditPaM
aOldEnd( pEditView
->pImpEditView
->GetEditSelection().Max() );
1024 pEditView
->pImpEditView
->GetEditSelection().Max() = aPaM
;
1025 if ( bKeyModifySelection
)
1027 // Dann wird die Selektion erweitert...
1028 EditSelection
aTmpNewSel( aOldEnd
, aPaM
);
1029 pEditView
->pImpEditView
->DrawSelection( aTmpNewSel
);
1032 pEditView
->pImpEditView
->GetEditSelection().Min() = aPaM
;
1034 return pEditView
->pImpEditView
->GetEditSelection();
1037 EditPaM
ImpEditEngine::CursorVisualStartEnd( EditView
* pEditView
, const EditPaM
& rPaM
, BOOL bStart
)
1039 EditPaM
aPaM( rPaM
);
1041 USHORT nPara
= GetEditDoc().GetPos( aPaM
.GetNode() );
1042 ParaPortion
* pParaPortion
= GetParaPortions().SaveGetObject( nPara
);
1044 USHORT nLine
= pParaPortion
->GetLines().FindLine( aPaM
.GetIndex(), sal_False
);
1045 EditLine
* pLine
= pParaPortion
->GetLines().GetObject( nLine
);
1046 BOOL bEmptyLine
= pLine
->GetStart() == pLine
->GetEnd();
1048 pEditView
->pImpEditView
->nExtraCursorFlags
= 0;
1052 String
aLine( *aPaM
.GetNode(), pLine
->GetStart(), pLine
->GetEnd() - pLine
->GetStart() );
1053 // USHORT nPosInLine = aPaM.GetIndex() - pLine->GetStart();
1055 const sal_Unicode
* pLineString
= aLine
.GetBuffer();
1057 UErrorCode nError
= U_ZERO_ERROR
;
1058 UBiDi
* pBidi
= ubidi_openSized( aLine
.Len(), 0, &nError
);
1060 const UBiDiLevel nBidiLevel
= IsRightToLeft( nPara
) ? 1 /*RTL*/ : 0 /*LTR*/;
1061 ubidi_setPara( pBidi
, reinterpret_cast<const UChar
*>(pLineString
), aLine
.Len(), nBidiLevel
, NULL
, &nError
); // UChar != sal_Unicode in MinGW
1063 USHORT nVisPos
= bStart
? 0 : aLine
.Len()-1;
1064 USHORT nLogPos
= (USHORT
)ubidi_getLogicalIndex( pBidi
, nVisPos
, &nError
);
1066 ubidi_close( pBidi
);
1068 aPaM
.GetIndex() = nLogPos
+ pLine
->GetStart();
1071 USHORT nTextPortion
= pParaPortion
->GetTextPortions().FindPortion( aPaM
.GetIndex(), nTmp
, TRUE
);
1072 TextPortion
* pTextPortion
= pParaPortion
->GetTextPortions().GetObject( nTextPortion
);
1073 USHORT nRTLLevel
= pTextPortion
->GetRightToLeft();
1074 // BOOL bParaRTL = IsRightToLeft( nPara );
1075 BOOL bPortionRTL
= nRTLLevel
%2 ? TRUE
: FALSE
;
1079 pEditView
->pImpEditView
->SetCursorBidiLevel( bPortionRTL
? 0 : 1 );
1080 // Maybe we must be *behind* the character
1081 if ( bPortionRTL
&& pEditView
->IsInsertMode() )
1086 pEditView
->pImpEditView
->SetCursorBidiLevel( bPortionRTL
? 1 : 0 );
1087 if ( !bPortionRTL
&& pEditView
->IsInsertMode() )
1095 EditPaM
ImpEditEngine::CursorVisualLeftRight( EditView
* pEditView
, const EditPaM
& rPaM
, USHORT nCharacterIteratorMode
, BOOL bVisualToLeft
)
1097 EditPaM
aPaM( rPaM
);
1099 USHORT nPara
= GetEditDoc().GetPos( aPaM
.GetNode() );
1100 ParaPortion
* pParaPortion
= GetParaPortions().SaveGetObject( nPara
);
1102 USHORT nLine
= pParaPortion
->GetLines().FindLine( aPaM
.GetIndex(), sal_False
);
1103 EditLine
* pLine
= pParaPortion
->GetLines().GetObject( nLine
);
1104 BOOL bEmptyLine
= pLine
->GetStart() == pLine
->GetEnd();
1106 // USHORT nCurrentCursorFlags = pEditView->pImpEditView->nExtraCursorFlags;
1107 pEditView
->pImpEditView
->nExtraCursorFlags
= 0;
1109 BOOL bParaRTL
= IsRightToLeft( nPara
);
1115 if ( bVisualToLeft
)
1117 aPaM
= CursorUp( aPaM
, pEditView
);
1119 aPaM
= CursorVisualStartEnd( pEditView
, aPaM
, FALSE
);
1123 aPaM
= CursorDown( aPaM
, pEditView
);
1125 aPaM
= CursorVisualStartEnd( pEditView
, aPaM
, TRUE
);
1131 BOOL bLogicalBackward
= bParaRTL
? !bVisualToLeft
: bVisualToLeft
;
1133 if ( !bDone
&& pEditView
->IsInsertMode() )
1135 // Check if we are within a portion and don't have overwrite mode, then it's easy...
1136 USHORT nPortionStart
;
1137 USHORT nTextPortion
= pParaPortion
->GetTextPortions().FindPortion( aPaM
.GetIndex(), nPortionStart
, FALSE
);
1138 TextPortion
* pTextPortion
= pParaPortion
->GetTextPortions().GetObject( nTextPortion
);
1140 BOOL bPortionBoundary
= ( aPaM
.GetIndex() == nPortionStart
) || ( aPaM
.GetIndex() == (nPortionStart
+pTextPortion
->GetLen()) );
1141 USHORT nRTLLevel
= pTextPortion
->GetRightToLeft();
1143 // Portion boundary doesn't matter if both have same RTL level
1144 USHORT nRTLLevelNextPortion
= 0xFFFF;
1145 if ( bPortionBoundary
&& aPaM
.GetIndex() && ( aPaM
.GetIndex() < aPaM
.GetNode()->Len() ) )
1148 USHORT nNextTextPortion
= pParaPortion
->GetTextPortions().FindPortion( aPaM
.GetIndex()+1, nTmp
, bLogicalBackward
? FALSE
: TRUE
);
1149 TextPortion
* pNextTextPortion
= pParaPortion
->GetTextPortions().GetObject( nNextTextPortion
);
1150 nRTLLevelNextPortion
= pNextTextPortion
->GetRightToLeft();
1153 if ( !bPortionBoundary
|| ( nRTLLevel
== nRTLLevelNextPortion
) )
1155 if ( ( bVisualToLeft
&& !(nRTLLevel
%2) ) || ( !bVisualToLeft
&& (nRTLLevel
%2) ) )
1157 aPaM
= CursorLeft( aPaM
, nCharacterIteratorMode
);
1158 pEditView
->pImpEditView
->SetCursorBidiLevel( 1 );
1162 aPaM
= CursorRight( aPaM
, nCharacterIteratorMode
);
1163 pEditView
->pImpEditView
->SetCursorBidiLevel( 0 );
1171 BOOL bGotoStartOfNextLine
= FALSE
;
1172 BOOL bGotoEndOfPrevLine
= FALSE
;
1174 String
aLine( *aPaM
.GetNode(), pLine
->GetStart(), pLine
->GetEnd() - pLine
->GetStart() );
1175 USHORT nPosInLine
= aPaM
.GetIndex() - pLine
->GetStart();
1177 const sal_Unicode
* pLineString
= aLine
.GetBuffer();
1179 UErrorCode nError
= U_ZERO_ERROR
;
1180 UBiDi
* pBidi
= ubidi_openSized( aLine
.Len(), 0, &nError
);
1182 const UBiDiLevel nBidiLevel
= IsRightToLeft( nPara
) ? 1 /*RTL*/ : 0 /*LTR*/;
1183 ubidi_setPara( pBidi
, reinterpret_cast<const UChar
*>(pLineString
), aLine
.Len(), nBidiLevel
, NULL
, &nError
); // UChar != sal_Unicode in MinGW
1185 if ( !pEditView
->IsInsertMode() )
1187 BOOL bEndOfLine
= nPosInLine
== aLine
.Len();
1188 USHORT nVisPos
= (USHORT
)ubidi_getVisualIndex( pBidi
, !bEndOfLine
? nPosInLine
: nPosInLine
-1, &nError
);
1189 if ( bVisualToLeft
)
1191 bGotoEndOfPrevLine
= nVisPos
== 0;
1197 bGotoStartOfNextLine
= nVisPos
== (aLine
.Len() - 1);
1202 if ( !bGotoEndOfPrevLine
&& !bGotoStartOfNextLine
)
1204 USHORT nLogPos
= (USHORT
)ubidi_getLogicalIndex( pBidi
, nVisPos
, &nError
);
1205 aPaM
.GetIndex() = pLine
->GetStart() + nLogPos
;
1206 pEditView
->pImpEditView
->SetCursorBidiLevel( 0 );
1211 BOOL bWasBehind
= FALSE
;
1212 BOOL bBeforePortion
= !nPosInLine
|| pEditView
->pImpEditView
->GetCursorBidiLevel() == 1;
1213 if ( nPosInLine
&& ( !bBeforePortion
) ) // before the next portion
1214 bWasBehind
= TRUE
; // step one back, otherwise visual will be unusable when rtl portion follows.
1216 USHORT nPortionStart
;
1217 USHORT nTextPortion
= pParaPortion
->GetTextPortions().FindPortion( aPaM
.GetIndex(), nPortionStart
, bBeforePortion
);
1218 TextPortion
* pTextPortion
= pParaPortion
->GetTextPortions().GetObject( nTextPortion
);
1219 BOOL bRTLPortion
= (pTextPortion
->GetRightToLeft() % 2) != 0;
1221 // -1: We are 'behind' the character
1222 long nVisPos
= (long)ubidi_getVisualIndex( pBidi
, bWasBehind
? nPosInLine
-1 : nPosInLine
, &nError
);
1223 if ( bVisualToLeft
)
1225 if ( !bWasBehind
|| bRTLPortion
)
1230 if ( bWasBehind
|| bRTLPortion
|| bBeforePortion
)
1232 // if ( bWasBehind && bRTLPortion )
1236 bGotoEndOfPrevLine
= nVisPos
< 0;
1237 bGotoStartOfNextLine
= nVisPos
>= aLine
.Len();
1239 if ( !bGotoEndOfPrevLine
&& !bGotoStartOfNextLine
)
1241 USHORT nLogPos
= (USHORT
)ubidi_getLogicalIndex( pBidi
, nVisPos
, &nError
);
1244 if ( nLogPos == aPaM.GetIndex() )
1246 if ( bVisualToLeft )
1247 bGotoEndOfPrevLine = TRUE;
1249 bGotoStartOfNextLine = TRUE;
1254 aPaM
.GetIndex() = pLine
->GetStart() + nLogPos
;
1256 // RTL portion, stay visually on the left side.
1257 USHORT _nPortionStart
;
1258 // USHORT nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), nPortionStart, !bRTLPortion );
1259 USHORT _nTextPortion
= pParaPortion
->GetTextPortions().FindPortion( aPaM
.GetIndex(), _nPortionStart
, TRUE
);
1260 TextPortion
* _pTextPortion
= pParaPortion
->GetTextPortions().GetObject( _nTextPortion
);
1261 if ( bVisualToLeft
&& !bRTLPortion
&& ( _pTextPortion
->GetRightToLeft() % 2 ) )
1263 else if ( !bVisualToLeft
&& bRTLPortion
&& ( bWasBehind
|| !(_pTextPortion
->GetRightToLeft() % 2 )) )
1266 pEditView
->pImpEditView
->SetCursorBidiLevel( _nPortionStart
);
1271 ubidi_close( pBidi
);
1273 if ( bGotoEndOfPrevLine
)
1275 aPaM
= CursorUp( aPaM
, pEditView
);
1277 aPaM
= CursorVisualStartEnd( pEditView
, aPaM
, FALSE
);
1279 else if ( bGotoStartOfNextLine
)
1281 aPaM
= CursorDown( aPaM
, pEditView
);
1283 aPaM
= CursorVisualStartEnd( pEditView
, aPaM
, TRUE
);
1290 EditPaM
ImpEditEngine::CursorLeft( const EditPaM
& rPaM
, USHORT nCharacterIteratorMode
)
1292 EditPaM
aCurPaM( rPaM
);
1293 EditPaM
aNewPaM( aCurPaM
);
1295 if ( aCurPaM
.GetIndex() )
1297 sal_Int32 nCount
= 1;
1298 uno::Reference
< i18n::XBreakIterator
> _xBI( ImplGetBreakIterator() );
1299 aNewPaM
.SetIndex( (USHORT
)_xBI
->previousCharacters( *aNewPaM
.GetNode(), aNewPaM
.GetIndex(), GetLocale( aNewPaM
), nCharacterIteratorMode
, nCount
, nCount
) );
1303 ContentNode
* pNode
= aCurPaM
.GetNode();
1304 pNode
= GetPrevVisNode( pNode
);
1307 aNewPaM
.SetNode( pNode
);
1308 aNewPaM
.SetIndex( pNode
->Len() );
1315 EditPaM
ImpEditEngine::CursorRight( const EditPaM
& rPaM
, USHORT nCharacterIteratorMode
)
1317 EditPaM
aCurPaM( rPaM
);
1318 EditPaM
aNewPaM( aCurPaM
);
1320 if ( aCurPaM
.GetIndex() < aCurPaM
.GetNode()->Len() )
1322 uno::Reference
< i18n::XBreakIterator
> _xBI( ImplGetBreakIterator() );
1323 sal_Int32 nCount
= 1;
1324 aNewPaM
.SetIndex( (USHORT
)_xBI
->nextCharacters( *aNewPaM
.GetNode(), aNewPaM
.GetIndex(), GetLocale( aNewPaM
), nCharacterIteratorMode
, nCount
, nCount
) );
1328 ContentNode
* pNode
= aCurPaM
.GetNode();
1329 pNode
= GetNextVisNode( pNode
);
1332 aNewPaM
.SetNode( pNode
);
1333 aNewPaM
.SetIndex( 0 );
1340 EditPaM
ImpEditEngine::CursorUp( const EditPaM
& rPaM
, EditView
* pView
)
1342 DBG_ASSERT( pView
, "Keine View - Keine Cursorbewegung!" );
1344 ParaPortion
* pPPortion
= FindParaPortion( rPaM
.GetNode() );
1345 DBG_ASSERT( pPPortion
, "Keine passende Portion gefunden: CursorUp" );
1346 USHORT nLine
= pPPortion
->GetLineNumber( rPaM
.GetIndex() );
1347 EditLine
* pLine
= pPPortion
->GetLines().GetObject( nLine
);
1350 if ( pView
->pImpEditView
->nTravelXPos
== TRAVEL_X_DONTKNOW
)
1352 nX
= GetXPos( pPPortion
, pLine
, rPaM
.GetIndex() );
1353 pView
->pImpEditView
->nTravelXPos
= nX
+nOnePixelInRef
;
1356 nX
= pView
->pImpEditView
->nTravelXPos
;
1358 EditPaM
aNewPaM( rPaM
);
1359 if ( nLine
) // gleicher Absatz
1361 EditLine
* pPrevLine
= pPPortion
->GetLines().GetObject(nLine
-1);
1362 aNewPaM
.SetIndex( GetChar( pPPortion
, pPrevLine
, nX
) );
1363 // Wenn davor eine autom.Umgebrochene Zeile, und ich muss genau an das
1364 // Ende dieser Zeile, landet der Cursor in der aktuellen Zeile am Anfang
1365 // Siehe Problem: Letztes Zeichen einer autom.umgebr. Zeile = Cursor
1366 if ( aNewPaM
.GetIndex() && ( aNewPaM
.GetIndex() == pLine
->GetStart() ) )
1367 aNewPaM
= CursorLeft( aNewPaM
);
1369 else // vorheriger Absatz
1371 ParaPortion
* pPrevPortion
= GetPrevVisPortion( pPPortion
);
1374 pLine
= pPrevPortion
->GetLines().GetObject( pPrevPortion
->GetLines().Count()-1 );
1375 DBG_ASSERT( pLine
, "Zeile davor nicht gefunden: CursorUp" );
1376 aNewPaM
.SetNode( pPrevPortion
->GetNode() );
1377 aNewPaM
.SetIndex( GetChar( pPrevPortion
, pLine
, nX
+nOnePixelInRef
) );
1384 EditPaM
ImpEditEngine::CursorDown( const EditPaM
& rPaM
, EditView
* pView
)
1386 DBG_ASSERT( pView
, "Keine View - Keine Cursorbewegung!" );
1388 ParaPortion
* pPPortion
= FindParaPortion( rPaM
.GetNode() );
1389 DBG_ASSERT( pPPortion
, "Keine passende Portion gefunden: CursorDown" );
1390 USHORT nLine
= pPPortion
->GetLineNumber( rPaM
.GetIndex() );
1393 if ( pView
->pImpEditView
->nTravelXPos
== TRAVEL_X_DONTKNOW
)
1395 EditLine
* pLine
= pPPortion
->GetLines().GetObject(nLine
);
1396 nX
= GetXPos( pPPortion
, pLine
, rPaM
.GetIndex() );
1397 pView
->pImpEditView
->nTravelXPos
= nX
+nOnePixelInRef
;
1400 nX
= pView
->pImpEditView
->nTravelXPos
;
1402 EditPaM
aNewPaM( rPaM
);
1403 if ( nLine
< pPPortion
->GetLines().Count()-1 )
1405 EditLine
* pNextLine
= pPPortion
->GetLines().GetObject(nLine
+1);
1406 aNewPaM
.SetIndex( GetChar( pPPortion
, pNextLine
, nX
) );
1407 // Sonderbehandlung siehe CursorUp...
1408 if ( ( aNewPaM
.GetIndex() == pNextLine
->GetEnd() ) && ( aNewPaM
.GetIndex() > pNextLine
->GetStart() ) && ( aNewPaM
.GetIndex() < pPPortion
->GetNode()->Len() ) )
1409 aNewPaM
= CursorLeft( aNewPaM
);
1411 else // naechster Absatz
1413 ParaPortion
* pNextPortion
= GetNextVisPortion( pPPortion
);
1416 EditLine
* pLine
= pNextPortion
->GetLines().GetObject(0);
1417 DBG_ASSERT( pLine
, "Zeile davor nicht gefunden: CursorUp" );
1418 aNewPaM
.SetNode( pNextPortion
->GetNode() );
1419 // Nie ganz ans Ende wenn mehrere Zeilen, da dann eine
1420 // Zeile darunter der Cursor angezeigt wird.
1421 aNewPaM
.SetIndex( GetChar( pNextPortion
, pLine
, nX
+nOnePixelInRef
) );
1422 if ( ( aNewPaM
.GetIndex() == pLine
->GetEnd() ) && ( aNewPaM
.GetIndex() > pLine
->GetStart() ) && ( pNextPortion
->GetLines().Count() > 1 ) )
1423 aNewPaM
= CursorLeft( aNewPaM
);
1430 EditPaM
ImpEditEngine::CursorStartOfLine( const EditPaM
& rPaM
)
1432 ParaPortion
* pCurPortion
= FindParaPortion( rPaM
.GetNode() );
1433 DBG_ASSERT( pCurPortion
, "Keine Portion fuer den PaM ?" );
1434 USHORT nLine
= pCurPortion
->GetLineNumber( rPaM
.GetIndex() );
1435 EditLine
* pLine
= pCurPortion
->GetLines().GetObject(nLine
);
1436 DBG_ASSERT( pLine
, "Aktuelle Zeile nicht gefunden ?!" );
1438 EditPaM
aNewPaM( rPaM
);
1439 aNewPaM
.SetIndex( pLine
->GetStart() );
1443 EditPaM
ImpEditEngine::CursorEndOfLine( const EditPaM
& rPaM
)
1445 ParaPortion
* pCurPortion
= FindParaPortion( rPaM
.GetNode() );
1446 DBG_ASSERT( pCurPortion
, "Keine Portion fuer den PaM ?" );
1447 USHORT nLine
= pCurPortion
->GetLineNumber( rPaM
.GetIndex() );
1448 EditLine
* pLine
= pCurPortion
->GetLines().GetObject(nLine
);
1449 DBG_ASSERT( pLine
, "Aktuelle Zeile nicht gefunden ?!" );
1451 EditPaM
aNewPaM( rPaM
);
1452 aNewPaM
.SetIndex( pLine
->GetEnd() );
1453 if ( pLine
->GetEnd() > pLine
->GetStart() )
1455 // xub_Unicode cLastChar = aNewPaM.GetNode()->GetChar( aNewPaM.GetIndex()-1 );
1456 if ( aNewPaM
.GetNode()->IsFeature( aNewPaM
.GetIndex() - 1 ) )
1458 // Bei einem weichen Umbruch muss ich davor stehen!
1459 EditCharAttrib
* pNextFeature
= aNewPaM
.GetNode()->GetCharAttribs().FindFeature( aNewPaM
.GetIndex()-1 );
1460 if ( pNextFeature
&& ( pNextFeature
->GetItem()->Which() == EE_FEATURE_LINEBR
) )
1461 aNewPaM
= CursorLeft( aNewPaM
);
1463 else if ( ( aNewPaM
.GetNode()->GetChar( aNewPaM
.GetIndex() - 1 ) == ' ' ) && ( aNewPaM
.GetIndex() != aNewPaM
.GetNode()->Len() ) )
1465 // Bei einem Blank in einer autom. umgebrochenen Zeile macht es Sinn,
1466 // davor zu stehen, da der Anwender hinter das Wort will.
1467 // Wenn diese geaendert wird, Sonderbehandlung fuer Pos1 nach End!
1468 aNewPaM
= CursorLeft( aNewPaM
);
1474 EditPaM
ImpEditEngine::CursorStartOfParagraph( const EditPaM
& rPaM
)
1476 EditPaM
aPaM( rPaM
.GetNode(), 0 );
1480 EditPaM
ImpEditEngine::CursorEndOfParagraph( const EditPaM
& rPaM
)
1482 EditPaM
aPaM( rPaM
.GetNode(), rPaM
.GetNode()->Len() );
1486 EditPaM
ImpEditEngine::CursorStartOfDoc()
1488 EditPaM
aPaM( aEditDoc
.SaveGetObject( 0 ), 0 );
1492 EditPaM
ImpEditEngine::CursorEndOfDoc()
1494 ContentNode
* pLastNode
= aEditDoc
.SaveGetObject( aEditDoc
.Count()-1 );
1495 ParaPortion
* pLastPortion
= GetParaPortions().SaveGetObject( aEditDoc
.Count()-1 );
1496 DBG_ASSERT( pLastNode
&& pLastPortion
, "CursorEndOfDoc: Node oder Portion nicht gefunden" );
1498 if ( !pLastPortion
->IsVisible() )
1500 pLastNode
= GetPrevVisNode( pLastPortion
->GetNode() );
1501 DBG_ASSERT( pLastNode
, "Kein sichtbarer Absatz?" );
1503 pLastNode
= aEditDoc
.SaveGetObject( aEditDoc
.Count()-1 );
1506 EditPaM
aPaM( pLastNode
, pLastNode
->Len() );
1510 EditPaM
ImpEditEngine::PageUp( const EditPaM
& rPaM
, EditView
* pView
)
1512 Rectangle aRec
= PaMtoEditCursor( rPaM
);
1513 Point aTopLeft
= aRec
.TopLeft();
1514 aTopLeft
.Y() -= pView
->GetVisArea().GetHeight() *9/10;
1515 aTopLeft
.X() += nOnePixelInRef
;
1516 if ( aTopLeft
.Y() < 0 )
1520 return GetPaM( aTopLeft
);
1523 EditPaM
ImpEditEngine::PageDown( const EditPaM
& rPaM
, EditView
* pView
)
1525 Rectangle aRec
= PaMtoEditCursor( rPaM
);
1526 Point aBottomRight
= aRec
.BottomRight();
1527 aBottomRight
.Y() += pView
->GetVisArea().GetHeight() *9/10;
1528 aBottomRight
.X() += nOnePixelInRef
;
1529 long nHeight
= GetTextHeight();
1530 if ( aBottomRight
.Y() > nHeight
)
1532 aBottomRight
.Y() = nHeight
-2;
1534 return GetPaM( aBottomRight
);
1537 EditPaM
ImpEditEngine::WordLeft( const EditPaM
& rPaM
, sal_Int16 nWordType
)
1539 USHORT nCurrentPos
= rPaM
.GetIndex();
1540 EditPaM
aNewPaM( rPaM
);
1541 if ( nCurrentPos
== 0 )
1543 // Vorheriger Absatz...
1544 USHORT nCurPara
= aEditDoc
.GetPos( aNewPaM
.GetNode() );
1545 ContentNode
* pPrevNode
= aEditDoc
.SaveGetObject( --nCurPara
);
1548 aNewPaM
.SetNode( pPrevNode
);
1549 aNewPaM
.SetIndex( pPrevNode
->Len() );
1554 // we need to increase the position by 1 when retrieving the locale
1555 // since the attribute for the char left to the cursor position is returned
1556 EditPaM
aTmpPaM( aNewPaM
);
1557 xub_StrLen nMax
= rPaM
.GetNode()->Len();
1558 if ( aTmpPaM
.GetIndex() < nMax
)
1559 aTmpPaM
.SetIndex( aTmpPaM
.GetIndex() + 1 );
1560 lang::Locale
aLocale( GetLocale( aTmpPaM
) );
1562 uno::Reference
< i18n::XBreakIterator
> _xBI( ImplGetBreakIterator() );
1563 i18n::Boundary aBoundary
= _xBI
->getWordBoundary( *aNewPaM
.GetNode(), nCurrentPos
, aLocale
, nWordType
, sal_True
);
1564 if ( aBoundary
.startPos
>= nCurrentPos
)
1565 aBoundary
= _xBI
->previousWord( *aNewPaM
.GetNode(), nCurrentPos
, aLocale
, nWordType
);
1566 aNewPaM
.SetIndex( ( aBoundary
.startPos
!= (-1) ) ? (USHORT
)aBoundary
.startPos
: 0 );
1572 EditPaM
ImpEditEngine::WordRight( const EditPaM
& rPaM
, sal_Int16 nWordType
)
1574 xub_StrLen nMax
= rPaM
.GetNode()->Len();
1575 EditPaM
aNewPaM( rPaM
);
1576 if ( aNewPaM
.GetIndex() < nMax
)
1578 // we need to increase the position by 1 when retrieving the locale
1579 // since the attribute for the char left to the cursor position is returned
1580 EditPaM
aTmpPaM( aNewPaM
);
1581 aTmpPaM
.SetIndex( aTmpPaM
.GetIndex() + 1 );
1582 lang::Locale
aLocale( GetLocale( aTmpPaM
) );
1584 uno::Reference
< i18n::XBreakIterator
> _xBI( ImplGetBreakIterator() );
1585 i18n::Boundary aBoundary
= _xBI
->nextWord( *aNewPaM
.GetNode(), aNewPaM
.GetIndex(), aLocale
, nWordType
);
1586 aNewPaM
.SetIndex( (USHORT
)aBoundary
.startPos
);
1588 // not 'else', maybe the index reached nMax now...
1589 if ( aNewPaM
.GetIndex() >= nMax
)
1591 // Naechster Absatz...
1592 USHORT nCurPara
= aEditDoc
.GetPos( aNewPaM
.GetNode() );
1593 ContentNode
* pNextNode
= aEditDoc
.SaveGetObject( ++nCurPara
);
1596 aNewPaM
.SetNode( pNextNode
);
1597 aNewPaM
.SetIndex( 0 );
1603 EditPaM
ImpEditEngine::StartOfWord( const EditPaM
& rPaM
, sal_Int16 nWordType
)
1605 EditPaM
aNewPaM( rPaM
);
1607 // we need to increase the position by 1 when retrieving the locale
1608 // since the attribute for the char left to the cursor position is returned
1609 EditPaM
aTmpPaM( aNewPaM
);
1610 xub_StrLen nMax
= rPaM
.GetNode()->Len();
1611 if ( aTmpPaM
.GetIndex() < nMax
)
1612 aTmpPaM
.SetIndex( aTmpPaM
.GetIndex() + 1 );
1613 lang::Locale
aLocale( GetLocale( aTmpPaM
) );
1615 uno::Reference
< i18n::XBreakIterator
> _xBI( ImplGetBreakIterator() );
1616 i18n::Boundary aBoundary
= _xBI
->getWordBoundary( *rPaM
.GetNode(), rPaM
.GetIndex(), aLocale
, nWordType
, sal_True
);
1617 aNewPaM
.SetIndex( (USHORT
)aBoundary
.startPos
);
1621 EditPaM
ImpEditEngine::EndOfWord( const EditPaM
& rPaM
, sal_Int16 nWordType
)
1623 EditPaM
aNewPaM( rPaM
);
1625 // we need to increase the position by 1 when retrieving the locale
1626 // since the attribute for the char left to the cursor position is returned
1627 EditPaM
aTmpPaM( aNewPaM
);
1628 xub_StrLen nMax
= rPaM
.GetNode()->Len();
1629 if ( aTmpPaM
.GetIndex() < nMax
)
1630 aTmpPaM
.SetIndex( aTmpPaM
.GetIndex() + 1 );
1631 lang::Locale
aLocale( GetLocale( aTmpPaM
) );
1633 uno::Reference
< i18n::XBreakIterator
> _xBI( ImplGetBreakIterator() );
1634 i18n::Boundary aBoundary
= _xBI
->getWordBoundary( *rPaM
.GetNode(), rPaM
.GetIndex(), aLocale
, nWordType
, sal_True
);
1635 aNewPaM
.SetIndex( (USHORT
)aBoundary
.endPos
);
1639 EditSelection
ImpEditEngine::SelectWord( const EditSelection
& rCurSel
, sal_Int16 nWordType
, BOOL bAcceptStartOfWord
)
1641 EditSelection
aNewSel( rCurSel
);
1642 EditPaM
aPaM( rCurSel
.Max() );
1644 // we need to increase the position by 1 when retrieving the locale
1645 // since the attribute for the char left to the cursor position is returned
1646 EditPaM
aTmpPaM( aPaM
);
1647 xub_StrLen nMax
= aPaM
.GetNode()->Len();
1648 if ( aTmpPaM
.GetIndex() < nMax
)
1649 aTmpPaM
.SetIndex( aTmpPaM
.GetIndex() + 1 );
1650 lang::Locale
aLocale( GetLocale( aTmpPaM
) );
1652 uno::Reference
< i18n::XBreakIterator
> _xBI( ImplGetBreakIterator() );
1653 sal_Int16 nType
= _xBI
->getWordType( *aPaM
.GetNode(), aPaM
.GetIndex(), aLocale
);
1654 if ( nType
== i18n::WordType::ANY_WORD
)
1656 i18n::Boundary aBoundary
= _xBI
->getWordBoundary( *aPaM
.GetNode(), aPaM
.GetIndex(), aLocale
, nWordType
, sal_True
);
1657 // don't select when curser at end of word
1658 if ( ( aBoundary
.endPos
> aPaM
.GetIndex() ) &&
1659 ( ( aBoundary
.startPos
< aPaM
.GetIndex() ) || ( bAcceptStartOfWord
&& ( aBoundary
.startPos
== aPaM
.GetIndex() ) ) ) )
1661 aNewSel
.Min().SetIndex( (USHORT
)aBoundary
.startPos
);
1662 aNewSel
.Max().SetIndex( (USHORT
)aBoundary
.endPos
);
1669 EditSelection
ImpEditEngine::SelectSentence( const EditSelection
& rCurSel
)
1671 uno::Reference
< i18n::XBreakIterator
> _xBI( ImplGetBreakIterator() );
1672 const EditPaM
& rPaM
= rCurSel
.Min();
1673 const ContentNode
* pNode
= rPaM
.GetNode();
1674 // #i50710# line breaks are marked with 0x01 - the break iterator prefers 0x0a for that
1675 String
sParagraph(*pNode
);
1676 sParagraph
.SearchAndReplaceAll(0x01,0x0a);
1677 //return Null if search starts at the beginning of the string
1678 long nStart
= rPaM
.GetIndex() ? _xBI
->beginOfSentence( sParagraph
, rPaM
.GetIndex(), GetLocale( rPaM
) ) : 0;
1680 long nEnd
= _xBI
->endOfSentence( *pNode
, rPaM
.GetIndex(), GetLocale( rPaM
) );
1681 EditSelection
aNewSel( rCurSel
);
1682 DBG_ASSERT(nStart
< pNode
->Len() && nEnd
<= pNode
->Len(), "sentence indices out of range");
1683 aNewSel
.Min().SetIndex( (USHORT
)nStart
);
1684 aNewSel
.Max().SetIndex( (USHORT
)nEnd
);
1688 sal_Bool
ImpEditEngine::IsInputSequenceCheckingRequired( sal_Unicode nChar
, const EditSelection
& rCurSel
) const
1690 uno::Reference
< i18n::XBreakIterator
> _xBI( ImplGetBreakIterator() );
1692 pCTLOptions
= new SvtCTLOptions
;
1694 // get the index that really is first
1695 USHORT nFirstPos
= rCurSel
.Min().GetIndex();
1696 USHORT nMaxPos
= rCurSel
.Max().GetIndex();
1697 if (nMaxPos
< nFirstPos
)
1698 nFirstPos
= nMaxPos
;
1700 sal_Bool bIsSequenceChecking
=
1701 pCTLOptions
->IsCTLFontEnabled() &&
1702 pCTLOptions
->IsCTLSequenceChecking() &&
1703 nFirstPos
!= 0 && /* first char needs not to be checked */
1704 _xBI
.is() && i18n::ScriptType::COMPLEX
== _xBI
->getScriptType( rtl::OUString( nChar
), 0 );
1706 return bIsSequenceChecking
;
1709 /*************************************************************************
1711 *************************************************************************/
1712 bool lcl_HasStrongLTR ( const String
& rTxt
, xub_StrLen nStart
, xub_StrLen nEnd
)
1714 for ( xub_StrLen nCharIdx
= nStart
; nCharIdx
< nEnd
; ++nCharIdx
)
1716 const UCharDirection nCharDir
= u_charDirection ( rTxt
.GetChar ( nCharIdx
));
1717 if ( nCharDir
== U_LEFT_TO_RIGHT
||
1718 nCharDir
== U_LEFT_TO_RIGHT_EMBEDDING
||
1719 nCharDir
== U_LEFT_TO_RIGHT_OVERRIDE
)
1727 void ImpEditEngine::InitScriptTypes( USHORT nPara
)
1729 ParaPortion
* pParaPortion
= GetParaPortions().SaveGetObject( nPara
);
1730 ScriptTypePosInfos
& rTypes
= pParaPortion
->aScriptInfos
;
1731 rTypes
.Remove( 0, rTypes
.Count() );
1733 // pParaPortion->aExtraCharInfos.Remove( 0, pParaPortion->aExtraCharInfos.Count() );
1735 ContentNode
* pNode
= pParaPortion
->GetNode();
1738 uno::Reference
< i18n::XBreakIterator
> _xBI( ImplGetBreakIterator() );
1740 String
aText( *pNode
);
1742 // To handle fields put the character from the field in the string,
1743 // because endOfScript( ... ) will skip the CH_FEATURE, because this is WEAK
1744 EditCharAttrib
* pField
= pNode
->GetCharAttribs().FindNextAttrib( EE_FEATURE_FIELD
, 0 );
1747 ::rtl::OUString
aFldText( ((EditCharAttribField
*)pField
)->GetFieldValue() );
1748 if ( aFldText
.getLength() )
1750 aText
.SetChar( pField
->GetStart(), aFldText
.getStr()[0] );
1751 short nFldScriptType
= _xBI
->getScriptType( aFldText
, 0 );
1753 for ( USHORT nCharInField
= 1; nCharInField
< aFldText
.getLength(); nCharInField
++ )
1755 short nTmpType
= _xBI
->getScriptType( aFldText
, nCharInField
);
1757 // First char from field wins...
1758 if ( nFldScriptType
== i18n::ScriptType::WEAK
)
1760 nFldScriptType
= nTmpType
;
1761 aText
.SetChar( pField
->GetStart(), aFldText
.getStr()[nCharInField
] );
1764 // ... but if the first one is LATIN, and there are CJK or CTL chars too,
1765 // we prefer that ScripType because we need an other font.
1766 if ( ( nTmpType
== i18n::ScriptType::ASIAN
) || ( nTmpType
== i18n::ScriptType::COMPLEX
) )
1768 aText
.SetChar( pField
->GetStart(), aFldText
.getStr()[nCharInField
] );
1773 // #112831# Last Field might go from 0xffff to 0x0000
1774 pField
= pField
->GetEnd() ? pNode
->GetCharAttribs().FindNextAttrib( EE_FEATURE_FIELD
, pField
->GetEnd() ) : NULL
;
1777 ::rtl::OUString
aOUText( aText
);
1778 USHORT nTextLen
= (USHORT
)aOUText
.getLength();
1781 short nScriptType
= _xBI
->getScriptType( aOUText
, nPos
);
1782 rTypes
.Insert( ScriptTypePosInfo( nScriptType
, (USHORT
)nPos
, nTextLen
), rTypes
.Count() );
1783 nPos
= _xBI
->endOfScript( aOUText
, nPos
, nScriptType
);
1784 while ( ( nPos
!= (-1) ) && ( nPos
< nTextLen
) )
1786 rTypes
[rTypes
.Count()-1].nEndPos
= (USHORT
)nPos
;
1788 nScriptType
= _xBI
->getScriptType( aOUText
, nPos
);
1789 long nEndPos
= _xBI
->endOfScript( aOUText
, nPos
, nScriptType
);
1791 if ( ( nScriptType
== i18n::ScriptType::WEAK
) || ( nScriptType
== rTypes
[rTypes
.Count()-1].nScriptType
) )
1793 // Expand last ScriptTypePosInfo, don't create weak or unecessary portions
1794 rTypes
[rTypes
.Count()-1].nEndPos
= (USHORT
)nEndPos
;
1798 if ( _xBI
->getScriptType( aOUText
, nPos
- 1 ) == i18n::ScriptType::WEAK
)
1800 switch ( u_charType(aOUText
.iterateCodePoints(&nPos
, 0) ) ) {
1801 case U_NON_SPACING_MARK
:
1802 case U_ENCLOSING_MARK
:
1803 case U_COMBINING_SPACING_MARK
:
1805 rTypes
[rTypes
.Count()-1].nEndPos
--;
1809 rTypes
.Insert( ScriptTypePosInfo( nScriptType
, (USHORT
)nPos
, nTextLen
), rTypes
.Count() );
1815 if ( rTypes
[0].nScriptType
== i18n::ScriptType::WEAK
)
1816 rTypes
[0].nScriptType
= ( rTypes
.Count() > 1 ) ? rTypes
[1].nScriptType
: GetI18NScriptTypeOfLanguage( GetDefaultLanguage() );
1818 // create writing direction information:
1819 if ( !pParaPortion
->aWritingDirectionInfos
.Count() )
1820 InitWritingDirections( nPara
);
1822 // i89825: Use CTL font for numbers embedded into an RTL run:
1823 WritingDirectionInfos
& rDirInfos
= pParaPortion
->aWritingDirectionInfos
;
1824 for ( USHORT n
= 0; n
< rDirInfos
.Count(); ++n
)
1826 const xub_StrLen nStart
= rDirInfos
[n
].nStartPos
;
1827 const xub_StrLen nEnd
= rDirInfos
[n
].nEndPos
;
1828 const BYTE nCurrDirType
= rDirInfos
[n
].nType
;
1830 if ( nCurrDirType
% 2 == UBIDI_RTL
|| // text in RTL run
1831 ( nCurrDirType
> UBIDI_LTR
&& !lcl_HasStrongLTR( aText
, nStart
, nEnd
) ) ) // non-strong text in embedded LTR run
1835 // Skip entries in ScriptArray which are not inside the RTL run:
1836 while ( nIdx
< rTypes
.Count() && rTypes
[nIdx
].nStartPos
< nStart
)
1839 // Remove any entries *inside* the current run:
1840 while ( nIdx
< rTypes
.Count() && rTypes
[nIdx
].nEndPos
<= nEnd
)
1841 rTypes
.Remove( nIdx
);
1844 if(nIdx
< rTypes
.Count() && rTypes
[nIdx
].nStartPos
< nStart
&& rTypes
[nIdx
].nEndPos
> nEnd
)
1846 rTypes
.Insert( ScriptTypePosInfo( rTypes
[nIdx
].nScriptType
, (USHORT
)nEnd
, rTypes
[nIdx
].nEndPos
), nIdx
);
1847 rTypes
[nIdx
].nEndPos
= nStart
;
1851 rTypes
[nIdx
- 1].nEndPos
= nStart
;
1853 rTypes
.Insert( ScriptTypePosInfo( i18n::ScriptType::COMPLEX
, (USHORT
)nStart
, (USHORT
)nEnd
), nIdx
);
1856 if( nIdx
< rTypes
.Count() )
1857 rTypes
[nIdx
].nStartPos
= nEnd
;
1861 #if OSL_DEBUG_LEVEL > 1
1862 USHORT nDebugStt
= 0;
1863 USHORT nDebugEnd
= 0;
1864 short nDebugType
= 0;
1865 for ( USHORT n
= 0; n
< rTypes
.Count(); ++n
)
1867 nDebugStt
= rTypes
[n
].nStartPos
;
1868 nDebugEnd
= rTypes
[n
].nEndPos
;
1869 nDebugType
= rTypes
[n
].nScriptType
;
1875 USHORT
ImpEditEngine::GetScriptType( const EditPaM
& rPaM
, USHORT
* pEndPos
) const
1877 USHORT nScriptType
= 0;
1880 *pEndPos
= rPaM
.GetNode()->Len();
1882 if ( rPaM
.GetNode()->Len() )
1884 USHORT nPara
= GetEditDoc().GetPos( rPaM
.GetNode() );
1885 ParaPortion
* pParaPortion
= GetParaPortions().SaveGetObject( nPara
);
1886 if ( !pParaPortion
->aScriptInfos
.Count() )
1887 ((ImpEditEngine
*)this)->InitScriptTypes( nPara
);
1889 ScriptTypePosInfos
& rTypes
= pParaPortion
->aScriptInfos
;
1890 USHORT nPos
= rPaM
.GetIndex();
1891 for ( USHORT n
= 0; n
< rTypes
.Count(); n
++ )
1893 if ( ( rTypes
[n
].nStartPos
<= nPos
) && ( rTypes
[n
].nEndPos
>= nPos
) )
1895 nScriptType
= rTypes
[n
].nScriptType
;
1897 *pEndPos
= rTypes
[n
].nEndPos
;
1902 return nScriptType
? nScriptType
: GetI18NScriptTypeOfLanguage( GetDefaultLanguage() );
1905 USHORT
ImpEditEngine::GetScriptType( const EditSelection
& rSel
) const
1907 EditSelection
aSel( rSel
);
1908 aSel
.Adjust( aEditDoc
);
1910 short nScriptType
= 0;
1912 USHORT nStartPara
= GetEditDoc().GetPos( aSel
.Min().GetNode() );
1913 USHORT nEndPara
= GetEditDoc().GetPos( aSel
.Max().GetNode() );
1915 for ( USHORT nPara
= nStartPara
; nPara
<= nEndPara
; nPara
++ )
1917 ParaPortion
* pParaPortion
= GetParaPortions().SaveGetObject( nPara
);
1918 if ( !pParaPortion
->aScriptInfos
.Count() )
1919 ((ImpEditEngine
*)this)->InitScriptTypes( nPara
);
1921 ScriptTypePosInfos
& rTypes
= pParaPortion
->aScriptInfos
;
1923 // find the first(!) script type position that holds the
1924 // complete selection. Thus it will work for selections as
1925 // well as with just moving the cursor from char to char.
1926 USHORT nS
= ( nPara
== nStartPara
) ? aSel
.Min().GetIndex() : 0;
1927 USHORT nE
= ( nPara
== nEndPara
) ? aSel
.Max().GetIndex() : pParaPortion
->GetNode()->Len();
1928 for ( USHORT n
= 0; n
< rTypes
.Count(); n
++ )
1930 if (rTypes
[n
].nStartPos
<= nS
&& nE
<= rTypes
[n
].nEndPos
)
1932 if ( rTypes
[n
].nScriptType
!= i18n::ScriptType::WEAK
)
1934 nScriptType
|= GetItemScriptType ( rTypes
[n
].nScriptType
);
1938 if ( !nScriptType
&& n
)
1940 // #93548# When starting with WEAK, use prev ScriptType...
1941 nScriptType
= rTypes
[n
-1].nScriptType
;
1948 return nScriptType
? nScriptType
: GetI18NScriptTypeOfLanguage( GetDefaultLanguage() );
1951 BOOL
ImpEditEngine::IsScriptChange( const EditPaM
& rPaM
) const
1953 BOOL bScriptChange
= FALSE
;
1955 if ( rPaM
.GetNode()->Len() )
1957 USHORT nPara
= GetEditDoc().GetPos( rPaM
.GetNode() );
1958 ParaPortion
* pParaPortion
= GetParaPortions().SaveGetObject( nPara
);
1959 if ( !pParaPortion
->aScriptInfos
.Count() )
1960 ((ImpEditEngine
*)this)->InitScriptTypes( nPara
);
1962 ScriptTypePosInfos
& rTypes
= pParaPortion
->aScriptInfos
;
1963 USHORT nPos
= rPaM
.GetIndex();
1964 for ( USHORT n
= 0; n
< rTypes
.Count(); n
++ )
1966 if ( rTypes
[n
].nStartPos
== nPos
)
1968 bScriptChange
= TRUE
;
1973 return bScriptChange
;
1976 BOOL
ImpEditEngine::HasScriptType( USHORT nPara
, USHORT nType
) const
1978 BOOL bTypeFound
= FALSE
;
1980 ParaPortion
* pParaPortion
= GetParaPortions().SaveGetObject( nPara
);
1981 if ( !pParaPortion
->aScriptInfos
.Count() )
1982 ((ImpEditEngine
*)this)->InitScriptTypes( nPara
);
1984 ScriptTypePosInfos
& rTypes
= pParaPortion
->aScriptInfos
;
1985 for ( USHORT n
= rTypes
.Count(); n
&& !bTypeFound
; )
1987 if ( rTypes
[--n
].nScriptType
== nType
)
1993 void ImpEditEngine::InitWritingDirections( USHORT nPara
)
1995 ParaPortion
* pParaPortion
= GetParaPortions().SaveGetObject( nPara
);
1996 WritingDirectionInfos
& rInfos
= pParaPortion
->aWritingDirectionInfos
;
1997 rInfos
.Remove( 0, rInfos
.Count() );
2000 ScriptTypePosInfos
& rTypes
= pParaPortion
->aScriptInfos
;
2001 for ( USHORT n
= 0; n
< rTypes
.Count(); n
++ )
2003 if ( rTypes
[n
].nScriptType
== i18n::ScriptType::COMPLEX
)
2010 const UBiDiLevel nBidiLevel
= IsRightToLeft( nPara
) ? 1 /*RTL*/ : 0 /*LTR*/;
2011 if ( ( bCTL
|| ( nBidiLevel
== 1 /*RTL*/ ) ) && pParaPortion
->GetNode()->Len() )
2014 String
aText( *pParaPortion
->GetNode() );
2017 // Bidi functions from icu 2.0
2019 UErrorCode nError
= U_ZERO_ERROR
;
2020 UBiDi
* pBidi
= ubidi_openSized( aText
.Len(), 0, &nError
);
2021 nError
= U_ZERO_ERROR
;
2023 ubidi_setPara( pBidi
, reinterpret_cast<const UChar
*>(aText
.GetBuffer()), aText
.Len(), nBidiLevel
, NULL
, &nError
); // UChar != sal_Unicode in MinGW
2024 nError
= U_ZERO_ERROR
;
2026 long nCount
= ubidi_countRuns( pBidi
, &nError
);
2030 UBiDiLevel nCurrDir
;
2032 for ( USHORT nIdx
= 0; nIdx
< nCount
; ++nIdx
)
2034 ubidi_getLogicalRun( pBidi
, nStart
, &nEnd
, &nCurrDir
);
2035 rInfos
.Insert( WritingDirectionInfo( nCurrDir
, (USHORT
)nStart
, (USHORT
)nEnd
), rInfos
.Count() );
2039 ubidi_close( pBidi
);
2042 // No infos mean no CTL and default dir is L2R...
2043 if ( !rInfos
.Count() )
2044 rInfos
.Insert( WritingDirectionInfo( 0, 0, (USHORT
)pParaPortion
->GetNode()->Len() ), rInfos
.Count() );
2048 BOOL
ImpEditEngine::IsRightToLeft( USHORT nPara
) const
2051 const SvxFrameDirectionItem
* pFrameDirItem
= NULL
;
2053 if ( !IsVertical() )
2055 bR2L
= GetDefaultHorizontalTextDirection() == EE_HTEXTDIR_R2L
;
2056 pFrameDirItem
= &(const SvxFrameDirectionItem
&)GetParaAttrib( nPara
, EE_PARA_WRITINGDIR
);
2057 if ( pFrameDirItem
->GetValue() == FRMDIR_ENVIRONMENT
)
2059 // #103045# if DefaultHorizontalTextDirection is set, use that value, otherwise pool default.
2060 if ( GetDefaultHorizontalTextDirection() != EE_HTEXTDIR_DEFAULT
)
2062 pFrameDirItem
= NULL
; // bR2L allready set to default horizontal text direction
2067 pFrameDirItem
= &(const SvxFrameDirectionItem
&)((ImpEditEngine
*)this)->GetEmptyItemSet().Get( EE_PARA_WRITINGDIR
);
2072 if ( pFrameDirItem
)
2073 bR2L
= pFrameDirItem
->GetValue() == FRMDIR_HORI_RIGHT_TOP
;
2078 BOOL
ImpEditEngine::HasDifferentRTLLevels( const ContentNode
* pNode
)
2080 USHORT nPara
= GetEditDoc().GetPos( (ContentNode
*)pNode
);
2081 ParaPortion
* pParaPortion
= GetParaPortions().SaveGetObject( nPara
);
2083 BOOL bHasDifferentRTLLevels
= FALSE
;
2085 USHORT nRTLLevel
= IsRightToLeft( nPara
) ? 1 : 0;
2086 for ( USHORT n
= 0; n
< pParaPortion
->GetTextPortions().Count(); n
++ )
2088 TextPortion
* pTextPortion
= pParaPortion
->GetTextPortions().GetObject( n
);
2089 if ( pTextPortion
->GetRightToLeft() != nRTLLevel
)
2091 bHasDifferentRTLLevels
= TRUE
;
2095 return bHasDifferentRTLLevels
;
2099 BYTE
ImpEditEngine::GetRightToLeft( USHORT nPara
, USHORT nPos
, USHORT
* pStart
, USHORT
* pEnd
)
2101 // BYTE nRightToLeft = IsRightToLeft( nPara ) ? 1 : 0;
2102 BYTE nRightToLeft
= 0;
2104 ContentNode
* pNode
= aEditDoc
.SaveGetObject( nPara
);
2105 if ( pNode
&& pNode
->Len() )
2107 ParaPortion
* pParaPortion
= GetParaPortions().SaveGetObject( nPara
);
2108 if ( !pParaPortion
->aWritingDirectionInfos
.Count() )
2109 InitWritingDirections( nPara
);
2112 WritingDirectionInfos
& rDirInfos
= pParaPortion
->aWritingDirectionInfos
;
2113 for ( USHORT n
= 0; n
< rDirInfos
.Count(); n
++ )
2115 if ( ( rDirInfos
[n
].nStartPos
<= nPos
) && ( rDirInfos
[n
].nEndPos
>= nPos
) )
2117 nRightToLeft
= rDirInfos
[n
].nType
;
2119 *pStart
= rDirInfos
[n
].nStartPos
;
2121 *pEnd
= rDirInfos
[n
].nEndPos
;
2126 return nRightToLeft
;
2129 SvxAdjust
ImpEditEngine::GetJustification( USHORT nPara
) const
2131 SvxAdjust eJustification
= SVX_ADJUST_LEFT
;
2133 if ( !aStatus
.IsOutliner() )
2135 eJustification
= ((const SvxAdjustItem
&) GetParaAttrib( nPara
, EE_PARA_JUST
)).GetAdjust();
2137 if ( IsRightToLeft( nPara
) )
2139 if ( eJustification
== SVX_ADJUST_LEFT
)
2140 eJustification
= SVX_ADJUST_RIGHT
;
2141 else if ( eJustification
== SVX_ADJUST_RIGHT
)
2142 eJustification
= SVX_ADJUST_LEFT
;
2145 return eJustification
;
2149 // ----------------------------------------------------------------------
2151 // ----------------------------------------------------------------------
2153 void ImpEditEngine::ImpRemoveChars( const EditPaM
& rPaM
, USHORT nChars
, EditUndoRemoveChars
* pCurUndo
)
2155 if ( IsUndoEnabled() && !IsInUndo() )
2157 XubString
aStr( rPaM
.GetNode()->Copy( rPaM
.GetIndex(), nChars
) );
2159 // Pruefen, ob Attribute geloescht oder geaendert werden:
2160 USHORT nStart
= rPaM
.GetIndex();
2161 USHORT nEnd
= nStart
+ nChars
;
2162 CharAttribArray
& rAttribs
= rPaM
.GetNode()->GetCharAttribs().GetAttribs();
2163 // USHORT nAttrs = rAttribs.Count();
2164 for ( USHORT nAttr
= 0; nAttr
< rAttribs
.Count(); nAttr
++ )
2166 EditCharAttrib
* pAttr
= rAttribs
[nAttr
];
2167 if ( ( pAttr
->GetEnd() >= nStart
) && ( pAttr
->GetStart() < nEnd
) )
2170 EditSelection
aSel( rPaM
);
2171 aSel
.Max().GetIndex() = aSel
.Max().GetIndex() + nChars
;
2172 EditUndoSetAttribs
* pAttrUndo
= CreateAttribUndo( aSel
, GetEmptyItemSet() );
2173 InsertUndo( pAttrUndo
);
2178 if ( pCurUndo
&& ( CreateEditPaM( pCurUndo
->GetEPaM() ) == rPaM
) )
2179 pCurUndo
->GetStr() += aStr
;
2182 InsertUndo( new EditUndoRemoveChars( this, CreateEPaM( rPaM
), aStr
) );
2186 aEditDoc
.RemoveChars( rPaM
, nChars
);
2190 EditSelection
ImpEditEngine::ImpMoveParagraphs( Range aOldPositions
, USHORT nNewPos
)
2192 aOldPositions
.Justify();
2193 BOOL bValidAction
= ( (long)nNewPos
< aOldPositions
.Min() ) || ( (long)nNewPos
> aOldPositions
.Max() );
2194 DBG_ASSERT( bValidAction
, "Move in sich selbst ?" );
2195 DBG_ASSERT( aOldPositions
.Max() <= (long)GetParaPortions().Count(), "Voll drueber weg: MoveParagraphs" );
2197 EditSelection aSelection
;
2199 if ( !bValidAction
)
2201 aSelection
= aEditDoc
.GetStartPaM();
2205 ULONG nParaCount
= GetParaPortions().Count();
2207 if ( nNewPos
>= nParaCount
)
2208 nNewPos
= GetParaPortions().Count();
2210 // Height may change when moving first or last Paragraph
2211 ParaPortion
* pRecalc1
= NULL
;
2212 ParaPortion
* pRecalc2
= NULL
;
2213 ParaPortion
* pRecalc3
= NULL
;
2214 ParaPortion
* pRecalc4
= NULL
;
2216 if ( nNewPos
== 0 ) // Move to Start
2218 pRecalc1
= GetParaPortions().GetObject( 0 );
2219 pRecalc2
= GetParaPortions().GetObject( (USHORT
)aOldPositions
.Min() );
2222 else if ( nNewPos
== nParaCount
)
2224 pRecalc1
= GetParaPortions().GetObject( (USHORT
)(nParaCount
-1) );
2225 pRecalc2
= GetParaPortions().GetObject( (USHORT
)aOldPositions
.Max() );
2228 if ( aOldPositions
.Min() == 0 ) // Move from Start
2230 pRecalc3
= GetParaPortions().GetObject( 0 );
2231 pRecalc4
= GetParaPortions().GetObject(
2232 sal::static_int_cast
< USHORT
>( aOldPositions
.Max()+1 ) );
2234 else if ( (USHORT
)aOldPositions
.Max() == (nParaCount
-1) )
2236 pRecalc3
= GetParaPortions().GetObject( (USHORT
)aOldPositions
.Max() );
2237 pRecalc4
= GetParaPortions().GetObject( (USHORT
)(aOldPositions
.Min()-1) );
2240 MoveParagraphsInfo
aMoveParagraphsInfo( sal::static_int_cast
< USHORT
>(aOldPositions
.Min()), sal::static_int_cast
< USHORT
>(aOldPositions
.Max()), nNewPos
);
2241 aBeginMovingParagraphsHdl
.Call( &aMoveParagraphsInfo
);
2243 if ( IsUndoEnabled() && !IsInUndo())
2244 InsertUndo( new EditUndoMoveParagraphs( this, aOldPositions
, nNewPos
) );
2246 // Position nicht aus dem Auge verlieren!
2247 ParaPortion
* pDestPortion
= GetParaPortions().SaveGetObject( nNewPos
);
2249 ParaPortionList aTmpPortionList
;
2251 for ( i
= (USHORT
)aOldPositions
.Min(); i
<= (USHORT
)aOldPositions
.Max(); i
++ )
2253 // Immer aOldPositions.Min(), da Remove().
2254 ParaPortion
* pTmpPortion
= GetParaPortions().GetObject( (USHORT
)aOldPositions
.Min() );
2255 GetParaPortions().Remove( (USHORT
)aOldPositions
.Min() );
2256 aEditDoc
.Remove( (USHORT
)aOldPositions
.Min() );
2257 aTmpPortionList
.Insert( pTmpPortion
, aTmpPortionList
.Count() );
2260 USHORT nRealNewPos
= pDestPortion
? GetParaPortions().GetPos( pDestPortion
) : GetParaPortions().Count();
2261 DBG_ASSERT( nRealNewPos
!= USHRT_MAX
, "ImpMoveParagraphs: Ungueltige Position!" );
2263 for ( i
= 0; i
< (USHORT
)aTmpPortionList
.Count(); i
++ )
2265 ParaPortion
* pTmpPortion
= aTmpPortionList
.GetObject( i
);
2267 aSelection
.Min().SetNode( pTmpPortion
->GetNode() );
2269 aSelection
.Max().SetNode( pTmpPortion
->GetNode() );
2270 aSelection
.Max().SetIndex( pTmpPortion
->GetNode()->Len() );
2272 ContentNode
* pN
= pTmpPortion
->GetNode();
2273 aEditDoc
.Insert( pN
, nRealNewPos
+i
);
2275 GetParaPortions().Insert( pTmpPortion
, nRealNewPos
+i
);
2278 aEndMovingParagraphsHdl
.Call( &aMoveParagraphsInfo
);
2280 if ( GetNotifyHdl().IsSet() )
2282 EENotify
aNotify( EE_NOTIFY_PARAGRAPHSMOVED
);
2283 aNotify
.pEditEngine
= GetEditEnginePtr();
2284 aNotify
.nParagraph
= nNewPos
;
2285 aNotify
.nParam1
= sal::static_int_cast
< USHORT
>(aOldPositions
.Min());
2286 aNotify
.nParam2
= sal::static_int_cast
< USHORT
>(aOldPositions
.Max());
2287 CallNotify( aNotify
);
2290 aEditDoc
.SetModified( TRUE
);
2293 CalcHeight( pRecalc1
);
2295 CalcHeight( pRecalc2
);
2297 CalcHeight( pRecalc3
);
2299 CalcHeight( pRecalc4
);
2301 aTmpPortionList
.Remove( 0, aTmpPortionList
.Count() ); // wichtig !
2304 GetParaPortions().DbgCheck(aEditDoc
);
2310 EditPaM
ImpEditEngine::ImpConnectParagraphs( ContentNode
* pLeft
, ContentNode
* pRight
, BOOL bBackward
)
2312 DBG_ASSERT( pLeft
!= pRight
, "Den gleichen Absatz zusammenfuegen ?" );
2313 DBG_ASSERT( aEditDoc
.GetPos( pLeft
) != USHRT_MAX
, "Einzufuegenden Node nicht gefunden(1)" );
2314 DBG_ASSERT( aEditDoc
.GetPos( pRight
) != USHRT_MAX
, "Einzufuegenden Node nicht gefunden(2)" );
2316 USHORT nParagraphTobeDeleted
= aEditDoc
.GetPos( pRight
);
2317 DeletedNodeInfo
* pInf
= new DeletedNodeInfo( (ULONG
)pRight
, nParagraphTobeDeleted
);
2318 aDeletedNodes
.Insert( pInf
, aDeletedNodes
.Count() );
2320 GetEditEnginePtr()->ParagraphConnected( aEditDoc
.GetPos( pLeft
), aEditDoc
.GetPos( pRight
) );
2323 if ( IsUndoEnabled() && !IsInUndo() )
2325 InsertUndo( new EditUndoConnectParas( this,
2326 aEditDoc
.GetPos( pLeft
), pLeft
->Len(),
2327 pLeft
->GetContentAttribs().GetItems(), pRight
->GetContentAttribs().GetItems(),
2328 pLeft
->GetStyleSheet(), pRight
->GetStyleSheet(), bBackward
) );
2334 pLeft
->SetStyleSheet( pRight
->GetStyleSheet(), TRUE
);
2335 pLeft
->GetContentAttribs().GetItems().Set( pRight
->GetContentAttribs().GetItems() );
2336 pLeft
->GetCharAttribs().GetDefFont() = pRight
->GetCharAttribs().GetDefFont();
2339 ParaAttribsChanged( pLeft
);
2341 // Erstmal Portions suchen, da pRight nach ConnectParagraphs weg.
2342 ParaPortion
* pLeftPortion
= FindParaPortion( pLeft
);
2343 ParaPortion
* pRightPortion
= FindParaPortion( pRight
);
2344 DBG_ASSERT( pLeftPortion
, "Blinde Portion in ImpConnectParagraphs(1)" );
2345 DBG_ASSERT( pRightPortion
, "Blinde Portion in ImpConnectParagraphs(2)" );
2346 DBG_ASSERT( nParagraphTobeDeleted
== GetParaPortions().GetPos( pRightPortion
), "NodePos != PortionPos?" );
2349 if ( GetStatus().DoOnlineSpelling() )
2351 xub_StrLen nEnd
= pLeft
->Len();
2352 xub_StrLen nInv
= nEnd
? nEnd
-1 : nEnd
;
2353 pLeft
->GetWrongList()->ClearWrongs( nInv
, 0xFFFF, pLeft
); // Evtl. einen wegnehmen
2354 pLeft
->GetWrongList()->MarkInvalid( nInv
, nEnd
+1 );
2355 // Falschgeschriebene Woerter ruebernehmen:
2356 USHORT nRWrongs
= pRight
->GetWrongList()->Count();
2357 for ( USHORT nW
= 0; nW
< nRWrongs
; nW
++ )
2359 WrongRange aWrong
= pRight
->GetWrongList()->GetObject( nW
);
2360 if ( aWrong
.nStart
!= 0 ) // Nicht ein anschliessender
2362 aWrong
.nStart
= aWrong
.nStart
+ nEnd
;
2363 aWrong
.nEnd
= aWrong
.nEnd
+ nEnd
;
2364 pLeft
->GetWrongList()->InsertWrong( aWrong
, pLeft
->GetWrongList()->Count() );
2370 if ( IsCallParaInsertedOrDeleted() )
2371 GetEditEnginePtr()->ParagraphDeleted( nParagraphTobeDeleted
);
2373 EditPaM aPaM
= aEditDoc
.ConnectParagraphs( pLeft
, pRight
);
2374 GetParaPortions().Remove( nParagraphTobeDeleted
);
2375 delete pRightPortion
;
2377 pLeftPortion
->MarkSelectionInvalid( aPaM
.GetIndex(), pLeft
->Len() );
2379 // der rechte Node wird von EditDoc::ConnectParagraphs() geloescht.
2381 if ( GetTextRanger() )
2383 // Durch das zusammenfuegen wird der linke zwar neu formatiert, aber
2384 // wenn sich dessen Hoehe nicht aendert bekommt die Formatierung die
2385 // Aenderung der Gesaamthoehe des Textes zu spaet mit...
2386 for ( USHORT n
= nParagraphTobeDeleted
; n
< GetParaPortions().Count(); n
++ )
2388 ParaPortion
* pPP
= GetParaPortions().GetObject( n
);
2389 pPP
->MarkSelectionInvalid( 0, pPP
->GetNode()->Len() );
2390 pPP
->GetLines().Reset();
2399 EditPaM
ImpEditEngine::DeleteLeftOrRight( const EditSelection
& rSel
, BYTE nMode
, BYTE nDelMode
)
2401 DBG_ASSERT( !EditSelection( rSel
).DbgIsBuggy( aEditDoc
), "Index im Wald in DeleteLeftOrRight" );
2403 if ( rSel
.HasRange() ) // dann nur Sel. loeschen
2404 return ImpDeleteSelection( rSel
);
2406 const EditPaM
aCurPos( rSel
.Max() );
2407 EditPaM
aDelStart( aCurPos
);
2408 EditPaM
aDelEnd( aCurPos
);
2409 if ( nMode
== DEL_LEFT
)
2411 if ( nDelMode
== DELMODE_SIMPLE
)
2413 aDelStart
= CursorLeft( aCurPos
, i18n::CharacterIteratorMode::SKIPCHARACTER
);
2415 else if ( nDelMode
== DELMODE_RESTOFWORD
)
2417 aDelStart
= StartOfWord( aCurPos
);
2418 if ( aDelStart
.GetIndex() == aCurPos
.GetIndex() )
2419 aDelStart
= WordLeft( aCurPos
);
2421 else // DELMODE_RESTOFCONTENT
2423 aDelStart
.SetIndex( 0 );
2424 if ( aDelStart
== aCurPos
)
2426 // kompletter Absatz davor
2427 ContentNode
* pPrev
= GetPrevVisNode( aCurPos
.GetNode() );
2429 aDelStart
= EditPaM( pPrev
, 0 );
2435 if ( nDelMode
== DELMODE_SIMPLE
)
2437 aDelEnd
= CursorRight( aCurPos
);
2439 else if ( nDelMode
== DELMODE_RESTOFWORD
)
2441 aDelEnd
= EndOfWord( aCurPos
);
2442 if (aDelEnd
.GetIndex() == aCurPos
.GetIndex())
2444 xub_StrLen nLen
= aCurPos
.GetNode()->Len();
2446 if (aDelEnd
.GetIndex() == nLen
)
2447 aDelEnd
= WordLeft( aCurPos
);
2448 else // there's still sth to delete on the right
2450 aDelEnd
= EndOfWord( WordRight( aCurPos
) );
2451 // if there'n no next word...
2452 if (aDelEnd
.GetIndex() == nLen
)
2453 aDelEnd
.SetIndex( nLen
);
2457 else // DELMODE_RESTOFCONTENT
2459 aDelEnd
.SetIndex( aCurPos
.GetNode()->Len() );
2460 if ( aDelEnd
== aCurPos
)
2462 // kompletter Absatz dahinter
2463 ContentNode
* pNext
= GetNextVisNode( aCurPos
.GetNode() );
2465 aDelEnd
= EditPaM( pNext
, pNext
->Len() );
2470 // Bei DELMODE_RESTOFCONTENT reicht bei verschiedenen Nodes
2471 // kein ConnectParagraphs.
2472 if ( ( nDelMode
== DELMODE_RESTOFCONTENT
) || ( aDelStart
.GetNode() == aDelEnd
.GetNode() ) )
2473 return ImpDeleteSelection( EditSelection( aDelStart
, aDelEnd
) );
2475 // Jetzt entscheiden, ob noch Selektion loeschen (RESTOFCONTENTS)
2476 BOOL bSpecialBackward
= ( ( nMode
== DEL_LEFT
) && ( nDelMode
== DELMODE_SIMPLE
) )
2478 if ( aStatus
.IsAnyOutliner() )
2479 bSpecialBackward
= FALSE
;
2481 return ImpConnectParagraphs( aDelStart
.GetNode(), aDelEnd
.GetNode(), bSpecialBackward
);
2484 EditPaM
ImpEditEngine::ImpDeleteSelection( EditSelection aSel
)
2486 if ( !aSel
.HasRange() )
2489 aSel
.Adjust( aEditDoc
);
2490 EditPaM
aStartPaM( aSel
.Min() );
2491 EditPaM
aEndPaM( aSel
.Max() );
2493 CursorMoved( aStartPaM
.GetNode() ); // nur damit neu eingestellte Attribute verschwinden...
2494 CursorMoved( aEndPaM
.GetNode() ); // nur damit neu eingestellte Attribute verschwinden...
2496 DBG_ASSERT( aStartPaM
.GetIndex() <= aStartPaM
.GetNode()->Len(), "Index im Wald in ImpDeleteSelection" );
2497 DBG_ASSERT( aEndPaM
.GetIndex() <= aEndPaM
.GetNode()->Len(), "Index im Wald in ImpDeleteSelection" );
2499 USHORT nStartNode
= aEditDoc
.GetPos( aStartPaM
.GetNode() );
2500 USHORT nEndNode
= aEditDoc
.GetPos( aEndPaM
.GetNode() );
2502 DBG_ASSERT( nEndNode
!= USHRT_MAX
, "Start > End ?!" );
2503 DBG_ASSERT( nStartNode
<= nEndNode
, "Start > End ?!" );
2505 // Alle Nodes dazwischen entfernen....
2506 for ( ULONG z
= nStartNode
+1; z
< nEndNode
; z
++ )
2508 // Immer nStartNode+1, wegen Remove()!
2509 ImpRemoveParagraph( nStartNode
+1 );
2512 if ( aStartPaM
.GetNode() != aEndPaM
.GetNode() )
2514 // Den Rest des StartNodes...
2516 nChars
= aStartPaM
.GetNode()->Len() - aStartPaM
.GetIndex();
2517 ImpRemoveChars( aStartPaM
, nChars
);
2518 ParaPortion
* pPortion
= FindParaPortion( aStartPaM
.GetNode() );
2519 DBG_ASSERT( pPortion
, "Blinde Portion in ImpDeleteSelection(3)" );
2520 pPortion
->MarkSelectionInvalid( aStartPaM
.GetIndex(), aStartPaM
.GetNode()->Len() );
2522 // Den Anfang des EndNodes....
2523 nChars
= aEndPaM
.GetIndex();
2524 aEndPaM
.SetIndex( 0 );
2525 ImpRemoveChars( aEndPaM
, nChars
);
2526 pPortion
= FindParaPortion( aEndPaM
.GetNode() );
2527 DBG_ASSERT( pPortion
, "Blinde Portion in ImpDeleteSelection(4)" );
2528 pPortion
->MarkSelectionInvalid( 0, aEndPaM
.GetNode()->Len() );
2529 // Zusammenfuegen....
2530 aStartPaM
= ImpConnectParagraphs( aStartPaM
.GetNode(), aEndPaM
.GetNode() );
2535 nChars
= aEndPaM
.GetIndex() - aStartPaM
.GetIndex();
2536 ImpRemoveChars( aStartPaM
, nChars
);
2537 ParaPortion
* pPortion
= FindParaPortion( aStartPaM
.GetNode() );
2538 DBG_ASSERT( pPortion
, "Blinde Portion in ImpDeleteSelection(5)" );
2539 pPortion
->MarkInvalid( aEndPaM
.GetIndex(), aStartPaM
.GetIndex() - aEndPaM
.GetIndex() );
2547 void ImpEditEngine::ImpRemoveParagraph( USHORT nPara
)
2549 ContentNode
* pNode
= aEditDoc
.SaveGetObject( nPara
);
2550 ContentNode
* pNextNode
= aEditDoc
.SaveGetObject( nPara
+1 );
2551 ParaPortion
* pPortion
= GetParaPortions().SaveGetObject( nPara
);
2553 DBG_ASSERT( pNode
, "Blinder Node in ImpRemoveParagraph" );
2554 DBG_ASSERT( pPortion
, "Blinde Portion in ImpRemoveParagraph(2)" );
2556 DeletedNodeInfo
* pInf
= new DeletedNodeInfo( (ULONG
)pNode
, nPara
);
2557 aDeletedNodes
.Insert( pInf
, aDeletedNodes
.Count() );
2559 // Der Node wird vom Undo verwaltet und ggf. zerstoert!
2560 /* delete */ aEditDoc
.Remove( nPara
);
2561 GetParaPortions().Remove( nPara
);
2564 if ( IsCallParaInsertedOrDeleted() )
2566 GetEditEnginePtr()->ParagraphDeleted( nPara
);
2569 // Im folgenden muss ggf. Extra-Space neu ermittelt werden.
2570 // Bei ParaAttribsChanged wird leider der Absatz neu formatiert,
2571 // aber diese Methode sollte nicht Zeitkritsch sein!
2573 ParaAttribsChanged( pNextNode
);
2576 if ( IsUndoEnabled() && !IsInUndo() )
2577 InsertUndo( new EditUndoDelContent( this, pNode
, nPara
) );
2581 aEditDoc
.RemoveItemsFromPool( pNode
);
2582 if ( pNode
->GetStyleSheet() )
2583 EndListening( *pNode
->GetStyleSheet(), FALSE
);
2588 EditPaM
ImpEditEngine::AutoCorrect( const EditSelection
& rCurSel
, xub_Unicode c
,
2589 bool bOverwrite
, Window
* pFrameWin
)
2591 EditSelection
aSel( rCurSel
);
2593 SvxAutoCorrect
* pAutoCorrect
= SvxAutoCorrCfg::Get()->GetAutoCorrect();
2596 if ( aSel
.HasRange() )
2597 aSel
= ImpDeleteSelection( rCurSel
);
2599 // #i78661 allow application to turn off capitalization of
2600 // start sentence explicitly.
2601 // (This is done by setting IsFirstWordCapitalization to FALSE.)
2602 BOOL bOldCptlSttSntnc
= pAutoCorrect
->IsAutoCorrFlag( CptlSttSntnc
);
2603 if (!IsFirstWordCapitalization())
2605 ESelection
aESel( CreateESel(aSel
) );
2606 EditSelection aFirstWordSel
;
2607 EditSelection aSecondWordSel
;
2608 if (aESel
.nEndPara
== 0) // is this the first para?
2610 // select first word...
2611 // start by checking if para starts with word.
2612 aFirstWordSel
= SelectWord( CreateSel(ESelection()) );
2613 if (aFirstWordSel
.Min().GetIndex() == 0 && aFirstWordSel
.Max().GetIndex() == 0)
2615 // para does not start with word -> select next/first word
2616 EditPaM
aRightWord( WordRight( aFirstWordSel
.Max(), 1 ) );
2617 aFirstWordSel
= SelectWord( EditSelection( aRightWord
) );
2620 // select second word
2621 // (sometimes aSel mightnot point to the end of the first word
2622 // but to some following char like '.'. ':', ...
2623 // In those cases we need aSecondWordSel to see if aSel
2624 // will actually effect the first word.)
2625 EditPaM
aRight2Word( WordRight( aFirstWordSel
.Max(), 1 ) );
2626 aSecondWordSel
= SelectWord( EditSelection( aRight2Word
) );
2628 BOOL bIsFirstWordInFirstPara
= aESel
.nEndPara
== 0 &&
2629 aFirstWordSel
.Max().GetIndex() <= aSel
.Max().GetIndex() &&
2630 aSel
.Max().GetIndex() <= aSecondWordSel
.Min().GetIndex();
2632 if (bIsFirstWordInFirstPara
)
2633 pAutoCorrect
->SetAutoCorrFlag( CptlSttSntnc
, IsFirstWordCapitalization() );
2636 ContentNode
* pNode
= aSel
.Max().GetNode();
2637 USHORT nIndex
= aSel
.Max().GetIndex();
2638 EdtAutoCorrDoc
aAuto( this, pNode
, nIndex
, c
);
2639 pAutoCorrect
->AutoCorrect( aAuto
, *pNode
, nIndex
, c
, !bOverwrite
, pFrameWin
);
2640 aSel
.Max().SetIndex( aAuto
.GetCursor() );
2642 // #i78661 since the SvxAutoCorrect object used here is
2643 // shared we need to reset the value to it's original state.
2644 pAutoCorrect
->SetAutoCorrFlag( CptlSttSntnc
, bOldCptlSttSntnc
);
2646 #endif // !SVX_LIGHT
2651 EditPaM
ImpEditEngine::InsertText( const EditSelection
& rCurSel
,
2652 xub_Unicode c
, BOOL bOverwrite
, sal_Bool bIsUserInput
)
2654 DBG_ASSERT( c
!= '\t', "Tab bei InsertText ?" );
2655 DBG_ASSERT( c
!= '\n', "Zeilenumbruch bei InsertText ?" );
2657 EditPaM
aPaM( rCurSel
.Min() );
2659 BOOL bDoOverwrite
= ( bOverwrite
&&
2660 ( aPaM
.GetIndex() < aPaM
.GetNode()->Len() ) ) ? TRUE
: FALSE
;
2662 BOOL bUndoAction
= ( rCurSel
.HasRange() || bDoOverwrite
);
2665 UndoActionStart( EDITUNDO_INSERT
);
2667 if ( rCurSel
.HasRange() )
2669 aPaM
= ImpDeleteSelection( rCurSel
);
2671 else if ( bDoOverwrite
)
2673 // Wenn Selektion, dann nicht auch noch ein Zeichen ueberschreiben!
2674 EditSelection
aTmpSel( aPaM
);
2675 aTmpSel
.Max().GetIndex()++;
2676 DBG_ASSERT( !aTmpSel
.DbgIsBuggy( aEditDoc
), "Overwrite: Fehlerhafte Selektion!" );
2677 ImpDeleteSelection( aTmpSel
);
2680 if ( aPaM
.GetNode()->Len() < MAXCHARSINPARA
)
2682 if (bIsUserInput
&& IsInputSequenceCheckingRequired( c
, rCurSel
))
2684 uno::Reference
< i18n::XExtendedInputSequenceChecker
> _xISC( ImplGetInputSequenceChecker() );
2686 pCTLOptions
= new SvtCTLOptions
;
2688 if (_xISC
.is() || pCTLOptions
)
2690 xub_StrLen nTmpPos
= aPaM
.GetIndex();
2691 sal_Int16 nCheckMode
= pCTLOptions
->IsCTLSequenceCheckingRestricted() ?
2692 i18n::InputSequenceCheckMode::STRICT
: i18n::InputSequenceCheckMode::BASIC
;
2694 // the text that needs to be checked is only the one
2695 // before the current cursor position
2696 rtl::OUString
aOldText( aPaM
.GetNode()->Copy(0, nTmpPos
) );
2697 rtl::OUString
aNewText( aOldText
);
2698 if (pCTLOptions
->IsCTLSequenceCheckingTypeAndReplace())
2700 /*const xub_StrLen nPrevPos = static_cast< xub_StrLen >*/( _xISC
->correctInputSequence( aNewText
, nTmpPos
- 1, c
, nCheckMode
) );
2702 // find position of first character that has changed
2703 sal_Int32 nOldLen
= aOldText
.getLength();
2704 sal_Int32 nNewLen
= aNewText
.getLength();
2705 const sal_Unicode
*pOldTxt
= aOldText
.getStr();
2706 const sal_Unicode
*pNewTxt
= aNewText
.getStr();
2707 sal_Int32 nChgPos
= 0;
2708 while ( nChgPos
< nOldLen
&& nChgPos
< nNewLen
&&
2709 pOldTxt
[nChgPos
] == pNewTxt
[nChgPos
] )
2712 xub_StrLen nChgLen
= static_cast< xub_StrLen
>( nNewLen
- nChgPos
);
2713 String
aChgText( aNewText
.copy( nChgPos
), nChgLen
);
2715 // select text from first pos to be changed to current pos
2716 EditSelection
aSel( EditPaM( aPaM
.GetNode(), (USHORT
) nChgPos
), aPaM
);
2719 return InsertText( aSel
, aChgText
); // implicitly handles undo
2725 // should the character be ignored (i.e. not get inserted) ?
2726 if (!_xISC
->checkInputSequence( aOldText
, nTmpPos
- 1, c
, nCheckMode
))
2727 return aPaM
; // nothing to be done -> no need for undo
2731 // at this point now we will insert the character 'normally' some lines below...
2734 if ( IsUndoEnabled() && !IsInUndo() )
2736 EditUndoInsertChars
* pNewUndo
= new EditUndoInsertChars( this, CreateEPaM( aPaM
), c
);
2737 BOOL bTryMerge
= ( !bDoOverwrite
&& ( c
!= ' ' ) ) ? TRUE
: FALSE
;
2738 InsertUndo( pNewUndo
, bTryMerge
);
2741 aEditDoc
.InsertText( (const EditPaM
&)aPaM
, c
);
2742 ParaPortion
* pPortion
= FindParaPortion( aPaM
.GetNode() );
2743 DBG_ASSERT( pPortion
, "Blinde Portion in InsertText" );
2744 pPortion
->MarkInvalid( aPaM
.GetIndex(), 1 );
2745 aPaM
.GetIndex()++; // macht EditDoc-Methode nicht mehr
2751 UndoActionEnd( EDITUNDO_INSERT
);
2756 EditPaM
ImpEditEngine::ImpInsertText( EditSelection aCurSel
, const XubString
& rStr
)
2758 UndoActionStart( EDITUNDO_INSERT
);
2761 if ( aCurSel
.HasRange() )
2762 aPaM
= ImpDeleteSelection( aCurSel
);
2764 aPaM
= aCurSel
.Max();
2766 EditPaM
aCurPaM( aPaM
); // fuers Invalidieren
2768 XubString
aText( rStr
);
2769 aText
.ConvertLineEnd( LINEEND_LF
);
2770 SfxVoidItem
aTabItem( EE_FEATURE_TAB
);
2772 // Konvertiert nach LineSep = \n
2773 // Token mit LINE_SEP abfragen,
2774 // da der MAC-Compiler aus \n etwas anderes macht!
2777 while ( nStart
< aText
.Len() )
2779 USHORT nEnd
= aText
.Search( LINE_SEP
, nStart
);
2780 if ( nEnd
== STRING_NOTFOUND
)
2781 nEnd
= aText
.Len(); // nicht dereferenzieren!
2783 // Start == End => Leerzeile
2784 if ( nEnd
> nStart
)
2786 XubString
aLine( aText
, nStart
, nEnd
-nStart
);
2787 xub_StrLen nChars
= aPaM
.GetNode()->Len() + aLine
.Len();
2788 if ( nChars
> MAXCHARSINPARA
)
2790 USHORT nMaxNewChars
= MAXCHARSINPARA
-aPaM
.GetNode()->Len();
2791 nEnd
-= ( aLine
.Len() - nMaxNewChars
); // Dann landen die Zeichen im naechsten Absatz.
2792 aLine
.Erase( nMaxNewChars
); // Del Rest...
2795 if ( IsUndoEnabled() && !IsInUndo() )
2796 InsertUndo( new EditUndoInsertChars( this, CreateEPaM( aPaM
), aLine
) );
2799 if ( aLine
.Search( '\t' ) == STRING_NOTFOUND
)
2800 aPaM
= aEditDoc
.InsertText( aPaM
, aLine
);
2804 while ( nStart2
< aLine
.Len() )
2806 USHORT nEnd2
= aLine
.Search( '\t', nStart2
);
2807 if ( nEnd2
== STRING_NOTFOUND
)
2808 nEnd2
= aLine
.Len(); // nicht dereferenzieren!
2810 if ( nEnd2
> nStart2
)
2811 aPaM
= aEditDoc
.InsertText( aPaM
, XubString( aLine
, nStart2
, nEnd2
-nStart2
) );
2812 if ( nEnd2
< aLine
.Len() )
2814 // aPaM = ImpInsertFeature( EditSelection( aPaM, aPaM ), );
2815 aPaM
= aEditDoc
.InsertFeature( aPaM
, aTabItem
);
2820 ParaPortion
* pPortion
= FindParaPortion( aPaM
.GetNode() );
2821 DBG_ASSERT( pPortion
, "Blinde Portion in InsertText" );
2822 pPortion
->MarkInvalid( aCurPaM
.GetIndex(), aLine
.Len() );
2824 if ( nEnd
< aText
.Len() )
2825 aPaM
= ImpInsertParaBreak( aPaM
);
2830 UndoActionEnd( EDITUNDO_INSERT
);
2836 EditPaM
ImpEditEngine::ImpFastInsertText( EditPaM aPaM
, const XubString
& rStr
)
2838 DBG_ASSERT( rStr
.Search( 0x0A ) == STRING_NOTFOUND
, "FastInsertText: Zeilentrenner nicht erlaubt!" );
2839 DBG_ASSERT( rStr
.Search( 0x0D ) == STRING_NOTFOUND
, "FastInsertText: Zeilentrenner nicht erlaubt!" );
2840 DBG_ASSERT( rStr
.Search( '\t' ) == STRING_NOTFOUND
, "FastInsertText: Features nicht erlaubt!" );
2842 if ( ( aPaM
.GetNode()->Len() + rStr
.Len() ) < MAXCHARSINPARA
)
2845 if ( IsUndoEnabled() && !IsInUndo() )
2846 InsertUndo( new EditUndoInsertChars( this, CreateEPaM( aPaM
), rStr
) );
2849 aPaM
= aEditDoc
.InsertText( aPaM
, rStr
);
2854 aPaM
= ImpInsertText( aPaM
, rStr
);
2860 EditPaM
ImpEditEngine::ImpInsertFeature( EditSelection aCurSel
, const SfxPoolItem
& rItem
)
2863 if ( aCurSel
.HasRange() )
2864 aPaM
= ImpDeleteSelection( aCurSel
);
2866 aPaM
= aCurSel
.Max();
2868 if ( aPaM
.GetIndex() >= 0xfffe )
2872 if ( IsUndoEnabled() && !IsInUndo() )
2873 InsertUndo( new EditUndoInsertFeature( this, CreateEPaM( aPaM
), rItem
) );
2875 aPaM
= aEditDoc
.InsertFeature( aPaM
, rItem
);
2877 ParaPortion
* pPortion
= FindParaPortion( aPaM
.GetNode() );
2878 DBG_ASSERT( pPortion
, "Blinde Portion in InsertFeature" );
2879 pPortion
->MarkInvalid( aPaM
.GetIndex()-1, 1 );
2886 EditPaM
ImpEditEngine::ImpInsertParaBreak( const EditSelection
& rCurSel
, BOOL bKeepEndingAttribs
)
2889 if ( rCurSel
.HasRange() )
2890 aPaM
= ImpDeleteSelection( rCurSel
);
2892 aPaM
= rCurSel
.Max();
2894 return ImpInsertParaBreak( aPaM
, bKeepEndingAttribs
);
2897 EditPaM
ImpEditEngine::ImpInsertParaBreak( const EditPaM
& rPaM
, BOOL bKeepEndingAttribs
)
2899 if ( aEditDoc
.Count() >= 0xFFFE )
2901 DBG_ERROR( "Can't process more than 64K paragraphs!" );
2906 if ( IsUndoEnabled() && !IsInUndo() )
2907 InsertUndo( new EditUndoSplitPara( this, aEditDoc
.GetPos( rPaM
.GetNode() ), rPaM
.GetIndex() ) );
2910 EditPaM
aPaM( aEditDoc
.InsertParaBreak( rPaM
, bKeepEndingAttribs
) );
2913 if ( GetStatus().DoOnlineSpelling() )
2915 xub_StrLen nEnd
= rPaM
.GetNode()->Len();
2916 aPaM
.GetNode()->CreateWrongList();
2917 WrongList
* pLWrongs
= rPaM
.GetNode()->GetWrongList();
2918 WrongList
* pRWrongs
= aPaM
.GetNode()->GetWrongList();
2919 // Falschgeschriebene Woerter ruebernehmen:
2920 USHORT nLWrongs
= pLWrongs
->Count();
2921 for ( USHORT nW
= 0; nW
< nLWrongs
; nW
++ )
2923 WrongRange
& rWrong
= pLWrongs
->GetObject( nW
);
2924 // Nur wenn wirklich dahinter, ein ueberlappendes wird beim Spell korrigiert
2925 if ( rWrong
.nStart
> nEnd
)
2927 pRWrongs
->InsertWrong( rWrong
, pRWrongs
->Count() );
2928 WrongRange
& rRWrong
= pRWrongs
->GetObject( pRWrongs
->Count() - 1 );
2929 rRWrong
.nStart
= rRWrong
.nStart
- nEnd
;
2930 rRWrong
.nEnd
= rRWrong
.nEnd
- nEnd
;
2932 else if ( ( rWrong
.nStart
< nEnd
) && ( rWrong
.nEnd
> nEnd
) )
2935 USHORT nInv
= nEnd
? nEnd
-1 : nEnd
;
2937 pLWrongs
->MarkInvalid( nInv
, nEnd
);
2939 pLWrongs
->SetValid();
2940 pRWrongs
->SetValid(); // sonst 0 - 0xFFFF
2941 pRWrongs
->MarkInvalid( 0, 1 ); // Nur das erste Wort testen
2943 #endif // !SVX_LIGHT
2946 ParaPortion
* pPortion
= FindParaPortion( rPaM
.GetNode() );
2947 DBG_ASSERT( pPortion
, "Blinde Portion in ImpInsertParaBreak" );
2948 pPortion
->MarkInvalid( rPaM
.GetIndex(), 0 );
2950 // Optimieren: Nicht unnoetig viele GetPos auf die Listen ansetzen!
2951 // Hier z.B. bei Undo, aber auch in allen anderen Methoden.
2952 USHORT nPos
= GetParaPortions().GetPos( pPortion
);
2953 ParaPortion
* pNewPortion
= new ParaPortion( aPaM
.GetNode() );
2954 GetParaPortions().Insert( pNewPortion
, nPos
+ 1 );
2955 ParaAttribsChanged( pNewPortion
->GetNode() );
2956 if ( IsCallParaInsertedOrDeleted() )
2957 GetEditEnginePtr()->ParagraphInserted( nPos
+1 );
2959 CursorMoved( rPaM
.GetNode() ); // falls leeres Attribut entstanden.
2964 EditPaM
ImpEditEngine::ImpFastInsertParagraph( USHORT nPara
)
2967 if ( IsUndoEnabled() && !IsInUndo() )
2971 DBG_ASSERT( aEditDoc
.SaveGetObject( nPara
-1 ), "FastInsertParagraph: Prev existiert nicht" );
2972 InsertUndo( new EditUndoSplitPara( this, nPara
-1, aEditDoc
.GetObject( nPara
-1 )->Len() ) );
2975 InsertUndo( new EditUndoSplitPara( this, 0, 0 ) );
2979 ContentNode
* pNode
= new ContentNode( aEditDoc
.GetItemPool() );
2980 // Falls FlatMode, wird spaeter kein Font eingestellt:
2981 pNode
->GetCharAttribs().GetDefFont() = aEditDoc
.GetDefFont();
2984 if ( GetStatus().DoOnlineSpelling() )
2985 pNode
->CreateWrongList();
2986 #endif // !SVX_LIGHT
2988 aEditDoc
.Insert( pNode
, nPara
);
2990 ParaPortion
* pNewPortion
= new ParaPortion( pNode
);
2991 GetParaPortions().Insert( pNewPortion
, nPara
);
2992 if ( IsCallParaInsertedOrDeleted() )
2993 GetEditEnginePtr()->ParagraphInserted( nPara
);
2995 return EditPaM( pNode
, 0 );
2998 EditPaM
ImpEditEngine::InsertParaBreak( EditSelection aCurSel
)
3000 EditPaM
aPaM( ImpInsertParaBreak( aCurSel
) );
3001 if ( aStatus
.DoAutoIndenting() )
3003 USHORT nPara
= aEditDoc
.GetPos( aPaM
.GetNode() );
3004 DBG_ASSERT( nPara
> 0, "AutoIndenting: Fehler!" );
3005 XubString
aPrevParaText( GetEditDoc().GetParaAsString( nPara
-1 ) );
3007 while ( ( n
< aPrevParaText
.Len() ) &&
3008 ( ( aPrevParaText
.GetChar(n
) == ' ' ) || ( aPrevParaText
.GetChar(n
) == '\t' ) ) )
3010 if ( aPrevParaText
.GetChar(n
) == '\t' )
3011 aPaM
= ImpInsertFeature( aPaM
, SfxVoidItem( EE_FEATURE_TAB
) );
3013 aPaM
= ImpInsertText( aPaM
, aPrevParaText
.GetChar(n
) );
3021 EditPaM
ImpEditEngine::InsertTab( EditSelection aCurSel
)
3023 EditPaM
aPaM( ImpInsertFeature( aCurSel
, SfxVoidItem( EE_FEATURE_TAB
) ) );
3027 EditPaM
ImpEditEngine::InsertField( EditSelection aCurSel
, const SvxFieldItem
& rFld
)
3029 EditPaM
aPaM( ImpInsertFeature( aCurSel
, rFld
) );
3033 BOOL
ImpEditEngine::UpdateFields()
3035 BOOL bChanges
= FALSE
;
3036 USHORT nParas
= GetEditDoc().Count();
3037 for ( USHORT nPara
= 0; nPara
< nParas
; nPara
++ )
3039 BOOL bChangesInPara
= FALSE
;
3040 ContentNode
* pNode
= GetEditDoc().GetObject( nPara
);
3041 DBG_ASSERT( pNode
, "NULL-Pointer im Doc" );
3042 CharAttribArray
& rAttribs
= pNode
->GetCharAttribs().GetAttribs();
3043 // USHORT nAttrs = rAttribs.Count();
3044 for ( USHORT nAttr
= 0; nAttr
< rAttribs
.Count(); nAttr
++ )
3046 EditCharAttrib
* pAttr
= rAttribs
[nAttr
];
3047 if ( pAttr
->Which() == EE_FEATURE_FIELD
)
3049 EditCharAttribField
* pField
= (EditCharAttribField
*)pAttr
;
3050 EditCharAttribField
* pCurrent
= new EditCharAttribField( *pField
);
3053 if ( aStatus
.MarkFields() )
3054 pField
->GetFldColor() = new Color( GetColorConfig().GetColorValue( svtools::WRITERFIELDSHADINGS
).nColor
);
3056 XubString aFldValue
= GetEditEnginePtr()->CalcFieldValue(
3057 (const SvxFieldItem
&)*pField
->GetItem(),
3058 nPara
, pField
->GetStart(),
3059 pField
->GetTxtColor(), pField
->GetFldColor() );
3060 pField
->GetFieldValue() = aFldValue
;
3061 if ( *pField
!= *pCurrent
)
3064 bChangesInPara
= TRUE
;
3069 if ( bChangesInPara
)
3071 // ggf. etwas genauer invalidieren.
3072 ParaPortion
* pPortion
= GetParaPortions().GetObject( nPara
);
3073 DBG_ASSERT( pPortion
, "NULL-Pointer im Doc" );
3074 pPortion
->MarkSelectionInvalid( 0, pNode
->Len() );
3080 EditPaM
ImpEditEngine::InsertLineBreak( EditSelection aCurSel
)
3082 EditPaM
aPaM( ImpInsertFeature( aCurSel
, SfxVoidItem( EE_FEATURE_LINEBR
) ) );
3086 // ----------------------------------------------------------------------
3088 // ----------------------------------------------------------------------
3089 Rectangle
ImpEditEngine::PaMtoEditCursor( EditPaM aPaM
, USHORT nFlags
)
3091 DBG_ASSERT( GetUpdateMode(), "Darf bei Update=FALSE nicht erreicht werden: PaMtoEditCursor" );
3093 Rectangle aEditCursor
;
3095 for ( USHORT nPortion
= 0; nPortion
< GetParaPortions().Count(); nPortion
++ )
3097 ParaPortion
* pPortion
= GetParaPortions().GetObject(nPortion
);
3098 ContentNode
* pNode
= pPortion
->GetNode();
3099 DBG_ASSERT( pNode
, "Ungueltiger Node in Portion!" );
3100 if ( pNode
!= aPaM
.GetNode() )
3102 nY
+= pPortion
->GetHeight();
3106 aEditCursor
= GetEditCursor( pPortion
, aPaM
.GetIndex(), nFlags
);
3107 aEditCursor
.Top() += nY
;
3108 aEditCursor
.Bottom() += nY
;
3112 DBG_ERROR( "Portion nicht gefunden!" );
3116 EditPaM
ImpEditEngine::GetPaM( Point aDocPos
, BOOL bSmart
)
3118 DBG_ASSERT( GetUpdateMode(), "Darf bei Update=FALSE nicht erreicht werden: GetPaM" );
3124 for ( nPortion
= 0; nPortion
< GetParaPortions().Count(); nPortion
++ )
3126 ParaPortion
* pPortion
= GetParaPortions().GetObject(nPortion
);
3127 nTmpHeight
= pPortion
->GetHeight(); // sollte auch bei !bVisible richtig sein!
3129 if ( nY
> aDocPos
.Y() )
3133 // unsichtbare Portions ueberspringen:
3134 while ( pPortion
&& !pPortion
->IsVisible() )
3137 pPortion
= GetParaPortions().SaveGetObject( nPortion
);
3139 DBG_ASSERT( pPortion
, "Keinen sichtbaren Absatz gefunden: GetPaM" );
3140 aPaM
= GetPaM( pPortion
, aDocPos
, bSmart
);
3145 // Dann den letzten sichtbaren Suchen:
3146 nPortion
= GetParaPortions().Count()-1;
3147 while ( nPortion
&& !GetParaPortions()[nPortion
]->IsVisible() )
3150 DBG_ASSERT( GetParaPortions()[nPortion
]->IsVisible(), "Keinen sichtbaren Absatz gefunden: GetPaM" );
3151 aPaM
.SetNode( GetParaPortions()[nPortion
]->GetNode() );
3152 aPaM
.SetIndex( GetParaPortions()[nPortion
]->GetNode()->Len() );
3156 sal_uInt32
ImpEditEngine::GetTextHeight() const
3158 DBG_ASSERT( GetUpdateMode(), "Sollte bei Update=FALSE nicht verwendet werden: GetTextHeight" );
3159 DBG_ASSERT( IsFormatted() || IsFormatting(), "GetTextHeight: Nicht formatiert" );
3160 return nCurTextHeight
;
3163 sal_uInt32
ImpEditEngine::CalcTextWidth( BOOL bIgnoreExtraSpace
)
3165 // Wenn noch nicht formatiert und nicht gerade dabei.
3166 // Wird in der Formatierung bei AutoPageSize gerufen.
3167 if ( !IsFormatted() && !IsFormatting() )
3175 // --------------------------------------------------
3176 // Ueber alle Absaetze...
3177 // --------------------------------------------------
3178 USHORT nParas
= GetParaPortions().Count();
3179 // USHORT nBiggestPara = 0;
3180 // USHORT nBiggestLine = 0;
3181 for ( USHORT nPara
= 0; nPara
< nParas
; nPara
++ )
3183 ParaPortion
* pPortion
= GetParaPortions().GetObject( nPara
);
3184 if ( pPortion
->IsVisible() )
3186 const SvxLRSpaceItem
& rLRItem
= GetLRSpaceItem( pPortion
->GetNode() );
3187 sal_Int32 nSpaceBeforeAndMinLabelWidth
= GetSpaceBeforeAndMinLabelWidth( pPortion
->GetNode() );
3189 // --------------------------------------------------
3190 // Ueber die Zeilen des Absatzes...
3191 // --------------------------------------------------
3192 ULONG nLines
= pPortion
->GetLines().Count();
3193 for ( USHORT nLine
= 0; nLine
< nLines
; nLine
++ )
3195 pLine
= pPortion
->GetLines().GetObject( nLine
);
3196 DBG_ASSERT( pLine
, "NULL-Pointer im Zeileniterator in CalcWidth" );
3197 // nCurWidth = pLine->GetStartPosX();
3198 // Bei Center oder Right haengt die breite von der
3199 // Papierbreite ab, hier nicht erwuenscht.
3200 // Am besten generell nicht auf StartPosX verlassen,
3201 // es muss auch die rechte Einrueckung beruecksichtigt werden!
3202 nCurWidth
= GetXValue( rLRItem
.GetTxtLeft() + nSpaceBeforeAndMinLabelWidth
);
3205 long nFI
= GetXValue( rLRItem
.GetTxtFirstLineOfst() );
3207 if ( pPortion
->GetBulletX() > nCurWidth
)
3209 nCurWidth
+= nFI
; // LI?
3210 if ( pPortion
->GetBulletX() > nCurWidth
)
3211 nCurWidth
= pPortion
->GetBulletX();
3214 nCurWidth
+= GetXValue( rLRItem
.GetRight() );
3215 nCurWidth
+= CalcLineWidth( pPortion
, pLine
, bIgnoreExtraSpace
);
3216 if ( nCurWidth
> nMaxWidth
)
3218 nMaxWidth
= nCurWidth
;
3223 if ( nMaxWidth
< 0 )
3226 nMaxWidth
++; // Ein breiter, da in CreateLines bei >= umgebrochen wird.
3227 return (sal_uInt32
)nMaxWidth
;
3230 sal_uInt32
ImpEditEngine::CalcLineWidth( ParaPortion
* pPortion
, EditLine
* pLine
, BOOL bIgnoreExtraSpace
)
3232 USHORT nPara
= GetEditDoc().GetPos( pPortion
->GetNode() );
3234 // #114278# Saving both layout mode and language (since I'm
3235 // potentially changing both)
3236 GetRefDevice()->Push( PUSH_TEXTLAYOUTMODE
|PUSH_TEXTLANGUAGE
);
3238 ImplInitLayoutMode( GetRefDevice(), nPara
, 0xFFFF );
3240 SvxAdjust eJustification
= GetJustification( nPara
);
3242 // Berechnung der Breite ohne die Indents...
3243 sal_uInt32 nWidth
= 0;
3244 USHORT nPos
= pLine
->GetStart();
3245 for ( USHORT nTP
= pLine
->GetStartPortion(); nTP
<= pLine
->GetEndPortion(); nTP
++ )
3247 TextPortion
* pTextPortion
= pPortion
->GetTextPortions().GetObject( nTP
);
3248 switch ( pTextPortion
->GetKind() )
3250 case PORTIONKIND_FIELD
:
3251 case PORTIONKIND_HYPHENATOR
:
3252 case PORTIONKIND_TAB
:
3254 nWidth
+= pTextPortion
->GetSize().Width();
3257 case PORTIONKIND_TEXT
:
3259 if ( ( eJustification
!= SVX_ADJUST_BLOCK
) || ( !bIgnoreExtraSpace
) )
3261 nWidth
+= pTextPortion
->GetSize().Width();
3265 SvxFont
aTmpFont( pPortion
->GetNode()->GetCharAttribs().GetDefFont() );
3266 SeekCursor( pPortion
->GetNode(), nPos
+1, aTmpFont
);
3267 aTmpFont
.SetPhysFont( GetRefDevice() );
3268 ImplInitDigitMode( GetRefDevice(), 0, 0, 0, aTmpFont
.GetLanguage() );
3269 nWidth
+= aTmpFont
.QuickGetTextSize( GetRefDevice(), *pPortion
->GetNode(), nPos
, pTextPortion
->GetLen(), NULL
).Width();
3274 nPos
= nPos
+ pTextPortion
->GetLen();
3277 GetRefDevice()->Pop();
3282 sal_uInt32
ImpEditEngine::CalcTextHeight()
3284 DBG_ASSERT( GetUpdateMode(), "Sollte bei Update=FALSE nicht verwendet werden: CalcTextHeight" );
3286 for ( USHORT nPortion
= 0; nPortion
< GetParaPortions().Count(); nPortion
++ )
3287 nY
+= GetParaPortions()[nPortion
]->GetHeight();
3291 USHORT
ImpEditEngine::GetLineCount( USHORT nParagraph
) const
3293 DBG_ASSERT( nParagraph
< GetParaPortions().Count(), "GetLineCount: Out of range" );
3294 ParaPortion
* pPPortion
= GetParaPortions().SaveGetObject( nParagraph
);
3295 DBG_ASSERT( pPPortion
, "Absatz nicht gefunden: GetLineCount" );
3297 return pPPortion
->GetLines().Count();
3302 xub_StrLen
ImpEditEngine::GetLineLen( USHORT nParagraph
, USHORT nLine
) const
3304 DBG_ASSERT( nParagraph
< GetParaPortions().Count(), "GetLineLen: Out of range" );
3305 ParaPortion
* pPPortion
= GetParaPortions().SaveGetObject( nParagraph
);
3306 DBG_ASSERT( pPPortion
, "Absatz nicht gefunden: GetLineLen" );
3307 if ( pPPortion
&& ( nLine
< pPPortion
->GetLines().Count() ) )
3309 EditLine
* pLine
= pPPortion
->GetLines().GetObject( nLine
);
3310 DBG_ASSERT( pLine
, "Zeile nicht gefunden: GetLineHeight" );
3311 return pLine
->GetLen();
3317 void ImpEditEngine::GetLineBoundaries( /*out*/USHORT
&rStart
, /*out*/USHORT
&rEnd
, USHORT nParagraph
, USHORT nLine
) const
3319 DBG_ASSERT( nParagraph
< GetParaPortions().Count(), "GetLineCount: Out of range" );
3320 ParaPortion
* pPPortion
= GetParaPortions().SaveGetObject( nParagraph
);
3321 DBG_ASSERT( pPPortion
, "Absatz nicht gefunden: GetLineBoundaries" );
3322 rStart
= rEnd
= 0xFFFF; // default values in case of error
3323 if ( pPPortion
&& ( nLine
< pPPortion
->GetLines().Count() ) )
3325 EditLine
* pLine
= pPPortion
->GetLines().GetObject( nLine
);
3326 DBG_ASSERT( pLine
, "Zeile nicht gefunden: GetLineBoundaries" );
3327 rStart
= pLine
->GetStart();
3328 rEnd
= pLine
->GetEnd();
3332 USHORT
ImpEditEngine::GetLineNumberAtIndex( USHORT nPara
, USHORT nIndex
) const
3334 USHORT nLineNo
= 0xFFFF;
3335 ContentNode
* pNode
= GetEditDoc().SaveGetObject( nPara
);
3336 DBG_ASSERT( pNode
, "GetLineNumberAtIndex: invalid paragraph index" );
3339 // we explicitly allow for the index to point at the character right behind the text
3340 const bool bValidIndex
= /*0 <= nIndex &&*/ nIndex
<= pNode
->Len();
3341 DBG_ASSERT( bValidIndex
, "GetLineNumberAtIndex: invalid index" );
3342 const USHORT nLineCount
= GetLineCount( nPara
);
3343 if (nIndex
== pNode
->Len())
3344 nLineNo
= nLineCount
> 0 ? nLineCount
- 1 : 0;
3345 else if (bValidIndex
) // nIndex < pNode->Len()
3347 USHORT nStart
= USHRT_MAX
, nEnd
= USHRT_MAX
;
3348 for (USHORT i
= 0; i
< nLineCount
&& nLineNo
== 0xFFFF; ++i
)
3350 GetLineBoundaries( nStart
, nEnd
, nPara
, i
);
3351 if (nStart
<= nIndex
&& nIndex
< nEnd
)
3359 USHORT
ImpEditEngine::GetLineHeight( USHORT nParagraph
, USHORT nLine
)
3361 DBG_ASSERT( nParagraph
< GetParaPortions().Count(), "GetLineCount: Out of range" );
3362 ParaPortion
* pPPortion
= GetParaPortions().SaveGetObject( nParagraph
);
3363 DBG_ASSERT( pPPortion
, "Absatz nicht gefunden: GetLineHeight" );
3364 if ( pPPortion
&& ( nLine
< pPPortion
->GetLines().Count() ) )
3366 EditLine
* pLine
= pPPortion
->GetLines().GetObject( nLine
);
3367 DBG_ASSERT( pLine
, "Zeile nicht gefunden: GetLineHeight" );
3368 return pLine
->GetHeight();
3374 sal_uInt32
ImpEditEngine::GetParaHeight( USHORT nParagraph
)
3376 sal_uInt32 nHeight
= 0;
3378 ParaPortion
* pPPortion
= GetParaPortions().SaveGetObject( nParagraph
);
3379 DBG_ASSERT( pPPortion
, "Absatz nicht gefunden: GetParaHeight" );
3382 nHeight
= pPPortion
->GetHeight();
3387 void ImpEditEngine::UpdateSelections()
3389 USHORT nInvNodes
= aDeletedNodes
.Count();
3391 // Pruefen, ob eine der Selektionen auf einem geloeschten Node steht...
3392 // Wenn der Node gueltig ist, muss noch der Index geprueft werden!
3393 for ( USHORT nView
= 0; nView
< aEditViews
.Count(); nView
++ )
3395 EditView
* pView
= aEditViews
.GetObject(nView
);
3396 DBG_CHKOBJ( pView
, EditView
, 0 );
3397 EditSelection
aCurSel( pView
->pImpEditView
->GetEditSelection() );
3398 BOOL bChanged
= FALSE
;
3399 for ( USHORT n
= 0; n
< nInvNodes
; n
++ )
3401 DeletedNodeInfo
* pInf
= aDeletedNodes
.GetObject( n
);
3402 if ( ( ( ULONG
)(aCurSel
.Min().GetNode()) == pInf
->GetInvalidAdress() ) ||
3403 ( ( ULONG
)(aCurSel
.Max().GetNode()) == pInf
->GetInvalidAdress() ) )
3405 // ParaPortions verwenden, da jetzt auch versteckte
3406 // Absaetze beruecksichtigt werden muessen!
3407 USHORT nPara
= pInf
->GetPosition();
3408 ParaPortion
* pPPortion
= GetParaPortions().SaveGetObject( nPara
);
3409 if ( !pPPortion
) // letzter Absatz
3411 nPara
= GetParaPortions().Count()-1;
3412 pPPortion
= GetParaPortions().GetObject( nPara
);
3414 DBG_ASSERT( pPPortion
, "Leeres Document in UpdateSelections ?" );
3415 // Nicht aus einem verstecktem Absatz landen:
3416 USHORT nCurPara
= nPara
;
3417 USHORT nLastPara
= GetParaPortions().Count()-1;
3418 while ( nPara
<= nLastPara
&& !GetParaPortions()[nPara
]->IsVisible() )
3420 if ( nPara
> nLastPara
) // dann eben rueckwaerts...
3423 while ( nPara
&& !GetParaPortions()[nPara
]->IsVisible() )
3426 DBG_ASSERT( GetParaPortions()[nPara
]->IsVisible(), "Keinen sichtbaren Absatz gefunden: UpdateSelections" );
3428 ParaPortion
* pParaPortion
= GetParaPortions()[nPara
];
3429 EditSelection
aTmpSelection( EditPaM( pParaPortion
->GetNode(), 0 ) );
3430 pView
->pImpEditView
->SetEditSelection( aTmpSelection
);
3432 break; // for-Schleife
3437 // Index prueffen, falls Node geschrumpft.
3438 if ( aCurSel
.Min().GetIndex() > aCurSel
.Min().GetNode()->Len() )
3440 aCurSel
.Min().GetIndex() = aCurSel
.Min().GetNode()->Len();
3441 pView
->pImpEditView
->SetEditSelection( aCurSel
);
3443 if ( aCurSel
.Max().GetIndex() > aCurSel
.Max().GetNode()->Len() )
3445 aCurSel
.Max().GetIndex() = aCurSel
.Max().GetNode()->Len();
3446 pView
->pImpEditView
->SetEditSelection( aCurSel
);
3452 for ( USHORT n
= 0; n
< nInvNodes
; n
++ )
3454 DeletedNodeInfo
* pInf
= aDeletedNodes
.GetObject( n
);
3457 aDeletedNodes
.Remove( 0, aDeletedNodes
.Count() );
3460 EditSelection
ImpEditEngine::ConvertSelection( USHORT nStartPara
, USHORT nStartPos
,
3461 USHORT nEndPara
, USHORT nEndPos
) const
3463 EditSelection aNewSelection
;
3466 ContentNode
* pNode
= aEditDoc
.SaveGetObject( nStartPara
);
3467 USHORT nIndex
= nStartPos
;
3470 pNode
= aEditDoc
[ aEditDoc
.Count()-1 ];
3471 nIndex
= pNode
->Len();
3473 else if ( nIndex
> pNode
->Len() )
3474 nIndex
= pNode
->Len();
3476 aNewSelection
.Min().SetNode( pNode
);
3477 aNewSelection
.Min().SetIndex( nIndex
);
3480 pNode
= aEditDoc
.SaveGetObject( nEndPara
);
3484 pNode
= aEditDoc
[ aEditDoc
.Count()-1 ];
3485 nIndex
= pNode
->Len();
3487 else if ( nIndex
> pNode
->Len() )
3488 nIndex
= pNode
->Len();
3490 aNewSelection
.Max().SetNode( pNode
);
3491 aNewSelection
.Max().SetIndex( nIndex
);
3493 return aNewSelection
;
3496 EditSelection
ImpEditEngine::MatchGroup( const EditSelection
& rSel
)
3498 EditSelection aMatchSel
;
3499 EditSelection
aTmpSel( rSel
);
3500 aTmpSel
.Adjust( GetEditDoc() );
3501 if ( ( aTmpSel
.Min().GetNode() != aTmpSel
.Max().GetNode() ) ||
3502 ( ( aTmpSel
.Max().GetIndex() - aTmpSel
.Min().GetIndex() ) > 1 ) )
3507 USHORT nPos
= aTmpSel
.Min().GetIndex();
3508 ContentNode
* pNode
= aTmpSel
.Min().GetNode();
3509 if ( nPos
>= pNode
->Len() )
3512 USHORT nMatchChar
= aGroupChars
.Search( pNode
->GetChar( nPos
) );
3513 if ( nMatchChar
!= STRING_NOTFOUND
)
3515 USHORT nNode
= aEditDoc
.GetPos( pNode
);
3516 if ( ( nMatchChar
% 2 ) == 0 )
3518 // Vorwaerts suchen...
3519 xub_Unicode nSC
= aGroupChars
.GetChar( nMatchChar
);
3520 DBG_ASSERT( aGroupChars
.Len() > (nMatchChar
+1), "Ungueltige Gruppe von MatchChars!" );
3521 xub_Unicode nEC
= aGroupChars
.GetChar( nMatchChar
+1 );
3523 USHORT nCur
= aTmpSel
.Min().GetIndex()+1;
3525 while ( pNode
&& nLevel
)
3527 XubString
& rStr
= *pNode
;
3528 while ( nCur
< rStr
.Len() )
3530 if ( rStr
.GetChar( nCur
) == nSC
)
3532 else if ( rStr
.GetChar( nCur
) == nEC
)
3536 break; // while nCur...
3544 pNode
= nNode
< aEditDoc
.Count() ? aEditDoc
.GetObject( nNode
) : 0;
3548 if ( nLevel
== 0 ) // gefunden
3550 aMatchSel
.Min() = aTmpSel
.Min();
3551 aMatchSel
.Max() = EditPaM( pNode
, nCur
+1 );
3556 // Rueckwaerts suchen...
3557 xub_Unicode nEC
= aGroupChars
.GetChar( nMatchChar
);
3558 xub_Unicode nSC
= aGroupChars
.GetChar( nMatchChar
-1 );
3560 USHORT nCur
= aTmpSel
.Min().GetIndex()-1;
3562 while ( pNode
&& nLevel
)
3566 XubString
& rStr
= *pNode
;
3569 if ( rStr
.GetChar( nCur
) == nSC
)
3573 break; // while nCur...
3575 else if ( rStr
.GetChar( nCur
) == nEC
)
3584 pNode
= nNode
? aEditDoc
.GetObject( --nNode
) : 0;
3586 nCur
= pNode
->Len()-1; // egal ob negativ, weil if Len()
3590 if ( nLevel
== 0 ) // gefunden
3592 aMatchSel
.Min() = aTmpSel
.Min();
3593 aMatchSel
.Min().GetIndex()++; // hinter das Zeichen
3594 aMatchSel
.Max() = EditPaM( pNode
, nCur
);
3601 void ImpEditEngine::StopSelectionMode()
3603 if ( ( IsInSelectionMode() || aSelEngine
.IsInSelection() ) && pActiveView
)
3605 pActiveView
->pImpEditView
->DrawSelection(); // Wegzeichnen...
3606 EditSelection
aSel( pActiveView
->pImpEditView
->GetEditSelection() );
3607 aSel
.Min() = aSel
.Max();
3608 pActiveView
->pImpEditView
->SetEditSelection( aSel
);
3609 pActiveView
->ShowCursor();
3611 bInSelection
= FALSE
;
3615 void ImpEditEngine::SetActiveView( EditView
* pView
)
3617 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
3618 // Eigentlich waere jetzt ein bHasVisSel und HideSelection notwendig !!!
3620 if ( pView
== pActiveView
)
3623 if ( pActiveView
&& pActiveView
->HasSelection() )
3624 pActiveView
->pImpEditView
->DrawSelection(); // Wegzeichnen...
3626 pActiveView
= pView
;
3628 if ( pActiveView
&& pActiveView
->HasSelection() )
3629 pActiveView
->pImpEditView
->DrawSelection(); // Wegzeichnen...
3631 // NN: Quick fix for #78668#:
3632 // When editing of a cell in Calc is ended, the edit engine is not deleted,
3633 // only the edit views are removed. If mpIMEInfos is still set in that case,
3634 // mpIMEInfos->aPos points to an invalid selection.
3635 // -> reset mpIMEInfos now
3636 // (probably something like this is necessary whenever the content is modified
3637 // from the outside)
3639 if ( !pView
&& mpIMEInfos
)
3646 uno::Reference
< datatransfer::XTransferable
> ImpEditEngine::CreateTransferable( const EditSelection
& rSelection
) const
3649 EditSelection
aSelection( rSelection
);
3650 aSelection
.Adjust( GetEditDoc() );
3652 EditDataObject
* pDataObj
= new EditDataObject
;
3653 uno::Reference
< datatransfer::XTransferable
> xDataObj
;
3654 xDataObj
= pDataObj
;
3656 XubString
aText( GetSelected( aSelection
) );
3657 aText
.ConvertLineEnd(); // Systemspezifisch
3658 pDataObj
->GetString() = aText
;
3660 SvxFontItem::EnableStoreUnicodeNames( TRUE
);
3661 WriteBin( pDataObj
->GetStream(), aSelection
, TRUE
);
3662 pDataObj
->GetStream().Seek( 0 );
3663 SvxFontItem::EnableStoreUnicodeNames( FALSE
);
3665 ((ImpEditEngine
*)this)->WriteRTF( pDataObj
->GetRTFStream(), aSelection
);
3666 pDataObj
->GetRTFStream().Seek( 0 );
3668 if ( ( aSelection
.Min().GetNode() == aSelection
.Max().GetNode() )
3669 && ( aSelection
.Max().GetIndex() == (aSelection
.Min().GetIndex()+1) ) )
3671 const EditCharAttrib
* pAttr
= aSelection
.Min().GetNode()->GetCharAttribs().
3672 FindFeature( aSelection
.Min().GetIndex() );
3674 ( pAttr
->GetStart() == aSelection
.Min().GetIndex() ) &&
3675 ( pAttr
->Which() == EE_FEATURE_FIELD
) )
3677 const SvxFieldItem
* pField
= (const SvxFieldItem
*)pAttr
->GetItem();
3678 const SvxFieldData
* pFld
= pField
->GetField();
3679 if ( pFld
&& pFld
->ISA( SvxURLField
) )
3682 String
aURL( ((const SvxURLField
*)pFld
)->GetURL() );
3683 String
aTxt( ((const SvxURLField
*)pFld
)->GetRepresentation() );
3684 pDataObj
->GetURL() = aURL
;
3691 return uno::Reference
< datatransfer::XTransferable
>();
3695 EditSelection
ImpEditEngine::InsertText( uno::Reference
< datatransfer::XTransferable
>& rxDataObj
, const String
& rBaseURL
, const EditPaM
& rPaM
, BOOL bUseSpecial
)
3697 EditSelection
aNewSelection( rPaM
);
3699 if ( rxDataObj
.is() )
3701 datatransfer::DataFlavor aFlavor
;
3707 SotExchange::GetFormatDataFlavor( SOT_FORMATSTR_ID_EDITENGINE
, aFlavor
);
3708 if ( rxDataObj
->isDataFlavorSupported( aFlavor
) )
3712 uno::Any aData
= rxDataObj
->getTransferData( aFlavor
);
3713 uno::Sequence
< sal_Int8
> aSeq
;
3716 SvMemoryStream
aBinStream( aSeq
.getArray(), aSeq
.getLength(), STREAM_READ
);
3717 aNewSelection
= Read( aBinStream
, rBaseURL
, EE_FORMAT_BIN
, rPaM
);
3721 catch( const ::com::sun::star::uno::Exception
& )
3732 // Feld nur einfuegen, wenn Factory vorhanden.
3733 if ( ITEMDATA() && ITEMDATA()->GetClassManager().Get( SVX_URLFIELD ) )
3735 SvxFieldItem aField( SvxURLField( aURL, aTxt, SVXURLFORMAT_URL ), EE_FEATURE_FIELD );
3736 aNewSelection = InsertField( aPaM, aField );
3740 aNewSelection = ImpInsertText( aPaM, aURL );
3747 SotExchange::GetFormatDataFlavor( SOT_FORMAT_RTF
, aFlavor
);
3748 if ( rxDataObj
->isDataFlavorSupported( aFlavor
) )
3752 uno::Any aData
= rxDataObj
->getTransferData( aFlavor
);
3753 uno::Sequence
< sal_Int8
> aSeq
;
3756 SvMemoryStream
aRTFStream( aSeq
.getArray(), aSeq
.getLength(), STREAM_READ
);
3757 aNewSelection
= Read( aRTFStream
, rBaseURL
, EE_FORMAT_RTF
, rPaM
);
3761 catch( const ::com::sun::star::uno::Exception
& )
3769 // Currently, there is nothing like "The" XML format, StarOffice doesn't offer plain XML in Clipboard...
3774 SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING
, aFlavor
);
3775 if ( rxDataObj
->isDataFlavorSupported( aFlavor
) )
3779 uno::Any aData
= rxDataObj
->getTransferData( aFlavor
);
3780 ::rtl::OUString aText
;
3782 aNewSelection
= ImpInsertText( rPaM
, aText
);
3787 ; // #i9286# can happen, even if isDataFlavorSupported returns true...
3793 return aNewSelection
;
3796 Range
ImpEditEngine::GetInvalidYOffsets( ParaPortion
* pPortion
)
3798 Range
aRange( 0, 0 );
3800 if ( pPortion
->IsVisible() )
3802 const SvxULSpaceItem
& rULSpace
= (const SvxULSpaceItem
&)pPortion
->GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE
);
3803 const SvxLineSpacingItem
& rLSItem
= (const SvxLineSpacingItem
&)pPortion
->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL
);
3804 USHORT nSBL
= ( rLSItem
.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_FIX
)
3805 ? GetYValue( rLSItem
.GetInterLineSpace() ) : 0;
3807 // erst von vorne...
3808 USHORT nFirstInvalid
= 0xFFFF;
3810 for ( nLine
= 0; nLine
< pPortion
->GetLines().Count(); nLine
++ )
3812 EditLine
* pL
= pPortion
->GetLines().GetObject( nLine
);
3813 if ( pL
->IsInvalid() )
3815 nFirstInvalid
= nLine
;
3818 if ( nLine
&& !aStatus
.IsOutliner() ) // nicht die erste Zeile
3819 aRange
.Min() += nSBL
;
3820 aRange
.Min() += pL
->GetHeight();
3822 DBG_ASSERT( nFirstInvalid
!= 0xFFFF, "Keine ungueltige Zeile gefunden in GetInvalidYOffset(1)" );
3825 // Abgleichen und weiter...
3826 aRange
.Max() = aRange
.Min();
3827 aRange
.Max() += pPortion
->GetFirstLineOffset();
3828 if ( nFirstInvalid
!= 0 ) // Nur wenn nicht die erste Zeile ungueltig
3829 aRange
.Min() = aRange
.Max();
3831 USHORT nLastInvalid
= pPortion
->GetLines().Count()-1;
3832 for ( nLine
= nFirstInvalid
; nLine
< pPortion
->GetLines().Count(); nLine
++ )
3834 EditLine
* pL
= pPortion
->GetLines().GetObject( nLine
);
3835 if ( pL
->IsValid() )
3837 nLastInvalid
= nLine
;
3841 if ( nLine
&& !aStatus
.IsOutliner() )
3842 aRange
.Max() += nSBL
;
3843 aRange
.Max() += pL
->GetHeight();
3846 // MT 07/00 SBL kann jetzt kleiner 100% sein => ggf. die Zeile davor neu ausgeben.
3847 if( ( rLSItem
.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_PROP
) && rLSItem
.GetPropLineSpace() &&
3848 ( rLSItem
.GetPropLineSpace() < 100 ) )
3850 EditLine
* pL
= pPortion
->GetLines().GetObject( nFirstInvalid
);
3851 long n
= pL
->GetTxtHeight() * ( 100 - rLSItem
.GetPropLineSpace() );
3857 if ( ( nLastInvalid
== pPortion
->GetLines().Count()-1 ) && ( !aStatus
.IsOutliner() ) )
3858 aRange
.Max() += GetYValue( rULSpace
.GetLower() );
3863 EditPaM
ImpEditEngine::GetPaM( ParaPortion
* pPortion
, Point aDocPos
, BOOL bSmart
)
3865 DBG_ASSERT( pPortion
->IsVisible(), "Wozu GetPaM() bei einem unsichtbaren Absatz?" );
3866 DBG_ASSERT( IsFormatted(), "GetPaM: Nicht formatiert" );
3868 USHORT nCurIndex
= 0;
3870 aPaM
.SetNode( pPortion
->GetNode() );
3872 const SvxLineSpacingItem
& rLSItem
= (const SvxLineSpacingItem
&)pPortion
->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL
);
3873 USHORT nSBL
= ( rLSItem
.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_FIX
)
3874 ? GetYValue( rLSItem
.GetInterLineSpace() ) : 0;
3876 long nY
= pPortion
->GetFirstLineOffset();
3878 DBG_ASSERT( pPortion
->GetLines().Count(), "Leere ParaPortion in GetPaM!" );
3880 EditLine
* pLine
= 0;
3881 for ( USHORT nLine
= 0; nLine
< pPortion
->GetLines().Count(); nLine
++ )
3883 EditLine
* pTmpLine
= pPortion
->GetLines().GetObject( nLine
);
3884 nY
+= pTmpLine
->GetHeight();
3885 if ( !aStatus
.IsOutliner() )
3887 if ( nY
> aDocPos
.Y() ) // das war 'se
3890 break; // richtige Y-Position intressiert nicht
3893 nCurIndex
= nCurIndex
+ pTmpLine
->GetLen();
3896 if ( !pLine
) // darf nur im Bereich von SA passieren!
3899 const SvxULSpaceItem
& rULSpace
=(const SvxULSpaceItem
&)pPortion
->GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE
);
3900 DBG_ASSERT( nY
+GetYValue( rULSpace
.GetLower() ) >= aDocPos
.Y() , "Index in keiner Zeile, GetPaM ?" );
3902 aPaM
.SetIndex( pPortion
->GetNode()->Len() );
3906 // Wenn Zeile gefunden, nur noch X-Position => Index
3907 nCurIndex
= GetChar( pPortion
, pLine
, aDocPos
.X(), bSmart
);
3908 aPaM
.SetIndex( nCurIndex
);
3910 if ( nCurIndex
&& ( nCurIndex
== pLine
->GetEnd() ) &&
3911 ( pLine
!= pPortion
->GetLines().GetObject( pPortion
->GetLines().Count()-1) ) )
3913 aPaM
= CursorLeft( aPaM
, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL
);
3919 USHORT
ImpEditEngine::GetChar( ParaPortion
* pParaPortion
, EditLine
* pLine
, long nXPos
, BOOL bSmart
)
3921 DBG_ASSERT( pLine
, "Keine Zeile erhalten: GetChar" );
3923 USHORT nChar
= 0xFFFF;
3924 USHORT nCurIndex
= pLine
->GetStart();
3927 // Search best matching portion with GetPortionXOffset()
3928 for ( USHORT i
= pLine
->GetStartPortion(); i
<= pLine
->GetEndPortion(); i
++ )
3930 TextPortion
* pPortion
= pParaPortion
->GetTextPortions().GetObject( i
);
3931 long nXLeft
= GetPortionXOffset( pParaPortion
, pLine
, i
);
3932 long nXRight
= nXLeft
+ pPortion
->GetSize().Width();
3933 if ( ( nXLeft
<= nXPos
) && ( nXRight
>= nXPos
) )
3937 // Search within Portion...
3939 // Don't search within special portions...
3940 if ( pPortion
->GetKind() != PORTIONKIND_TEXT
)
3942 // ...but check on which side
3945 long nLeftDiff
= nXPos
-nXLeft
;
3946 long nRightDiff
= nXRight
-nXPos
;
3947 if ( nRightDiff
< nLeftDiff
)
3953 USHORT nMax
= pPortion
->GetLen();
3954 USHORT nOffset
= 0xFFFF;
3955 USHORT nTmpCurIndex
= nChar
- pLine
->GetStart();
3957 long nXInPortion
= nXPos
- nXLeft
;
3958 if ( pPortion
->IsRightToLeft() )
3959 nXInPortion
= nXRight
- nXPos
;
3961 // Search in Array...
3962 for ( USHORT x
= 0; x
< nMax
; x
++ )
3964 long nTmpPosMax
= pLine
->GetCharPosArray().GetObject( nTmpCurIndex
+x
);
3965 if ( nTmpPosMax
> nXInPortion
)
3967 // pruefen, ob dieser oder der davor...
3968 long nTmpPosMin
= x
? pLine
->GetCharPosArray().GetObject( nTmpCurIndex
+x
-1 ) : 0;
3969 long nDiffLeft
= nXInPortion
- nTmpPosMin
;
3970 long nDiffRight
= nTmpPosMax
- nXInPortion
;
3971 DBG_ASSERT( nDiffLeft
>= 0, "DiffLeft negativ" );
3972 DBG_ASSERT( nDiffRight
>= 0, "DiffRight negativ" );
3973 nOffset
= ( bSmart
&& ( nDiffRight
< nDiffLeft
) ) ? x
+1 : x
;
3974 // I18N: If there are character position with the length of 0,
3975 // they belong to the same character, we can not use this position as an index.
3976 // Skip all 0-positions, cheaper than using XBreakIterator:
3977 if ( nOffset
< nMax
)
3979 const long nX
= pLine
->GetCharPosArray().GetObject(nOffset
);
3980 while ( ( (nOffset
+1) < nMax
) && ( pLine
->GetCharPosArray().GetObject(nOffset
+1) == nX
) )
3987 // Bei Verwendung des CharPosArray duerfte es keine Ungenauigkeiten geben!
3988 // Vielleicht bei Kerning ?
3989 // 0xFFF passiert z.B. bei Outline-Font, wenn ganz hinten.
3990 if ( nOffset
== 0xFFFF )
3993 DBG_ASSERT( nOffset
<= nMax
, "nOffset > nMax" );
3995 nChar
= nChar
+ nOffset
;
3997 // Check if index is within a cell:
3998 if ( nChar
&& ( nChar
< pParaPortion
->GetNode()->Len() ) )
4000 EditPaM
aPaM( pParaPortion
->GetNode(), nChar
+1 );
4001 USHORT nScriptType
= GetScriptType( aPaM
);
4002 if ( nScriptType
== i18n::ScriptType::COMPLEX
)
4004 uno::Reference
< i18n::XBreakIterator
> _xBI( ImplGetBreakIterator() );
4005 sal_Int32 nCount
= 1;
4006 lang::Locale aLocale
= GetLocale( aPaM
);
4007 USHORT nRight
= (USHORT
)_xBI
->nextCharacters( *pParaPortion
->GetNode(), nChar
, aLocale
, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL
, nCount
, nCount
);
4008 USHORT nLeft
= (USHORT
)_xBI
->previousCharacters( *pParaPortion
->GetNode(), nRight
, aLocale
, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL
, nCount
, nCount
);
4009 if ( ( nLeft
!= nChar
) && ( nRight
!= nChar
) )
4011 nChar
= ( Abs( nRight
- nChar
) < Abs( nLeft
- nChar
) ) ? nRight
: nLeft
;
4018 nCurIndex
= nCurIndex
+ pPortion
->GetLen();
4021 if ( nChar
== 0xFFFF )
4023 nChar
= ( nXPos
<= pLine
->GetStartPosX() ) ? pLine
->GetStart() : pLine
->GetEnd();
4029 Range
ImpEditEngine::GetLineXPosStartEnd( ParaPortion
* pParaPortion
, EditLine
* pLine
)
4031 Range aLineXPosStartEnd
;
4033 USHORT nPara
= GetEditDoc().GetPos( pParaPortion
->GetNode() );
4034 if ( !IsRightToLeft( nPara
) )
4036 aLineXPosStartEnd
.Min() = pLine
->GetStartPosX();
4037 aLineXPosStartEnd
.Max() = pLine
->GetStartPosX() + pLine
->GetTextWidth();
4041 aLineXPosStartEnd
.Min() = GetPaperSize().Width() - ( pLine
->GetStartPosX() + pLine
->GetTextWidth() );
4042 aLineXPosStartEnd
.Max() = GetPaperSize().Width() - pLine
->GetStartPosX();
4046 return aLineXPosStartEnd
;
4049 long ImpEditEngine::GetPortionXOffset( ParaPortion
* pParaPortion
, EditLine
* pLine
, USHORT nTextPortion
)
4051 long nX
= pLine
->GetStartPosX();
4053 for ( USHORT i
= pLine
->GetStartPortion(); i
< nTextPortion
; i
++ )
4055 TextPortion
* pPortion
= pParaPortion
->GetTextPortions().GetObject( i
);
4056 switch ( pPortion
->GetKind() )
4058 case PORTIONKIND_FIELD
:
4059 case PORTIONKIND_TEXT
:
4060 case PORTIONKIND_HYPHENATOR
:
4061 case PORTIONKIND_TAB
:
4062 // case PORTIONKIND_EXTRASPACE:
4064 nX
+= pPortion
->GetSize().Width();
4070 USHORT nPara
= GetEditDoc().GetPos( pParaPortion
->GetNode() );
4071 BOOL bR2LPara
= IsRightToLeft( nPara
);
4073 TextPortion
* pDestPortion
= pParaPortion
->GetTextPortions().GetObject( nTextPortion
);
4074 if ( pDestPortion
->GetKind() != PORTIONKIND_TAB
)
4076 if ( !bR2LPara
&& pDestPortion
->GetRightToLeft() )
4078 // Portions behind must be added, visual before this portion
4079 sal_uInt16 nTmpPortion
= nTextPortion
+1;
4080 while ( nTmpPortion
<= pLine
->GetEndPortion() )
4082 TextPortion
* pNextTextPortion
= pParaPortion
->GetTextPortions().GetObject( nTmpPortion
);
4083 if ( pNextTextPortion
->GetRightToLeft() && ( pNextTextPortion
->GetKind() != PORTIONKIND_TAB
) )
4084 nX
+= pNextTextPortion
->GetSize().Width();
4089 // Portions before must be removed, visual behind this portion
4090 nTmpPortion
= nTextPortion
;
4091 while ( nTmpPortion
> pLine
->GetStartPortion() )
4094 TextPortion
* pPrevTextPortion
= pParaPortion
->GetTextPortions().GetObject( nTmpPortion
);
4095 if ( pPrevTextPortion
->GetRightToLeft() && ( pPrevTextPortion
->GetKind() != PORTIONKIND_TAB
) )
4096 nX
-= pPrevTextPortion
->GetSize().Width();
4101 else if ( bR2LPara
&& !pDestPortion
->IsRightToLeft() )
4103 // Portions behind must be ermoved, visual behind this portion
4104 sal_uInt16 nTmpPortion
= nTextPortion
+1;
4105 while ( nTmpPortion
<= pLine
->GetEndPortion() )
4107 TextPortion
* pNextTextPortion
= pParaPortion
->GetTextPortions().GetObject( nTmpPortion
);
4108 if ( !pNextTextPortion
->IsRightToLeft() && ( pNextTextPortion
->GetKind() != PORTIONKIND_TAB
) )
4109 nX
+= pNextTextPortion
->GetSize().Width();
4114 // Portions before must be added, visual before this portion
4115 nTmpPortion
= nTextPortion
;
4116 while ( nTmpPortion
> pLine
->GetStartPortion() )
4119 TextPortion
* pPrevTextPortion
= pParaPortion
->GetTextPortions().GetObject( nTmpPortion
);
4120 if ( !pPrevTextPortion
->IsRightToLeft() && ( pPrevTextPortion
->GetKind() != PORTIONKIND_TAB
) )
4121 nX
-= pPrevTextPortion
->GetSize().Width();
4129 // Switch X postions...
4130 DBG_ASSERT( GetTextRanger() || GetPaperSize().Width(), "GetPortionXOffset - paper size?!" );
4131 DBG_ASSERT( GetTextRanger() || (nX
<= GetPaperSize().Width()), "GetPortionXOffset - position out of paper size!" );
4132 nX
= GetPaperSize().Width() - nX
;
4133 nX
-= pDestPortion
->GetSize().Width();
4139 long ImpEditEngine::GetXPos( ParaPortion
* pParaPortion
, EditLine
* pLine
, USHORT nIndex
, BOOL bPreferPortionStart
)
4141 DBG_ASSERT( pLine
, "Keine Zeile erhalten: GetXPos" );
4142 DBG_ASSERT( ( nIndex
>= pLine
->GetStart() ) && ( nIndex
<= pLine
->GetEnd() ) , "GetXPos muss richtig gerufen werden!" );
4144 BOOL bDoPreferPortionStart
= bPreferPortionStart
;
4145 // Assure that the portion belongs to this line:
4146 if ( nIndex
== pLine
->GetStart() )
4147 bDoPreferPortionStart
= TRUE
;
4148 else if ( nIndex
== pLine
->GetEnd() )
4149 bDoPreferPortionStart
= FALSE
;
4151 USHORT nTextPortionStart
= 0;
4152 USHORT nTextPortion
= pParaPortion
->GetTextPortions().FindPortion( nIndex
, nTextPortionStart
, bDoPreferPortionStart
);
4154 DBG_ASSERT( ( nTextPortion
>= pLine
->GetStartPortion() ) && ( nTextPortion
<= pLine
->GetEndPortion() ), "GetXPos: Portion not in current line! " );
4156 TextPortion
* pPortion
= pParaPortion
->GetTextPortions().GetObject( nTextPortion
);
4158 long nX
= GetPortionXOffset( pParaPortion
, pLine
, nTextPortion
);
4160 // calc text width, portion size may include CJK/CTL spacing...
4161 // But the array migh not be init yet, if using text ranger this method is called within CreateLines()...
4162 long nPortionTextWidth
= pPortion
->GetSize().Width();
4163 if ( ( pPortion
->GetKind() == PORTIONKIND_TEXT
) && pPortion
->GetLen() && !GetTextRanger() )
4164 nPortionTextWidth
= pLine
->GetCharPosArray().GetObject( nTextPortionStart
+ pPortion
->GetLen() - 1 - pLine
->GetStart() );
4166 if ( nTextPortionStart
!= nIndex
)
4168 // Search within portion...
4169 if ( nIndex
== ( nTextPortionStart
+ pPortion
->GetLen() ) )
4172 if ( pPortion
->GetKind() == PORTIONKIND_TAB
)
4174 if ( (nTextPortion
+1) < pParaPortion
->GetTextPortions().Count() )
4176 TextPortion
* pNextPortion
= pParaPortion
->GetTextPortions().GetObject( nTextPortion
+1 );
4177 if ( pNextPortion
->GetKind() != PORTIONKIND_TAB
)
4179 // DBG_ASSERT( !bPreferPortionStart, "GetXPos - How can we this tab portion here???" );
4180 // #109879# We loop if nIndex == pLine->GetEnd, because bPreferPortionStart will be reset
4181 if ( !bPreferPortionStart
)
4182 nX
= GetXPos( pParaPortion
, pLine
, nIndex
, TRUE
);
4183 else if ( !IsRightToLeft( GetEditDoc().GetPos( pParaPortion
->GetNode() ) ) )
4184 nX
+= nPortionTextWidth
;
4187 else if ( !IsRightToLeft( GetEditDoc().GetPos( pParaPortion
->GetNode() ) ) )
4189 nX
+= nPortionTextWidth
;
4192 else if ( !pPortion
->IsRightToLeft() )
4194 nX
+= nPortionTextWidth
;
4197 else if ( pPortion
->GetKind() == PORTIONKIND_TEXT
)
4199 DBG_ASSERT( nIndex
!= pLine
->GetStart(), "Strange behavior in new GetXPos()" );
4200 DBG_ASSERT( pLine
&& pLine
->GetCharPosArray().Count(), "svx::ImpEditEngine::GetXPos(), portion in an empty line?" );
4202 if( pLine
->GetCharPosArray().Count() )
4204 USHORT nPos
= nIndex
- 1 - pLine
->GetStart();
4205 if( nPos
>= pLine
->GetCharPosArray().Count() )
4207 nPos
= pLine
->GetCharPosArray().Count()-1;
4208 DBG_ERROR("svx::ImpEditEngine::GetXPos(), index out of range!");
4211 long nPosInPortion
= pLine
->GetCharPosArray().GetObject( nPos
);
4213 if ( !pPortion
->IsRightToLeft() )
4215 nX
+= nPosInPortion
;
4219 nX
+= nPortionTextWidth
- nPosInPortion
;
4222 if ( pPortion
->GetExtraInfos() && pPortion
->GetExtraInfos()->bCompressed
)
4224 nX
+= pPortion
->GetExtraInfos()->nPortionOffsetX
;
4225 if ( pPortion
->GetExtraInfos()->nAsianCompressionTypes
& CHAR_PUNCTUATIONRIGHT
)
4227 BYTE nType
= GetCharTypeForCompression( pParaPortion
->GetNode()->GetChar( nIndex
) );
4228 if ( nType
== CHAR_PUNCTUATIONRIGHT
)
4230 USHORT n
= nIndex
- nTextPortionStart
;
4231 const sal_Int32
* pDXArray
= pLine
->GetCharPosArray().GetData()+( nTextPortionStart
-pLine
->GetStart() );
4232 sal_Int32 nCharWidth
= ( ( (n
+1) < pPortion
->GetLen() ) ? pDXArray
[n
] : pPortion
->GetSize().Width() )
4233 - ( n
? pDXArray
[n
-1] : 0 );
4234 if ( (n
+1) < pPortion
->GetLen() )
4236 // smaller, when char behind is CHAR_PUNCTUATIONRIGHT also
4237 nType
= GetCharTypeForCompression( pParaPortion
->GetNode()->GetChar( nIndex
+1 ) );
4238 if ( nType
== CHAR_PUNCTUATIONRIGHT
)
4240 sal_Int32 nNextCharWidth
= ( ( (n
+2) < pPortion
->GetLen() ) ? pDXArray
[n
+1] : pPortion
->GetSize().Width() )
4242 sal_Int32 nCompressed
= nNextCharWidth
/2;
4243 nCompressed
*= pPortion
->GetExtraInfos()->nMaxCompression100thPercent
;
4244 nCompressed
/= 10000;
4245 nCharWidth
+= nCompressed
;
4250 nCharWidth
*= 2; // last char pos to portion end is only compressed size
4252 nX
+= nCharWidth
/2; // 50% compression
4259 else // if ( nIndex == pLine->GetStart() )
4261 if ( pPortion
->IsRightToLeft() )
4263 nX
+= nPortionTextWidth
;
4270 void ImpEditEngine::CalcHeight( ParaPortion
* pPortion
)
4272 pPortion
->nHeight
= 0;
4273 pPortion
->nFirstLineOffset
= 0;
4275 if ( pPortion
->IsVisible() )
4277 DBG_ASSERT( pPortion
->GetLines().Count(), "Absatz ohne Zeilen in ParaPortion::CalcHeight" );
4278 for ( USHORT nLine
= 0; nLine
< pPortion
->GetLines().Count(); nLine
++ )
4279 pPortion
->nHeight
+= pPortion
->GetLines().GetObject( nLine
)->GetHeight();
4281 if ( !aStatus
.IsOutliner() )
4283 const SvxULSpaceItem
& rULItem
= (const SvxULSpaceItem
&)pPortion
->GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE
);
4284 const SvxLineSpacingItem
& rLSItem
= (const SvxLineSpacingItem
&)pPortion
->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL
);
4285 USHORT nSBL
= ( rLSItem
.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_FIX
) ? GetYValue( rLSItem
.GetInterLineSpace() ) : 0;
4289 if ( pPortion
->GetLines().Count() > 1 )
4290 pPortion
->nHeight
+= ( pPortion
->GetLines().Count() - 1 ) * nSBL
;
4291 if ( aStatus
.ULSpaceSummation() )
4292 pPortion
->nHeight
+= nSBL
;
4295 USHORT nPortion
= GetParaPortions().GetPos( pPortion
);
4296 if ( nPortion
|| aStatus
.ULSpaceFirstParagraph() )
4298 USHORT nUpper
= GetYValue( rULItem
.GetUpper() );
4299 pPortion
->nHeight
+= nUpper
;
4300 pPortion
->nFirstLineOffset
= nUpper
;
4303 if ( ( nPortion
!= (GetParaPortions().Count()-1) ) )
4305 pPortion
->nHeight
+= GetYValue( rULItem
.GetLower() ); // nicht in letzter
4309 if ( nPortion
&& !aStatus
.ULSpaceSummation() )
4311 ParaPortion
* pPrev
= GetParaPortions().SaveGetObject( nPortion
-1 );
4312 const SvxULSpaceItem
& rPrevULItem
= (const SvxULSpaceItem
&)pPrev
->GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE
);
4313 const SvxLineSpacingItem
& rPrevLSItem
= (const SvxLineSpacingItem
&)pPrev
->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL
);
4315 // Verhalten WinWord6/Writer3:
4316 // Bei einem proportionalen Zeilenabstand wird auch der Absatzabstand
4318 // Nur Writer3: Nicht aufaddieren, sondern Mindestabstand.
4320 // Pruefen, ob Abstand durch LineSpacing > Upper:
4321 USHORT nExtraSpace
= GetYValue( lcl_CalcExtraSpace( pPortion
, rLSItem
) );
4322 if ( nExtraSpace
> pPortion
->nFirstLineOffset
)
4324 // Absatz wird 'groesser':
4325 pPortion
->nHeight
+= ( nExtraSpace
- pPortion
->nFirstLineOffset
);
4326 pPortion
->nFirstLineOffset
= nExtraSpace
;
4329 // nFirstLineOffset jetzt f(pNode) => jetzt f(pNode, pPrev) ermitteln:
4330 USHORT nPrevLower
= GetYValue( rPrevULItem
.GetLower() );
4332 // Dieser PrevLower steckt noch in der Hoehe der PrevPortion...
4333 if ( nPrevLower
> pPortion
->nFirstLineOffset
)
4335 // Absatz wird 'kleiner':
4336 pPortion
->nHeight
-= pPortion
->nFirstLineOffset
;
4337 pPortion
->nFirstLineOffset
= 0;
4339 else if ( nPrevLower
)
4341 // Absatz wird 'etwas kleiner':
4342 pPortion
->nHeight
-= nPrevLower
;
4343 pPortion
->nFirstLineOffset
=
4344 pPortion
->nFirstLineOffset
- nPrevLower
;
4347 // Finde ich zwar nicht so gut, aber Writer3-Feature:
4348 // Pruefen, ob Abstand durch LineSpacing > Lower:
4349 // Dieser Wert steckt nicht in der Hoehe der PrevPortion.
4350 if ( !pPrev
->IsInvalid() )
4352 nExtraSpace
= GetYValue( lcl_CalcExtraSpace( pPrev
, rPrevLSItem
) );
4353 if ( nExtraSpace
> nPrevLower
)
4355 USHORT nMoreLower
= nExtraSpace
- nPrevLower
;
4356 // Absatz wird 'groesser', 'waechst' nach unten:
4357 if ( nMoreLower
> pPortion
->nFirstLineOffset
)
4359 pPortion
->nHeight
+= ( nMoreLower
- pPortion
->nFirstLineOffset
);
4360 pPortion
->nFirstLineOffset
= nMoreLower
;
4369 Rectangle
ImpEditEngine::GetEditCursor( ParaPortion
* pPortion
, USHORT nIndex
, USHORT nFlags
)
4371 DBG_ASSERT( pPortion
->IsVisible(), "Wozu GetEditCursor() bei einem unsichtbaren Absatz?" );
4372 DBG_ASSERT( IsFormatted() || GetTextRanger(), "GetEditCursor: Nicht formatiert" );
4375 GETCRSR_ENDOFLINE: Wenn hinter dem letzten Zeichen einer umgebrochenen Zeile,
4376 am Ende der Zeile bleiben, nicht am Anfang der naechsten.
4377 Zweck: - END => wirklich hinter das letzte Zeichen
4381 long nY
= pPortion
->GetFirstLineOffset();
4383 const SvxLineSpacingItem
& rLSItem
= (const SvxLineSpacingItem
&)pPortion
->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL
);
4384 USHORT nSBL
= ( rLSItem
.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_FIX
)
4385 ? GetYValue( rLSItem
.GetInterLineSpace() ) : 0;
4387 USHORT nCurIndex
= 0;
4388 DBG_ASSERT( pPortion
->GetLines().Count(), "Leere ParaPortion in GetEditCursor!" );
4389 EditLine
* pLine
= 0;
4390 BOOL bEOL
= ( nFlags
& GETCRSR_ENDOFLINE
) ? TRUE
: FALSE
;
4391 for ( USHORT nLine
= 0; nLine
< pPortion
->GetLines().Count(); nLine
++ )
4393 EditLine
* pTmpLine
= pPortion
->GetLines().GetObject( nLine
);
4394 if ( ( pTmpLine
->GetStart() == nIndex
) || ( pTmpLine
->IsIn( nIndex
, bEOL
) ) )
4400 nCurIndex
= nCurIndex
+ pTmpLine
->GetLen();
4401 nY
+= pTmpLine
->GetHeight();
4402 if ( !aStatus
.IsOutliner() )
4407 // Cursor am Ende des Absatzes.
4408 DBG_ASSERT( nIndex
== nCurIndex
, "Index voll daneben in GetEditCursor!" );
4410 pLine
= pPortion
->GetLines().GetObject( pPortion
->GetLines().Count()-1 );
4411 nY
-= pLine
->GetHeight();
4412 if ( !aStatus
.IsOutliner() )
4414 nCurIndex
= nCurIndex
- pLine
->GetLen();
4417 Rectangle aEditCursor
;
4419 aEditCursor
.Top() = nY
;
4420 nY
+= pLine
->GetHeight();
4421 aEditCursor
.Bottom() = nY
-1;
4423 // innerhalb der Zeile suchen...
4426 if ( ( nIndex
== pLine
->GetStart() ) && ( nFlags
& GETCRSR_STARTOFLINE
) )
4428 Range aXRange
= GetLineXPosStartEnd( pPortion
, pLine
);
4429 nX
= !IsRightToLeft( GetEditDoc().GetPos( pPortion
->GetNode() ) ) ? aXRange
.Min() : aXRange
.Max();
4431 else if ( ( nIndex
== pLine
->GetEnd() ) && ( nFlags
& GETCRSR_ENDOFLINE
) )
4433 Range aXRange
= GetLineXPosStartEnd( pPortion
, pLine
);
4434 nX
= !IsRightToLeft( GetEditDoc().GetPos( pPortion
->GetNode() ) ) ? aXRange
.Max() : aXRange
.Min();
4438 nX
= GetXPos( pPortion
, pLine
, nIndex
, ( nFlags
& GETCRSR_PREFERPORTIONSTART
) ? TRUE
: FALSE
);
4441 aEditCursor
.Left() = aEditCursor
.Right() = nX
;
4443 if ( nFlags
& GETCRSR_TXTONLY
)
4444 aEditCursor
.Top() = aEditCursor
.Bottom() - pLine
->GetTxtHeight() + 1;
4446 aEditCursor
.Top() = aEditCursor
.Bottom() - Min( pLine
->GetTxtHeight(), pLine
->GetHeight() ) + 1;
4451 void ImpEditEngine::SetValidPaperSize( const Size
& rNewSz
)
4453 aPaperSize
= rNewSz
;
4455 long nMinWidth
= aStatus
.AutoPageWidth() ? aMinAutoPaperSize
.Width() : 0;
4456 long nMaxWidth
= aStatus
.AutoPageWidth() ? aMaxAutoPaperSize
.Width() : 0x7FFFFFFF;
4457 long nMinHeight
= aStatus
.AutoPageHeight() ? aMinAutoPaperSize
.Height() : 0;
4458 long nMaxHeight
= aStatus
.AutoPageHeight() ? aMaxAutoPaperSize
.Height() : 0x7FFFFFFF;
4460 // Minimale/Maximale Breite:
4461 if ( aPaperSize
.Width() < nMinWidth
)
4462 aPaperSize
.Width() = nMinWidth
;
4463 else if ( aPaperSize
.Width() > nMaxWidth
)
4464 aPaperSize
.Width() = nMaxWidth
;
4466 // Minimale/Maximale Hoehe:
4467 if ( aPaperSize
.Height() < nMinHeight
)
4468 aPaperSize
.Height() = nMinHeight
;
4469 else if ( aPaperSize
.Height() > nMaxHeight
)
4470 aPaperSize
.Height() = nMaxHeight
;
4473 void ImpEditEngine::IndentBlock( EditView
* pEditView
, BOOL bRight
)
4475 ESelection
aESel( CreateESel( pEditView
->pImpEditView
->GetEditSelection() ) );
4478 // Nur wenn mehrere selektierte Absaetze...
4479 if ( aESel
.nEndPara
> aESel
.nStartPara
)
4481 ESelection aNewSel
= aESel
;
4482 aNewSel
.nStartPos
= 0;
4483 aNewSel
.nEndPos
= 0xFFFF;
4485 if ( aESel
.nEndPos
== 0 )
4487 aESel
.nEndPara
--; // dann diesen Absatz nicht...
4488 aNewSel
.nEndPos
= 0;
4491 pEditView
->pImpEditView
->DrawSelection();
4492 pEditView
->pImpEditView
->SetEditSelection(
4493 pEditView
->pImpEditView
->GetEditSelection().Max() );
4494 UndoActionStart( bRight
? EDITUNDO_INDENTBLOCK
: EDITUNDO_UNINDENTBLOCK
);
4496 for ( USHORT nPara
= aESel
.nStartPara
; nPara
<= aESel
.nEndPara
; nPara
++ )
4498 ContentNode
* pNode
= GetEditDoc().GetObject( nPara
);
4502 EditPaM
aPaM( pNode
, 0 );
4508 EditCharAttrib
* pFeature
= pNode
->GetCharAttribs().FindFeature( 0 );
4509 if ( pFeature
&& ( pFeature
->GetStart() == 0 ) &&
4510 ( pFeature
->GetItem()->Which() == EE_FEATURE_TAB
) )
4512 EditPaM
aStartPaM( pNode
, 0 );
4513 EditPaM
aEndPaM( pNode
, 1 );
4514 ImpDeleteSelection( EditSelection( aStartPaM
, aEndPaM
) );
4519 UndoActionEnd( bRight
? EDITUNDO_INDENTBLOCK
: EDITUNDO_UNINDENTBLOCK
);
4521 FormatAndUpdate( pEditView
);
4523 ContentNode
* pLastNode
= GetEditDoc().GetObject( aNewSel
.nEndPara
);
4524 if ( pLastNode
->Len() < aNewSel
.nEndPos
)
4525 aNewSel
.nEndPos
= pLastNode
->Len();
4526 pEditView
->pImpEditView
->SetEditSelection( CreateSel( aNewSel
) );
4527 pEditView
->pImpEditView
->DrawSelection();
4528 pEditView
->pImpEditView
->ShowCursor( FALSE
, TRUE
);
4532 vos::ORef
<SvxForbiddenCharactersTable
> ImpEditEngine::GetForbiddenCharsTable( BOOL bGetInternal
) const
4534 vos::ORef
<SvxForbiddenCharactersTable
> xF
= xForbiddenCharsTable
;
4535 if ( !xF
.isValid() && bGetInternal
)
4536 xF
= EE_DLL()->GetGlobalData()->GetForbiddenCharsTable();
4540 void ImpEditEngine::SetForbiddenCharsTable( vos::ORef
<SvxForbiddenCharactersTable
> xForbiddenChars
)
4542 EE_DLL()->GetGlobalData()->SetForbiddenCharsTable( xForbiddenChars
);
4545 svtools::ColorConfig
& ImpEditEngine::GetColorConfig()
4547 if ( !pColorConfig
)
4548 pColorConfig
= new svtools::ColorConfig
;
4550 return *pColorConfig
;
4553 BOOL
ImpEditEngine::IsVisualCursorTravelingEnabled()
4555 BOOL bVisualCursorTravaling
= FALSE
;
4558 pCTLOptions
= new SvtCTLOptions
;
4560 if ( pCTLOptions
->IsCTLFontEnabled() && ( pCTLOptions
->GetCTLCursorMovement() == SvtCTLOptions::MOVEMENT_VISUAL
) )
4562 bVisualCursorTravaling
= TRUE
;
4565 return bVisualCursorTravaling
;
4569 BOOL
ImpEditEngine::DoVisualCursorTraveling( const ContentNode
* )
4571 // Don't check if it's necessary, because we also need it when leaving the paragraph
4572 return IsVisualCursorTravelingEnabled();
4574 BOOL bDoVisualCursorTraveling = FALSE;
4576 if ( IsVisualCursorTravelingEnabled() && pNode->Len() )
4578 // Only necessary when RTL text in LTR para or LTR text in RTL para
4579 bDoVisualCursorTraveling = HasDifferentRTLLevels( pNode );
4582 return bDoVisualCursorTraveling;
4587 void ImpEditEngine::CallNotify( EENotify
& rNotify
)
4589 if ( !nBlockNotifications
)
4591 GetNotifyHdl().Call( &rNotify
);
4595 EENotify
* pNewNotify
= new EENotify( rNotify
);
4596 aNotifyCache
.Insert( pNewNotify
, aNotifyCache
.Count() );
4600 void ImpEditEngine::EnterBlockNotifications()
4602 if( !nBlockNotifications
)
4604 // #109864# Send out START notification immediately, to allow
4605 // external, non-queued events to be captured as well from
4607 EENotify
aNotify( EE_NOTIFY_BLOCKNOTIFICATION_START
);
4608 aNotify
.pEditEngine
= GetEditEnginePtr();
4609 GetNotifyHdl().Call( &aNotify
);
4612 nBlockNotifications
++;
4615 void ImpEditEngine::LeaveBlockNotifications()
4617 DBG_ASSERT( nBlockNotifications
, "LeaveBlockNotifications - Why?" );
4619 nBlockNotifications
--;
4620 if ( !nBlockNotifications
)
4622 // Call blocked notify events...
4623 while ( aNotifyCache
.Count() )
4625 EENotify
* pNotify
= aNotifyCache
[0];
4626 // Remove from list before calling, maybe we enter LeaveBlockNotifications while calling the handler...
4627 aNotifyCache
.Remove( 0 );
4628 GetNotifyHdl().Call( pNotify
);
4632 EENotify
aNotify( EE_NOTIFY_BLOCKNOTIFICATION_END
);
4633 aNotify
.pEditEngine
= GetEditEnginePtr();
4634 GetNotifyHdl().Call( &aNotify
);
4638 IMPL_LINK( ImpEditEngine
, DocModified
, void*, EMPTYARG
)
4640 aModifyHdl
.Call( NULL
/*GetEditEnginePtr()*/ ); // NULL, because also used for Outliner