update dev300-m58
[ooovba.git] / vcl / source / control / edit.cxx
bloba598faa3544fceaa31ca342fce8fb66ec408baa6
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: edit.cxx,v $
10 * $Revision: 1.101 $
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_vcl.hxx"
34 #ifndef _SV_RC_H
35 #include <tools/rc.h>
36 #endif
37 #include <vcl/svdata.hxx>
38 #include <vcl/decoview.hxx>
39 #include <vcl/event.hxx>
40 #include <vcl/cursor.hxx>
41 #include <vcl/virdev.hxx>
42 #ifndef _SV_SVIDS_HRC
43 #include <vcl/svids.hrc>
44 #endif
45 #include <vcl/menu.hxx>
46 #include <vcl/cmdevt.h>
47 #include <vcl/subedit.hxx>
48 #include <vcl/edit.hxx>
49 #include <vcl/svapp.hxx>
50 #include <vcl/controllayout.hxx>
51 #include <vcl/msgbox.hxx>
52 #include <vcl/window.h>
54 #include <vos/mutex.hxx>
57 #include <com/sun/star/i18n/XBreakIterator.hpp>
58 #include <com/sun/star/i18n/CharacterIteratorMode.hpp>
59 #include <com/sun/star/i18n/WordType.hpp>
60 #include <cppuhelper/weak.hxx>
61 #include <com/sun/star/datatransfer/XTransferable.hpp>
62 #include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
63 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
65 #ifndef _COM_SUN_STAR_DATATRANSFER_DND_DNDCONSTANS_HPP_
66 #include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
67 #endif
68 #include <com/sun/star/datatransfer/dnd/XDragGestureRecognizer.hpp>
69 #include <com/sun/star/datatransfer/dnd/XDropTarget.hpp>
71 #ifndef _COM_SUN_STAR_I18N_XEXTENDEDINPUTSEQUENCECHECKER_HDL_
72 #include <com/sun/star/i18n/XExtendedInputSequenceChecker.hpp>
73 #endif
74 #include <com/sun/star/i18n/InputSequenceCheckMode.hpp>
75 #include <com/sun/star/i18n/ScriptType.hpp>
76 #include <com/sun/star/container/XNameAccess.hpp>
78 #include <com/sun/star/uno/Any.hxx>
80 #include <comphelper/processfactory.hxx>
81 #include <comphelper/configurationhelper.hxx>
83 #include <sot/exchange.hxx>
84 #include <sot/formats.hxx>
85 #include <rtl/memory.h>
87 #include <vcl/unohelp.hxx>
88 #include <vcl/unohelp2.hxx>
93 using namespace ::com::sun::star;
94 using namespace ::com::sun::star::uno;
95 using namespace ::com::sun::star::lang;
96 using namespace ::rtl;
98 // - Redo
99 // - Bei Tracking-Cancel DefaultSelection wieder herstellen
101 // =======================================================================
103 static FncGetSpecialChars pImplFncGetSpecialChars = NULL;
105 // =======================================================================
107 #define EDIT_ALIGN_LEFT 1
108 #define EDIT_ALIGN_CENTER 2
109 #define EDIT_ALIGN_RIGHT 3
111 #define EDIT_DEL_LEFT 1
112 #define EDIT_DEL_RIGHT 2
114 #define EDIT_DELMODE_SIMPLE 11
115 #define EDIT_DELMODE_RESTOFWORD 12
116 #define EDIT_DELMODE_RESTOFCONTENT 13
118 // =======================================================================
120 struct DDInfo
122 Cursor aCursor;
123 Selection aDndStartSel;
124 xub_StrLen nDropPos;
125 BOOL bStarterOfDD;
126 BOOL bDroppedInMe;
127 BOOL bVisCursor;
129 DDInfo()
131 aCursor.SetStyle( CURSOR_SHADOW );
132 nDropPos = 0;
133 bStarterOfDD = FALSE;
134 bDroppedInMe = FALSE;
135 bVisCursor = FALSE;
139 // =======================================================================
141 struct Impl_IMEInfos
143 String aOldTextAfterStartPos;
144 USHORT* pAttribs;
145 xub_StrLen nPos;
146 xub_StrLen nLen;
147 BOOL bCursor;
148 BOOL bWasCursorOverwrite;
150 Impl_IMEInfos( xub_StrLen nPos, const String& rOldTextAfterStartPos );
151 ~Impl_IMEInfos();
153 void CopyAttribs( const xub_StrLen* pA, xub_StrLen nL );
154 void DestroyAttribs();
157 // -----------------------------------------------------------------------
159 Impl_IMEInfos::Impl_IMEInfos( xub_StrLen nP, const String& rOldTextAfterStartPos )
160 : aOldTextAfterStartPos( rOldTextAfterStartPos )
162 nPos = nP;
163 nLen = 0;
164 bCursor = TRUE;
165 pAttribs = NULL;
166 bWasCursorOverwrite = FALSE;
169 // -----------------------------------------------------------------------
171 Impl_IMEInfos::~Impl_IMEInfos()
173 delete[] pAttribs;
176 // -----------------------------------------------------------------------
178 void Impl_IMEInfos::CopyAttribs( const xub_StrLen* pA, xub_StrLen nL )
180 nLen = nL;
181 delete[] pAttribs;
182 pAttribs = new USHORT[ nL ];
183 rtl_copyMemory( pAttribs, pA, nL*sizeof(USHORT) );
186 // -----------------------------------------------------------------------
188 void Impl_IMEInfos::DestroyAttribs()
190 delete[] pAttribs;
191 pAttribs = NULL;
192 nLen = 0;
195 // =======================================================================
197 Edit::Edit( WindowType nType ) :
198 Control( nType )
200 ImplInitEditData();
203 // -----------------------------------------------------------------------
205 Edit::Edit( Window* pParent, WinBits nStyle ) :
206 Control( WINDOW_EDIT )
208 ImplInitEditData();
209 ImplInit( pParent, nStyle );
212 // -----------------------------------------------------------------------
214 Edit::Edit( Window* pParent, const ResId& rResId ) :
215 Control( WINDOW_EDIT )
217 ImplInitEditData();
218 rResId.SetRT( RSC_EDIT );
219 WinBits nStyle = ImplInitRes( rResId );
220 ImplInit( pParent, nStyle );
221 ImplLoadRes( rResId );
223 // Derived MultiLineEdit takes care to call Show only after MultiLineEdit
224 // ctor has already started:
225 if ( !(nStyle & WB_HIDE) && rResId.GetRT() != RSC_MULTILINEEDIT )
226 Show();
229 // -----------------------------------------------------------------------
231 Edit::Edit( Window* pParent, const ResId& rResId, bool bDisableAccessibleLabeledByRelation ) :
232 Control( WINDOW_EDIT )
234 ImplInitEditData();
235 rResId.SetRT( RSC_EDIT );
236 WinBits nStyle = ImplInitRes( rResId );
237 ImplInit( pParent, nStyle );
238 ImplLoadRes( rResId );
239 if ( bDisableAccessibleLabeledByRelation )
240 ImplGetWindowImpl()->mbDisableAccessibleLabeledByRelation = TRUE;
242 // Derived MultiLineEdit takes care to call Show only after MultiLineEdit
243 // ctor has already started:
244 if ( !(nStyle & WB_HIDE) && rResId.GetRT() != RSC_MULTILINEEDIT )
245 Show();
248 // -----------------------------------------------------------------------
250 Edit::~Edit()
252 delete mpDDInfo;
253 Cursor* pCursor = GetCursor();
254 if ( pCursor )
256 SetCursor( NULL );
257 delete pCursor;
260 delete mpIMEInfos;
262 if ( mpUpdateDataTimer )
263 delete mpUpdateDataTimer;
265 if ( mxDnDListener.is() )
267 if ( GetDragGestureRecognizer().is() )
269 uno::Reference< datatransfer::dnd::XDragGestureListener> xDGL( mxDnDListener, uno::UNO_QUERY );
270 GetDragGestureRecognizer()->removeDragGestureListener( xDGL );
272 if ( GetDropTarget().is() )
274 uno::Reference< datatransfer::dnd::XDropTargetListener> xDTL( mxDnDListener, uno::UNO_QUERY );
275 GetDropTarget()->removeDropTargetListener( xDTL );
278 uno::Reference< lang::XEventListener> xEL( mxDnDListener, uno::UNO_QUERY );
279 xEL->disposing( lang::EventObject() ); // #95154# #96585# Empty Source means it's the Client
283 // -----------------------------------------------------------------------
285 void Edit::ImplInitEditData()
287 mpSubEdit = NULL;
288 mpUpdateDataTimer = NULL;
289 mnXOffset = 0;
290 mnAlign = EDIT_ALIGN_LEFT;
291 mnMaxTextLen = EDIT_NOLIMIT;
292 meAutocompleteAction = AUTOCOMPLETE_KEYINPUT;
293 mbModified = FALSE;
294 mbInternModified = FALSE;
295 mbReadOnly = FALSE;
296 mbInsertMode = TRUE;
297 mbClickedInSelection = FALSE;
298 mbActivePopup = FALSE;
299 mbIsSubEdit = FALSE;
300 mbInMBDown = FALSE;
301 mpDDInfo = NULL;
302 mpIMEInfos = NULL;
303 mcEchoChar = 0;
305 // --- RTL --- no default mirroring for Edit controls
306 // note: controls that use a subedit will revert this (SpinField, ComboBox)
307 EnableRTL( FALSE );
309 vcl::unohelper::DragAndDropWrapper* pDnDWrapper = new vcl::unohelper::DragAndDropWrapper( this );
310 mxDnDListener = pDnDWrapper;
313 // -----------------------------------------------------------------------
315 bool Edit::ImplUseNativeBorder( WinBits nStyle )
317 bool bRet =
318 IsNativeControlSupported(ImplGetNativeControlType(), HAS_BACKGROUND_TEXTURE)
319 && ((nStyle&WB_BORDER) && !(nStyle&WB_NOBORDER));
320 if( ! bRet && mbIsSubEdit )
322 Window* pWindow = GetParent();
323 nStyle = pWindow->GetStyle();
324 bRet = pWindow->IsNativeControlSupported(ImplGetNativeControlType(), HAS_BACKGROUND_TEXTURE)
325 && ((nStyle&WB_BORDER) && !(nStyle&WB_NOBORDER));
327 return bRet;
330 void Edit::ImplInit( Window* pParent, WinBits nStyle )
332 nStyle = ImplInitStyle( nStyle );
333 if ( !(nStyle & (WB_CENTER | WB_RIGHT)) )
334 nStyle |= WB_LEFT;
336 Control::ImplInit( pParent, nStyle, NULL );
338 mbReadOnly = (nStyle & WB_READONLY) != 0;
340 mnAlign = EDIT_ALIGN_LEFT;
342 // --- RTL --- hack: right align until keyinput and cursor travelling works
343 if( IsRTLEnabled() )
344 mnAlign = EDIT_ALIGN_RIGHT;
346 if ( nStyle & WB_RIGHT )
347 mnAlign = EDIT_ALIGN_RIGHT;
348 else if ( nStyle & WB_CENTER )
349 mnAlign = EDIT_ALIGN_CENTER;
351 SetCursor( new Cursor );
353 SetPointer( Pointer( POINTER_TEXT ) );
354 ImplInitSettings( TRUE, TRUE, TRUE );
356 uno::Reference< datatransfer::dnd::XDragGestureListener> xDGL( mxDnDListener, uno::UNO_QUERY );
357 uno::Reference< datatransfer::dnd::XDragGestureRecognizer > xDGR = GetDragGestureRecognizer();
358 if ( xDGR.is() )
360 xDGR->addDragGestureListener( xDGL );
361 uno::Reference< datatransfer::dnd::XDropTargetListener> xDTL( mxDnDListener, uno::UNO_QUERY );
362 GetDropTarget()->addDropTargetListener( xDTL );
363 GetDropTarget()->setActive( sal_True );
364 GetDropTarget()->setDefaultActions( datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE );
368 // -----------------------------------------------------------------------
370 WinBits Edit::ImplInitStyle( WinBits nStyle )
372 if ( !(nStyle & WB_NOTABSTOP) )
373 nStyle |= WB_TABSTOP;
374 if ( !(nStyle & WB_NOGROUP) )
375 nStyle |= WB_GROUP;
377 return nStyle;
380 // -----------------------------------------------------------------------
382 BOOL Edit::IsCharInput( const KeyEvent& rKeyEvent )
384 // In the future we must use new Unicode functions for this
385 xub_Unicode cCharCode = rKeyEvent.GetCharCode();
386 return ((cCharCode >= 32) && (cCharCode != 127) &&
387 !rKeyEvent.GetKeyCode().IsMod3() &&
388 !rKeyEvent.GetKeyCode().IsMod2() &&
389 !rKeyEvent.GetKeyCode().IsMod1() );
392 // -----------------------------------------------------------------------
394 void Edit::ImplModified()
396 mbModified = TRUE;
397 Modify();
400 // -----------------------------------------------------------------------
402 void Edit::ImplInitSettings( BOOL bFont, BOOL bForeground, BOOL bBackground )
404 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
406 if ( bFont )
408 Font aFont = rStyleSettings.GetFieldFont();
409 if ( IsControlFont() )
410 aFont.Merge( GetControlFont() );
411 SetZoomedPointFont( aFont );
412 delete mpLayoutData, mpLayoutData = NULL;
415 if ( bFont || bForeground )
417 Color aTextColor = rStyleSettings.GetFieldTextColor();
418 if ( IsControlForeground() )
419 aTextColor = GetControlForeground();
420 SetTextColor( aTextColor );
423 if ( bBackground )
425 if ( ImplUseNativeBorder( GetStyle() ) || IsPaintTransparent() )
427 // Transparent background
428 SetBackground();
429 SetFillColor();
431 else if ( IsControlBackground() )
433 SetBackground( GetControlBackground() );
434 SetFillColor( GetControlBackground() );
436 else
438 SetBackground( rStyleSettings.GetFieldColor() );
439 SetFillColor( rStyleSettings.GetFieldColor() );
444 // -----------------------------------------------------------------------
446 long Edit::ImplGetExtraOffset() const
448 // MT 09/2002: nExtraOffsetX should become a member, instead of checking every time,
449 // but I need an incompatible update for this...
450 // #94095# Use extra offset only when edit has a border
451 long nExtraOffset = 0;
452 if( ( GetStyle() & WB_BORDER ) || ( mbIsSubEdit && ( GetParent()->GetStyle() & WB_BORDER ) ) )
453 nExtraOffset = 2;
455 return nExtraOffset;
459 // -----------------------------------------------------------------------
461 XubString Edit::ImplGetText() const
463 if ( mcEchoChar || (GetStyle() & WB_PASSWORD) )
465 XubString aText;
466 xub_Unicode cEchoChar;
467 if ( mcEchoChar )
468 cEchoChar = mcEchoChar;
469 else
470 cEchoChar = '*';
471 aText.Fill( maText.Len(), cEchoChar );
472 return aText;
474 else
475 return maText;
478 // -----------------------------------------------------------------------
480 void Edit::ImplInvalidateOrRepaint( xub_StrLen nStart, xub_StrLen nEnd )
482 if( IsPaintTransparent() )
484 Invalidate();
485 // FIXME: this is currently only on aqua
486 if( ImplGetSVData()->maNWFData.mbNoFocusRects )
487 Update();
489 else
490 ImplRepaint( nStart, nEnd );
493 // -----------------------------------------------------------------------
495 void Edit::ImplRepaint( xub_StrLen nStart, xub_StrLen nEnd, bool bLayout )
497 if ( !IsReallyVisible() )
498 return;
500 XubString aText = ImplGetText();
501 nStart = 0;
502 nEnd = aText.Len();
504 sal_Int32 nDXBuffer[256];
505 sal_Int32* pDXBuffer = NULL;
506 sal_Int32* pDX = nDXBuffer;
508 if( aText.Len() )
510 if( 2*aText.Len() > xub_StrLen(sizeof(nDXBuffer)/sizeof(nDXBuffer[0])) )
512 pDXBuffer = new sal_Int32[2*(aText.Len()+1)];
513 pDX = pDXBuffer;
516 GetCaretPositions( aText, pDX, nStart, nEnd );
519 // center vertically
520 long nH = GetOutputSize().Height();
521 long nTH = GetTextHeight();
522 Point aPos( mnXOffset, (nH-nTH)/2 );
524 if( bLayout )
526 long nPos = nStart ? pDX[2*nStart] : 0;
527 aPos.X() = nPos + mnXOffset + ImplGetExtraOffset();
529 MetricVector* pVector = &mpLayoutData->m_aUnicodeBoundRects;
530 String* pDisplayText = &mpLayoutData->m_aDisplayText;
532 DrawText( aPos, aText, nStart, nEnd - nStart, pVector, pDisplayText );
534 if( pDXBuffer )
535 delete [] pDXBuffer;
536 return;
539 Cursor* pCursor = GetCursor();
540 BOOL bVisCursor = pCursor ? pCursor->IsVisible() : FALSE;
541 if ( pCursor )
542 pCursor->Hide();
544 ImplClearBackground( 0, GetOutputSizePixel().Width() );
546 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
547 if ( IsEnabled() )
548 ImplInitSettings( FALSE, TRUE, FALSE );
549 else
550 SetTextColor( rStyleSettings.GetDisableColor() );
552 // Set background color of the normal text
553 if( (GetStyle() & WB_FORCECTRLBACKGROUND) != 0 && IsControlBackground() )
555 // check if we need to set ControlBackground even in NWF case
556 Push( PUSH_FILLCOLOR | PUSH_LINECOLOR );
557 SetLineColor();
558 SetFillColor( GetControlBackground() );
559 DrawRect( Rectangle( aPos, Size( GetOutputSizePixel().Width() - 2*mnXOffset, nTH ) ) );
560 Pop();
562 SetTextFillColor( GetControlBackground() );
564 else if( IsPaintTransparent() || ImplUseNativeBorder( GetStyle() ) )
565 SetTextFillColor();
566 else
567 SetTextFillColor( IsControlBackground() ? GetControlBackground() : rStyleSettings.GetFieldColor() );
569 BOOL bDrawSelection = maSelection.Len() && ( HasFocus() || ( GetStyle() & WB_NOHIDESELECTION ) || mbActivePopup );
571 long nPos = nStart ? pDX[2*nStart] : 0;
572 aPos.X() = nPos + mnXOffset + ImplGetExtraOffset();
573 if ( !bDrawSelection && !mpIMEInfos )
575 DrawText( aPos, aText, nStart, nEnd - nStart );
577 else
579 // save graphics state
580 Push();
581 // first calculate higlighted and non highlighted clip regions
582 Region aHiglightClipRegion;
583 Region aNormalClipRegion;
584 Selection aTmpSel( maSelection );
585 aTmpSel.Justify();
586 // selection is highlighted
587 int i;
588 for( i = 0; i < aText.Len(); i++ )
590 Rectangle aRect( aPos, Size( 10, nTH ) );
591 aRect.Left() = pDX[2*i] + mnXOffset + ImplGetExtraOffset();
592 aRect.Right() = pDX[2*i+1] + mnXOffset + ImplGetExtraOffset();
593 aRect.Justify();
594 bool bHighlight = false;
595 if( i >= aTmpSel.Min() && i < aTmpSel.Max() )
596 bHighlight = true;
598 if( mpIMEInfos && mpIMEInfos->pAttribs &&
599 i >= mpIMEInfos->nPos && i < (mpIMEInfos->nPos+mpIMEInfos->nLen ) &&
600 ( mpIMEInfos->pAttribs[i-mpIMEInfos->nPos] & EXTTEXTINPUT_ATTR_HIGHLIGHT) )
601 bHighlight = true;
603 if( bHighlight )
604 aHiglightClipRegion.Union( aRect );
605 else
606 aNormalClipRegion.Union( aRect );
608 // draw normal text
609 Color aNormalTextColor = GetTextColor();
610 SetClipRegion( aNormalClipRegion );
612 if( IsPaintTransparent() )
613 SetTextFillColor();
614 else
616 // Set background color when part of the text is selected
617 if ( ImplUseNativeBorder( GetStyle() ) )
619 if( (GetStyle() & WB_FORCECTRLBACKGROUND) != 0 && IsControlBackground() )
620 SetTextFillColor( GetControlBackground() );
621 else
622 SetTextFillColor();
624 else
625 SetTextFillColor( IsControlBackground() ? GetControlBackground() : rStyleSettings.GetFieldColor() );
627 DrawText( aPos, aText, nStart, nEnd - nStart );
629 // draw highlighted text
630 SetClipRegion( aHiglightClipRegion );
631 SetTextColor( rStyleSettings.GetHighlightTextColor() );
632 SetTextFillColor( rStyleSettings.GetHighlightColor() );
633 DrawText( aPos, aText, nStart, nEnd - nStart );
635 // if IME info exists loop over portions and output different font attributes
636 if( mpIMEInfos && mpIMEInfos->pAttribs )
638 for( int n = 0; n < 2; n++ )
640 Region aRegion;
641 if( n == 0 )
643 SetTextColor( aNormalTextColor );
644 if( IsPaintTransparent() )
645 SetTextFillColor();
646 else
647 SetTextFillColor( IsControlBackground() ? GetControlBackground() : rStyleSettings.GetFieldColor() );
648 aRegion = aNormalClipRegion;
650 else
652 SetTextColor( rStyleSettings.GetHighlightTextColor() );
653 SetTextFillColor( rStyleSettings.GetHighlightColor() );
654 aRegion = aHiglightClipRegion;
657 for( i = 0; i < mpIMEInfos->nLen; )
659 USHORT nAttr = mpIMEInfos->pAttribs[i];
660 Region aClip;
661 int nIndex = i;
662 while( nIndex < mpIMEInfos->nLen && mpIMEInfos->pAttribs[nIndex] == nAttr) // #112631# check nIndex before using it
664 Rectangle aRect( aPos, Size( 10, nTH ) );
665 aRect.Left() = pDX[2*(nIndex+mpIMEInfos->nPos)] + mnXOffset + ImplGetExtraOffset();
666 aRect.Right() = pDX[2*(nIndex+mpIMEInfos->nPos)+1] + mnXOffset + ImplGetExtraOffset();
667 aRect.Justify();
668 aClip.Union( aRect );
669 nIndex++;
671 i = nIndex;
672 if( aClip.Intersect( aRegion ) && nAttr )
674 Font aFont = GetFont();
675 if ( nAttr & EXTTEXTINPUT_ATTR_UNDERLINE )
676 aFont.SetUnderline( UNDERLINE_SINGLE );
677 else if ( nAttr & EXTTEXTINPUT_ATTR_BOLDUNDERLINE )
678 aFont.SetUnderline( UNDERLINE_BOLD );
679 else if ( nAttr & EXTTEXTINPUT_ATTR_DOTTEDUNDERLINE )
680 aFont.SetUnderline( UNDERLINE_DOTTED );
681 else if ( nAttr & EXTTEXTINPUT_ATTR_DASHDOTUNDERLINE )
682 aFont.SetUnderline( UNDERLINE_DOTTED );
683 else if ( nAttr & EXTTEXTINPUT_ATTR_GRAYWAVELINE )
685 aFont.SetUnderline( UNDERLINE_WAVE );
686 SetTextLineColor( Color( COL_LIGHTGRAY ) );
688 SetFont( aFont );
690 if ( nAttr & EXTTEXTINPUT_ATTR_REDTEXT )
691 SetTextColor( Color( COL_RED ) );
692 else if ( nAttr & EXTTEXTINPUT_ATTR_HALFTONETEXT )
693 SetTextColor( Color( COL_LIGHTGRAY ) );
695 SetClipRegion( aClip );
696 DrawText( aPos, aText, nStart, nEnd - nStart );
702 // restore graphics state
703 Pop();
706 if ( bVisCursor && ( !mpIMEInfos || mpIMEInfos->bCursor ) )
707 pCursor->Show();
709 if( pDXBuffer )
710 delete [] pDXBuffer;
713 // -----------------------------------------------------------------------
715 void Edit::ImplDelete( const Selection& rSelection, BYTE nDirection, BYTE nMode )
717 XubString aText = ImplGetText();
719 // loeschen moeglich?
720 if ( !rSelection.Len() &&
721 (((rSelection.Min() == 0) && (nDirection == EDIT_DEL_LEFT)) ||
722 ((rSelection.Max() == aText.Len()) && (nDirection == EDIT_DEL_RIGHT))) )
723 return;
725 delete mpLayoutData, mpLayoutData = NULL;
727 Selection aSelection( rSelection );
728 aSelection.Justify();
730 if ( !aSelection.Len() )
732 uno::Reference < i18n::XBreakIterator > xBI = ImplGetBreakIterator();
733 if ( nDirection == EDIT_DEL_LEFT )
735 if ( nMode == EDIT_DELMODE_RESTOFWORD )
737 i18n::Boundary aBoundary = xBI->getWordBoundary( maText, aSelection.Min(), GetSettings().GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True );
738 if ( aBoundary.startPos == aSelection.Min() )
739 aBoundary = xBI->previousWord( maText, aSelection.Min(), GetSettings().GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES );
740 aSelection.Min() = aBoundary.startPos;
742 else if ( nMode == EDIT_DELMODE_RESTOFCONTENT )
744 aSelection.Min() = 0;
746 else
748 sal_Int32 nCount = 1;
749 aSelection.Min() = xBI->previousCharacters( maText, aSelection.Min(), GetSettings().GetLocale(), i18n::CharacterIteratorMode::SKIPCHARACTER, nCount, nCount );
752 else
754 if ( nMode == EDIT_DELMODE_RESTOFWORD )
756 i18n::Boundary aBoundary = xBI->nextWord( maText, aSelection.Max(), GetSettings().GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES );
757 aSelection.Max() = aBoundary.startPos;
759 else if ( nMode == EDIT_DELMODE_RESTOFCONTENT )
761 aSelection.Max() = aText.Len();
763 else
765 sal_Int32 nCount = 1;
766 aSelection.Max() = xBI->nextCharacters( maText, aSelection.Max(), GetSettings().GetLocale(), i18n::CharacterIteratorMode::SKIPCHARACTER, nCount, nCount );;
771 maText.Erase( (xub_StrLen)aSelection.Min(), (xub_StrLen)aSelection.Len() );
772 maSelection.Min() = aSelection.Min();
773 maSelection.Max() = aSelection.Min();
774 ImplAlignAndPaint();
775 mbInternModified = TRUE;
778 // -----------------------------------------------------------------------
780 String Edit::ImplGetValidString( const String& rString ) const
782 String aValidString( rString );
783 aValidString.EraseAllChars( _LF );
784 aValidString.EraseAllChars( _CR );
785 aValidString.SearchAndReplaceAll( '\t', ' ' );
786 return aValidString;
789 // -----------------------------------------------------------------------
790 Reference < i18n::XBreakIterator > Edit::ImplGetBreakIterator() const
792 //!! since we don't want to become incompatible in the next minor update
793 //!! where this code will get integrated into, xISC will be a local
794 //!! variable instead of a class member!
795 Reference < i18n::XBreakIterator > xBI;
796 // if ( !xBI.is() )
798 Reference< lang::XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory();
799 Reference < XInterface > xI = xMSF->createInstance( OUString::createFromAscii( "com.sun.star.i18n.BreakIterator" ) );
800 if ( xI.is() )
802 Any x = xI->queryInterface( ::getCppuType((const Reference< i18n::XBreakIterator >*)0) );
803 x >>= xBI;
806 return xBI;
808 // -----------------------------------------------------------------------
810 Reference < i18n::XExtendedInputSequenceChecker > Edit::ImplGetInputSequenceChecker() const
812 //!! since we don't want to become incompatible in the next minor update
813 //!! where this code will get integrated into, xISC will be a local
814 //!! variable instead of a class member!
815 Reference < i18n::XExtendedInputSequenceChecker > xISC;
816 // if ( !xISC.is() )
818 Reference< lang::XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory();
819 Reference < XInterface > xI = xMSF->createInstance( OUString::createFromAscii( "com.sun.star.i18n.InputSequenceChecker" ) );
820 if ( xI.is() )
822 Any x = xI->queryInterface( ::getCppuType((const Reference< i18n::XExtendedInputSequenceChecker >*)0) );
823 x >>= xISC;
826 return xISC;
829 // -----------------------------------------------------------------------
831 void Edit::ShowTruncationWarning( Window* pParent )
833 ResMgr* pResMgr = ImplGetResMgr();
834 if( pResMgr )
836 WarningBox aBox( pParent, ResId( SV_EDIT_WARNING_BOX, *pResMgr ) );
837 aBox.Execute();
841 // -----------------------------------------------------------------------
843 bool Edit::ImplTruncateToMaxLen( rtl::OUString& rStr, sal_uInt32 nSelectionLen ) const
845 bool bWasTruncated = false;
846 const sal_uInt32 nMaxLen = mnMaxTextLen < 65534 ? mnMaxTextLen : 65534;
847 sal_uInt32 nLenAfter = static_cast<sal_uInt32>(maText.Len()) + rStr.getLength() - nSelectionLen;
848 if ( nLenAfter > nMaxLen )
850 sal_uInt32 nErasePos = nMaxLen - static_cast<sal_uInt32>(maText.Len()) + nSelectionLen;
851 rStr = rStr.copy( 0, nErasePos );
852 bWasTruncated = true;
854 return bWasTruncated;
857 // -----------------------------------------------------------------------
859 void Edit::ImplInsertText( const XubString& rStr, const Selection* pNewSel, sal_Bool bIsUserInput )
861 Selection aSelection( maSelection );
862 aSelection.Justify();
864 rtl::OUString aNewText( ImplGetValidString( rStr ) );
865 ImplTruncateToMaxLen( aNewText, aSelection.Len() );
867 delete mpLayoutData, mpLayoutData = NULL;
869 if ( aSelection.Len() )
870 maText.Erase( (xub_StrLen)aSelection.Min(), (xub_StrLen)aSelection.Len() );
871 else if ( !mbInsertMode && (aSelection.Max() < maText.Len()) )
872 maText.Erase( (xub_StrLen)aSelection.Max(), 1 );
874 // take care of input-sequence-checking now
875 if (bIsUserInput && rStr.Len())
877 DBG_ASSERT( rStr.Len() == 1, "unexpected string length. User input is expected to providse 1 char only!" );
879 // determine if input-sequence-checking should be applied or not
881 static OUString sModule( OUString::createFromAscii( "/org.openoffice.Office.Common/I18N" ) );
882 static OUString sRelNode( OUString::createFromAscii( "CTL" ) );
883 static OUString sCTLSequenceChecking( OUString::createFromAscii( "CTLSequenceChecking" ) );
884 static OUString sCTLSequenceCheckingRestricted( OUString::createFromAscii( "CTLSequenceCheckingRestricted" ) );
885 static OUString sCTLSequenceCheckingTypeAndReplace( OUString::createFromAscii( "CTLSequenceCheckingTypeAndReplace" ) );
886 static OUString sCTLFont( OUString::createFromAscii( "CTLFont" ) );
888 sal_Bool bCTLSequenceChecking = sal_False;
889 sal_Bool bCTLSequenceCheckingRestricted = sal_False;
890 sal_Bool bCTLSequenceCheckingTypeAndReplace = sal_False;
891 sal_Bool bCTLFontEnabled = sal_False;
892 sal_Bool bIsInputSequenceChecking = sal_False;
894 // get access to the configuration of this office module
897 Reference< lang::XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory();
898 Reference< container::XNameAccess > xModuleCfg( ::comphelper::ConfigurationHelper::openConfig(
899 xMSF,
900 sModule,
901 ::comphelper::ConfigurationHelper::E_READONLY ),
902 uno::UNO_QUERY );
904 //!! get values from configuration.
905 //!! we can't use SvtCTLOptions here since vcl must not be linked
906 //!! against svtools. (It is already the other way around.)
907 Any aCTLSequenceChecking = ::comphelper::ConfigurationHelper::readRelativeKey( xModuleCfg, sRelNode, sCTLSequenceChecking );
908 Any aCTLSequenceCheckingRestricted = ::comphelper::ConfigurationHelper::readRelativeKey( xModuleCfg, sRelNode, sCTLSequenceCheckingRestricted );
909 Any aCTLSequenceCheckingTypeAndReplace = ::comphelper::ConfigurationHelper::readRelativeKey( xModuleCfg, sRelNode, sCTLSequenceCheckingTypeAndReplace );
910 Any aCTLFontEnabled = ::comphelper::ConfigurationHelper::readRelativeKey( xModuleCfg, sRelNode, sCTLFont );
911 aCTLSequenceChecking >>= bCTLSequenceChecking;
912 aCTLSequenceCheckingRestricted >>= bCTLSequenceCheckingRestricted;
913 aCTLSequenceCheckingTypeAndReplace >>= bCTLSequenceCheckingTypeAndReplace;
914 aCTLFontEnabled >>= bCTLFontEnabled;
916 catch(...)
918 bIsInputSequenceChecking = sal_False; // continue with inserting the new text
921 uno::Reference < i18n::XBreakIterator > xBI( ImplGetBreakIterator(), UNO_QUERY );
922 bIsInputSequenceChecking = rStr.Len() == 1 &&
923 bCTLFontEnabled &&
924 bCTLSequenceChecking &&
925 aSelection.Min() > 0 && /* first char needs not to be checked */
926 xBI.is() && i18n::ScriptType::COMPLEX == xBI->getScriptType( rStr, 0 );
929 uno::Reference < i18n::XExtendedInputSequenceChecker > xISC;
930 if (bIsInputSequenceChecking && (xISC = ImplGetInputSequenceChecker()).is())
932 sal_Unicode cChar = rStr.GetChar(0);
933 xub_StrLen nTmpPos = static_cast< xub_StrLen >( aSelection.Min() );
934 sal_Int16 nCheckMode = bCTLSequenceCheckingRestricted ?
935 i18n::InputSequenceCheckMode::STRICT : i18n::InputSequenceCheckMode::BASIC;
937 // the text that needs to be checked is only the one
938 // before the current cursor position
939 rtl::OUString aOldText( maText.Copy(0, nTmpPos) );
940 rtl::OUString aTmpText( aOldText );
941 if (bCTLSequenceCheckingTypeAndReplace)
943 xISC->correctInputSequence( aTmpText, nTmpPos - 1, cChar, nCheckMode );
945 // find position of first character that has changed
946 sal_Int32 nOldLen = aOldText.getLength();
947 sal_Int32 nTmpLen = aTmpText.getLength();
948 const sal_Unicode *pOldTxt = aOldText.getStr();
949 const sal_Unicode *pTmpTxt = aTmpText.getStr();
950 sal_Int32 nChgPos = 0;
951 while ( nChgPos < nOldLen && nChgPos < nTmpLen &&
952 pOldTxt[nChgPos] == pTmpTxt[nChgPos] )
953 ++nChgPos;
955 xub_StrLen nChgLen = static_cast< xub_StrLen >( nTmpLen - nChgPos );
956 String aChgText( aTmpText.copy( nChgPos ), nChgLen );
958 // remove text from first pos to be changed to current pos
959 maText.Erase( static_cast< xub_StrLen >( nChgPos ), static_cast< xub_StrLen >( nTmpPos - nChgPos ) );
961 if (aChgText.Len())
963 aNewText = aChgText;
964 aSelection.Min() = nChgPos; // position for new text to be inserted
966 else
967 aNewText = String::EmptyString();
969 else
971 // should the character be ignored (i.e. not get inserted) ?
972 if (!xISC->checkInputSequence( aOldText, nTmpPos - 1, cChar, nCheckMode ))
973 aNewText = String::EmptyString();
977 // at this point now we will insert the non-empty text 'normally' some lines below...
980 if ( aNewText.getLength() )
981 maText.Insert( String( aNewText ), (xub_StrLen)aSelection.Min() );
983 if ( !pNewSel )
985 maSelection.Min() = aSelection.Min() + aNewText.getLength();
986 maSelection.Max() = maSelection.Min();
988 else
990 maSelection = *pNewSel;
991 if ( maSelection.Min() > maText.Len() )
992 maSelection.Min() = maText.Len();
993 if ( maSelection.Max() > maText.Len() )
994 maSelection.Max() = maText.Len();
997 ImplAlignAndPaint();
998 mbInternModified = TRUE;
1001 // -----------------------------------------------------------------------
1003 void Edit::ImplSetText( const XubString& rText, const Selection* pNewSelection )
1005 // Der Text wird dadurch geloescht das der alte Text komplett 'selektiert'
1006 // wird, dann InsertText, damit flackerfrei.
1007 if ( ( rText.Len() <= mnMaxTextLen ) && ( (rText != maText) || (pNewSelection && (*pNewSelection != maSelection)) ) )
1009 delete mpLayoutData, mpLayoutData = NULL;
1010 maSelection.Min() = 0;
1011 maSelection.Max() = maText.Len();
1012 if ( mnXOffset || HasPaintEvent() )
1014 mnXOffset = 0;
1015 maText = ImplGetValidString( rText );
1017 // #i54929# recalculate mnXOffset before ImplSetSelection,
1018 // else cursor ends up in wrong position
1019 ImplAlign();
1021 if ( pNewSelection )
1022 ImplSetSelection( *pNewSelection, FALSE );
1024 if ( mnXOffset && !pNewSelection )
1025 maSelection.Max() = 0;
1027 Invalidate();
1029 else
1030 ImplInsertText( rText, pNewSelection );
1032 ImplCallEventListeners( VCLEVENT_EDIT_MODIFY );
1036 // -----------------------------------------------------------------------
1038 int Edit::ImplGetNativeControlType()
1040 int nCtrl = 0;
1041 Window *pControl = mbIsSubEdit ? GetParent() : this;
1043 switch( pControl->GetType() )
1045 case WINDOW_COMBOBOX:
1046 case WINDOW_PATTERNBOX:
1047 case WINDOW_NUMERICBOX:
1048 case WINDOW_METRICBOX:
1049 case WINDOW_CURRENCYBOX:
1050 case WINDOW_DATEBOX:
1051 case WINDOW_TIMEBOX:
1052 case WINDOW_LONGCURRENCYBOX:
1053 nCtrl = CTRL_COMBOBOX;
1054 break;
1056 case WINDOW_MULTILINEEDIT:
1057 if ( GetWindow( WINDOW_BORDER ) != this )
1058 nCtrl = CTRL_MULTILINE_EDITBOX;
1059 else
1060 nCtrl = CTRL_EDITBOX_NOBORDER;
1061 break;
1063 case WINDOW_EDIT:
1064 case WINDOW_PATTERNFIELD:
1065 case WINDOW_METRICFIELD:
1066 case WINDOW_CURRENCYFIELD:
1067 case WINDOW_DATEFIELD:
1068 case WINDOW_TIMEFIELD:
1069 case WINDOW_LONGCURRENCYFIELD:
1070 case WINDOW_NUMERICFIELD:
1071 case WINDOW_SPINFIELD:
1072 if( pControl->GetStyle() & WB_SPIN )
1073 nCtrl = CTRL_SPINBOX;
1074 else
1076 if ( GetWindow( WINDOW_BORDER ) != this )
1077 nCtrl = CTRL_EDITBOX;
1078 else
1079 nCtrl = CTRL_EDITBOX_NOBORDER;
1081 break;
1083 default:
1084 nCtrl = CTRL_EDITBOX;
1086 return nCtrl;
1089 void Edit::ImplClearBackground( long nXStart, long nXEnd )
1092 * note: at this point the cursor must be switched off already
1094 Point aTmpPoint;
1095 Rectangle aRect( aTmpPoint, GetOutputSizePixel() );
1096 aRect.Left() = nXStart;
1097 aRect.Right() = nXEnd;
1099 if( ImplUseNativeBorder( GetStyle() ) || IsPaintTransparent() )
1101 // draw the inner part by painting the whole control using its border window
1102 Window *pControl = this;
1103 Window *pBorder = GetWindow( WINDOW_BORDER );
1104 if( pBorder == this )
1106 // we have no border, use parent
1107 pControl = mbIsSubEdit ? GetParent() : this;
1108 pBorder = pControl->GetWindow( WINDOW_BORDER );
1109 if( pBorder == this )
1110 pBorder = GetParent();
1113 if( pBorder )
1115 // set proper clipping region to not overdraw the whole control
1116 Region aClipRgn = GetPaintRegion();
1117 if( !aClipRgn.IsNull() )
1119 // transform clipping region to border window's coordinate system
1120 if( IsRTLEnabled() != pBorder->IsRTLEnabled() && Application::GetSettings().GetLayoutRTL() )
1122 // need to mirror in case border is not RTL but edit is (or vice versa)
1124 // mirror
1125 Rectangle aBounds( aClipRgn.GetBoundRect() );
1126 int xNew = GetOutputSizePixel().Width() - aBounds.GetWidth() - aBounds.Left();
1127 aClipRgn.Move( xNew - aBounds.Left(), 0 );
1129 // move offset of border window
1130 Point aBorderOffs;
1131 aBorderOffs = pBorder->ScreenToOutputPixel( OutputToScreenPixel( aBorderOffs ) );
1132 aClipRgn.Move( aBorderOffs.X(), aBorderOffs.Y() );
1134 else
1136 // normal case
1137 Point aBorderOffs;
1138 aBorderOffs = pBorder->ScreenToOutputPixel( OutputToScreenPixel( aBorderOffs ) );
1139 aClipRgn.Move( aBorderOffs.X(), aBorderOffs.Y() );
1142 Region oldRgn( pBorder->GetClipRegion() );
1143 pBorder->SetClipRegion( aClipRgn );
1145 pBorder->Paint( Rectangle() );
1147 pBorder->SetClipRegion( oldRgn );
1149 else
1150 pBorder->Paint( Rectangle() );
1154 else
1155 Erase( aRect );
1158 // -----------------------------------------------------------------------
1160 void Edit::ImplShowCursor( BOOL bOnlyIfVisible )
1162 if ( !IsUpdateMode() || ( bOnlyIfVisible && !IsReallyVisible() ) )
1163 return;
1165 Cursor* pCursor = GetCursor();
1166 XubString aText = ImplGetText();
1168 long nTextPos = 0;
1170 sal_Int32 nDXBuffer[256];
1171 sal_Int32* pDXBuffer = NULL;
1172 sal_Int32* pDX = nDXBuffer;
1174 if( aText.Len() )
1176 if( 2*aText.Len() > xub_StrLen(sizeof(nDXBuffer)/sizeof(nDXBuffer[0])) )
1178 pDXBuffer = new sal_Int32[2*(aText.Len()+1)];
1179 pDX = pDXBuffer;
1182 GetCaretPositions( aText, pDX, 0, aText.Len() );
1184 if( maSelection.Max() < aText.Len() )
1185 nTextPos = pDX[ 2*maSelection.Max() ];
1186 else
1187 nTextPos = pDX[ 2*aText.Len()-1 ];
1190 long nCursorWidth = 0;
1191 if ( !mbInsertMode && !maSelection.Len() && (maSelection.Max() < aText.Len()) )
1192 nCursorWidth = GetTextWidth( aText, (xub_StrLen)maSelection.Max(), 1 );
1193 long nCursorPosX = nTextPos + mnXOffset + ImplGetExtraOffset();
1195 // Cursor muss im sichtbaren Bereich landen:
1196 Size aOutSize = GetOutputSizePixel();
1197 if ( (nCursorPosX < 0) || (nCursorPosX >= aOutSize.Width()) )
1199 long nOldXOffset = mnXOffset;
1201 if ( nCursorPosX < 0 )
1203 mnXOffset = - nTextPos;
1204 long nMaxX = 0;
1205 mnXOffset += aOutSize.Width() / 5;
1206 if ( mnXOffset > nMaxX )
1207 mnXOffset = nMaxX;
1209 else
1211 mnXOffset = (aOutSize.Width()-ImplGetExtraOffset()) - nTextPos;
1212 // Etwas mehr?
1213 if ( (aOutSize.Width()-ImplGetExtraOffset()) < nTextPos )
1215 long nMaxNegX = (aOutSize.Width()-ImplGetExtraOffset()) - GetTextWidth( aText );
1216 mnXOffset -= aOutSize.Width() / 5;
1217 if ( mnXOffset < nMaxNegX ) // beides negativ...
1218 mnXOffset = nMaxNegX;
1222 nCursorPosX = nTextPos + mnXOffset + ImplGetExtraOffset();
1223 if ( nCursorPosX == aOutSize.Width() ) // dann nicht sichtbar...
1224 nCursorPosX--;
1226 if ( mnXOffset != nOldXOffset )
1227 ImplInvalidateOrRepaint();
1230 long nTextHeight = GetTextHeight();
1231 long nCursorPosY = (aOutSize.Height()-nTextHeight) / 2;
1232 pCursor->SetPos( Point( nCursorPosX, nCursorPosY ) );
1233 pCursor->SetSize( Size( nCursorWidth, nTextHeight ) );
1234 pCursor->Show();
1236 if( pDXBuffer )
1237 delete [] pDXBuffer;
1240 // -----------------------------------------------------------------------
1242 void Edit::ImplAlign()
1244 long nTextWidth = GetTextWidth( ImplGetText() );
1245 long nOutWidth = GetOutputSizePixel().Width();
1247 if ( mnAlign == EDIT_ALIGN_LEFT )
1249 if( mnXOffset && ( nTextWidth < nOutWidth ) )
1250 mnXOffset = 0;
1253 else if ( mnAlign == EDIT_ALIGN_RIGHT )
1255 long nMinXOffset = nOutWidth - nTextWidth - 1 - ImplGetExtraOffset();
1256 bool bRTL = IsRTLEnabled();
1257 if( mbIsSubEdit && GetParent() )
1258 bRTL = GetParent()->IsRTLEnabled();
1259 if( bRTL )
1261 if( nTextWidth < nOutWidth )
1262 mnXOffset = nMinXOffset;
1264 else
1266 if( nTextWidth < nOutWidth )
1267 mnXOffset = nMinXOffset;
1268 else if ( mnXOffset < nMinXOffset )
1269 mnXOffset = nMinXOffset;
1272 else if( mnAlign == EDIT_ALIGN_CENTER )
1274 // Mit Abfrage schoener, wenn gescrollt, dann aber nicht zentriert im gescrollten Zustand...
1275 // if ( nTextWidth < nOutWidth )
1276 mnXOffset = (nOutWidth - nTextWidth) / 2;
1281 // -----------------------------------------------------------------------
1283 void Edit::ImplAlignAndPaint()
1285 ImplAlign();
1286 ImplInvalidateOrRepaint( 0, STRING_LEN );
1287 ImplShowCursor();
1290 // -----------------------------------------------------------------------
1292 xub_StrLen Edit::ImplGetCharPos( const Point& rWindowPos ) const
1294 xub_StrLen nIndex = STRING_LEN;
1295 String aText = ImplGetText();
1297 sal_Int32 nDXBuffer[256];
1298 sal_Int32* pDXBuffer = NULL;
1299 sal_Int32* pDX = nDXBuffer;
1300 if( 2*aText.Len() > xub_StrLen(sizeof(nDXBuffer)/sizeof(nDXBuffer[0])) )
1302 pDXBuffer = new sal_Int32[2*(aText.Len()+1)];
1303 pDX = pDXBuffer;
1306 GetCaretPositions( aText, pDX, 0, aText.Len() );
1307 long nX = rWindowPos.X() - mnXOffset - ImplGetExtraOffset();
1308 for( int i = 0; i < aText.Len(); i++ )
1310 if( (pDX[2*i] >= nX && pDX[2*i+1] <= nX) ||
1311 (pDX[2*i+1] >= nX && pDX[2*i] <= nX))
1313 nIndex = sal::static_int_cast<xub_StrLen>(i);
1314 if( pDX[2*i] < pDX[2*i+1] )
1316 if( nX > (pDX[2*i]+pDX[2*i+1])/2 )
1317 nIndex++;
1319 else
1321 if( nX < (pDX[2*i]+pDX[2*i+1])/2 )
1322 nIndex++;
1324 break;
1327 if( nIndex == STRING_LEN )
1329 nIndex = 0;
1330 long nDiff = Abs( pDX[0]-nX );
1331 for( int i = 1; i < aText.Len(); i++ )
1333 long nNewDiff = Abs( pDX[2*i]-nX );
1335 if( nNewDiff < nDiff )
1337 nIndex = sal::static_int_cast<xub_StrLen>(i);
1338 nDiff = nNewDiff;
1341 if( nIndex == aText.Len()-1 && Abs( pDX[2*nIndex+1] - nX ) < nDiff )
1342 nIndex = STRING_LEN;
1345 if( pDXBuffer )
1346 delete [] pDXBuffer;
1348 return nIndex;
1351 // -----------------------------------------------------------------------
1353 void Edit::ImplSetCursorPos( xub_StrLen nChar, BOOL bSelect )
1355 Selection aSelection( maSelection );
1356 aSelection.Max() = nChar;
1357 if ( !bSelect )
1358 aSelection.Min() = aSelection.Max();
1359 ImplSetSelection( aSelection );
1362 // -----------------------------------------------------------------------
1364 void Edit::ImplLoadRes( const ResId& rResId )
1366 Control::ImplLoadRes( rResId );
1368 xub_StrLen nTextLength = ReadShortRes();
1369 if ( nTextLength )
1370 SetMaxTextLen( nTextLength );
1373 // -----------------------------------------------------------------------
1375 void Edit::ImplCopyToSelectionClipboard()
1377 if ( GetSelection().Len() )
1379 ::com::sun::star::uno::Reference<com::sun::star::datatransfer::clipboard::XClipboard> aSelection(GetPrimarySelection());
1380 ImplCopy( aSelection );
1384 void Edit::ImplCopy( uno::Reference< datatransfer::clipboard::XClipboard >& rxClipboard )
1386 ::vcl::unohelper::TextDataObject::CopyStringTo( GetSelected(), rxClipboard );
1389 // -----------------------------------------------------------------------
1391 void Edit::ImplPaste( uno::Reference< datatransfer::clipboard::XClipboard >& rxClipboard )
1393 if ( rxClipboard.is() )
1395 uno::Reference< datatransfer::XTransferable > xDataObj;
1397 const sal_uInt32 nRef = Application::ReleaseSolarMutex();
1401 xDataObj = rxClipboard->getContents();
1403 catch( const ::com::sun::star::uno::Exception& )
1407 Application::AcquireSolarMutex( nRef );
1409 if ( xDataObj.is() )
1411 datatransfer::DataFlavor aFlavor;
1412 SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aFlavor );
1415 uno::Any aData = xDataObj->getTransferData( aFlavor );
1416 ::rtl::OUString aText;
1417 aData >>= aText;
1418 if( ImplTruncateToMaxLen( aText, maSelection.Len() ) )
1419 ShowTruncationWarning( const_cast<Edit*>(this) );
1420 ReplaceSelected( aText );
1422 catch( const ::com::sun::star::uno::Exception& )
1429 // -----------------------------------------------------------------------
1431 void Edit::MouseButtonDown( const MouseEvent& rMEvt )
1433 if ( mpSubEdit )
1435 Control::MouseButtonDown( rMEvt );
1436 return;
1439 xub_StrLen nChar = ImplGetCharPos( rMEvt.GetPosPixel() );
1440 Selection aSelection( maSelection );
1441 aSelection.Justify();
1443 if ( rMEvt.GetClicks() < 4 )
1445 mbClickedInSelection = FALSE;
1446 if ( rMEvt.GetClicks() == 3 )
1448 ImplSetSelection( Selection( 0, 0xFFFF ) );
1449 ImplCopyToSelectionClipboard();
1452 else if ( rMEvt.GetClicks() == 2 )
1454 uno::Reference < i18n::XBreakIterator > xBI = ImplGetBreakIterator();
1455 i18n::Boundary aBoundary = xBI->getWordBoundary( maText, aSelection.Max(), GetSettings().GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True );
1456 ImplSetSelection( Selection( aBoundary.startPos, aBoundary.endPos ) );
1457 ImplCopyToSelectionClipboard();
1459 else if ( !rMEvt.IsShift() && HasFocus() && aSelection.IsInside( nChar ) )
1460 mbClickedInSelection = TRUE;
1461 else if ( rMEvt.IsLeft() )
1462 ImplSetCursorPos( nChar, rMEvt.IsShift() );
1464 if ( !mbClickedInSelection && rMEvt.IsLeft() && ( rMEvt.GetClicks() == 1 ) )
1465 StartTracking( STARTTRACK_SCROLLREPEAT );
1468 mbInMBDown = TRUE; // Dann im GetFocus nicht alles selektieren
1469 GrabFocus();
1470 mbInMBDown = FALSE;
1473 // -----------------------------------------------------------------------
1475 void Edit::MouseButtonUp( const MouseEvent& rMEvt )
1477 if ( mbClickedInSelection && rMEvt.IsLeft() )
1479 xub_StrLen nChar = ImplGetCharPos( rMEvt.GetPosPixel() );
1480 ImplSetCursorPos( nChar, FALSE );
1481 mbClickedInSelection = FALSE;
1483 else if ( rMEvt.IsMiddle() && !mbReadOnly &&
1484 ( GetSettings().GetMouseSettings().GetMiddleButtonAction() == MOUSE_MIDDLE_PASTESELECTION ) )
1486 ::com::sun::star::uno::Reference<com::sun::star::datatransfer::clipboard::XClipboard> aSelection(Window::GetPrimarySelection());
1487 ImplPaste( aSelection );
1488 ImplModified();
1492 // -----------------------------------------------------------------------
1494 void Edit::Tracking( const TrackingEvent& rTEvt )
1496 if ( rTEvt.IsTrackingEnded() )
1498 if ( mbClickedInSelection )
1500 xub_StrLen nChar = ImplGetCharPos( rTEvt.GetMouseEvent().GetPosPixel() );
1501 ImplSetCursorPos( nChar, FALSE );
1502 mbClickedInSelection = FALSE;
1504 else if ( rTEvt.GetMouseEvent().IsLeft() )
1506 ImplCopyToSelectionClipboard();
1509 else
1511 if( !mbClickedInSelection )
1513 xub_StrLen nChar = ImplGetCharPos( rTEvt.GetMouseEvent().GetPosPixel() );
1514 ImplSetCursorPos( nChar, TRUE );
1518 if ( mpUpdateDataTimer && !mbIsSubEdit && mpUpdateDataTimer->IsActive() )
1519 mpUpdateDataTimer->Start();//do not update while the user is still travelling in the control
1522 // -----------------------------------------------------------------------
1524 BOOL Edit::ImplHandleKeyEvent( const KeyEvent& rKEvt )
1526 BOOL bDone = FALSE;
1527 USHORT nCode = rKEvt.GetKeyCode().GetCode();
1528 KeyFuncType eFunc = rKEvt.GetKeyCode().GetFunction();
1530 mbInternModified = FALSE;
1532 if ( eFunc != KEYFUNC_DONTKNOW )
1534 switch ( eFunc )
1536 case KEYFUNC_CUT:
1538 if ( !mbReadOnly && maSelection.Len() && !(GetStyle() & WB_PASSWORD) )
1540 Cut();
1541 ImplModified();
1542 bDone = TRUE;
1545 break;
1547 case KEYFUNC_COPY:
1549 if ( !(GetStyle() & WB_PASSWORD) )
1551 Copy();
1552 bDone = TRUE;
1555 break;
1557 case KEYFUNC_PASTE:
1559 if ( !mbReadOnly )
1561 Paste();
1562 bDone = TRUE;
1565 break;
1567 case KEYFUNC_UNDO:
1569 if ( !mbReadOnly )
1571 Undo();
1572 bDone = TRUE;
1575 break;
1577 default: // wird dann evtl. unten bearbeitet.
1578 eFunc = KEYFUNC_DONTKNOW;
1582 if ( !bDone && rKEvt.GetKeyCode().IsMod1() && !rKEvt.GetKeyCode().IsMod2() )
1584 if ( nCode == KEY_A )
1586 ImplSetSelection( Selection( 0, maText.Len() ) );
1587 bDone = TRUE;
1589 else if ( rKEvt.GetKeyCode().IsShift() && (nCode == KEY_S) )
1591 if ( pImplFncGetSpecialChars )
1593 Selection aSaveSel = GetSelection(); // Falls jemand in Get/LoseFocus die Selektion verbiegt, z.B. URL-Zeile...
1594 XubString aChars = pImplFncGetSpecialChars( this, GetFont() );
1595 SetSelection( aSaveSel );
1596 if ( aChars.Len() )
1598 ImplInsertText( aChars );
1599 ImplModified();
1601 bDone = TRUE;
1606 if ( eFunc == KEYFUNC_DONTKNOW && ! bDone )
1608 switch ( nCode )
1610 case com::sun::star::awt::Key::SELECT_ALL:
1612 ImplSetSelection( Selection( 0, maText.Len() ) );
1613 bDone = TRUE;
1615 break;
1617 case KEY_LEFT:
1618 case KEY_RIGHT:
1619 case KEY_HOME:
1620 case KEY_END:
1621 case com::sun::star::awt::Key::MOVE_WORD_FORWARD:
1622 case com::sun::star::awt::Key::SELECT_WORD_FORWARD:
1623 case com::sun::star::awt::Key::MOVE_WORD_BACKWARD:
1624 case com::sun::star::awt::Key::SELECT_WORD_BACKWARD:
1625 case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE:
1626 case com::sun::star::awt::Key::MOVE_TO_END_OF_LINE:
1627 case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE:
1628 case com::sun::star::awt::Key::SELECT_TO_END_OF_LINE:
1629 case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH:
1630 case com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH:
1631 case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH:
1632 case com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH:
1633 case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT:
1634 case com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT:
1635 case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT:
1636 case com::sun::star::awt::Key::SELECT_TO_END_OF_DOCUMENT:
1638 if ( !rKEvt.GetKeyCode().IsMod2() )
1640 delete mpLayoutData, mpLayoutData = NULL;
1641 uno::Reference < i18n::XBreakIterator > xBI = ImplGetBreakIterator();
1643 Selection aSel( maSelection );
1644 bool bWord = rKEvt.GetKeyCode().IsMod1();
1645 bool bSelect = rKEvt.GetKeyCode().IsShift();
1646 bool bGoLeft = (nCode == KEY_LEFT);
1647 bool bGoRight = (nCode == KEY_RIGHT);
1648 bool bGoHome = (nCode == KEY_HOME);
1649 bool bGoEnd = (nCode == KEY_END);
1651 switch( nCode )
1653 case com::sun::star::awt::Key::MOVE_WORD_FORWARD:
1654 bGoRight = bWord = true;break;
1655 case com::sun::star::awt::Key::SELECT_WORD_FORWARD:
1656 bGoRight = bSelect = bWord = true;break;
1657 case com::sun::star::awt::Key::MOVE_WORD_BACKWARD:
1658 bGoLeft = bWord = true;break;
1659 case com::sun::star::awt::Key::SELECT_WORD_BACKWARD:
1660 bGoLeft = bSelect = bWord = true;break;
1661 case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE:
1662 case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH:
1663 case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT:
1664 bSelect = true;
1665 // fallthrough intended
1666 case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE:
1667 case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH:
1668 case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT:
1669 bGoHome = true;break;
1670 case com::sun::star::awt::Key::SELECT_TO_END_OF_LINE:
1671 case com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH:
1672 case com::sun::star::awt::Key::SELECT_TO_END_OF_DOCUMENT:
1673 bSelect = true;
1674 // fallthrough intended
1675 case com::sun::star::awt::Key::MOVE_TO_END_OF_LINE:
1676 case com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH:
1677 case com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT:
1678 bGoEnd = true;break;
1679 default:
1680 break;
1683 // Range wird in ImplSetSelection geprueft...
1684 if ( bGoLeft && aSel.Max() )
1686 if ( bWord )
1688 i18n::Boundary aBoundary = xBI->getWordBoundary( maText, aSel.Max(), GetSettings().GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True );
1689 if ( aBoundary.startPos == aSel.Max() )
1690 aBoundary = xBI->previousWord( maText, aSel.Max(), GetSettings().GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES );
1691 aSel.Max() = aBoundary.startPos;
1693 else
1695 sal_Int32 nCount = 1;
1696 aSel.Max() = xBI->previousCharacters( maText, aSel.Max(), GetSettings().GetLocale(), i18n::CharacterIteratorMode::SKIPCHARACTER, nCount, nCount );
1699 else if ( bGoRight && ( aSel.Max() < maText.Len() ) )
1701 if ( bWord )
1703 i18n::Boundary aBoundary = xBI->nextWord( maText, aSel.Max(), GetSettings().GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES );
1704 aSel.Max() = aBoundary.startPos;
1706 else
1708 sal_Int32 nCount = 1;
1709 aSel.Max() = xBI->nextCharacters( maText, aSel.Max(), GetSettings().GetLocale(), i18n::CharacterIteratorMode::SKIPCHARACTER, nCount, nCount );
1712 else if ( bGoHome )
1714 aSel.Max() = 0;
1716 else if ( bGoEnd )
1718 aSel.Max() = 0xFFFF;
1721 if ( !bSelect )
1722 aSel.Min() = aSel.Max();
1724 if ( aSel != GetSelection() )
1726 ImplSetSelection( aSel );
1727 ImplCopyToSelectionClipboard();
1730 if ( bGoEnd && maAutocompleteHdl.IsSet() && !rKEvt.GetKeyCode().GetModifier() )
1732 if ( (maSelection.Min() == maSelection.Max()) && (maSelection.Min() == maText.Len()) )
1734 meAutocompleteAction = AUTOCOMPLETE_KEYINPUT;
1735 maAutocompleteHdl.Call( this );
1739 bDone = TRUE;
1742 break;
1744 case com::sun::star::awt::Key::DELETE_WORD_BACKWARD:
1745 case com::sun::star::awt::Key::DELETE_WORD_FORWARD:
1746 case com::sun::star::awt::Key::DELETE_TO_BEGIN_OF_LINE:
1747 case com::sun::star::awt::Key::DELETE_TO_END_OF_LINE:
1748 case KEY_BACKSPACE:
1749 case KEY_DELETE:
1751 if ( !mbReadOnly && !rKEvt.GetKeyCode().IsMod2() )
1753 BYTE nDel = (nCode == KEY_DELETE) ? EDIT_DEL_RIGHT : EDIT_DEL_LEFT;
1754 BYTE nMode = rKEvt.GetKeyCode().IsMod1() ? EDIT_DELMODE_RESTOFWORD : EDIT_DELMODE_SIMPLE;
1755 if ( (nMode == EDIT_DELMODE_RESTOFWORD) && rKEvt.GetKeyCode().IsShift() )
1756 nMode = EDIT_DELMODE_RESTOFCONTENT;
1757 switch( nCode )
1759 case com::sun::star::awt::Key::DELETE_WORD_BACKWARD:
1760 nDel = EDIT_DEL_LEFT;
1761 nMode = EDIT_DELMODE_RESTOFWORD;
1762 break;
1763 case com::sun::star::awt::Key::DELETE_WORD_FORWARD:
1764 nDel = EDIT_DEL_RIGHT;
1765 nMode = EDIT_DELMODE_RESTOFWORD;
1766 break;
1767 case com::sun::star::awt::Key::DELETE_TO_BEGIN_OF_LINE:
1768 nDel = EDIT_DEL_LEFT;
1769 nMode = EDIT_DELMODE_RESTOFCONTENT;
1770 break;
1771 case com::sun::star::awt::Key::DELETE_TO_END_OF_LINE:
1772 nDel = EDIT_DEL_RIGHT;
1773 nMode = EDIT_DELMODE_RESTOFCONTENT;
1774 break;
1775 default: break;
1777 xub_StrLen nOldLen = maText.Len();
1778 ImplDelete( maSelection, nDel, nMode );
1779 if ( maText.Len() != nOldLen )
1780 ImplModified();
1781 bDone = TRUE;
1784 break;
1786 case KEY_INSERT:
1788 if ( !mpIMEInfos && !mbReadOnly && !rKEvt.GetKeyCode().IsMod2() )
1790 SetInsertMode( !mbInsertMode );
1791 bDone = TRUE;
1794 break;
1796 case KEY_TAB:
1798 if ( !mbReadOnly && maAutocompleteHdl.IsSet() &&
1799 maSelection.Min() && (maSelection.Min() == maText.Len()) &&
1800 !rKEvt.GetKeyCode().IsMod1() && !rKEvt.GetKeyCode().IsMod2() )
1802 // Kein Autocomplete wenn alles Selektiert oder Edit leer, weil dann
1803 // keine vernuenftige Tab-Steuerung!
1804 if ( rKEvt.GetKeyCode().IsShift() )
1805 meAutocompleteAction = AUTOCOMPLETE_TABBACKWARD;
1806 else
1807 meAutocompleteAction = AUTOCOMPLETE_TABFORWARD;
1809 maAutocompleteHdl.Call( this );
1811 // Wurde nichts veraendert, dann TAB fuer DialogControl
1812 if ( GetSelection().Len() )
1813 bDone = TRUE;
1816 break;
1818 default:
1820 if ( IsCharInput( rKEvt ) )
1822 bDone = TRUE; // Auch bei ReadOnly die Zeichen schlucken.
1823 if ( !mbReadOnly )
1825 ImplInsertText( rKEvt.GetCharCode(), 0, sal_True );
1826 if ( maAutocompleteHdl.IsSet() )
1828 if ( (maSelection.Min() == maSelection.Max()) && (maSelection.Min() == maText.Len()) )
1830 meAutocompleteAction = AUTOCOMPLETE_KEYINPUT;
1831 maAutocompleteHdl.Call( this );
1840 if ( mbInternModified )
1841 ImplModified();
1843 return bDone;
1846 // -----------------------------------------------------------------------
1848 void Edit::KeyInput( const KeyEvent& rKEvt )
1850 if ( mpUpdateDataTimer && !mbIsSubEdit && mpUpdateDataTimer->IsActive() )
1851 mpUpdateDataTimer->Start();//do not update while the user is still travelling in the control
1853 if ( mpSubEdit || !ImplHandleKeyEvent( rKEvt ) )
1854 Control::KeyInput( rKEvt );
1857 // -----------------------------------------------------------------------
1859 void Edit::FillLayoutData() const
1861 mpLayoutData = new vcl::ControlLayoutData();
1862 const_cast<Edit*>(this)->ImplRepaint( 0, STRING_LEN, true );
1865 // -----------------------------------------------------------------------
1867 void Edit::Paint( const Rectangle& )
1869 if ( !mpSubEdit )
1870 ImplRepaint();
1873 // -----------------------------------------------------------------------
1875 void Edit::Resize()
1877 if ( !mpSubEdit && IsReallyVisible() )
1879 Control::Resize();
1880 // Wegen vertikaler Zentrierung...
1881 mnXOffset = 0;
1882 ImplAlign();
1883 Invalidate();
1884 ImplShowCursor();
1888 // -----------------------------------------------------------------------
1890 void Edit::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, ULONG nFlags )
1892 ImplInitSettings( TRUE, TRUE, TRUE );
1894 Point aPos = pDev->LogicToPixel( rPos );
1895 Size aSize = pDev->LogicToPixel( rSize );
1896 Font aFont = GetDrawPixelFont( pDev );
1897 OutDevType eOutDevType = pDev->GetOutDevType();
1899 pDev->Push();
1900 pDev->SetMapMode();
1901 pDev->SetFont( aFont );
1902 pDev->SetTextFillColor();
1904 // Border/Background
1905 pDev->SetLineColor();
1906 pDev->SetFillColor();
1907 BOOL bBorder = !(nFlags & WINDOW_DRAW_NOBORDER ) && (GetStyle() & WB_BORDER);
1908 BOOL bBackground = !(nFlags & WINDOW_DRAW_NOBACKGROUND) && IsControlBackground();
1909 if ( bBorder || bBackground )
1911 Rectangle aRect( aPos, aSize );
1912 if ( bBorder )
1914 ImplDrawFrame( pDev, aRect );
1916 if ( bBackground )
1918 pDev->SetFillColor( GetControlBackground() );
1919 pDev->DrawRect( aRect );
1923 // Inhalt
1924 if ( ( nFlags & WINDOW_DRAW_MONO ) || ( eOutDevType == OUTDEV_PRINTER ) )
1925 pDev->SetTextColor( Color( COL_BLACK ) );
1926 else
1928 if ( !(nFlags & WINDOW_DRAW_NODISABLE ) && !IsEnabled() )
1930 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
1931 pDev->SetTextColor( rStyleSettings.GetDisableColor() );
1933 else
1935 pDev->SetTextColor( GetTextColor() );
1939 XubString aText = ImplGetText();
1940 long nTextHeight = pDev->GetTextHeight();
1941 long nTextWidth = pDev->GetTextWidth( aText );
1942 long nOnePixel = GetDrawPixel( pDev, 1 );
1943 long nOffX = 3*nOnePixel;
1944 long nOffY = (aSize.Height() - nTextHeight) / 2;
1946 // Clipping?
1947 if ( (nOffY < 0) ||
1948 ((nOffY+nTextHeight) > aSize.Height()) ||
1949 ((nOffX+nTextWidth) > aSize.Width()) )
1951 Rectangle aClip( aPos, aSize );
1952 if ( nTextHeight > aSize.Height() )
1953 aClip.Bottom() += nTextHeight-aSize.Height()+1; // Damit HP-Drucker nicht 'weg-optimieren'
1954 pDev->IntersectClipRegion( aClip );
1957 if ( GetStyle() & WB_CENTER )
1959 aPos.X() += (aSize.Width() - nTextWidth) / 2;
1960 nOffX = 0;
1962 else if ( GetStyle() & WB_RIGHT )
1964 aPos.X() += aSize.Width() - nTextWidth;
1965 nOffX = -nOffX;
1968 pDev->DrawText( Point( aPos.X() + nOffX, aPos.Y() + nOffY ), aText );
1969 pDev->Pop();
1971 if ( GetSubEdit() )
1973 GetSubEdit()->Draw( pDev, rPos, rSize, nFlags );
1977 // -----------------------------------------------------------------------
1979 void Edit::ImplInvalidateOutermostBorder( Window* pWin )
1981 // allow control to show focused state
1982 Window *pInvalWin = pWin, *pBorder = pWin;
1983 while( ( pBorder = pInvalWin->GetWindow( WINDOW_BORDER ) ) != pInvalWin && pBorder &&
1984 pInvalWin->ImplGetFrame() == pBorder->ImplGetFrame() )
1986 pInvalWin = pBorder;
1989 pInvalWin->Invalidate( INVALIDATE_CHILDREN | INVALIDATE_UPDATE );
1992 void Edit::GetFocus()
1994 if ( mpSubEdit )
1995 mpSubEdit->ImplGrabFocus( GetGetFocusFlags() );
1996 else if ( !mbActivePopup )
1998 maUndoText = maText;
2000 ULONG nSelOptions = GetSettings().GetStyleSettings().GetSelectionOptions();
2001 if ( !( GetStyle() & (WB_NOHIDESELECTION|WB_READONLY) )
2002 && ( GetGetFocusFlags() & (GETFOCUS_INIT|GETFOCUS_TAB|GETFOCUS_CURSOR|GETFOCUS_MNEMONIC) ) )
2004 if ( nSelOptions & SELECTION_OPTION_SHOWFIRST )
2006 maSelection.Min() = maText.Len();
2007 maSelection.Max() = 0;
2009 else
2011 maSelection.Min() = 0;
2012 maSelection.Max() = maText.Len();
2014 if ( mbIsSubEdit )
2015 ((Edit*)GetParent())->ImplCallEventListeners( VCLEVENT_EDIT_SELECTIONCHANGED );
2016 else
2017 ImplCallEventListeners( VCLEVENT_EDIT_SELECTIONCHANGED );
2020 ImplShowCursor();
2022 // FIXME: this is currently only on aqua
2023 // check for other platforms that need similar handling
2024 if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
2025 IsNativeWidgetEnabled() &&
2026 IsNativeControlSupported( CTRL_EDITBOX, PART_ENTIRE_CONTROL ) )
2028 ImplInvalidateOutermostBorder( mbIsSubEdit ? GetParent() : this );
2030 else if ( maSelection.Len() )
2032 // Selektion malen
2033 if ( !HasPaintEvent() )
2034 ImplInvalidateOrRepaint();
2035 else
2036 Invalidate();
2039 SetInputContext( InputContext( GetFont(), !IsReadOnly() ? INPUTCONTEXT_TEXT|INPUTCONTEXT_EXTTEXTINPUT : 0 ) );
2042 Control::GetFocus();
2045 // -----------------------------------------------------------------------
2047 Window* Edit::GetPreferredKeyInputWindow()
2049 if ( mpSubEdit )
2050 return mpSubEdit->GetPreferredKeyInputWindow();
2051 else
2052 return this;
2055 // -----------------------------------------------------------------------
2057 void Edit::LoseFocus()
2059 if ( mpUpdateDataTimer && !mbIsSubEdit && mpUpdateDataTimer->IsActive() )
2061 //notify an update latest when the focus is lost
2062 mpUpdateDataTimer->Stop();
2063 mpUpdateDataTimer->Timeout();
2066 if ( !mpSubEdit )
2068 // FIXME: this is currently only on aqua
2069 // check for other platforms that need similar handling
2070 if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
2071 IsNativeWidgetEnabled() &&
2072 IsNativeControlSupported( CTRL_EDITBOX, PART_ENTIRE_CONTROL ) )
2074 ImplInvalidateOutermostBorder( mbIsSubEdit ? GetParent() : this );
2077 if ( !mbActivePopup && !( GetStyle() & WB_NOHIDESELECTION ) && maSelection.Len() )
2078 ImplInvalidateOrRepaint(); // Selektion malen
2081 Control::LoseFocus();
2084 // -----------------------------------------------------------------------
2086 void Edit::Command( const CommandEvent& rCEvt )
2088 if ( rCEvt.GetCommand() == COMMAND_CONTEXTMENU )
2090 PopupMenu* pPopup = Edit::CreatePopupMenu();
2091 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
2092 if ( rStyleSettings.GetOptions() & STYLE_OPTION_HIDEDISABLED )
2093 pPopup->SetMenuFlags( MENU_FLAG_HIDEDISABLEDENTRIES );
2095 if ( !maSelection.Len() )
2097 pPopup->EnableItem( SV_MENU_EDIT_CUT, FALSE );
2098 pPopup->EnableItem( SV_MENU_EDIT_COPY, FALSE );
2099 pPopup->EnableItem( SV_MENU_EDIT_DELETE, FALSE );
2102 if ( IsReadOnly() )
2104 pPopup->EnableItem( SV_MENU_EDIT_CUT, FALSE );
2105 pPopup->EnableItem( SV_MENU_EDIT_PASTE, FALSE );
2106 pPopup->EnableItem( SV_MENU_EDIT_DELETE, FALSE );
2107 pPopup->EnableItem( SV_MENU_EDIT_INSERTSYMBOL, FALSE );
2109 else
2111 // Paste nur, wenn Text im Clipboard
2112 BOOL bData = FALSE;
2113 uno::Reference< datatransfer::clipboard::XClipboard > xClipboard = GetClipboard();
2114 if ( xClipboard.is() )
2116 const sal_uInt32 nRef = Application::ReleaseSolarMutex();
2117 uno::Reference< datatransfer::XTransferable > xDataObj = xClipboard->getContents();
2118 Application::AcquireSolarMutex( nRef );
2119 if ( xDataObj.is() )
2121 datatransfer::DataFlavor aFlavor;
2122 SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aFlavor );
2123 bData = xDataObj->isDataFlavorSupported( aFlavor );
2126 pPopup->EnableItem( SV_MENU_EDIT_PASTE, bData );
2129 if ( maUndoText == maText )
2130 pPopup->EnableItem( SV_MENU_EDIT_UNDO, FALSE );
2131 if ( ( maSelection.Min() == 0 ) && ( maSelection.Max() == maText.Len() ) )
2132 pPopup->EnableItem( SV_MENU_EDIT_SELECTALL, FALSE );
2133 if ( !pImplFncGetSpecialChars )
2135 USHORT nPos = pPopup->GetItemPos( SV_MENU_EDIT_INSERTSYMBOL );
2136 pPopup->RemoveItem( nPos );
2137 pPopup->RemoveItem( nPos-1 );
2140 mbActivePopup = TRUE;
2141 Selection aSaveSel = GetSelection(); // Falls jemand in Get/LoseFocus die Selektion verbiegt, z.B. URL-Zeile...
2142 Point aPos = rCEvt.GetMousePosPixel();
2143 if ( !rCEvt.IsMouseEvent() )
2145 // !!! Irgendwann einmal Menu zentriert in der Selektion anzeigen !!!
2146 Size aSize = GetOutputSizePixel();
2147 aPos = Point( aSize.Width()/2, aSize.Height()/2 );
2149 USHORT n = pPopup->Execute( this, aPos );
2150 Edit::DeletePopupMenu( pPopup );
2151 SetSelection( aSaveSel );
2152 switch ( n )
2154 case SV_MENU_EDIT_UNDO:
2155 Undo();
2156 ImplModified();
2157 break;
2158 case SV_MENU_EDIT_CUT:
2159 Cut();
2160 ImplModified();
2161 break;
2162 case SV_MENU_EDIT_COPY:
2163 Copy();
2164 break;
2165 case SV_MENU_EDIT_PASTE:
2166 Paste();
2167 ImplModified();
2168 break;
2169 case SV_MENU_EDIT_DELETE:
2170 DeleteSelected();
2171 ImplModified();
2172 break;
2173 case SV_MENU_EDIT_SELECTALL:
2174 ImplSetSelection( Selection( 0, maText.Len() ) );
2175 break;
2176 case SV_MENU_EDIT_INSERTSYMBOL:
2178 XubString aChars = pImplFncGetSpecialChars( this, GetFont() );
2179 SetSelection( aSaveSel );
2180 if ( aChars.Len() )
2182 ImplInsertText( aChars );
2183 ImplModified();
2186 break;
2188 mbActivePopup = FALSE;
2190 else if ( rCEvt.GetCommand() == COMMAND_VOICE )
2192 const CommandVoiceData* pData = rCEvt.GetVoiceData();
2193 if ( pData->GetType() == VOICECOMMANDTYPE_DICTATION )
2195 switch ( pData->GetCommand() )
2197 case DICTATIONCOMMAND_UNKNOWN:
2199 ReplaceSelected( pData->GetText() );
2201 break;
2202 case DICTATIONCOMMAND_LEFT:
2204 ImplHandleKeyEvent( KeyEvent( 0, KeyCode( KEY_LEFT, KEY_MOD1 ) ) );
2206 break;
2207 case DICTATIONCOMMAND_RIGHT:
2209 ImplHandleKeyEvent( KeyEvent( 0, KeyCode( KEY_RIGHT, KEY_MOD1 ) ) );
2211 break;
2212 case DICTATIONCOMMAND_UNDO:
2214 Undo();
2216 break;
2217 case DICTATIONCOMMAND_DEL:
2219 ImplHandleKeyEvent( KeyEvent( 0, KeyCode( KEY_LEFT, KEY_MOD1|KEY_SHIFT ) ) );
2220 DeleteSelected();
2222 break;
2226 else if ( rCEvt.GetCommand() == COMMAND_STARTEXTTEXTINPUT )
2228 DeleteSelected();
2229 delete mpIMEInfos;
2230 xub_StrLen nPos = (xub_StrLen)maSelection.Max();
2231 mpIMEInfos = new Impl_IMEInfos( nPos, maText.Copy( nPos ) );
2232 mpIMEInfos->bWasCursorOverwrite = !IsInsertMode();
2234 else if ( rCEvt.GetCommand() == COMMAND_ENDEXTTEXTINPUT )
2236 BOOL bInsertMode = !mpIMEInfos->bWasCursorOverwrite;
2237 delete mpIMEInfos;
2238 mpIMEInfos = NULL;
2239 // Font wieder ohne Attribute einstellen, wird jetzt im Repaint nicht
2240 // mehr neu initialisiert
2241 ImplInitSettings( TRUE, FALSE, FALSE );
2243 SetInsertMode( bInsertMode );
2245 ImplModified();
2247 // #i25161# call auto complete handler for ext text commit also
2248 if ( maAutocompleteHdl.IsSet() )
2250 if ( (maSelection.Min() == maSelection.Max()) && (maSelection.Min() == maText.Len()) )
2252 meAutocompleteAction = AUTOCOMPLETE_KEYINPUT;
2253 maAutocompleteHdl.Call( this );
2257 else if ( rCEvt.GetCommand() == COMMAND_EXTTEXTINPUT )
2259 const CommandExtTextInputData* pData = rCEvt.GetExtTextInputData();
2261 maText.Erase( mpIMEInfos->nPos, mpIMEInfos->nLen );
2262 maText.Insert( pData->GetText(), mpIMEInfos->nPos );
2263 if ( mpIMEInfos->bWasCursorOverwrite )
2265 USHORT nOldIMETextLen = mpIMEInfos->nLen;
2266 USHORT nNewIMETextLen = pData->GetText().Len();
2267 if ( ( nOldIMETextLen > nNewIMETextLen ) &&
2268 ( nNewIMETextLen < mpIMEInfos->aOldTextAfterStartPos.Len() ) )
2270 // restore old characters
2271 USHORT nRestore = nOldIMETextLen - nNewIMETextLen;
2272 maText.Insert( mpIMEInfos->aOldTextAfterStartPos.Copy( nNewIMETextLen, nRestore ), mpIMEInfos->nPos + nNewIMETextLen );
2274 else if ( ( nOldIMETextLen < nNewIMETextLen ) &&
2275 ( nOldIMETextLen < mpIMEInfos->aOldTextAfterStartPos.Len() ) )
2277 // overwrite
2278 USHORT nOverwrite = nNewIMETextLen - nOldIMETextLen;
2279 if ( ( nOldIMETextLen + nOverwrite ) > mpIMEInfos->aOldTextAfterStartPos.Len() )
2280 nOverwrite = mpIMEInfos->aOldTextAfterStartPos.Len() - nOldIMETextLen;
2281 maText.Erase( mpIMEInfos->nPos + nNewIMETextLen, nOverwrite );
2286 if ( pData->GetTextAttr() )
2288 mpIMEInfos->CopyAttribs( pData->GetTextAttr(), pData->GetText().Len() );
2289 mpIMEInfos->bCursor = pData->IsCursorVisible();
2291 else
2293 mpIMEInfos->DestroyAttribs();
2296 ImplAlignAndPaint();
2297 xub_StrLen nCursorPos = mpIMEInfos->nPos + pData->GetCursorPos();
2298 SetSelection( Selection( nCursorPos, nCursorPos ) );
2299 SetInsertMode( !pData->IsCursorOverwrite() );
2301 if ( pData->IsCursorVisible() )
2302 GetCursor()->Show();
2303 else
2304 GetCursor()->Hide();
2306 else if ( rCEvt.GetCommand() == COMMAND_CURSORPOS )
2308 if ( mpIMEInfos )
2310 xub_StrLen nCursorPos = (USHORT)GetSelection().Max();
2311 SetCursorRect( NULL, GetTextWidth(
2312 maText, nCursorPos, mpIMEInfos->nPos+mpIMEInfos->nLen-nCursorPos ) );
2314 else
2316 SetCursorRect();
2319 else if ( rCEvt.GetCommand() == COMMAND_SELECTIONCHANGE )
2321 const CommandSelectionChangeData *pData = rCEvt.GetSelectionChangeData();
2322 Selection aSelection( pData->GetStart(), pData->GetEnd() );
2323 SetSelection(aSelection);
2325 else
2326 Control::Command( rCEvt );
2329 // -----------------------------------------------------------------------
2331 void Edit::StateChanged( StateChangedType nType )
2333 if ( nType == STATE_CHANGE_INITSHOW )
2335 if ( !mpSubEdit )
2337 mnXOffset = 0; // Falls vorher GrabFocus, als Groesse noch falsch.
2338 ImplAlign();
2339 if ( !mpSubEdit )
2340 ImplShowCursor( FALSE );
2342 // update background (eventual SetPaintTransparent)
2343 ImplInitSettings( FALSE, FALSE, TRUE );
2345 else if ( nType == STATE_CHANGE_ENABLE )
2347 if ( !mpSubEdit )
2349 // Es aendert sich nur die Textfarbe...
2350 ImplInvalidateOrRepaint( 0, 0xFFFF );
2353 else if ( nType == STATE_CHANGE_STYLE || nType == STATE_CHANGE_MIRRORING )
2355 WinBits nStyle = GetStyle();
2356 if( nType == STATE_CHANGE_STYLE )
2358 nStyle = ImplInitStyle( GetStyle() );
2359 SetStyle( nStyle );
2362 USHORT nOldAlign = mnAlign;
2363 mnAlign = EDIT_ALIGN_LEFT;
2365 // --- RTL --- hack: right align until keyinput and cursor travelling works
2366 // edits are always RTL disabled
2367 // however the parent edits contain the correct setting
2368 if( mbIsSubEdit && GetParent()->IsRTLEnabled() )
2370 if( GetParent()->GetStyle() & WB_LEFT )
2371 mnAlign = EDIT_ALIGN_RIGHT;
2372 if ( nType == STATE_CHANGE_MIRRORING )
2373 SetLayoutMode( TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_TEXTORIGIN_LEFT );
2375 else if( mbIsSubEdit && !GetParent()->IsRTLEnabled() )
2377 if ( nType == STATE_CHANGE_MIRRORING )
2378 SetLayoutMode( TEXT_LAYOUT_BIDI_LTR | TEXT_LAYOUT_TEXTORIGIN_LEFT );
2381 if ( nStyle & WB_RIGHT )
2382 mnAlign = EDIT_ALIGN_RIGHT;
2383 else if ( nStyle & WB_CENTER )
2384 mnAlign = EDIT_ALIGN_CENTER;
2385 if ( maText.Len() && ( mnAlign != nOldAlign ) )
2387 ImplAlign();
2388 Invalidate();
2392 else if ( nType == STATE_CHANGE_ZOOM )
2394 if ( !mpSubEdit )
2396 ImplInitSettings( TRUE, FALSE, FALSE );
2397 ImplShowCursor( TRUE );
2398 Invalidate();
2401 else if ( nType == STATE_CHANGE_CONTROLFONT )
2403 if ( !mpSubEdit )
2405 ImplInitSettings( TRUE, FALSE, FALSE );
2406 ImplShowCursor();
2407 Invalidate();
2410 else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
2412 if ( !mpSubEdit )
2414 ImplInitSettings( FALSE, TRUE, FALSE );
2415 Invalidate();
2418 else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
2420 if ( !mpSubEdit )
2422 ImplInitSettings( FALSE, FALSE, TRUE );
2423 Invalidate();
2427 Control::StateChanged( nType );
2430 // -----------------------------------------------------------------------
2432 void Edit::DataChanged( const DataChangedEvent& rDCEvt )
2434 if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
2435 (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
2436 ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
2437 (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
2439 if ( !mpSubEdit )
2441 ImplInitSettings( TRUE, TRUE, TRUE );
2442 ImplShowCursor( TRUE );
2443 Invalidate();
2447 Control::DataChanged( rDCEvt );
2450 // -----------------------------------------------------------------------
2452 void Edit::ImplShowDDCursor()
2454 if ( !mpDDInfo->bVisCursor )
2456 long nTextWidth = GetTextWidth( maText, 0, mpDDInfo->nDropPos );
2457 long nTextHeight = GetTextHeight();
2458 Rectangle aCursorRect( Point( nTextWidth + mnXOffset, (GetOutputSize().Height()-nTextHeight)/2 ), Size( 2, nTextHeight ) );
2459 mpDDInfo->aCursor.SetWindow( this );
2460 mpDDInfo->aCursor.SetPos( aCursorRect.TopLeft() );
2461 mpDDInfo->aCursor.SetSize( aCursorRect.GetSize() );
2462 mpDDInfo->aCursor.Show();
2463 mpDDInfo->bVisCursor = TRUE;
2467 // -----------------------------------------------------------------------
2469 void Edit::ImplHideDDCursor()
2471 if ( mpDDInfo && mpDDInfo->bVisCursor )
2473 mpDDInfo->aCursor.Hide();
2474 mpDDInfo->bVisCursor = FALSE;
2478 // -----------------------------------------------------------------------
2480 void Edit::Modify()
2482 if ( mbIsSubEdit )
2484 ((Edit*)GetParent())->Modify();
2486 else
2488 if ( mpUpdateDataTimer )
2489 mpUpdateDataTimer->Start();
2491 if ( ImplCallEventListenersAndHandler( VCLEVENT_EDIT_MODIFY, maModifyHdl, this ) )
2492 // have been destroyed while calling into the handlers
2493 return;
2495 // #i13677# notify edit listeners about caret position change
2496 ImplCallEventListeners( VCLEVENT_EDIT_SELECTIONCHANGED );
2498 // FIXME: this is currently only on aqua
2499 // check for other platforms that need similar handling
2500 if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
2501 IsNativeWidgetEnabled() &&
2502 IsNativeControlSupported( CTRL_EDITBOX, PART_ENTIRE_CONTROL ) )
2504 ImplInvalidateOutermostBorder( this );
2509 // -----------------------------------------------------------------------
2511 void Edit::UpdateData()
2513 maUpdateDataHdl.Call( this );
2516 // -----------------------------------------------------------------------
2518 IMPL_LINK( Edit, ImplUpdateDataHdl, Timer*, EMPTYARG )
2520 UpdateData();
2521 return 0;
2524 // -----------------------------------------------------------------------
2526 void Edit::EnableUpdateData( ULONG nTimeout )
2528 if ( !nTimeout )
2529 DisableUpdateData();
2530 else
2532 if ( !mpUpdateDataTimer )
2534 mpUpdateDataTimer = new Timer;
2535 mpUpdateDataTimer->SetTimeoutHdl( LINK( this, Edit, ImplUpdateDataHdl ) );
2538 mpUpdateDataTimer->SetTimeout( nTimeout );
2542 // -----------------------------------------------------------------------
2544 void Edit::SetEchoChar( xub_Unicode c )
2546 mcEchoChar = c;
2547 if ( mpSubEdit )
2548 mpSubEdit->SetEchoChar( c );
2551 // -----------------------------------------------------------------------
2553 void Edit::SetReadOnly( BOOL bReadOnly )
2555 if ( mbReadOnly != bReadOnly )
2557 mbReadOnly = bReadOnly;
2558 if ( mpSubEdit )
2559 mpSubEdit->SetReadOnly( bReadOnly );
2561 StateChanged( STATE_CHANGE_READONLY );
2565 // -----------------------------------------------------------------------
2567 void Edit::SetAutocompleteHdl( const Link& rHdl )
2569 maAutocompleteHdl = rHdl;
2570 if ( mpSubEdit )
2571 mpSubEdit->SetAutocompleteHdl( rHdl );
2574 // -----------------------------------------------------------------------
2576 void Edit::SetInsertMode( BOOL bInsert )
2578 if ( bInsert != mbInsertMode )
2580 mbInsertMode = bInsert;
2581 if ( mpSubEdit )
2582 mpSubEdit->SetInsertMode( bInsert );
2583 else
2584 ImplShowCursor();
2588 // -----------------------------------------------------------------------
2590 BOOL Edit::IsInsertMode() const
2592 if ( mpSubEdit )
2593 return mpSubEdit->IsInsertMode();
2594 else
2595 return mbInsertMode;
2598 // -----------------------------------------------------------------------
2600 void Edit::SetMaxTextLen( xub_StrLen nMaxLen )
2602 mnMaxTextLen = nMaxLen ? nMaxLen : EDIT_NOLIMIT;
2604 if ( mpSubEdit )
2605 mpSubEdit->SetMaxTextLen( mnMaxTextLen );
2606 else
2608 if ( maText.Len() > mnMaxTextLen )
2609 ImplDelete( Selection( mnMaxTextLen, maText.Len() ), EDIT_DEL_RIGHT, EDIT_DELMODE_SIMPLE );
2613 // -----------------------------------------------------------------------
2615 void Edit::SetSelection( const Selection& rSelection )
2617 // Wenn von aussen z.B. im MouseButtonDown die Selektion geaendert wird,
2618 // soll nicht gleich ein Tracking() zuschlagen und die Selektion aendern.
2619 if ( IsTracking() )
2620 EndTracking();
2621 else if ( mpSubEdit && mpSubEdit->IsTracking() )
2622 mpSubEdit->EndTracking();
2624 ImplSetSelection( rSelection );
2627 // -----------------------------------------------------------------------
2629 void Edit::ImplSetSelection( const Selection& rSelection, BOOL bPaint )
2631 if ( mpSubEdit )
2632 mpSubEdit->ImplSetSelection( rSelection );
2633 else
2635 if ( rSelection != maSelection )
2637 Selection aOld( maSelection );
2638 Selection aNew( rSelection );
2640 if ( aNew.Min() > maText.Len() )
2641 aNew.Min() = maText.Len();
2642 if ( aNew.Max() > maText.Len() )
2643 aNew.Max() = maText.Len();
2644 if ( aNew.Min() < 0 )
2645 aNew.Min() = 0;
2646 if ( aNew.Max() < 0 )
2647 aNew.Max() = 0;
2649 if ( aNew != maSelection )
2651 delete mpLayoutData, mpLayoutData = NULL;
2652 maSelection = aNew;
2654 if ( bPaint && ( aOld.Len() || aNew.Len() || IsPaintTransparent() ) )
2655 ImplInvalidateOrRepaint( 0, maText.Len() );
2656 ImplShowCursor();
2657 if ( mbIsSubEdit )
2658 ((Edit*)GetParent())->ImplCallEventListeners( VCLEVENT_EDIT_SELECTIONCHANGED );
2659 else
2660 ImplCallEventListeners( VCLEVENT_EDIT_SELECTIONCHANGED );
2661 // #103511# notify combobox listeners of deselection
2662 if( !maSelection && GetParent() && GetParent()->GetType() == WINDOW_COMBOBOX )
2663 ((Edit*)GetParent())->ImplCallEventListeners( VCLEVENT_COMBOBOX_DESELECT );
2669 // -----------------------------------------------------------------------
2671 const Selection& Edit::GetSelection() const
2673 if ( mpSubEdit )
2674 return mpSubEdit->GetSelection();
2675 else
2676 return maSelection;
2679 // -----------------------------------------------------------------------
2681 void Edit::ReplaceSelected( const XubString& rStr )
2683 if ( mpSubEdit )
2684 mpSubEdit->ReplaceSelected( rStr );
2685 else
2686 ImplInsertText( rStr );
2689 // -----------------------------------------------------------------------
2691 void Edit::DeleteSelected()
2693 if ( mpSubEdit )
2694 mpSubEdit->DeleteSelected();
2695 else
2697 if ( maSelection.Len() )
2698 ImplDelete( maSelection, EDIT_DEL_RIGHT, EDIT_DELMODE_SIMPLE );
2702 // -----------------------------------------------------------------------
2704 XubString Edit::GetSelected() const
2706 if ( mpSubEdit )
2707 return mpSubEdit->GetSelected();
2708 else
2710 Selection aSelection( maSelection );
2711 aSelection.Justify();
2712 return maText.Copy( (xub_StrLen)aSelection.Min(), (xub_StrLen)aSelection.Len() );
2716 // -----------------------------------------------------------------------
2718 void Edit::Cut()
2720 if ( !(GetStyle() & WB_PASSWORD ) )
2722 Copy();
2723 ReplaceSelected( ImplGetSVEmptyStr() );
2727 // -----------------------------------------------------------------------
2729 void Edit::Copy()
2731 if ( !(GetStyle() & WB_PASSWORD ) )
2733 ::com::sun::star::uno::Reference<com::sun::star::datatransfer::clipboard::XClipboard> aClipboard(GetClipboard());
2734 ImplCopy( aClipboard );
2738 // -----------------------------------------------------------------------
2740 void Edit::Paste()
2742 ::com::sun::star::uno::Reference<com::sun::star::datatransfer::clipboard::XClipboard> aClipboard(GetClipboard());
2743 ImplPaste( aClipboard );
2746 // -----------------------------------------------------------------------
2748 void Edit::Undo()
2750 if ( mpSubEdit )
2751 mpSubEdit->Undo();
2752 else
2754 XubString aText( maText );
2755 ImplDelete( Selection( 0, aText.Len() ), EDIT_DEL_RIGHT, EDIT_DELMODE_SIMPLE );
2756 ImplInsertText( maUndoText );
2757 ImplSetSelection( Selection( 0, maUndoText.Len() ) );
2758 maUndoText = aText;
2762 // -----------------------------------------------------------------------
2764 void Edit::SetText( const XubString& rStr )
2766 if ( mpSubEdit )
2767 mpSubEdit->SetText( rStr ); // Nicht direkt ImplSetText, falls SetText ueberladen
2768 else
2770 Selection aNewSel( 0, 0 ); // Damit nicht gescrollt wird
2771 ImplSetText( rStr, &aNewSel );
2775 // -----------------------------------------------------------------------
2777 void Edit::SetText( const XubString& rStr, const Selection& rSelection )
2779 if ( mpSubEdit )
2780 mpSubEdit->SetText( rStr, rSelection );
2781 else
2782 ImplSetText( rStr, &rSelection );
2785 // -----------------------------------------------------------------------
2787 XubString Edit::GetText() const
2789 if ( mpSubEdit )
2790 return mpSubEdit->GetText();
2791 else
2792 return maText;
2795 // -----------------------------------------------------------------------
2797 void Edit::SetModifyFlag()
2799 if ( mpSubEdit )
2800 mpSubEdit->mbModified = TRUE;
2801 else
2802 mbModified = TRUE;
2805 // -----------------------------------------------------------------------
2807 void Edit::ClearModifyFlag()
2809 if ( mpSubEdit )
2810 mpSubEdit->mbModified = FALSE;
2811 else
2812 mbModified = FALSE;
2815 // -----------------------------------------------------------------------
2817 void Edit::SetSubEdit( Edit* pEdit )
2819 mpSubEdit = pEdit;
2820 if ( mpSubEdit )
2822 SetPointer( POINTER_ARROW ); // Nur das SubEdit hat den BEAM...
2823 mpSubEdit->mbIsSubEdit = TRUE;
2825 mpSubEdit->SetReadOnly( mbReadOnly );
2829 // -----------------------------------------------------------------------
2831 Size Edit::CalcMinimumSize() const
2833 Size aSize ( GetTextWidth( GetText() ), GetTextHeight() );
2834 return CalcWindowSize( aSize );
2837 // -----------------------------------------------------------------------
2839 Size Edit::GetOptimalSize(WindowSizeType eType) const
2841 switch (eType) {
2842 case WINDOWSIZE_MINIMUM:
2843 return CalcMinimumSize();
2844 default:
2845 return Control::GetOptimalSize( eType );
2849 // -----------------------------------------------------------------------
2851 Size Edit::CalcSize( xub_StrLen nChars ) const
2853 // Breite fuer n Zeichen, unabhaengig vom Inhalt.
2854 // Funktioniert nur bei FixedFont richtig, sonst Mittelwert.
2855 Size aSz( GetTextWidth( XubString( 'x' ) ), GetTextHeight() );
2856 aSz.Width() *= nChars;
2857 aSz = CalcWindowSize( aSz );
2858 return aSz;
2861 // -----------------------------------------------------------------------
2863 xub_StrLen Edit::GetMaxVisChars() const
2865 const Window* pW = mpSubEdit ? mpSubEdit : this;
2866 long nOutWidth = pW->GetOutputSizePixel().Width();
2867 long nCharWidth = GetTextWidth( XubString( 'x' ) );
2868 return nCharWidth ? (xub_StrLen)(nOutWidth/nCharWidth) : 0;
2871 // -----------------------------------------------------------------------
2873 xub_StrLen Edit::GetCharPos( const Point& rWindowPos ) const
2875 return ImplGetCharPos( rWindowPos );
2878 // -----------------------------------------------------------------------
2880 void Edit::SetGetSpecialCharsFunction( FncGetSpecialChars fn )
2882 pImplFncGetSpecialChars = fn;
2885 // -----------------------------------------------------------------------
2887 FncGetSpecialChars Edit::GetGetSpecialCharsFunction()
2889 return pImplFncGetSpecialChars;
2892 // -----------------------------------------------------------------------
2894 PopupMenu* Edit::CreatePopupMenu()
2896 ResMgr* pResMgr = ImplGetResMgr();
2897 if( ! pResMgr )
2898 return new PopupMenu();
2900 PopupMenu* pPopup = new PopupMenu( ResId( SV_RESID_MENU_EDIT, *pResMgr ) );
2901 pPopup->SetAccelKey( SV_MENU_EDIT_UNDO, KeyCode( KEYFUNC_UNDO ) );
2902 pPopup->SetAccelKey( SV_MENU_EDIT_CUT, KeyCode( KEYFUNC_CUT ) );
2903 pPopup->SetAccelKey( SV_MENU_EDIT_COPY, KeyCode( KEYFUNC_COPY ) );
2904 pPopup->SetAccelKey( SV_MENU_EDIT_PASTE, KeyCode( KEYFUNC_PASTE ) );
2905 pPopup->SetAccelKey( SV_MENU_EDIT_DELETE, KeyCode( KEYFUNC_DELETE ) );
2906 pPopup->SetAccelKey( SV_MENU_EDIT_SELECTALL, KeyCode( KEY_A, FALSE, TRUE, FALSE, FALSE ) );
2907 pPopup->SetAccelKey( SV_MENU_EDIT_INSERTSYMBOL, KeyCode( KEY_S, TRUE, TRUE, FALSE, FALSE ) );
2908 return pPopup;
2911 // -----------------------------------------------------------------------
2913 void Edit::DeletePopupMenu( PopupMenu* pMenu )
2915 delete pMenu;
2918 // ::com::sun::star::datatransfer::dnd::XDragGestureListener
2919 void Edit::dragGestureRecognized( const ::com::sun::star::datatransfer::dnd::DragGestureEvent& rDGE ) throw (::com::sun::star::uno::RuntimeException)
2921 vos::OGuard aVclGuard( Application::GetSolarMutex() );
2923 if ( !IsTracking() && maSelection.Len() &&
2924 !(GetStyle() & WB_PASSWORD) && (!mpDDInfo || mpDDInfo->bStarterOfDD == FALSE) ) // Kein Mehrfach D&D
2926 Selection aSel( maSelection );
2927 aSel.Justify();
2929 // Nur wenn Maus in der Selektion...
2930 Point aMousePos( rDGE.DragOriginX, rDGE.DragOriginY );
2931 xub_StrLen nChar = ImplGetCharPos( aMousePos );
2932 if ( (nChar >= aSel.Min()) && (nChar < aSel.Max()) )
2934 if ( !mpDDInfo )
2935 mpDDInfo = new DDInfo;
2937 mpDDInfo->bStarterOfDD = TRUE;
2938 mpDDInfo->aDndStartSel = aSel;
2941 if ( IsTracking() )
2942 EndTracking(); // Vor D&D Tracking ausschalten
2944 ::vcl::unohelper::TextDataObject* pDataObj = new ::vcl::unohelper::TextDataObject( GetSelected() );
2945 sal_Int8 nActions = datatransfer::dnd::DNDConstants::ACTION_COPY;
2946 if ( !IsReadOnly() )
2947 nActions |= datatransfer::dnd::DNDConstants::ACTION_MOVE;
2948 rDGE.DragSource->startDrag( rDGE, nActions, 0 /*cursor*/, 0 /*image*/, pDataObj, mxDnDListener );
2949 if ( GetCursor() )
2950 GetCursor()->Hide();
2956 // ::com::sun::star::datatransfer::dnd::XDragSourceListener
2957 void Edit::dragDropEnd( const ::com::sun::star::datatransfer::dnd::DragSourceDropEvent& rDSDE ) throw (::com::sun::star::uno::RuntimeException)
2959 vos::OGuard aVclGuard( Application::GetSolarMutex() );
2961 if ( rDSDE.DropSuccess && ( rDSDE.DropAction & datatransfer::dnd::DNDConstants::ACTION_MOVE ) )
2963 Selection aSel( mpDDInfo->aDndStartSel );
2964 if ( mpDDInfo->bDroppedInMe )
2966 if ( aSel.Max() > mpDDInfo->nDropPos )
2968 long nLen = aSel.Len();
2969 aSel.Min() += nLen;
2970 aSel.Max() += nLen;
2973 ImplDelete( aSel, EDIT_DEL_RIGHT, EDIT_DELMODE_SIMPLE );
2974 ImplModified();
2977 ImplHideDDCursor();
2978 delete mpDDInfo;
2979 mpDDInfo = NULL;
2982 // ::com::sun::star::datatransfer::dnd::XDropTargetListener
2983 void Edit::drop( const ::com::sun::star::datatransfer::dnd::DropTargetDropEvent& rDTDE ) throw (::com::sun::star::uno::RuntimeException)
2985 vos::OGuard aVclGuard( Application::GetSolarMutex() );
2987 BOOL bChanges = FALSE;
2988 if ( !mbReadOnly && mpDDInfo )
2990 ImplHideDDCursor();
2992 Selection aSel( maSelection );
2993 aSel.Justify();
2995 if ( aSel.Len() && !mpDDInfo->bStarterOfDD )
2996 ImplDelete( aSel, EDIT_DEL_RIGHT, EDIT_DELMODE_SIMPLE );
2998 mpDDInfo->bDroppedInMe = TRUE;
3000 aSel.Min() = mpDDInfo->nDropPos;
3001 aSel.Max() = mpDDInfo->nDropPos;
3002 ImplSetSelection( aSel );
3004 uno::Reference< datatransfer::XTransferable > xDataObj = rDTDE.Transferable;
3005 if ( xDataObj.is() )
3007 datatransfer::DataFlavor aFlavor;
3008 SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aFlavor );
3009 if ( xDataObj->isDataFlavorSupported( aFlavor ) )
3011 uno::Any aData = xDataObj->getTransferData( aFlavor );
3012 ::rtl::OUString aText;
3013 aData >>= aText;
3014 ImplInsertText( aText );
3015 bChanges = TRUE;
3016 ImplModified();
3020 if ( !mpDDInfo->bStarterOfDD )
3022 delete mpDDInfo;
3023 mpDDInfo = NULL;
3027 rDTDE.Context->dropComplete( bChanges );
3030 void Edit::dragEnter( const ::com::sun::star::datatransfer::dnd::DropTargetDragEnterEvent& ) throw (::com::sun::star::uno::RuntimeException)
3032 if ( !mpDDInfo )
3034 mpDDInfo = new DDInfo;
3036 // sal_Bool bTextContent = mbReadOnly ? sal_False : sal_True; // quiery from rDTDEE.SupportedDataFlavors()
3037 // if ( bTextContent )
3038 // rDTDEE.Context->acceptDrop(datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE);
3039 // else
3040 // rDTDEE.Context->rejectDrop();
3043 void Edit::dragExit( const ::com::sun::star::datatransfer::dnd::DropTargetEvent& ) throw (::com::sun::star::uno::RuntimeException)
3045 vos::OGuard aVclGuard( Application::GetSolarMutex() );
3047 ImplHideDDCursor();
3050 void Edit::dragOver( const ::com::sun::star::datatransfer::dnd::DropTargetDragEvent& rDTDE ) throw (::com::sun::star::uno::RuntimeException)
3052 vos::OGuard aVclGuard( Application::GetSolarMutex() );
3054 Point aMousePos( rDTDE.LocationX, rDTDE.LocationY );
3056 xub_StrLen nPrevDropPos = mpDDInfo->nDropPos;
3057 mpDDInfo->nDropPos = ImplGetCharPos( aMousePos );
3060 Size aOutSize = GetOutputSizePixel();
3061 if ( ( aMousePos.X() < 0 ) || ( aMousePos.X() > aOutSize.Width() ) )
3063 // Scroll?
3064 // No, I will not receive events in this case....
3068 Selection aSel( maSelection );
3069 aSel.Justify();
3071 // Don't accept drop in selection or read-only field...
3072 if ( IsReadOnly() || aSel.IsInside( mpDDInfo->nDropPos ) )
3074 ImplHideDDCursor();
3075 rDTDE.Context->rejectDrag();
3077 else
3079 // Alten Cursor wegzeichnen...
3080 if ( !mpDDInfo->bVisCursor || ( nPrevDropPos != mpDDInfo->nDropPos ) )
3082 ImplHideDDCursor();
3083 ImplShowDDCursor();
3085 rDTDE.Context->acceptDrag( rDTDE.DropAction );
3089 ImplSubEdit::ImplSubEdit( Edit* pParent, WinBits nStyle ) :
3090 Edit( pParent, nStyle )
3092 pParent->SetSubEdit( this );
3095 // -----------------------------------------------------------------------
3097 void ImplSubEdit::Modify()
3099 GetParent()->Modify();
3102 XubString Edit::GetSurroundingText() const
3104 if ( mpSubEdit )
3105 return mpSubEdit->GetSurroundingText();
3106 else
3107 return maText;
3110 Selection Edit::GetSurroundingTextSelection() const
3112 return GetSelection();