update credits
[LibreOffice.git] / vcl / source / control / edit.cxx
blobbb94ee3c8bc855e2531c06e127fb3f1a99bd046c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <tools/rc.h>
22 #include <vcl/decoview.hxx>
23 #include <vcl/event.hxx>
24 #include <vcl/cursor.hxx>
25 #include <vcl/virdev.hxx>
26 #include <vcl/menu.hxx>
27 #include <vcl/edit.hxx>
28 #include <vcl/svapp.hxx>
29 #include <vcl/msgbox.hxx>
31 #include <window.h>
32 #include <svdata.hxx>
33 #include <svids.hrc>
34 #include <controldata.hxx>
36 #include <osl/mutex.hxx>
39 #include <com/sun/star/i18n/BreakIterator.hpp>
40 #include <com/sun/star/i18n/CharacterIteratorMode.hpp>
41 #include <com/sun/star/i18n/WordType.hpp>
42 #include <cppuhelper/weak.hxx>
43 #include <com/sun/star/datatransfer/XTransferable.hpp>
44 #include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
45 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
47 #include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
48 #include <com/sun/star/datatransfer/dnd/XDragGestureRecognizer.hpp>
49 #include <com/sun/star/datatransfer/dnd/XDropTarget.hpp>
51 #include <com/sun/star/i18n/InputSequenceChecker.hpp>
52 #include <com/sun/star/i18n/InputSequenceCheckMode.hpp>
53 #include <com/sun/star/i18n/ScriptType.hpp>
54 #include <com/sun/star/container/XNameAccess.hpp>
56 #include <com/sun/star/uno/Any.hxx>
58 #include <comphelper/configurationhelper.hxx>
59 #include <comphelper/processfactory.hxx>
60 #include <comphelper/string.hxx>
62 #include <sot/exchange.hxx>
63 #include <sot/formats.hxx>
64 #include <sal/macros.h>
66 #include <vcl/unohelp.hxx>
67 #include <vcl/unohelp2.hxx>
72 using namespace ::com::sun::star;
73 using namespace ::com::sun::star::uno;
74 using namespace ::com::sun::star::lang;
75 using namespace ::rtl;
77 // - Redo
78 // - Bei Tracking-Cancel DefaultSelection wieder herstellen
80 // =======================================================================
82 static FncGetSpecialChars pImplFncGetSpecialChars = NULL;
84 // =======================================================================
86 #define EDIT_ALIGN_LEFT 1
87 #define EDIT_ALIGN_CENTER 2
88 #define EDIT_ALIGN_RIGHT 3
90 #define EDIT_DEL_LEFT 1
91 #define EDIT_DEL_RIGHT 2
93 #define EDIT_DELMODE_SIMPLE 11
94 #define EDIT_DELMODE_RESTOFWORD 12
95 #define EDIT_DELMODE_RESTOFCONTENT 13
97 // =======================================================================
99 struct DDInfo
101 Cursor aCursor;
102 Selection aDndStartSel;
103 xub_StrLen nDropPos;
104 bool bStarterOfDD;
105 bool bDroppedInMe;
106 bool bVisCursor;
107 bool bIsStringSupported;
109 DDInfo()
111 aCursor.SetStyle( CURSOR_SHADOW );
112 nDropPos = 0;
113 bStarterOfDD = false;
114 bDroppedInMe = false;
115 bVisCursor = false;
116 bIsStringSupported = false;
120 // =======================================================================
122 struct Impl_IMEInfos
124 OUString aOldTextAfterStartPos;
125 sal_uInt16* pAttribs;
126 xub_StrLen nPos;
127 xub_StrLen nLen;
128 bool bCursor;
129 bool bWasCursorOverwrite;
131 Impl_IMEInfos( xub_StrLen nPos, const OUString& rOldTextAfterStartPos );
132 ~Impl_IMEInfos();
134 void CopyAttribs( const xub_StrLen* pA, xub_StrLen nL );
135 void DestroyAttribs();
138 // -----------------------------------------------------------------------
140 Impl_IMEInfos::Impl_IMEInfos( xub_StrLen nP, const OUString& rOldTextAfterStartPos )
141 : aOldTextAfterStartPos( rOldTextAfterStartPos )
143 nPos = nP;
144 nLen = 0;
145 bCursor = true;
146 pAttribs = NULL;
147 bWasCursorOverwrite = false;
150 // -----------------------------------------------------------------------
152 Impl_IMEInfos::~Impl_IMEInfos()
154 delete[] pAttribs;
157 // -----------------------------------------------------------------------
159 void Impl_IMEInfos::CopyAttribs( const xub_StrLen* pA, xub_StrLen nL )
161 nLen = nL;
162 delete[] pAttribs;
163 pAttribs = new sal_uInt16[ nL ];
164 memcpy( pAttribs, pA, nL*sizeof(sal_uInt16) );
167 // -----------------------------------------------------------------------
169 void Impl_IMEInfos::DestroyAttribs()
171 delete[] pAttribs;
172 pAttribs = NULL;
173 nLen = 0;
176 // =======================================================================
178 Edit::Edit( WindowType nType ) :
179 Control( nType )
181 ImplInitEditData();
184 // -----------------------------------------------------------------------
186 Edit::Edit( Window* pParent, WinBits nStyle ) :
187 Control( WINDOW_EDIT )
189 ImplInitEditData();
190 ImplInit( pParent, nStyle );
193 Edit::Edit( Window* pParent, const ResId& rResId ) :
194 Control( WINDOW_EDIT )
196 rResId.SetRT( RSC_EDIT );
197 WinBits nStyle = ImplInitRes( rResId );
198 ImplInitEditData();
199 ImplInit( pParent, nStyle );
200 ImplLoadRes( rResId );
202 // Derived MultiLineEdit takes care to call Show only after MultiLineEdit
203 // ctor has already started:
204 if ( !(nStyle & WB_HIDE) && rResId.GetRT() != RSC_MULTILINEEDIT )
205 Show();
208 void Edit::SetWidthInChars(sal_Int32 nWidthInChars)
210 if (mnWidthInChars != nWidthInChars)
212 mnWidthInChars = nWidthInChars;
213 queue_resize();
217 void Edit::setMaxWidthChars(sal_Int32 nWidth)
219 if (nWidth != mnMaxWidthChars)
221 mnMaxWidthChars = nWidth;
222 queue_resize();
226 bool Edit::set_property(const OString &rKey, const OString &rValue)
228 if (rKey == "width-chars")
229 SetWidthInChars(rValue.toInt32());
230 else if (rKey == "max-width-chars")
231 setMaxWidthChars(rValue.toInt32());
232 else if (rKey == "max-length")
234 sal_Int32 nTextLen = rValue.toInt32();
235 SetMaxTextLen(nTextLen == 0 ? EDIT_NOLIMIT : nTextLen);
237 else if (rKey == "editable")
239 bool bReadOnly = !toBool(rValue);
240 SetReadOnly(bReadOnly);
241 //disable tab to traverse into readonly editables
242 WinBits nBits = GetStyle();
243 nBits &= ~(WB_TABSTOP|WB_NOTABSTOP);
244 if (!bReadOnly)
245 nBits |= WB_TABSTOP;
246 else
247 nBits |= WB_NOTABSTOP;
248 SetStyle(nBits);
250 else if (rKey == "visibility")
252 WinBits nBits = GetStyle();
253 nBits &= ~(WB_PASSWORD);
254 if (!toBool(rValue))
255 nBits |= WB_PASSWORD;
256 SetStyle(nBits);
258 else if (rKey == "placeholder-text")
259 SetPlaceholderText(OStringToOUString(rValue, RTL_TEXTENCODING_UTF8));
260 else
261 return Control::set_property(rKey, rValue);
262 return true;
265 // -----------------------------------------------------------------------
267 Edit::~Edit()
269 delete mpDDInfo;
270 Cursor* pCursor = GetCursor();
271 if ( pCursor )
273 SetCursor( NULL );
274 delete pCursor;
277 delete mpIMEInfos;
279 delete mpUpdateDataTimer;
281 if ( mxDnDListener.is() )
283 if ( GetDragGestureRecognizer().is() )
285 uno::Reference< datatransfer::dnd::XDragGestureListener> xDGL( mxDnDListener, uno::UNO_QUERY );
286 GetDragGestureRecognizer()->removeDragGestureListener( xDGL );
288 if ( GetDropTarget().is() )
290 uno::Reference< datatransfer::dnd::XDropTargetListener> xDTL( mxDnDListener, uno::UNO_QUERY );
291 GetDropTarget()->removeDropTargetListener( xDTL );
294 uno::Reference< lang::XEventListener> xEL( mxDnDListener, uno::UNO_QUERY );
295 xEL->disposing( lang::EventObject() ); // #95154# #96585# Empty Source means it's the Client
299 // -----------------------------------------------------------------------
301 void Edit::ImplInitEditData()
303 mpSubEdit = NULL;
304 mpUpdateDataTimer = NULL;
305 mnXOffset = 0;
306 mnAlign = EDIT_ALIGN_LEFT;
307 mnMaxTextLen = EDIT_NOLIMIT;
308 mnWidthInChars = -1;
309 mnMaxWidthChars = -1;
310 meAutocompleteAction = AUTOCOMPLETE_KEYINPUT;
311 mbModified = sal_False;
312 mbInternModified = sal_False;
313 mbReadOnly = sal_False;
314 mbInsertMode = sal_True;
315 mbClickedInSelection = sal_False;
316 mbActivePopup = sal_False;
317 mbIsSubEdit = sal_False;
318 mbInMBDown = sal_False;
319 mpDDInfo = NULL;
320 mpIMEInfos = NULL;
321 mcEchoChar = 0;
323 // --- RTL --- no default mirroring for Edit controls
324 // note: controls that use a subedit will revert this (SpinField, ComboBox)
325 EnableRTL( sal_False );
327 vcl::unohelper::DragAndDropWrapper* pDnDWrapper = new vcl::unohelper::DragAndDropWrapper( this );
328 mxDnDListener = pDnDWrapper;
331 // -----------------------------------------------------------------------
333 bool Edit::ImplUseNativeBorder( WinBits nStyle )
335 bool bRet =
336 IsNativeControlSupported(ImplGetNativeControlType(), HAS_BACKGROUND_TEXTURE)
337 && ((nStyle&WB_BORDER) && !(nStyle&WB_NOBORDER));
338 if( ! bRet && mbIsSubEdit )
340 Window* pWindow = GetParent();
341 nStyle = pWindow->GetStyle();
342 bRet = pWindow->IsNativeControlSupported(ImplGetNativeControlType(), HAS_BACKGROUND_TEXTURE)
343 && ((nStyle&WB_BORDER) && !(nStyle&WB_NOBORDER));
345 return bRet;
348 void Edit::ImplInit( Window* pParent, WinBits nStyle )
350 nStyle = ImplInitStyle( nStyle );
351 if ( !(nStyle & (WB_CENTER | WB_RIGHT)) )
352 nStyle |= WB_LEFT;
354 Control::ImplInit( pParent, nStyle, NULL );
356 mbReadOnly = (nStyle & WB_READONLY) != 0;
358 mnAlign = EDIT_ALIGN_LEFT;
360 // --- RTL --- hack: right align until keyinput and cursor travelling works
361 if( IsRTLEnabled() )
362 mnAlign = EDIT_ALIGN_RIGHT;
364 if ( nStyle & WB_RIGHT )
365 mnAlign = EDIT_ALIGN_RIGHT;
366 else if ( nStyle & WB_CENTER )
367 mnAlign = EDIT_ALIGN_CENTER;
369 SetCursor( new Cursor );
371 SetPointer( Pointer( POINTER_TEXT ) );
372 ImplInitSettings( sal_True, sal_True, sal_True );
374 uno::Reference< datatransfer::dnd::XDragGestureListener> xDGL( mxDnDListener, uno::UNO_QUERY );
375 uno::Reference< datatransfer::dnd::XDragGestureRecognizer > xDGR = GetDragGestureRecognizer();
376 if ( xDGR.is() )
378 xDGR->addDragGestureListener( xDGL );
379 uno::Reference< datatransfer::dnd::XDropTargetListener> xDTL( mxDnDListener, uno::UNO_QUERY );
380 GetDropTarget()->addDropTargetListener( xDTL );
381 GetDropTarget()->setActive( sal_True );
382 GetDropTarget()->setDefaultActions( datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE );
386 // -----------------------------------------------------------------------
388 WinBits Edit::ImplInitStyle( WinBits nStyle )
390 if ( !(nStyle & WB_NOTABSTOP) )
391 nStyle |= WB_TABSTOP;
392 if ( !(nStyle & WB_NOGROUP) )
393 nStyle |= WB_GROUP;
395 return nStyle;
398 // -----------------------------------------------------------------------
400 sal_Bool Edit::IsCharInput( const KeyEvent& rKeyEvent )
402 // In the future we must use new Unicode functions for this
403 sal_Unicode cCharCode = rKeyEvent.GetCharCode();
404 return ((cCharCode >= 32) && (cCharCode != 127) &&
405 !rKeyEvent.GetKeyCode().IsMod3() &&
406 !rKeyEvent.GetKeyCode().IsMod2() &&
407 !rKeyEvent.GetKeyCode().IsMod1() );
410 // -----------------------------------------------------------------------
412 void Edit::ImplModified()
414 mbModified = sal_True;
415 Modify();
418 // -----------------------------------------------------------------------
420 void Edit::ImplInitSettings( sal_Bool bFont, sal_Bool bForeground, sal_Bool bBackground )
422 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
424 if ( bFont )
426 Font aFont = rStyleSettings.GetFieldFont();
427 if ( IsControlFont() )
428 aFont.Merge( GetControlFont() );
429 SetZoomedPointFont( aFont );
430 ImplClearLayoutData();
433 if ( bFont || bForeground )
435 Color aTextColor = rStyleSettings.GetFieldTextColor();
436 if ( IsControlForeground() )
437 aTextColor = GetControlForeground();
438 SetTextColor( aTextColor );
441 if ( bBackground )
443 if ( ImplUseNativeBorder( GetStyle() ) || IsPaintTransparent() )
445 // Transparent background
446 SetBackground();
447 SetFillColor();
449 else if ( IsControlBackground() )
451 SetBackground( GetControlBackground() );
452 SetFillColor( GetControlBackground() );
454 else
456 SetBackground( rStyleSettings.GetFieldColor() );
457 SetFillColor( rStyleSettings.GetFieldColor() );
462 // -----------------------------------------------------------------------
464 long Edit::ImplGetExtraOffset() const
466 // MT 09/2002: nExtraOffsetX should become a member, instead of checking every time,
467 // but I need an incompatible update for this...
468 // #94095# Use extra offset only when edit has a border
469 long nExtraOffset = 0;
470 if( ( GetStyle() & WB_BORDER ) || ( mbIsSubEdit && ( GetParent()->GetStyle() & WB_BORDER ) ) )
471 nExtraOffset = 2;
473 return nExtraOffset;
477 // -----------------------------------------------------------------------
479 OUString Edit::ImplGetText() const
481 if ( mcEchoChar || (GetStyle() & WB_PASSWORD) )
483 sal_Unicode cEchoChar;
484 if ( mcEchoChar )
485 cEchoChar = mcEchoChar;
486 else
487 cEchoChar = '*';
488 OUStringBuffer aText;
489 comphelper::string::padToLength(aText, maText.getLength(), cEchoChar);
490 return aText.makeStringAndClear();
492 else
493 return maText.toString();
496 // -----------------------------------------------------------------------
498 void Edit::ImplInvalidateOrRepaint( xub_StrLen nStart, xub_StrLen nEnd )
500 if( IsPaintTransparent() )
502 Invalidate();
503 // FIXME: this is currently only on aqua
504 if( ImplGetSVData()->maNWFData.mbNoFocusRects )
505 Update();
507 else
508 ImplRepaint( nStart, nEnd );
511 // -----------------------------------------------------------------------
513 long Edit::ImplGetTextYPosition() const
515 if ( GetStyle() & WB_TOP )
516 return ImplGetExtraOffset();
517 else if ( GetStyle() & WB_BOTTOM )
518 return GetOutputSizePixel().Height() - GetTextHeight() - ImplGetExtraOffset();
519 return ( GetOutputSizePixel().Height() - GetTextHeight() ) / 2;
522 // -----------------------------------------------------------------------
524 void Edit::ImplRepaint( xub_StrLen nStart, xub_StrLen nEnd, bool bLayout )
526 if ( !IsReallyVisible() )
527 return;
529 OUString aText = ImplGetText();
530 nStart = 0;
531 nEnd = aText.getLength();
533 sal_Int32 nDXBuffer[256];
534 sal_Int32* pDXBuffer = NULL;
535 sal_Int32* pDX = nDXBuffer;
537 if( !aText.isEmpty() )
539 if( (size_t) (2*aText.getLength()) > SAL_N_ELEMENTS(nDXBuffer) )
541 pDXBuffer = new sal_Int32[2*(aText.getLength()+1)];
542 pDX = pDXBuffer;
545 GetCaretPositions( aText, pDX, nStart, nEnd );
548 long nTH = GetTextHeight();
549 Point aPos( mnXOffset, ImplGetTextYPosition() );
551 if( bLayout )
553 long nPos = nStart ? pDX[2*nStart] : 0;
554 aPos.X() = nPos + mnXOffset + ImplGetExtraOffset();
556 MetricVector* pVector = &mpControlData->mpLayoutData->m_aUnicodeBoundRects;
557 OUString* pDisplayText = &mpControlData->mpLayoutData->m_aDisplayText;
559 DrawText( aPos, aText, nStart, nEnd - nStart, pVector, pDisplayText );
561 if( pDXBuffer )
562 delete [] pDXBuffer;
563 return;
566 Cursor* pCursor = GetCursor();
567 bool bVisCursor = pCursor ? pCursor->IsVisible() : false;
568 if ( pCursor )
569 pCursor->Hide();
571 ImplClearBackground( 0, GetOutputSizePixel().Width() );
573 bool bPaintPlaceholderText = aText.isEmpty() && !maPlaceholderText.isEmpty();
575 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
576 if ( IsEnabled() )
577 ImplInitSettings( sal_False, sal_True, sal_False );
578 if ( !IsEnabled() || bPaintPlaceholderText )
579 SetTextColor( rStyleSettings.GetDisableColor() );
581 // Set background color of the normal text
582 if( (GetStyle() & WB_FORCECTRLBACKGROUND) != 0 && IsControlBackground() )
584 // check if we need to set ControlBackground even in NWF case
585 Push( PUSH_FILLCOLOR | PUSH_LINECOLOR );
586 SetLineColor();
587 SetFillColor( GetControlBackground() );
588 DrawRect( Rectangle( aPos, Size( GetOutputSizePixel().Width() - 2*mnXOffset, GetOutputSizePixel().Height() ) ) );
589 Pop();
591 SetTextFillColor( GetControlBackground() );
593 else if( IsPaintTransparent() || ImplUseNativeBorder( GetStyle() ) )
594 SetTextFillColor();
595 else
596 SetTextFillColor( IsControlBackground() ? GetControlBackground() : rStyleSettings.GetFieldColor() );
598 ImplPaintBorder( 0, GetOutputSizePixel().Width() );
600 bool bDrawSelection = maSelection.Len() && ( HasFocus() || ( GetStyle() & WB_NOHIDESELECTION ) || mbActivePopup );
602 long nPos = nStart ? pDX[2*nStart] : 0;
603 aPos.X() = nPos + mnXOffset + ImplGetExtraOffset();
604 if ( bPaintPlaceholderText )
606 DrawText( aPos, maPlaceholderText );
608 else if ( !bDrawSelection && !mpIMEInfos )
610 DrawText( aPos, aText, nStart, nEnd - nStart );
612 else
614 // save graphics state
615 Push();
616 // first calculate higlighted and non highlighted clip regions
617 Region aHiglightClipRegion;
618 Region aNormalClipRegion;
619 Selection aTmpSel( maSelection );
620 aTmpSel.Justify();
621 // selection is highlighted
622 int i;
623 for( i = 0; i < aText.getLength(); i++ )
625 Rectangle aRect( aPos, Size( 10, nTH ) );
626 aRect.Left() = pDX[2*i] + mnXOffset + ImplGetExtraOffset();
627 aRect.Right() = pDX[2*i+1] + mnXOffset + ImplGetExtraOffset();
628 aRect.Justify();
629 bool bHighlight = false;
630 if( i >= aTmpSel.Min() && i < aTmpSel.Max() )
631 bHighlight = true;
633 if( mpIMEInfos && mpIMEInfos->pAttribs &&
634 i >= mpIMEInfos->nPos && i < (mpIMEInfos->nPos+mpIMEInfos->nLen ) &&
635 ( mpIMEInfos->pAttribs[i-mpIMEInfos->nPos] & EXTTEXTINPUT_ATTR_HIGHLIGHT) )
636 bHighlight = true;
638 if( bHighlight )
639 aHiglightClipRegion.Union( aRect );
640 else
641 aNormalClipRegion.Union( aRect );
643 // draw normal text
644 Color aNormalTextColor = GetTextColor();
645 SetClipRegion( aNormalClipRegion );
647 if( IsPaintTransparent() )
648 SetTextFillColor();
649 else
651 // Set background color when part of the text is selected
652 if ( ImplUseNativeBorder( GetStyle() ) )
654 if( (GetStyle() & WB_FORCECTRLBACKGROUND) != 0 && IsControlBackground() )
655 SetTextFillColor( GetControlBackground() );
656 else
657 SetTextFillColor();
659 else
660 SetTextFillColor( IsControlBackground() ? GetControlBackground() : rStyleSettings.GetFieldColor() );
662 DrawText( aPos, aText, nStart, nEnd - nStart );
664 // draw highlighted text
665 SetClipRegion( aHiglightClipRegion );
666 SetTextColor( rStyleSettings.GetHighlightTextColor() );
667 SetTextFillColor( rStyleSettings.GetHighlightColor() );
668 DrawText( aPos, aText, nStart, nEnd - nStart );
670 // if IME info exists loop over portions and output different font attributes
671 if( mpIMEInfos && mpIMEInfos->pAttribs )
673 for( int n = 0; n < 2; n++ )
675 Region aRegion;
676 if( n == 0 )
678 SetTextColor( aNormalTextColor );
679 if( IsPaintTransparent() )
680 SetTextFillColor();
681 else
682 SetTextFillColor( IsControlBackground() ? GetControlBackground() : rStyleSettings.GetFieldColor() );
683 aRegion = aNormalClipRegion;
685 else
687 SetTextColor( rStyleSettings.GetHighlightTextColor() );
688 SetTextFillColor( rStyleSettings.GetHighlightColor() );
689 aRegion = aHiglightClipRegion;
692 for( i = 0; i < mpIMEInfos->nLen; )
694 sal_uInt16 nAttr = mpIMEInfos->pAttribs[i];
695 Region aClip;
696 int nIndex = i;
697 while( nIndex < mpIMEInfos->nLen && mpIMEInfos->pAttribs[nIndex] == nAttr) // #112631# check nIndex before using it
699 Rectangle aRect( aPos, Size( 10, nTH ) );
700 aRect.Left() = pDX[2*(nIndex+mpIMEInfos->nPos)] + mnXOffset + ImplGetExtraOffset();
701 aRect.Right() = pDX[2*(nIndex+mpIMEInfos->nPos)+1] + mnXOffset + ImplGetExtraOffset();
702 aRect.Justify();
703 aClip.Union( aRect );
704 nIndex++;
706 i = nIndex;
707 aClip.Intersect(aRegion);
708 if( !aClip.IsEmpty() && nAttr )
710 Font aFont = GetFont();
711 if ( nAttr & EXTTEXTINPUT_ATTR_UNDERLINE )
712 aFont.SetUnderline( UNDERLINE_SINGLE );
713 else if ( nAttr & EXTTEXTINPUT_ATTR_BOLDUNDERLINE )
714 aFont.SetUnderline( UNDERLINE_BOLD );
715 else if ( nAttr & EXTTEXTINPUT_ATTR_DOTTEDUNDERLINE )
716 aFont.SetUnderline( UNDERLINE_DOTTED );
717 else if ( nAttr & EXTTEXTINPUT_ATTR_DASHDOTUNDERLINE )
718 aFont.SetUnderline( UNDERLINE_DASHDOT );
719 else if ( nAttr & EXTTEXTINPUT_ATTR_GRAYWAVELINE )
721 aFont.SetUnderline( UNDERLINE_WAVE );
722 SetTextLineColor( Color( COL_LIGHTGRAY ) );
724 SetFont( aFont );
726 if ( nAttr & EXTTEXTINPUT_ATTR_REDTEXT )
727 SetTextColor( Color( COL_RED ) );
728 else if ( nAttr & EXTTEXTINPUT_ATTR_HALFTONETEXT )
729 SetTextColor( Color( COL_LIGHTGRAY ) );
731 SetClipRegion( aClip );
732 DrawText( aPos, aText, nStart, nEnd - nStart );
738 // restore graphics state
739 Pop();
742 if ( bVisCursor && ( !mpIMEInfos || mpIMEInfos->bCursor ) )
743 pCursor->Show();
745 if( pDXBuffer )
746 delete [] pDXBuffer;
749 // -----------------------------------------------------------------------
751 void Edit::ImplDelete( const Selection& rSelection, sal_uInt8 nDirection, sal_uInt8 nMode )
753 OUString aText = ImplGetText();
755 // loeschen moeglich?
756 if ( !rSelection.Len() &&
757 (((rSelection.Min() == 0) && (nDirection == EDIT_DEL_LEFT)) ||
758 ((rSelection.Max() == aText.getLength()) && (nDirection == EDIT_DEL_RIGHT))) )
759 return;
761 ImplClearLayoutData();
763 Selection aSelection( rSelection );
764 aSelection.Justify();
766 if ( !aSelection.Len() )
768 uno::Reference < i18n::XBreakIterator > xBI = ImplGetBreakIterator();
769 if ( nDirection == EDIT_DEL_LEFT )
771 if ( nMode == EDIT_DELMODE_RESTOFWORD )
773 i18n::Boundary aBoundary = xBI->getWordBoundary( maText.toString(), aSelection.Min(),
774 GetSettings().GetLanguageTag().getLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True );
775 if ( aBoundary.startPos == aSelection.Min() )
776 aBoundary = xBI->previousWord( maText.toString(), aSelection.Min(),
777 GetSettings().GetLanguageTag().getLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES );
778 aSelection.Min() = aBoundary.startPos;
780 else if ( nMode == EDIT_DELMODE_RESTOFCONTENT )
782 aSelection.Min() = 0;
784 else
786 sal_Int32 nCount = 1;
787 aSelection.Min() = xBI->previousCharacters( maText.toString(), aSelection.Min(),
788 GetSettings().GetLanguageTag().getLocale(), i18n::CharacterIteratorMode::SKIPCHARACTER, nCount, nCount );
791 else
793 if ( nMode == EDIT_DELMODE_RESTOFWORD )
795 i18n::Boundary aBoundary = xBI->nextWord( maText.toString(), aSelection.Max(),
796 GetSettings().GetLanguageTag().getLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES );
797 aSelection.Max() = aBoundary.startPos;
799 else if ( nMode == EDIT_DELMODE_RESTOFCONTENT )
801 aSelection.Max() = aText.getLength();
803 else
805 sal_Int32 nCount = 1;
806 aSelection.Max() = xBI->nextCharacters( maText.toString(), aSelection.Max(),
807 GetSettings().GetLanguageTag().getLocale(), i18n::CharacterIteratorMode::SKIPCHARACTER, nCount, nCount );
812 maText.remove( static_cast<sal_Int32>(aSelection.Min()), static_cast<sal_Int32>(aSelection.Len()) );
813 maSelection.Min() = aSelection.Min();
814 maSelection.Max() = aSelection.Min();
815 ImplAlignAndPaint();
816 mbInternModified = sal_True;
819 // -----------------------------------------------------------------------
821 OUString Edit::ImplGetValidString( const OUString& rString ) const
823 OUString aValidString( rString );
824 aValidString = comphelper::string::remove(aValidString, '\n');
825 aValidString = comphelper::string::remove(aValidString, '\r');
826 aValidString = aValidString.replace('\t', ' ');
827 return aValidString;
830 // -----------------------------------------------------------------------
831 uno::Reference < i18n::XBreakIterator > Edit::ImplGetBreakIterator() const
833 //!! since we don't want to become incompatible in the next minor update
834 //!! where this code will get integrated into, xISC will be a local
835 //!! variable instead of a class member!
836 uno::Reference< uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
837 return i18n::BreakIterator::create(xContext);
839 // -----------------------------------------------------------------------
841 uno::Reference < i18n::XExtendedInputSequenceChecker > Edit::ImplGetInputSequenceChecker() const
843 //!! since we don't want to become incompatible in the next minor update
844 //!! where this code will get integrated into, xISC will be a local
845 //!! variable instead of a class member!
846 uno::Reference < i18n::XExtendedInputSequenceChecker > xISC;
847 // if ( !xISC.is() )
849 uno::Reference< uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
850 xISC = i18n::InputSequenceChecker::create(xContext);
852 return xISC;
855 // -----------------------------------------------------------------------
857 void Edit::ShowTruncationWarning( Window* pParent )
859 ResMgr* pResMgr = ImplGetResMgr();
860 if( pResMgr )
862 WarningBox aBox( pParent, ResId( SV_EDIT_WARNING_BOX, *pResMgr ) );
863 aBox.Execute();
867 // -----------------------------------------------------------------------
869 bool Edit::ImplTruncateToMaxLen( OUString& rStr, sal_uInt32 nSelectionLen ) const
871 bool bWasTruncated = false;
872 const sal_uInt32 nMaxLen = mnMaxTextLen < 65534 ? mnMaxTextLen : 65534;
873 sal_uInt32 nLenAfter = static_cast<sal_uInt32>(maText.getLength()) + rStr.getLength() - nSelectionLen;
874 if ( nLenAfter > nMaxLen )
876 sal_uInt32 nErasePos = nMaxLen - static_cast<sal_uInt32>(maText.getLength()) + nSelectionLen;
877 rStr = rStr.copy( 0, nErasePos );
878 bWasTruncated = true;
880 return bWasTruncated;
883 // -----------------------------------------------------------------------
885 void Edit::ImplInsertText( const OUString& rStr, const Selection* pNewSel, sal_Bool bIsUserInput )
887 Selection aSelection( maSelection );
888 aSelection.Justify();
890 OUString aNewText( ImplGetValidString( rStr ) );
891 ImplTruncateToMaxLen( aNewText, aSelection.Len() );
893 ImplClearLayoutData();
895 if ( aSelection.Len() )
896 maText.remove( static_cast<sal_Int32>(aSelection.Min()), static_cast<sal_Int32>(aSelection.Len()) );
897 else if ( !mbInsertMode && (aSelection.Max() < maText.getLength()) )
898 maText.remove( static_cast<sal_Int32>(aSelection.Max()), 1 );
900 // take care of input-sequence-checking now
901 if (bIsUserInput && !rStr.isEmpty())
903 DBG_ASSERT( rStr.getLength() == 1, "unexpected string length. User input is expected to providse 1 char only!" );
905 // determine if input-sequence-checking should be applied or not
907 static OUString sModule( "/org.openoffice.Office.Common/I18N" );
908 static OUString sRelNode( "CTL" );
909 static OUString sCTLSequenceChecking( "CTLSequenceChecking" );
910 static OUString sCTLSequenceCheckingRestricted( "CTLSequenceCheckingRestricted" );
911 static OUString sCTLSequenceCheckingTypeAndReplace( "CTLSequenceCheckingTypeAndReplace" );
912 static OUString sCTLFont( "CTLFont" );
914 sal_Bool bCTLSequenceChecking = sal_False;
915 sal_Bool bCTLSequenceCheckingRestricted = sal_False;
916 sal_Bool bCTLSequenceCheckingTypeAndReplace = sal_False;
917 sal_Bool bCTLFontEnabled = sal_False;
918 bool bIsInputSequenceChecking = false;
920 // get access to the configuration of this office module
923 uno::Reference< uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
924 uno::Reference< container::XNameAccess > xModuleCfg( ::comphelper::ConfigurationHelper::openConfig(
925 xContext,
926 sModule,
927 ::comphelper::ConfigurationHelper::E_READONLY ),
928 uno::UNO_QUERY );
930 //!! get values from configuration.
931 //!! we can't use SvtCTLOptions here since vcl must not be linked
932 //!! against svtools. (It is already the other way around.)
933 Any aCTLSequenceChecking = ::comphelper::ConfigurationHelper::readRelativeKey( xModuleCfg, sRelNode, sCTLSequenceChecking );
934 Any aCTLSequenceCheckingRestricted = ::comphelper::ConfigurationHelper::readRelativeKey( xModuleCfg, sRelNode, sCTLSequenceCheckingRestricted );
935 Any aCTLSequenceCheckingTypeAndReplace = ::comphelper::ConfigurationHelper::readRelativeKey( xModuleCfg, sRelNode, sCTLSequenceCheckingTypeAndReplace );
936 Any aCTLFontEnabled = ::comphelper::ConfigurationHelper::readRelativeKey( xModuleCfg, sRelNode, sCTLFont );
937 aCTLSequenceChecking >>= bCTLSequenceChecking;
938 aCTLSequenceCheckingRestricted >>= bCTLSequenceCheckingRestricted;
939 aCTLSequenceCheckingTypeAndReplace >>= bCTLSequenceCheckingTypeAndReplace;
940 aCTLFontEnabled >>= bCTLFontEnabled;
942 catch(...)
944 bIsInputSequenceChecking = false; // continue with inserting the new text
947 uno::Reference < i18n::XBreakIterator > xBI( ImplGetBreakIterator(), UNO_QUERY );
948 bIsInputSequenceChecking = rStr.getLength() == 1 &&
949 bCTLFontEnabled &&
950 bCTLSequenceChecking &&
951 aSelection.Min() > 0 && /* first char needs not to be checked */
952 xBI.is() && i18n::ScriptType::COMPLEX == xBI->getScriptType( rStr, 0 );
955 uno::Reference < i18n::XExtendedInputSequenceChecker > xISC;
956 if (bIsInputSequenceChecking && (xISC = ImplGetInputSequenceChecker()).is())
958 sal_Unicode cChar = rStr[0];
959 sal_Int32 nTmpPos = static_cast< sal_Int32 >( aSelection.Min() );
960 sal_Int16 nCheckMode = bCTLSequenceCheckingRestricted ?
961 i18n::InputSequenceCheckMode::STRICT : i18n::InputSequenceCheckMode::BASIC;
963 // the text that needs to be checked is only the one
964 // before the current cursor position
965 OUString aOldText( maText.getStr(), nTmpPos);
966 OUString aTmpText( aOldText );
967 if (bCTLSequenceCheckingTypeAndReplace)
969 xISC->correctInputSequence( aTmpText, nTmpPos - 1, cChar, nCheckMode );
971 // find position of first character that has changed
972 sal_Int32 nOldLen = aOldText.getLength();
973 sal_Int32 nTmpLen = aTmpText.getLength();
974 const sal_Unicode *pOldTxt = aOldText.getStr();
975 const sal_Unicode *pTmpTxt = aTmpText.getStr();
976 sal_Int32 nChgPos = 0;
977 while ( nChgPos < nOldLen && nChgPos < nTmpLen &&
978 pOldTxt[nChgPos] == pTmpTxt[nChgPos] )
979 ++nChgPos;
981 OUString aChgText( aTmpText.copy( nChgPos ) );
983 // remove text from first pos to be changed to current pos
984 maText.remove( nChgPos, nTmpPos - nChgPos );
986 if (!aChgText.isEmpty())
988 aNewText = aChgText;
989 aSelection.Min() = nChgPos; // position for new text to be inserted
991 else
992 aNewText = "";
994 else
996 // should the character be ignored (i.e. not get inserted) ?
997 if (!xISC->checkInputSequence( aOldText, nTmpPos - 1, cChar, nCheckMode ))
998 aNewText = "";
1002 // at this point now we will insert the non-empty text 'normally' some lines below...
1005 if ( !aNewText.isEmpty() )
1006 maText.insert( static_cast<sal_Int32>(aSelection.Min()), aNewText );
1008 if ( !pNewSel )
1010 maSelection.Min() = aSelection.Min() + aNewText.getLength();
1011 maSelection.Max() = maSelection.Min();
1013 else
1015 maSelection = *pNewSel;
1016 if ( maSelection.Min() > maText.getLength() )
1017 maSelection.Min() = maText.getLength();
1018 if ( maSelection.Max() > maText.getLength() )
1019 maSelection.Max() = maText.getLength();
1022 ImplAlignAndPaint();
1023 mbInternModified = sal_True;
1026 // -----------------------------------------------------------------------
1028 void Edit::ImplSetText( const OUString& rText, const Selection* pNewSelection )
1030 // we delete text by "selecting" the old text completely then calling InsertText; this is flicker free
1031 if ( ( rText.getLength() <= mnMaxTextLen ) &&
1032 ( (rText != maText.getStr()) || (pNewSelection && (*pNewSelection != maSelection)) ) )
1034 ImplClearLayoutData();
1035 maSelection.Min() = 0;
1036 maSelection.Max() = maText.getLength();
1037 if ( mnXOffset || HasPaintEvent() )
1039 mnXOffset = 0;
1040 maText = ImplGetValidString( rText );
1042 // #i54929# recalculate mnXOffset before ImplSetSelection,
1043 // else cursor ends up in wrong position
1044 ImplAlign();
1046 if ( pNewSelection )
1047 ImplSetSelection( *pNewSelection, sal_False );
1049 if ( mnXOffset && !pNewSelection )
1050 maSelection.Max() = 0;
1052 Invalidate();
1054 else
1055 ImplInsertText( rText, pNewSelection );
1057 ImplCallEventListeners( VCLEVENT_EDIT_MODIFY );
1061 // -----------------------------------------------------------------------
1063 int Edit::ImplGetNativeControlType() const
1065 int nCtrl = 0;
1066 const Window *pControl = mbIsSubEdit ? GetParent() : this;
1068 switch( pControl->GetType() )
1070 case WINDOW_COMBOBOX:
1071 case WINDOW_PATTERNBOX:
1072 case WINDOW_NUMERICBOX:
1073 case WINDOW_METRICBOX:
1074 case WINDOW_CURRENCYBOX:
1075 case WINDOW_DATEBOX:
1076 case WINDOW_TIMEBOX:
1077 case WINDOW_LONGCURRENCYBOX:
1078 nCtrl = CTRL_COMBOBOX;
1079 break;
1081 case WINDOW_MULTILINEEDIT:
1082 if ( GetWindow( WINDOW_BORDER ) != this )
1083 nCtrl = CTRL_MULTILINE_EDITBOX;
1084 else
1085 nCtrl = CTRL_EDITBOX_NOBORDER;
1086 break;
1088 case WINDOW_EDIT:
1089 case WINDOW_PATTERNFIELD:
1090 case WINDOW_METRICFIELD:
1091 case WINDOW_CURRENCYFIELD:
1092 case WINDOW_DATEFIELD:
1093 case WINDOW_TIMEFIELD:
1094 case WINDOW_LONGCURRENCYFIELD:
1095 case WINDOW_NUMERICFIELD:
1096 case WINDOW_SPINFIELD:
1097 if( pControl->GetStyle() & WB_SPIN )
1098 nCtrl = CTRL_SPINBOX;
1099 else
1101 if ( GetWindow( WINDOW_BORDER ) != this )
1102 nCtrl = CTRL_EDITBOX;
1103 else
1104 nCtrl = CTRL_EDITBOX_NOBORDER;
1106 break;
1108 default:
1109 nCtrl = CTRL_EDITBOX;
1111 return nCtrl;
1114 void Edit::ImplClearBackground( long nXStart, long nXEnd )
1117 * note: at this point the cursor must be switched off already
1119 Point aTmpPoint;
1120 Rectangle aRect( aTmpPoint, GetOutputSizePixel() );
1121 aRect.Left() = nXStart;
1122 aRect.Right() = nXEnd;
1124 if( !(ImplUseNativeBorder( GetStyle() ) || IsPaintTransparent()) )
1125 Erase( aRect );
1128 void Edit::ImplPaintBorder( long nXStart, long nXEnd )
1130 Point aTmpPoint;
1131 Rectangle aRect( aTmpPoint, GetOutputSizePixel() );
1132 aRect.Left() = nXStart;
1133 aRect.Right() = nXEnd;
1135 if( ImplUseNativeBorder( GetStyle() ) || IsPaintTransparent() )
1137 // draw the inner part by painting the whole control using its border window
1138 Window *pControl = this;
1139 Window *pBorder = GetWindow( WINDOW_BORDER );
1140 if( pBorder == this )
1142 // we have no border, use parent
1143 pControl = mbIsSubEdit ? GetParent() : this;
1144 pBorder = pControl->GetWindow( WINDOW_BORDER );
1145 if( pBorder == this )
1146 pBorder = GetParent();
1149 if( pBorder )
1151 // set proper clipping region to not overdraw the whole control
1152 Region aClipRgn = GetPaintRegion();
1153 if( !aClipRgn.IsNull() )
1155 // transform clipping region to border window's coordinate system
1156 if( IsRTLEnabled() != pBorder->IsRTLEnabled() && Application::GetSettings().GetLayoutRTL() )
1158 // need to mirror in case border is not RTL but edit is (or vice versa)
1160 // mirror
1161 Rectangle aBounds( aClipRgn.GetBoundRect() );
1162 int xNew = GetOutputSizePixel().Width() - aBounds.GetWidth() - aBounds.Left();
1163 aClipRgn.Move( xNew - aBounds.Left(), 0 );
1165 // move offset of border window
1166 Point aBorderOffs;
1167 aBorderOffs = pBorder->ScreenToOutputPixel( OutputToScreenPixel( aBorderOffs ) );
1168 aClipRgn.Move( aBorderOffs.X(), aBorderOffs.Y() );
1170 else
1172 // normal case
1173 Point aBorderOffs;
1174 aBorderOffs = pBorder->ScreenToOutputPixel( OutputToScreenPixel( aBorderOffs ) );
1175 aClipRgn.Move( aBorderOffs.X(), aBorderOffs.Y() );
1178 Region oldRgn( pBorder->GetClipRegion() );
1179 pBorder->SetClipRegion( aClipRgn );
1181 pBorder->Paint( Rectangle() );
1183 pBorder->SetClipRegion( oldRgn );
1185 else
1186 pBorder->Paint( Rectangle() );
1192 // -----------------------------------------------------------------------
1194 void Edit::ImplShowCursor( sal_Bool bOnlyIfVisible )
1196 if ( !IsUpdateMode() || ( bOnlyIfVisible && !IsReallyVisible() ) )
1197 return;
1199 Cursor* pCursor = GetCursor();
1200 OUString aText = ImplGetText();
1202 long nTextPos = 0;
1204 sal_Int32 nDXBuffer[256];
1205 sal_Int32* pDXBuffer = NULL;
1206 sal_Int32* pDX = nDXBuffer;
1208 if( !aText.isEmpty() )
1210 if( (size_t) (2*aText.getLength()) > SAL_N_ELEMENTS(nDXBuffer) )
1212 pDXBuffer = new sal_Int32[2*(aText.getLength()+1)];
1213 pDX = pDXBuffer;
1216 GetCaretPositions( aText, pDX, 0, aText.getLength() );
1218 if( maSelection.Max() < aText.getLength() )
1219 nTextPos = pDX[ 2*maSelection.Max() ];
1220 else
1221 nTextPos = pDX[ 2*aText.getLength()-1 ];
1224 long nCursorWidth = 0;
1225 if ( !mbInsertMode && !maSelection.Len() && (maSelection.Max() < aText.getLength()) )
1226 nCursorWidth = GetTextWidth( aText, (xub_StrLen)maSelection.Max(), 1 );
1227 long nCursorPosX = nTextPos + mnXOffset + ImplGetExtraOffset();
1229 // cursor should land in visible area
1230 const Size aOutSize = GetOutputSizePixel();
1231 if ( (nCursorPosX < 0) || (nCursorPosX >= aOutSize.Width()) )
1233 long nOldXOffset = mnXOffset;
1235 if ( nCursorPosX < 0 )
1237 mnXOffset = - nTextPos;
1238 long nMaxX = 0;
1239 mnXOffset += aOutSize.Width() / 5;
1240 if ( mnXOffset > nMaxX )
1241 mnXOffset = nMaxX;
1243 else
1245 mnXOffset = (aOutSize.Width()-ImplGetExtraOffset()) - nTextPos;
1246 // Etwas mehr?
1247 if ( (aOutSize.Width()-ImplGetExtraOffset()) < nTextPos )
1249 long nMaxNegX = (aOutSize.Width()-ImplGetExtraOffset()) - GetTextWidth( aText );
1250 mnXOffset -= aOutSize.Width() / 5;
1251 if ( mnXOffset < nMaxNegX ) // beides negativ...
1252 mnXOffset = nMaxNegX;
1256 nCursorPosX = nTextPos + mnXOffset + ImplGetExtraOffset();
1257 if ( nCursorPosX == aOutSize.Width() ) // dann nicht sichtbar...
1258 nCursorPosX--;
1260 if ( mnXOffset != nOldXOffset )
1261 ImplInvalidateOrRepaint();
1264 const long nTextHeight = GetTextHeight();
1265 const long nCursorPosY = ImplGetTextYPosition();
1266 pCursor->SetPos( Point( nCursorPosX, nCursorPosY ) );
1267 pCursor->SetSize( Size( nCursorWidth, nTextHeight ) );
1268 pCursor->Show();
1270 if( pDXBuffer )
1271 delete [] pDXBuffer;
1274 // -----------------------------------------------------------------------
1276 void Edit::ImplAlign()
1278 long nTextWidth = GetTextWidth( ImplGetText() );
1279 long nOutWidth = GetOutputSizePixel().Width();
1281 if ( mnAlign == EDIT_ALIGN_LEFT )
1283 if( mnXOffset && ( nTextWidth < nOutWidth ) )
1284 mnXOffset = 0;
1287 else if ( mnAlign == EDIT_ALIGN_RIGHT )
1289 long nMinXOffset = nOutWidth - nTextWidth - 1 - ImplGetExtraOffset();
1290 bool bRTL = IsRTLEnabled();
1291 if( mbIsSubEdit && GetParent() )
1292 bRTL = GetParent()->IsRTLEnabled();
1293 if( bRTL )
1295 if( nTextWidth < nOutWidth )
1296 mnXOffset = nMinXOffset;
1298 else
1300 if( nTextWidth < nOutWidth )
1301 mnXOffset = nMinXOffset;
1302 else if ( mnXOffset < nMinXOffset )
1303 mnXOffset = nMinXOffset;
1306 else if( mnAlign == EDIT_ALIGN_CENTER )
1308 // would be nicer with check while scrolling but then it's not centred in scrolled state
1309 mnXOffset = (nOutWidth - nTextWidth) / 2;
1314 // -----------------------------------------------------------------------
1316 void Edit::ImplAlignAndPaint()
1318 ImplAlign();
1319 ImplInvalidateOrRepaint( 0, STRING_LEN );
1320 ImplShowCursor();
1323 // -----------------------------------------------------------------------
1325 xub_StrLen Edit::ImplGetCharPos( const Point& rWindowPos ) const
1327 xub_StrLen nIndex = STRING_LEN;
1328 OUString aText = ImplGetText();
1330 sal_Int32 nDXBuffer[256];
1331 sal_Int32* pDXBuffer = NULL;
1332 sal_Int32* pDX = nDXBuffer;
1333 if( (size_t) (2*aText.getLength()) > SAL_N_ELEMENTS(nDXBuffer) )
1335 pDXBuffer = new sal_Int32[2*(aText.getLength()+1)];
1336 pDX = pDXBuffer;
1339 GetCaretPositions( aText, pDX, 0, aText.getLength() );
1340 long nX = rWindowPos.X() - mnXOffset - ImplGetExtraOffset();
1341 for( int i = 0; i < aText.getLength(); i++ )
1343 if( (pDX[2*i] >= nX && pDX[2*i+1] <= nX) ||
1344 (pDX[2*i+1] >= nX && pDX[2*i] <= nX))
1346 nIndex = sal::static_int_cast<xub_StrLen>(i);
1347 if( pDX[2*i] < pDX[2*i+1] )
1349 if( nX > (pDX[2*i]+pDX[2*i+1])/2 )
1350 nIndex++;
1352 else
1354 if( nX < (pDX[2*i]+pDX[2*i+1])/2 )
1355 nIndex++;
1357 break;
1360 if( nIndex == STRING_LEN )
1362 nIndex = 0;
1363 long nDiff = std::abs( pDX[0]-nX );
1364 for( int i = 1; i < aText.getLength(); i++ )
1366 long nNewDiff = std::abs( pDX[2*i]-nX );
1368 if( nNewDiff < nDiff )
1370 nIndex = sal::static_int_cast<xub_StrLen>(i);
1371 nDiff = nNewDiff;
1374 if( nIndex == aText.getLength()-1 && std::abs( pDX[2*nIndex+1] - nX ) < nDiff )
1375 nIndex = STRING_LEN;
1378 if( pDXBuffer )
1379 delete [] pDXBuffer;
1381 return nIndex;
1384 // -----------------------------------------------------------------------
1386 void Edit::ImplSetCursorPos( xub_StrLen nChar, sal_Bool bSelect )
1388 Selection aSelection( maSelection );
1389 aSelection.Max() = nChar;
1390 if ( !bSelect )
1391 aSelection.Min() = aSelection.Max();
1392 ImplSetSelection( aSelection );
1395 // -----------------------------------------------------------------------
1397 void Edit::ImplLoadRes( const ResId& rResId )
1399 Control::ImplLoadRes( rResId );
1401 xub_StrLen nTextLength = ReadShortRes();
1402 if ( nTextLength )
1403 SetMaxTextLen( nTextLength );
1406 // -----------------------------------------------------------------------
1408 void Edit::ImplCopyToSelectionClipboard()
1410 if ( GetSelection().Len() )
1412 ::com::sun::star::uno::Reference<com::sun::star::datatransfer::clipboard::XClipboard> aSelection(GetPrimarySelection());
1413 ImplCopy( aSelection );
1417 void Edit::ImplCopy( uno::Reference< datatransfer::clipboard::XClipboard >& rxClipboard )
1419 ::vcl::unohelper::TextDataObject::CopyStringTo( GetSelected(), rxClipboard );
1422 // -----------------------------------------------------------------------
1424 void Edit::ImplPaste( uno::Reference< datatransfer::clipboard::XClipboard >& rxClipboard )
1426 if ( rxClipboard.is() )
1428 uno::Reference< datatransfer::XTransferable > xDataObj;
1430 const sal_uInt32 nRef = Application::ReleaseSolarMutex();
1434 xDataObj = rxClipboard->getContents();
1436 catch( const ::com::sun::star::uno::Exception& )
1440 Application::AcquireSolarMutex( nRef );
1442 if ( xDataObj.is() )
1444 datatransfer::DataFlavor aFlavor;
1445 SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aFlavor );
1448 uno::Any aData = xDataObj->getTransferData( aFlavor );
1449 OUString aText;
1450 aData >>= aText;
1451 if( ImplTruncateToMaxLen( aText, maSelection.Len() ) )
1452 ShowTruncationWarning( const_cast<Edit*>(this) );
1453 ReplaceSelected( aText );
1455 catch( const ::com::sun::star::uno::Exception& )
1462 // -----------------------------------------------------------------------
1464 void Edit::MouseButtonDown( const MouseEvent& rMEvt )
1466 if ( mpSubEdit )
1468 Control::MouseButtonDown( rMEvt );
1469 return;
1472 xub_StrLen nChar = ImplGetCharPos( rMEvt.GetPosPixel() );
1473 Selection aSelection( maSelection );
1474 aSelection.Justify();
1476 if ( rMEvt.GetClicks() < 4 )
1478 mbClickedInSelection = sal_False;
1479 if ( rMEvt.GetClicks() == 3 )
1481 ImplSetSelection( Selection( 0, 0xFFFF ) );
1482 ImplCopyToSelectionClipboard();
1485 else if ( rMEvt.GetClicks() == 2 )
1487 uno::Reference < i18n::XBreakIterator > xBI = ImplGetBreakIterator();
1488 i18n::Boundary aBoundary = xBI->getWordBoundary( maText.toString(), aSelection.Max(),
1489 GetSettings().GetLanguageTag().getLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True );
1490 ImplSetSelection( Selection( aBoundary.startPos, aBoundary.endPos ) );
1491 ImplCopyToSelectionClipboard();
1493 else if ( !rMEvt.IsShift() && HasFocus() && aSelection.IsInside( nChar ) )
1494 mbClickedInSelection = sal_True;
1495 else if ( rMEvt.IsLeft() )
1496 ImplSetCursorPos( nChar, rMEvt.IsShift() );
1498 if ( !mbClickedInSelection && rMEvt.IsLeft() && ( rMEvt.GetClicks() == 1 ) )
1499 StartTracking( STARTTRACK_SCROLLREPEAT );
1502 mbInMBDown = sal_True; // then do not select all in GetFocus
1503 GrabFocus();
1504 mbInMBDown = sal_False;
1507 // -----------------------------------------------------------------------
1509 void Edit::MouseButtonUp( const MouseEvent& rMEvt )
1511 if ( mbClickedInSelection && rMEvt.IsLeft() )
1513 xub_StrLen nChar = ImplGetCharPos( rMEvt.GetPosPixel() );
1514 ImplSetCursorPos( nChar, sal_False );
1515 mbClickedInSelection = sal_False;
1517 else if ( rMEvt.IsMiddle() && !mbReadOnly &&
1518 ( GetSettings().GetMouseSettings().GetMiddleButtonAction() == MOUSE_MIDDLE_PASTESELECTION ) )
1520 ::com::sun::star::uno::Reference<com::sun::star::datatransfer::clipboard::XClipboard> aSelection(Window::GetPrimarySelection());
1521 ImplPaste( aSelection );
1522 ImplModified();
1526 // -----------------------------------------------------------------------
1528 void Edit::Tracking( const TrackingEvent& rTEvt )
1530 if ( rTEvt.IsTrackingEnded() )
1532 if ( mbClickedInSelection )
1534 xub_StrLen nChar = ImplGetCharPos( rTEvt.GetMouseEvent().GetPosPixel() );
1535 ImplSetCursorPos( nChar, sal_False );
1536 mbClickedInSelection = sal_False;
1538 else if ( rTEvt.GetMouseEvent().IsLeft() )
1540 ImplCopyToSelectionClipboard();
1543 else
1545 if( !mbClickedInSelection )
1547 xub_StrLen nChar = ImplGetCharPos( rTEvt.GetMouseEvent().GetPosPixel() );
1548 ImplSetCursorPos( nChar, sal_True );
1552 if ( mpUpdateDataTimer && !mbIsSubEdit && mpUpdateDataTimer->IsActive() )
1553 mpUpdateDataTimer->Start();//do not update while the user is still travelling in the control
1556 // -----------------------------------------------------------------------
1558 sal_Bool Edit::ImplHandleKeyEvent( const KeyEvent& rKEvt )
1560 sal_Bool bDone = sal_False;
1561 sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
1562 KeyFuncType eFunc = rKEvt.GetKeyCode().GetFunction();
1564 mbInternModified = sal_False;
1566 if ( eFunc != KEYFUNC_DONTKNOW )
1568 switch ( eFunc )
1570 case KEYFUNC_CUT:
1572 if ( !mbReadOnly && maSelection.Len() && !(GetStyle() & WB_PASSWORD) )
1574 Cut();
1575 ImplModified();
1576 bDone = sal_True;
1579 break;
1581 case KEYFUNC_COPY:
1583 if ( !(GetStyle() & WB_PASSWORD) )
1585 Copy();
1586 bDone = sal_True;
1589 break;
1591 case KEYFUNC_PASTE:
1593 if ( !mbReadOnly )
1595 Paste();
1596 bDone = sal_True;
1599 break;
1601 case KEYFUNC_UNDO:
1603 if ( !mbReadOnly )
1605 Undo();
1606 bDone = sal_True;
1609 break;
1611 default:
1612 eFunc = KEYFUNC_DONTKNOW;
1616 if ( !bDone && rKEvt.GetKeyCode().IsMod1() && !rKEvt.GetKeyCode().IsMod2() )
1618 if ( nCode == KEY_A )
1620 ImplSetSelection( Selection( 0, maText.getLength() ) );
1621 bDone = sal_True;
1623 else if ( rKEvt.GetKeyCode().IsShift() && (nCode == KEY_S) )
1625 if ( pImplFncGetSpecialChars )
1627 Selection aSaveSel = GetSelection(); // if someone changes the selection in Get/LoseFocus, e.g. URL bar
1628 XubString aChars = pImplFncGetSpecialChars( this, GetFont() );
1629 SetSelection( aSaveSel );
1630 if ( aChars.Len() )
1632 ImplInsertText( aChars );
1633 ImplModified();
1635 bDone = sal_True;
1640 if ( eFunc == KEYFUNC_DONTKNOW && ! bDone )
1642 switch ( nCode )
1644 case com::sun::star::awt::Key::SELECT_ALL:
1646 ImplSetSelection( Selection( 0, maText.getLength() ) );
1647 bDone = sal_True;
1649 break;
1651 case KEY_LEFT:
1652 case KEY_RIGHT:
1653 case KEY_HOME:
1654 case KEY_END:
1655 case com::sun::star::awt::Key::MOVE_WORD_FORWARD:
1656 case com::sun::star::awt::Key::SELECT_WORD_FORWARD:
1657 case com::sun::star::awt::Key::MOVE_WORD_BACKWARD:
1658 case com::sun::star::awt::Key::SELECT_WORD_BACKWARD:
1659 case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE:
1660 case com::sun::star::awt::Key::MOVE_TO_END_OF_LINE:
1661 case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE:
1662 case com::sun::star::awt::Key::SELECT_TO_END_OF_LINE:
1663 case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH:
1664 case com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH:
1665 case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH:
1666 case com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH:
1667 case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT:
1668 case com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT:
1669 case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT:
1670 case com::sun::star::awt::Key::SELECT_TO_END_OF_DOCUMENT:
1672 if ( !rKEvt.GetKeyCode().IsMod2() )
1674 ImplClearLayoutData();
1675 uno::Reference < i18n::XBreakIterator > xBI = ImplGetBreakIterator();
1677 Selection aSel( maSelection );
1678 bool bWord = rKEvt.GetKeyCode().IsMod1();
1679 bool bSelect = rKEvt.GetKeyCode().IsShift();
1680 bool bGoLeft = (nCode == KEY_LEFT);
1681 bool bGoRight = (nCode == KEY_RIGHT);
1682 bool bGoHome = (nCode == KEY_HOME);
1683 bool bGoEnd = (nCode == KEY_END);
1685 switch( nCode )
1687 case com::sun::star::awt::Key::MOVE_WORD_FORWARD:
1688 bGoRight = bWord = true;break;
1689 case com::sun::star::awt::Key::SELECT_WORD_FORWARD:
1690 bGoRight = bSelect = bWord = true;break;
1691 case com::sun::star::awt::Key::MOVE_WORD_BACKWARD:
1692 bGoLeft = bWord = true;break;
1693 case com::sun::star::awt::Key::SELECT_WORD_BACKWARD:
1694 bGoLeft = bSelect = bWord = true;break;
1695 case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE:
1696 case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH:
1697 case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT:
1698 bSelect = true;
1699 // fallthrough intended
1700 case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE:
1701 case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH:
1702 case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT:
1703 bGoHome = true;break;
1704 case com::sun::star::awt::Key::SELECT_TO_END_OF_LINE:
1705 case com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH:
1706 case com::sun::star::awt::Key::SELECT_TO_END_OF_DOCUMENT:
1707 bSelect = true;
1708 // fallthrough intended
1709 case com::sun::star::awt::Key::MOVE_TO_END_OF_LINE:
1710 case com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH:
1711 case com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT:
1712 bGoEnd = true;break;
1713 default:
1714 break;
1717 // Range wird in ImplSetSelection geprueft...
1718 if ( bGoLeft && aSel.Max() )
1720 if ( bWord )
1722 i18n::Boundary aBoundary = xBI->getWordBoundary( maText.toString(), aSel.Max(),
1723 GetSettings().GetLanguageTag().getLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True );
1724 if ( aBoundary.startPos == aSel.Max() )
1725 aBoundary = xBI->previousWord( maText.toString(), aSel.Max(),
1726 GetSettings().GetLanguageTag().getLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES );
1727 aSel.Max() = aBoundary.startPos;
1729 else
1731 sal_Int32 nCount = 1;
1732 aSel.Max() = xBI->previousCharacters( maText.toString(), aSel.Max(),
1733 GetSettings().GetLanguageTag().getLocale(), i18n::CharacterIteratorMode::SKIPCHARACTER, nCount, nCount );
1736 else if ( bGoRight && ( aSel.Max() < maText.getLength() ) )
1738 if ( bWord )
1740 i18n::Boundary aBoundary = xBI->nextWord( maText.toString(), aSel.Max(),
1741 GetSettings().GetLanguageTag().getLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES );
1742 aSel.Max() = aBoundary.startPos;
1744 else
1746 sal_Int32 nCount = 1;
1747 aSel.Max() = xBI->nextCharacters( maText.toString(), aSel.Max(),
1748 GetSettings().GetLanguageTag().getLocale(), i18n::CharacterIteratorMode::SKIPCHARACTER, nCount, nCount );
1751 else if ( bGoHome )
1753 aSel.Max() = 0;
1755 else if ( bGoEnd )
1757 aSel.Max() = 0xFFFF;
1760 if ( !bSelect )
1761 aSel.Min() = aSel.Max();
1763 if ( aSel != GetSelection() )
1765 ImplSetSelection( aSel );
1766 ImplCopyToSelectionClipboard();
1769 if ( bGoEnd && maAutocompleteHdl.IsSet() && !rKEvt.GetKeyCode().GetModifier() )
1771 if ( (maSelection.Min() == maSelection.Max()) && (maSelection.Min() == maText.getLength()) )
1773 meAutocompleteAction = AUTOCOMPLETE_KEYINPUT;
1774 maAutocompleteHdl.Call( this );
1778 bDone = sal_True;
1781 break;
1783 case com::sun::star::awt::Key::DELETE_WORD_BACKWARD:
1784 case com::sun::star::awt::Key::DELETE_WORD_FORWARD:
1785 case com::sun::star::awt::Key::DELETE_TO_BEGIN_OF_LINE:
1786 case com::sun::star::awt::Key::DELETE_TO_END_OF_LINE:
1787 case KEY_BACKSPACE:
1788 case KEY_DELETE:
1790 if ( !mbReadOnly && !rKEvt.GetKeyCode().IsMod2() )
1792 sal_uInt8 nDel = (nCode == KEY_DELETE) ? EDIT_DEL_RIGHT : EDIT_DEL_LEFT;
1793 sal_uInt8 nMode = rKEvt.GetKeyCode().IsMod1() ? EDIT_DELMODE_RESTOFWORD : EDIT_DELMODE_SIMPLE;
1794 if ( (nMode == EDIT_DELMODE_RESTOFWORD) && rKEvt.GetKeyCode().IsShift() )
1795 nMode = EDIT_DELMODE_RESTOFCONTENT;
1796 switch( nCode )
1798 case com::sun::star::awt::Key::DELETE_WORD_BACKWARD:
1799 nDel = EDIT_DEL_LEFT;
1800 nMode = EDIT_DELMODE_RESTOFWORD;
1801 break;
1802 case com::sun::star::awt::Key::DELETE_WORD_FORWARD:
1803 nDel = EDIT_DEL_RIGHT;
1804 nMode = EDIT_DELMODE_RESTOFWORD;
1805 break;
1806 case com::sun::star::awt::Key::DELETE_TO_BEGIN_OF_LINE:
1807 nDel = EDIT_DEL_LEFT;
1808 nMode = EDIT_DELMODE_RESTOFCONTENT;
1809 break;
1810 case com::sun::star::awt::Key::DELETE_TO_END_OF_LINE:
1811 nDel = EDIT_DEL_RIGHT;
1812 nMode = EDIT_DELMODE_RESTOFCONTENT;
1813 break;
1814 default: break;
1816 sal_Int32 nOldLen = maText.getLength();
1817 ImplDelete( maSelection, nDel, nMode );
1818 if ( maText.getLength() != nOldLen )
1819 ImplModified();
1820 bDone = sal_True;
1823 break;
1825 case KEY_INSERT:
1827 if ( !mpIMEInfos && !mbReadOnly && !rKEvt.GetKeyCode().IsMod2() )
1829 SetInsertMode( !mbInsertMode );
1830 bDone = sal_True;
1833 break;
1835 /* #i101255# disable autocomplete tab forward/backward
1836 users expect tab/shif-tab to move the focus to other controls
1837 not suddenly to cycle the autocompletion
1838 case KEY_TAB:
1840 if ( !mbReadOnly && maAutocompleteHdl.IsSet() &&
1841 maSelection.Min() && (maSelection.Min() == maText.Len()) &&
1842 !rKEvt.GetKeyCode().IsMod1() && !rKEvt.GetKeyCode().IsMod2() )
1844 // Kein Autocomplete wenn alles Selektiert oder Edit leer, weil dann
1845 // keine vernuenftige Tab-Steuerung!
1846 if ( rKEvt.GetKeyCode().IsShift() )
1847 meAutocompleteAction = AUTOCOMPLETE_TABBACKWARD;
1848 else
1849 meAutocompleteAction = AUTOCOMPLETE_TABFORWARD;
1851 maAutocompleteHdl.Call( this );
1853 // Wurde nichts veraendert, dann TAB fuer DialogControl
1854 if ( GetSelection().Len() )
1855 bDone = sal_True;
1858 break;
1861 default:
1863 if ( IsCharInput( rKEvt ) )
1865 bDone = sal_True; // read characters also when in ReadOnly
1866 if ( !mbReadOnly )
1868 ImplInsertText(OUString(rKEvt.GetCharCode()), 0, sal_True);
1869 if ( maAutocompleteHdl.IsSet() )
1871 if ( (maSelection.Min() == maSelection.Max()) && (maSelection.Min() == maText.getLength()) )
1873 meAutocompleteAction = AUTOCOMPLETE_KEYINPUT;
1874 maAutocompleteHdl.Call( this );
1883 if ( mbInternModified )
1884 ImplModified();
1886 return bDone;
1889 // -----------------------------------------------------------------------
1891 void Edit::KeyInput( const KeyEvent& rKEvt )
1893 if ( mpUpdateDataTimer && !mbIsSubEdit && mpUpdateDataTimer->IsActive() )
1894 mpUpdateDataTimer->Start();//do not update while the user is still travelling in the control
1896 if ( mpSubEdit || !ImplHandleKeyEvent( rKEvt ) )
1897 Control::KeyInput( rKEvt );
1900 // -----------------------------------------------------------------------
1902 void Edit::FillLayoutData() const
1904 mpControlData->mpLayoutData = new vcl::ControlLayoutData();
1905 const_cast<Edit*>(this)->ImplRepaint( 0, STRING_LEN, true );
1908 // -----------------------------------------------------------------------
1910 void Edit::Paint( const Rectangle& )
1912 if ( !mpSubEdit )
1913 ImplRepaint();
1916 // -----------------------------------------------------------------------
1918 void Edit::Resize()
1920 if ( !mpSubEdit && IsReallyVisible() )
1922 Control::Resize();
1923 // Wegen vertikaler Zentrierung...
1924 mnXOffset = 0;
1925 ImplAlign();
1926 Invalidate();
1927 ImplShowCursor();
1931 // -----------------------------------------------------------------------
1933 void Edit::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, sal_uLong nFlags )
1935 ImplInitSettings( sal_True, sal_True, sal_True );
1937 Point aPos = pDev->LogicToPixel( rPos );
1938 Size aSize = pDev->LogicToPixel( rSize );
1939 Font aFont = GetDrawPixelFont( pDev );
1940 OutDevType eOutDevType = pDev->GetOutDevType();
1942 pDev->Push();
1943 pDev->SetMapMode();
1944 pDev->SetFont( aFont );
1945 pDev->SetTextFillColor();
1947 // Border/Background
1948 pDev->SetLineColor();
1949 pDev->SetFillColor();
1950 bool bBorder = !(nFlags & WINDOW_DRAW_NOBORDER ) && (GetStyle() & WB_BORDER);
1951 bool bBackground = !(nFlags & WINDOW_DRAW_NOBACKGROUND) && IsControlBackground();
1952 if ( bBorder || bBackground )
1954 Rectangle aRect( aPos, aSize );
1955 if ( bBorder )
1957 ImplDrawFrame( pDev, aRect );
1959 if ( bBackground )
1961 pDev->SetFillColor( GetControlBackground() );
1962 pDev->DrawRect( aRect );
1966 // Inhalt
1967 if ( ( nFlags & WINDOW_DRAW_MONO ) || ( eOutDevType == OUTDEV_PRINTER ) )
1968 pDev->SetTextColor( Color( COL_BLACK ) );
1969 else
1971 if ( !(nFlags & WINDOW_DRAW_NODISABLE ) && !IsEnabled() )
1973 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
1974 pDev->SetTextColor( rStyleSettings.GetDisableColor() );
1976 else
1978 pDev->SetTextColor( GetTextColor() );
1982 OUString aText = ImplGetText();
1983 long nTextHeight = pDev->GetTextHeight();
1984 long nTextWidth = pDev->GetTextWidth( aText );
1985 long nOnePixel = GetDrawPixel( pDev, 1 );
1986 long nOffX = 3*nOnePixel;
1987 long nOffY = (aSize.Height() - nTextHeight) / 2;
1989 // Clipping?
1990 if ( (nOffY < 0) ||
1991 ((nOffY+nTextHeight) > aSize.Height()) ||
1992 ((nOffX+nTextWidth) > aSize.Width()) )
1994 Rectangle aClip( aPos, aSize );
1995 if ( nTextHeight > aSize.Height() )
1996 aClip.Bottom() += nTextHeight-aSize.Height()+1; // prevent HP printers from 'optimizing'
1997 pDev->IntersectClipRegion( aClip );
2000 if ( GetStyle() & WB_CENTER )
2002 aPos.X() += (aSize.Width() - nTextWidth) / 2;
2003 nOffX = 0;
2005 else if ( GetStyle() & WB_RIGHT )
2007 aPos.X() += aSize.Width() - nTextWidth;
2008 nOffX = -nOffX;
2011 pDev->DrawText( Point( aPos.X() + nOffX, aPos.Y() + nOffY ), aText );
2012 pDev->Pop();
2014 if ( GetSubEdit() )
2016 GetSubEdit()->Draw( pDev, rPos, rSize, nFlags );
2020 // -----------------------------------------------------------------------
2022 void Edit::ImplInvalidateOutermostBorder( Window* pWin )
2024 // allow control to show focused state
2025 Window *pInvalWin = pWin, *pBorder = pWin;
2026 while( ( pBorder = pInvalWin->GetWindow( WINDOW_BORDER ) ) != pInvalWin && pBorder &&
2027 pInvalWin->ImplGetFrame() == pBorder->ImplGetFrame() )
2029 pInvalWin = pBorder;
2032 pInvalWin->Invalidate( INVALIDATE_CHILDREN | INVALIDATE_UPDATE );
2035 void Edit::GetFocus()
2037 if ( mpSubEdit )
2038 mpSubEdit->ImplGrabFocus( GetGetFocusFlags() );
2039 else if ( !mbActivePopup )
2041 maUndoText = maText.toString();
2043 sal_uLong nSelOptions = GetSettings().GetStyleSettings().GetSelectionOptions();
2044 if ( !( GetStyle() & (WB_NOHIDESELECTION|WB_READONLY) )
2045 && ( GetGetFocusFlags() & (GETFOCUS_INIT|GETFOCUS_TAB|GETFOCUS_CURSOR|GETFOCUS_MNEMONIC) ) )
2047 if ( nSelOptions & SELECTION_OPTION_SHOWFIRST )
2049 maSelection.Min() = maText.getLength();
2050 maSelection.Max() = 0;
2052 else
2054 maSelection.Min() = 0;
2055 maSelection.Max() = maText.getLength();
2057 if ( mbIsSubEdit )
2058 ((Edit*)GetParent())->ImplCallEventListeners( VCLEVENT_EDIT_SELECTIONCHANGED );
2059 else
2060 ImplCallEventListeners( VCLEVENT_EDIT_SELECTIONCHANGED );
2063 ImplShowCursor();
2065 // FIXME: this is currently only on aqua
2066 // check for other platforms that need similar handling
2067 if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
2068 IsNativeWidgetEnabled() &&
2069 IsNativeControlSupported( CTRL_EDITBOX, PART_ENTIRE_CONTROL ) )
2071 ImplInvalidateOutermostBorder( mbIsSubEdit ? GetParent() : this );
2073 else if ( maSelection.Len() )
2075 // Selektion malen
2076 if ( !HasPaintEvent() )
2077 ImplInvalidateOrRepaint();
2078 else
2079 Invalidate();
2082 SetInputContext( InputContext( GetFont(), !IsReadOnly() ? INPUTCONTEXT_TEXT|INPUTCONTEXT_EXTTEXTINPUT : 0 ) );
2085 Control::GetFocus();
2088 // -----------------------------------------------------------------------
2090 Window* Edit::GetPreferredKeyInputWindow()
2092 if ( mpSubEdit )
2093 return mpSubEdit->GetPreferredKeyInputWindow();
2094 else
2095 return this;
2098 // -----------------------------------------------------------------------
2100 void Edit::LoseFocus()
2102 if ( mpUpdateDataTimer && !mbIsSubEdit && mpUpdateDataTimer->IsActive() )
2104 //notify an update latest when the focus is lost
2105 mpUpdateDataTimer->Stop();
2106 mpUpdateDataTimer->Timeout();
2109 if ( !mpSubEdit )
2111 // FIXME: this is currently only on aqua
2112 // check for other platforms that need similar handling
2113 if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
2114 IsNativeWidgetEnabled() &&
2115 IsNativeControlSupported( CTRL_EDITBOX, PART_ENTIRE_CONTROL ) )
2117 ImplInvalidateOutermostBorder( mbIsSubEdit ? GetParent() : this );
2120 if ( !mbActivePopup && !( GetStyle() & WB_NOHIDESELECTION ) && maSelection.Len() )
2121 ImplInvalidateOrRepaint(); // Selektion malen
2124 Control::LoseFocus();
2127 // -----------------------------------------------------------------------
2129 void Edit::Command( const CommandEvent& rCEvt )
2131 if ( rCEvt.GetCommand() == COMMAND_CONTEXTMENU )
2133 PopupMenu* pPopup = Edit::CreatePopupMenu();
2135 if ( !maSelection.Len() )
2137 pPopup->EnableItem( SV_MENU_EDIT_CUT, sal_False );
2138 pPopup->EnableItem( SV_MENU_EDIT_COPY, sal_False );
2139 pPopup->EnableItem( SV_MENU_EDIT_DELETE, sal_False );
2142 if ( IsReadOnly() )
2144 pPopup->EnableItem( SV_MENU_EDIT_CUT, sal_False );
2145 pPopup->EnableItem( SV_MENU_EDIT_PASTE, sal_False );
2146 pPopup->EnableItem( SV_MENU_EDIT_DELETE, sal_False );
2147 pPopup->EnableItem( SV_MENU_EDIT_INSERTSYMBOL, sal_False );
2149 else
2151 // Paste nur, wenn Text im Clipboard
2152 sal_Bool bData = sal_False;
2153 uno::Reference< datatransfer::clipboard::XClipboard > xClipboard = GetClipboard();
2154 if ( xClipboard.is() )
2156 const sal_uInt32 nRef = Application::ReleaseSolarMutex();
2157 uno::Reference< datatransfer::XTransferable > xDataObj = xClipboard->getContents();
2158 Application::AcquireSolarMutex( nRef );
2159 if ( xDataObj.is() )
2161 datatransfer::DataFlavor aFlavor;
2162 SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aFlavor );
2163 bData = xDataObj->isDataFlavorSupported( aFlavor );
2166 pPopup->EnableItem( SV_MENU_EDIT_PASTE, bData );
2169 if ( maUndoText == maText.getStr() )
2170 pPopup->EnableItem( SV_MENU_EDIT_UNDO, sal_False );
2171 if ( ( maSelection.Min() == 0 ) && ( maSelection.Max() == maText.getLength() ) )
2172 pPopup->EnableItem( SV_MENU_EDIT_SELECTALL, sal_False );
2173 if ( !pImplFncGetSpecialChars )
2175 sal_uInt16 nPos = pPopup->GetItemPos( SV_MENU_EDIT_INSERTSYMBOL );
2176 pPopup->RemoveItem( nPos );
2177 pPopup->RemoveItem( nPos-1 );
2180 mbActivePopup = sal_True;
2181 Selection aSaveSel = GetSelection(); // if someone changes selection in Get/LoseFocus, e.g. URL bar
2182 Point aPos = rCEvt.GetMousePosPixel();
2183 if ( !rCEvt.IsMouseEvent() )
2185 // Show menu enventually centered in selection
2186 Size aSize = GetOutputSizePixel();
2187 aPos = Point( aSize.Width()/2, aSize.Height()/2 );
2189 sal_uInt16 n = pPopup->Execute( this, aPos );
2190 Edit::DeletePopupMenu( pPopup );
2191 SetSelection( aSaveSel );
2192 switch ( n )
2194 case SV_MENU_EDIT_UNDO:
2195 Undo();
2196 ImplModified();
2197 break;
2198 case SV_MENU_EDIT_CUT:
2199 Cut();
2200 ImplModified();
2201 break;
2202 case SV_MENU_EDIT_COPY:
2203 Copy();
2204 break;
2205 case SV_MENU_EDIT_PASTE:
2206 Paste();
2207 ImplModified();
2208 break;
2209 case SV_MENU_EDIT_DELETE:
2210 DeleteSelected();
2211 ImplModified();
2212 break;
2213 case SV_MENU_EDIT_SELECTALL:
2214 ImplSetSelection( Selection( 0, maText.getLength() ) );
2215 break;
2216 case SV_MENU_EDIT_INSERTSYMBOL:
2218 XubString aChars = pImplFncGetSpecialChars( this, GetFont() );
2219 SetSelection( aSaveSel );
2220 if ( aChars.Len() )
2222 ImplInsertText( aChars );
2223 ImplModified();
2226 break;
2228 mbActivePopup = sal_False;
2230 else if ( rCEvt.GetCommand() == COMMAND_STARTEXTTEXTINPUT )
2232 DeleteSelected();
2233 delete mpIMEInfos;
2234 sal_Int32 nPos = static_cast<sal_Int32>(maSelection.Max());
2235 mpIMEInfos = new Impl_IMEInfos( nPos, OUString(maText.getStr() + nPos ) );
2236 mpIMEInfos->bWasCursorOverwrite = !IsInsertMode();
2238 else if ( rCEvt.GetCommand() == COMMAND_ENDEXTTEXTINPUT )
2240 sal_Bool bInsertMode = !mpIMEInfos->bWasCursorOverwrite;
2241 delete mpIMEInfos;
2242 mpIMEInfos = NULL;
2244 // set font without attributes, because it will not be re-initialised in Repaint anymore
2245 ImplInitSettings( sal_True, sal_False, sal_False );
2247 SetInsertMode( bInsertMode );
2249 ImplModified();
2251 // #i25161# call auto complete handler for ext text commit also
2252 if ( maAutocompleteHdl.IsSet() )
2254 if ( (maSelection.Min() == maSelection.Max()) && (maSelection.Min() == maText.getLength()) )
2256 meAutocompleteAction = AUTOCOMPLETE_KEYINPUT;
2257 maAutocompleteHdl.Call( this );
2261 else if ( rCEvt.GetCommand() == COMMAND_EXTTEXTINPUT )
2263 const CommandExtTextInputData* pData = rCEvt.GetExtTextInputData();
2265 maText.remove( mpIMEInfos->nPos, mpIMEInfos->nLen );
2266 maText.insert( mpIMEInfos->nPos, pData->GetText() );
2267 if ( mpIMEInfos->bWasCursorOverwrite )
2269 sal_uInt16 nOldIMETextLen = mpIMEInfos->nLen;
2270 sal_uInt16 nNewIMETextLen = pData->GetText().Len();
2271 if ( ( nOldIMETextLen > nNewIMETextLen ) &&
2272 ( nNewIMETextLen < mpIMEInfos->aOldTextAfterStartPos.getLength() ) )
2274 // restore old characters
2275 sal_uInt16 nRestore = nOldIMETextLen - nNewIMETextLen;
2276 maText.insert( mpIMEInfos->nPos + nNewIMETextLen, mpIMEInfos->aOldTextAfterStartPos.copy( nNewIMETextLen, nRestore ) );
2278 else if ( ( nOldIMETextLen < nNewIMETextLen ) &&
2279 ( nOldIMETextLen < mpIMEInfos->aOldTextAfterStartPos.getLength() ) )
2281 // overwrite
2282 sal_uInt16 nOverwrite = nNewIMETextLen - nOldIMETextLen;
2283 if ( ( nOldIMETextLen + nOverwrite ) > mpIMEInfos->aOldTextAfterStartPos.getLength() )
2284 nOverwrite = mpIMEInfos->aOldTextAfterStartPos.getLength() - nOldIMETextLen;
2285 maText.remove( mpIMEInfos->nPos + nNewIMETextLen, nOverwrite );
2290 if ( pData->GetTextAttr() )
2292 mpIMEInfos->CopyAttribs( pData->GetTextAttr(), pData->GetText().Len() );
2293 mpIMEInfos->bCursor = pData->IsCursorVisible();
2295 else
2297 mpIMEInfos->DestroyAttribs();
2300 ImplAlignAndPaint();
2301 xub_StrLen nCursorPos = mpIMEInfos->nPos + pData->GetCursorPos();
2302 SetSelection( Selection( nCursorPos, nCursorPos ) );
2303 SetInsertMode( !pData->IsCursorOverwrite() );
2305 if ( pData->IsCursorVisible() )
2306 GetCursor()->Show();
2307 else
2308 GetCursor()->Hide();
2310 else if ( rCEvt.GetCommand() == COMMAND_CURSORPOS )
2312 if ( mpIMEInfos )
2314 xub_StrLen nCursorPos = (sal_uInt16)GetSelection().Max();
2315 SetCursorRect( NULL, GetTextWidth( maText.toString(), nCursorPos, mpIMEInfos->nPos+mpIMEInfos->nLen-nCursorPos ) );
2317 else
2319 SetCursorRect();
2322 else if ( rCEvt.GetCommand() == COMMAND_SELECTIONCHANGE )
2324 const CommandSelectionChangeData *pData = rCEvt.GetSelectionChangeData();
2325 Selection aSelection( pData->GetStart(), pData->GetEnd() );
2326 SetSelection(aSelection);
2328 else if ( rCEvt.GetCommand() == COMMAND_QUERYCHARPOSITION )
2330 if (mpIMEInfos && mpIMEInfos->nLen > 0)
2332 OUString aText = ImplGetText();
2333 sal_Int32 nDXBuffer[256];
2334 sal_Int32* pDXBuffer = NULL;
2335 sal_Int32* pDX = nDXBuffer;
2337 if( !aText.isEmpty() )
2339 if( (size_t) (2*aText.getLength()) > SAL_N_ELEMENTS(nDXBuffer) )
2341 pDXBuffer = new sal_Int32[2*(aText.getLength()+1)];
2342 pDX = pDXBuffer;
2345 GetCaretPositions( aText, pDX, 0, aText.getLength() );
2347 long nTH = GetTextHeight();
2348 Point aPos( mnXOffset, ImplGetTextYPosition() );
2350 Rectangle* aRects = new Rectangle[ mpIMEInfos->nLen ];
2351 for ( int nIndex = 0; nIndex < mpIMEInfos->nLen; ++nIndex )
2353 Rectangle aRect( aPos, Size( 10, nTH ) );
2354 aRect.Left() = pDX[2*(nIndex+mpIMEInfos->nPos)] + mnXOffset + ImplGetExtraOffset();
2355 aRects[ nIndex ] = aRect;
2357 SetCompositionCharRect( aRects, mpIMEInfos->nLen );
2358 delete[] aRects;
2359 delete[] pDXBuffer;
2362 else
2363 Control::Command( rCEvt );
2366 // -----------------------------------------------------------------------
2368 void Edit::StateChanged( StateChangedType nType )
2370 if ( nType == STATE_CHANGE_INITSHOW )
2372 if ( !mpSubEdit )
2374 mnXOffset = 0; // if GrabFocus before while size was still wrong
2375 ImplAlign();
2376 if ( !mpSubEdit )
2377 ImplShowCursor( sal_False );
2379 // update background (eventual SetPaintTransparent)
2380 ImplInitSettings( sal_False, sal_False, sal_True );
2382 else if ( nType == STATE_CHANGE_ENABLE )
2384 if ( !mpSubEdit )
2386 // change text color only
2387 ImplInvalidateOrRepaint( 0, 0xFFFF );
2390 else if ( nType == STATE_CHANGE_STYLE || nType == STATE_CHANGE_MIRRORING )
2392 WinBits nStyle = GetStyle();
2393 if( nType == STATE_CHANGE_STYLE )
2395 nStyle = ImplInitStyle( GetStyle() );
2396 SetStyle( nStyle );
2399 sal_uInt16 nOldAlign = mnAlign;
2400 mnAlign = EDIT_ALIGN_LEFT;
2402 // --- RTL --- hack: right align until keyinput and cursor travelling works
2403 // edits are always RTL disabled
2404 // however the parent edits contain the correct setting
2405 if( mbIsSubEdit && GetParent()->IsRTLEnabled() )
2407 if( GetParent()->GetStyle() & WB_LEFT )
2408 mnAlign = EDIT_ALIGN_RIGHT;
2409 if ( nType == STATE_CHANGE_MIRRORING )
2410 SetLayoutMode( TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_TEXTORIGIN_LEFT );
2412 else if( mbIsSubEdit && !GetParent()->IsRTLEnabled() )
2414 if ( nType == STATE_CHANGE_MIRRORING )
2415 SetLayoutMode( TEXT_LAYOUT_BIDI_LTR | TEXT_LAYOUT_TEXTORIGIN_LEFT );
2418 if ( nStyle & WB_RIGHT )
2419 mnAlign = EDIT_ALIGN_RIGHT;
2420 else if ( nStyle & WB_CENTER )
2421 mnAlign = EDIT_ALIGN_CENTER;
2422 if ( maText.getLength() && ( mnAlign != nOldAlign ) )
2424 ImplAlign();
2425 Invalidate();
2429 else if ( nType == STATE_CHANGE_ZOOM )
2431 if ( !mpSubEdit )
2433 ImplInitSettings( sal_True, sal_False, sal_False );
2434 ImplShowCursor( sal_True );
2435 Invalidate();
2438 else if ( nType == STATE_CHANGE_CONTROLFONT )
2440 if ( !mpSubEdit )
2442 ImplInitSettings( sal_True, sal_False, sal_False );
2443 ImplShowCursor();
2444 Invalidate();
2447 else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
2449 if ( !mpSubEdit )
2451 ImplInitSettings( sal_False, sal_True, sal_False );
2452 Invalidate();
2455 else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
2457 if ( !mpSubEdit )
2459 ImplInitSettings( sal_False, sal_False, sal_True );
2460 Invalidate();
2464 Control::StateChanged( nType );
2467 // -----------------------------------------------------------------------
2469 void Edit::DataChanged( const DataChangedEvent& rDCEvt )
2471 if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
2472 (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
2473 ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
2474 (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
2476 if ( !mpSubEdit )
2478 ImplInitSettings( sal_True, sal_True, sal_True );
2479 ImplShowCursor( sal_True );
2480 Invalidate();
2484 Control::DataChanged( rDCEvt );
2487 // -----------------------------------------------------------------------
2489 void Edit::ImplShowDDCursor()
2491 if ( !mpDDInfo->bVisCursor )
2493 long nTextWidth = GetTextWidth( maText.toString(), 0, mpDDInfo->nDropPos );
2494 long nTextHeight = GetTextHeight();
2495 Rectangle aCursorRect( Point( nTextWidth + mnXOffset, (GetOutputSize().Height()-nTextHeight)/2 ), Size( 2, nTextHeight ) );
2496 mpDDInfo->aCursor.SetWindow( this );
2497 mpDDInfo->aCursor.SetPos( aCursorRect.TopLeft() );
2498 mpDDInfo->aCursor.SetSize( aCursorRect.GetSize() );
2499 mpDDInfo->aCursor.Show();
2500 mpDDInfo->bVisCursor = true;
2504 // -----------------------------------------------------------------------
2506 void Edit::ImplHideDDCursor()
2508 if ( mpDDInfo && mpDDInfo->bVisCursor )
2510 mpDDInfo->aCursor.Hide();
2511 mpDDInfo->bVisCursor = false;
2515 // -----------------------------------------------------------------------
2517 void Edit::Modify()
2519 if ( mbIsSubEdit )
2521 ((Edit*)GetParent())->Modify();
2523 else
2525 if ( mpUpdateDataTimer )
2526 mpUpdateDataTimer->Start();
2528 if ( ImplCallEventListenersAndHandler( VCLEVENT_EDIT_MODIFY, maModifyHdl, this ) )
2529 // have been destroyed while calling into the handlers
2530 return;
2532 // #i13677# notify edit listeners about caret position change
2533 ImplCallEventListeners( VCLEVENT_EDIT_SELECTIONCHANGED );
2535 // FIXME: this is currently only on aqua
2536 // check for other platforms that need similar handling
2537 if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
2538 IsNativeWidgetEnabled() &&
2539 IsNativeControlSupported( CTRL_EDITBOX, PART_ENTIRE_CONTROL ) )
2541 ImplInvalidateOutermostBorder( this );
2546 // -----------------------------------------------------------------------
2548 void Edit::UpdateData()
2550 maUpdateDataHdl.Call( this );
2553 // -----------------------------------------------------------------------
2555 IMPL_LINK_NOARG(Edit, ImplUpdateDataHdl)
2557 UpdateData();
2558 return 0;
2561 // -----------------------------------------------------------------------
2563 void Edit::EnableUpdateData( sal_uLong nTimeout )
2565 if ( !nTimeout )
2566 DisableUpdateData();
2567 else
2569 if ( !mpUpdateDataTimer )
2571 mpUpdateDataTimer = new Timer;
2572 mpUpdateDataTimer->SetTimeoutHdl( LINK( this, Edit, ImplUpdateDataHdl ) );
2575 mpUpdateDataTimer->SetTimeout( nTimeout );
2579 // -----------------------------------------------------------------------
2581 void Edit::SetEchoChar( sal_Unicode c )
2583 mcEchoChar = c;
2584 if ( mpSubEdit )
2585 mpSubEdit->SetEchoChar( c );
2588 // -----------------------------------------------------------------------
2590 void Edit::SetReadOnly( sal_Bool bReadOnly )
2592 if ( mbReadOnly != bReadOnly )
2594 mbReadOnly = bReadOnly;
2595 if ( mpSubEdit )
2596 mpSubEdit->SetReadOnly( bReadOnly );
2598 StateChanged( STATE_CHANGE_READONLY );
2602 // -----------------------------------------------------------------------
2604 void Edit::SetAutocompleteHdl( const Link& rHdl )
2606 maAutocompleteHdl = rHdl;
2607 if ( mpSubEdit )
2608 mpSubEdit->SetAutocompleteHdl( rHdl );
2611 // -----------------------------------------------------------------------
2613 void Edit::SetInsertMode( sal_Bool bInsert )
2615 if ( bInsert != mbInsertMode )
2617 mbInsertMode = bInsert;
2618 if ( mpSubEdit )
2619 mpSubEdit->SetInsertMode( bInsert );
2620 else
2621 ImplShowCursor();
2625 // -----------------------------------------------------------------------
2627 sal_Bool Edit::IsInsertMode() const
2629 if ( mpSubEdit )
2630 return mpSubEdit->IsInsertMode();
2631 else
2632 return mbInsertMode;
2635 // -----------------------------------------------------------------------
2637 void Edit::SetMaxTextLen( xub_StrLen nMaxLen )
2639 mnMaxTextLen = nMaxLen ? nMaxLen : EDIT_NOLIMIT;
2641 if ( mpSubEdit )
2642 mpSubEdit->SetMaxTextLen( mnMaxTextLen );
2643 else
2645 if ( maText.getLength() > mnMaxTextLen )
2646 ImplDelete( Selection( mnMaxTextLen, maText.getLength() ), EDIT_DEL_RIGHT, EDIT_DELMODE_SIMPLE );
2650 // -----------------------------------------------------------------------
2652 void Edit::SetSelection( const Selection& rSelection )
2654 // If the selection was changed from outside, e.g. by MouseButtonDown, don't call Tracking()
2655 // directly afterwards which would change the selection again
2656 if ( IsTracking() )
2657 EndTracking();
2658 else if ( mpSubEdit && mpSubEdit->IsTracking() )
2659 mpSubEdit->EndTracking();
2661 ImplSetSelection( rSelection );
2664 // -----------------------------------------------------------------------
2666 void Edit::ImplSetSelection( const Selection& rSelection, sal_Bool bPaint )
2668 if ( mpSubEdit )
2669 mpSubEdit->ImplSetSelection( rSelection );
2670 else
2672 if ( rSelection != maSelection )
2674 Selection aOld( maSelection );
2675 Selection aNew( rSelection );
2677 if ( aNew.Min() > maText.getLength() )
2678 aNew.Min() = maText.getLength();
2679 if ( aNew.Max() > maText.getLength() )
2680 aNew.Max() = maText.getLength();
2681 if ( aNew.Min() < 0 )
2682 aNew.Min() = 0;
2683 if ( aNew.Max() < 0 )
2684 aNew.Max() = 0;
2686 if ( aNew != maSelection )
2688 ImplClearLayoutData();
2689 maSelection = aNew;
2691 if ( bPaint && ( aOld.Len() || aNew.Len() || IsPaintTransparent() ) )
2692 ImplInvalidateOrRepaint( 0, maText.getLength() );
2693 ImplShowCursor();
2694 if ( mbIsSubEdit )
2695 ((Edit*)GetParent())->ImplCallEventListeners( VCLEVENT_EDIT_SELECTIONCHANGED );
2696 else
2697 ImplCallEventListeners( VCLEVENT_EDIT_SELECTIONCHANGED );
2698 // #103511# notify combobox listeners of deselection
2699 if( !maSelection && GetParent() && GetParent()->GetType() == WINDOW_COMBOBOX )
2700 ((Edit*)GetParent())->ImplCallEventListeners( VCLEVENT_COMBOBOX_DESELECT );
2706 // -----------------------------------------------------------------------
2708 const Selection& Edit::GetSelection() const
2710 if ( mpSubEdit )
2711 return mpSubEdit->GetSelection();
2712 else
2713 return maSelection;
2716 // -----------------------------------------------------------------------
2718 void Edit::ReplaceSelected( const OUString& rStr )
2720 if ( mpSubEdit )
2721 mpSubEdit->ReplaceSelected( rStr );
2722 else
2723 ImplInsertText( rStr );
2726 // -----------------------------------------------------------------------
2728 void Edit::DeleteSelected()
2730 if ( mpSubEdit )
2731 mpSubEdit->DeleteSelected();
2732 else
2734 if ( maSelection.Len() )
2735 ImplDelete( maSelection, EDIT_DEL_RIGHT, EDIT_DELMODE_SIMPLE );
2739 // -----------------------------------------------------------------------
2741 OUString Edit::GetSelected() const
2743 if ( mpSubEdit )
2744 return mpSubEdit->GetSelected();
2745 else
2747 Selection aSelection( maSelection );
2748 aSelection.Justify();
2749 return OUString( maText.getStr() + aSelection.Min(), aSelection.Len() );
2753 // -----------------------------------------------------------------------
2755 void Edit::Cut()
2757 if ( !(GetStyle() & WB_PASSWORD ) )
2759 Copy();
2760 ReplaceSelected( ImplGetSVEmptyStr() );
2764 // -----------------------------------------------------------------------
2766 void Edit::Copy()
2768 if ( !(GetStyle() & WB_PASSWORD ) )
2770 ::com::sun::star::uno::Reference<com::sun::star::datatransfer::clipboard::XClipboard> aClipboard(GetClipboard());
2771 ImplCopy( aClipboard );
2775 // -----------------------------------------------------------------------
2777 void Edit::Paste()
2779 ::com::sun::star::uno::Reference<com::sun::star::datatransfer::clipboard::XClipboard> aClipboard(GetClipboard());
2780 ImplPaste( aClipboard );
2783 // -----------------------------------------------------------------------
2785 void Edit::Undo()
2787 if ( mpSubEdit )
2788 mpSubEdit->Undo();
2789 else
2791 OUString aText( maText.toString() );
2792 ImplDelete( Selection( 0, aText.getLength() ), EDIT_DEL_RIGHT, EDIT_DELMODE_SIMPLE );
2793 ImplInsertText( maUndoText );
2794 ImplSetSelection( Selection( 0, maUndoText.getLength() ) );
2795 maUndoText = aText;
2799 // -----------------------------------------------------------------------
2801 void Edit::SetText( const OUString& rStr )
2803 if ( mpSubEdit )
2804 mpSubEdit->SetText( rStr ); // not directly ImplSetText if SetText overloaded
2805 else
2807 Selection aNewSel( 0, 0 ); // prevent scrolling
2808 ImplSetText( rStr, &aNewSel );
2812 // -----------------------------------------------------------------------
2814 void Edit::SetText( const OUString& rStr, const Selection& rSelection )
2816 if ( mpSubEdit )
2817 mpSubEdit->SetText( rStr, rSelection );
2818 else
2819 ImplSetText( rStr, &rSelection );
2822 // -----------------------------------------------------------------------
2824 OUString Edit::GetText() const
2826 if ( mpSubEdit )
2827 return mpSubEdit->GetText();
2828 else
2829 return maText.toString();
2832 // -----------------------------------------------------------------------
2834 void Edit::SetPlaceholderText( const OUString& rStr )
2836 if ( mpSubEdit )
2837 mpSubEdit->SetPlaceholderText( rStr );
2838 else if ( maPlaceholderText != rStr )
2840 maPlaceholderText = rStr;
2841 if ( GetText().isEmpty() )
2842 Invalidate();
2846 // -----------------------------------------------------------------------
2848 OUString Edit::GetPlaceholderText() const
2850 if ( mpSubEdit )
2851 return mpSubEdit->GetPlaceholderText();
2853 return maPlaceholderText;
2856 // -----------------------------------------------------------------------
2858 void Edit::SetModifyFlag()
2860 if ( mpSubEdit )
2861 mpSubEdit->mbModified = sal_True;
2862 else
2863 mbModified = sal_True;
2866 // -----------------------------------------------------------------------
2868 void Edit::ClearModifyFlag()
2870 if ( mpSubEdit )
2871 mpSubEdit->mbModified = sal_False;
2872 else
2873 mbModified = sal_False;
2876 // -----------------------------------------------------------------------
2878 void Edit::SetSubEdit( Edit* pEdit )
2880 mpSubEdit = pEdit;
2881 if ( mpSubEdit )
2883 SetPointer( POINTER_ARROW ); // Nur das SubEdit hat den BEAM...
2884 mpSubEdit->mbIsSubEdit = sal_True;
2886 mpSubEdit->SetReadOnly( mbReadOnly );
2890 Size Edit::CalcMinimumSizeForText(const OUString &rString) const
2892 int eCtrlType = ImplGetNativeControlType();
2894 Size aSize;
2895 if (mnWidthInChars != -1)
2897 //CalcSize calls CalcWindowSize, but we will call that also in this
2898 //function, so undo the first one with CalcOutputSize
2899 aSize = CalcOutputSize(CalcSize(mnWidthInChars));
2901 else
2903 OUString aString;
2904 if (mnMaxWidthChars != -1 && mnMaxWidthChars < rString.getLength())
2905 aString = rString.copy(0, mnMaxWidthChars);
2906 else
2907 aString = rString;
2909 aSize.Height() = GetTextHeight();
2910 aSize.Width() = GetTextWidth(aString);
2911 aSize.Width() += ImplGetExtraOffset() * 2;
2913 // do not create edit fields in which one cannot enter anything
2914 // a default minimum width should exist for at least 3 characters
2916 //CalcSize calls CalcWindowSize, but we will call that also in this
2917 //function, so undo the first one with CalcOutputSize
2918 Size aMinSize(CalcOutputSize(CalcSize(3)));
2919 if (aSize.Width() < aMinSize.Width())
2920 aSize.Width() = aMinSize.Width();
2923 if (eCtrlType != CTRL_EDITBOX_NOBORDER)
2925 // add some space between text entry and border
2926 aSize.Height() += 4;
2929 aSize = CalcWindowSize( aSize );
2931 // ask NWF what if it has an opinion, too
2932 ImplControlValue aControlValue;
2933 Rectangle aRect( Point( 0, 0 ), aSize );
2934 Rectangle aContent, aBound;
2935 if( const_cast<Edit*>(this)->GetNativeControlRegion(
2936 eCtrlType, PART_ENTIRE_CONTROL,
2937 aRect, 0, aControlValue, OUString(), aBound, aContent) )
2939 if( aBound.GetHeight() > aSize.Height() )
2940 aSize.Height() = aBound.GetHeight();
2942 return aSize;
2945 Size Edit::CalcMinimumSize() const
2947 return CalcMinimumSizeForText(GetText());
2950 Size Edit::GetMinimumEditSize()
2952 Window* pDefWin = ImplGetDefaultWindow();
2953 Edit aEdit( pDefWin, WB_BORDER );
2954 Size aSize( aEdit.CalcMinimumSize() );
2955 return aSize;
2958 // -----------------------------------------------------------------------
2960 Size Edit::GetOptimalSize() const
2962 return CalcMinimumSize();
2965 // -----------------------------------------------------------------------
2967 Size Edit::CalcSize( xub_StrLen nChars ) const
2969 // width for N characters, independent from content.
2970 // works only correct for fixed fonts, average otherwise
2971 Size aSz( GetTextWidth( OUString('x') ), GetTextHeight() );
2972 aSz.Width() *= nChars;
2973 aSz.Width() += ImplGetExtraOffset() * 2;
2974 aSz = CalcWindowSize( aSz );
2975 return aSz;
2978 // -----------------------------------------------------------------------
2980 xub_StrLen Edit::GetMaxVisChars() const
2982 const Window* pW = mpSubEdit ? mpSubEdit : this;
2983 long nOutWidth = pW->GetOutputSizePixel().Width();
2984 long nCharWidth = GetTextWidth( OUString('x') );
2985 return nCharWidth ? (xub_StrLen)(nOutWidth/nCharWidth) : 0;
2988 // -----------------------------------------------------------------------
2990 xub_StrLen Edit::GetCharPos( const Point& rWindowPos ) const
2992 return ImplGetCharPos( rWindowPos );
2995 // -----------------------------------------------------------------------
2997 void Edit::SetGetSpecialCharsFunction( FncGetSpecialChars fn )
2999 pImplFncGetSpecialChars = fn;
3002 // -----------------------------------------------------------------------
3004 FncGetSpecialChars Edit::GetGetSpecialCharsFunction()
3006 return pImplFncGetSpecialChars;
3009 // -----------------------------------------------------------------------
3011 PopupMenu* Edit::CreatePopupMenu()
3013 ResMgr* pResMgr = ImplGetResMgr();
3014 if( ! pResMgr )
3015 return new PopupMenu();
3017 PopupMenu* pPopup = new PopupMenu( ResId( SV_RESID_MENU_EDIT, *pResMgr ) );
3018 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
3019 if ( rStyleSettings.GetHideDisabledMenuItems() )
3020 pPopup->SetMenuFlags( MENU_FLAG_HIDEDISABLEDENTRIES );
3021 else
3022 pPopup->SetMenuFlags ( MENU_FLAG_ALWAYSSHOWDISABLEDENTRIES );
3023 if ( rStyleSettings.GetAcceleratorsInContextMenus() )
3025 pPopup->SetAccelKey( SV_MENU_EDIT_UNDO, KeyCode( KEYFUNC_UNDO ) );
3026 pPopup->SetAccelKey( SV_MENU_EDIT_CUT, KeyCode( KEYFUNC_CUT ) );
3027 pPopup->SetAccelKey( SV_MENU_EDIT_COPY, KeyCode( KEYFUNC_COPY ) );
3028 pPopup->SetAccelKey( SV_MENU_EDIT_PASTE, KeyCode( KEYFUNC_PASTE ) );
3029 pPopup->SetAccelKey( SV_MENU_EDIT_DELETE, KeyCode( KEYFUNC_DELETE ) );
3030 pPopup->SetAccelKey( SV_MENU_EDIT_SELECTALL, KeyCode( KEY_A, sal_False, sal_True, sal_False, sal_False ) );
3031 pPopup->SetAccelKey( SV_MENU_EDIT_INSERTSYMBOL, KeyCode( KEY_S, sal_True, sal_True, sal_False, sal_False ) );
3033 return pPopup;
3036 // -----------------------------------------------------------------------
3038 void Edit::DeletePopupMenu( PopupMenu* pMenu )
3040 delete pMenu;
3043 // ::com::sun::star::datatransfer::dnd::XDragGestureListener
3044 void Edit::dragGestureRecognized( const ::com::sun::star::datatransfer::dnd::DragGestureEvent& rDGE ) throw (::com::sun::star::uno::RuntimeException)
3046 SolarMutexGuard aVclGuard;
3048 if ( !IsTracking() && maSelection.Len() &&
3049 !(GetStyle() & WB_PASSWORD) && (!mpDDInfo || mpDDInfo->bStarterOfDD == false) ) // Kein Mehrfach D&D
3051 Selection aSel( maSelection );
3052 aSel.Justify();
3054 // Nur wenn Maus in der Selektion...
3055 Point aMousePos( rDGE.DragOriginX, rDGE.DragOriginY );
3056 xub_StrLen nChar = ImplGetCharPos( aMousePos );
3057 if ( (nChar >= aSel.Min()) && (nChar < aSel.Max()) )
3059 if ( !mpDDInfo )
3060 mpDDInfo = new DDInfo;
3062 mpDDInfo->bStarterOfDD = true;
3063 mpDDInfo->aDndStartSel = aSel;
3066 if ( IsTracking() )
3067 EndTracking(); // Vor D&D Tracking ausschalten
3069 ::vcl::unohelper::TextDataObject* pDataObj = new ::vcl::unohelper::TextDataObject( GetSelected() );
3070 sal_Int8 nActions = datatransfer::dnd::DNDConstants::ACTION_COPY;
3071 if ( !IsReadOnly() )
3072 nActions |= datatransfer::dnd::DNDConstants::ACTION_MOVE;
3073 rDGE.DragSource->startDrag( rDGE, nActions, 0 /*cursor*/, 0 /*image*/, pDataObj, mxDnDListener );
3074 if ( GetCursor() )
3075 GetCursor()->Hide();
3081 // ::com::sun::star::datatransfer::dnd::XDragSourceListener
3082 void Edit::dragDropEnd( const ::com::sun::star::datatransfer::dnd::DragSourceDropEvent& rDSDE ) throw (::com::sun::star::uno::RuntimeException)
3084 SolarMutexGuard aVclGuard;
3086 if ( rDSDE.DropSuccess && ( rDSDE.DropAction & datatransfer::dnd::DNDConstants::ACTION_MOVE ) )
3088 Selection aSel( mpDDInfo->aDndStartSel );
3089 if ( mpDDInfo->bDroppedInMe )
3091 if ( aSel.Max() > mpDDInfo->nDropPos )
3093 long nLen = aSel.Len();
3094 aSel.Min() += nLen;
3095 aSel.Max() += nLen;
3098 ImplDelete( aSel, EDIT_DEL_RIGHT, EDIT_DELMODE_SIMPLE );
3099 ImplModified();
3102 ImplHideDDCursor();
3103 delete mpDDInfo;
3104 mpDDInfo = NULL;
3107 // ::com::sun::star::datatransfer::dnd::XDropTargetListener
3108 void Edit::drop( const ::com::sun::star::datatransfer::dnd::DropTargetDropEvent& rDTDE ) throw (::com::sun::star::uno::RuntimeException)
3110 SolarMutexGuard aVclGuard;
3112 sal_Bool bChanges = sal_False;
3113 if ( !mbReadOnly && mpDDInfo )
3115 ImplHideDDCursor();
3117 Selection aSel( maSelection );
3118 aSel.Justify();
3120 if ( aSel.Len() && !mpDDInfo->bStarterOfDD )
3121 ImplDelete( aSel, EDIT_DEL_RIGHT, EDIT_DELMODE_SIMPLE );
3123 mpDDInfo->bDroppedInMe = true;
3125 aSel.Min() = mpDDInfo->nDropPos;
3126 aSel.Max() = mpDDInfo->nDropPos;
3127 ImplSetSelection( aSel );
3129 uno::Reference< datatransfer::XTransferable > xDataObj = rDTDE.Transferable;
3130 if ( xDataObj.is() )
3132 datatransfer::DataFlavor aFlavor;
3133 SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aFlavor );
3134 if ( xDataObj->isDataFlavorSupported( aFlavor ) )
3136 uno::Any aData = xDataObj->getTransferData( aFlavor );
3137 OUString aText;
3138 aData >>= aText;
3139 ImplInsertText( aText );
3140 bChanges = sal_True;
3141 ImplModified();
3145 if ( !mpDDInfo->bStarterOfDD )
3147 delete mpDDInfo;
3148 mpDDInfo = NULL;
3152 rDTDE.Context->dropComplete( bChanges );
3155 void Edit::dragEnter( const ::com::sun::star::datatransfer::dnd::DropTargetDragEnterEvent& rDTDE ) throw (::com::sun::star::uno::RuntimeException)
3157 if ( !mpDDInfo )
3159 mpDDInfo = new DDInfo;
3161 // search for string data type
3162 const Sequence< com::sun::star::datatransfer::DataFlavor >& rFlavors( rDTDE.SupportedDataFlavors );
3163 sal_Int32 nEle = rFlavors.getLength();
3164 mpDDInfo->bIsStringSupported = false;
3165 for( sal_Int32 i = 0; i < nEle; i++ )
3167 sal_Int32 nIndex = 0;
3168 OUString aMimetype = rFlavors[i].MimeType.getToken( 0, ';', nIndex );
3169 if ( aMimetype == "text/plain" )
3171 mpDDInfo->bIsStringSupported = true;
3172 break;
3177 void Edit::dragExit( const ::com::sun::star::datatransfer::dnd::DropTargetEvent& ) throw (::com::sun::star::uno::RuntimeException)
3179 SolarMutexGuard aVclGuard;
3181 ImplHideDDCursor();
3184 void Edit::dragOver( const ::com::sun::star::datatransfer::dnd::DropTargetDragEvent& rDTDE ) throw (::com::sun::star::uno::RuntimeException)
3186 SolarMutexGuard aVclGuard;
3188 Point aMousePos( rDTDE.LocationX, rDTDE.LocationY );
3190 xub_StrLen nPrevDropPos = mpDDInfo->nDropPos;
3191 mpDDInfo->nDropPos = ImplGetCharPos( aMousePos );
3194 Size aOutSize = GetOutputSizePixel();
3195 if ( ( aMousePos.X() < 0 ) || ( aMousePos.X() > aOutSize.Width() ) )
3197 // Scroll?
3198 // No, I will not receive events in this case....
3202 Selection aSel( maSelection );
3203 aSel.Justify();
3205 // Don't accept drop in selection or read-only field...
3206 if ( IsReadOnly() || aSel.IsInside( mpDDInfo->nDropPos ) || ! mpDDInfo->bIsStringSupported )
3208 ImplHideDDCursor();
3209 rDTDE.Context->rejectDrag();
3211 else
3213 // Alten Cursor wegzeichnen...
3214 if ( !mpDDInfo->bVisCursor || ( nPrevDropPos != mpDDInfo->nDropPos ) )
3216 ImplHideDDCursor();
3217 ImplShowDDCursor();
3219 rDTDE.Context->acceptDrag( rDTDE.DropAction );
3223 OUString Edit::GetSurroundingText() const
3225 if (mpSubEdit)
3226 return mpSubEdit->GetSurroundingText();
3227 return maText.toString();
3230 Selection Edit::GetSurroundingTextSelection() const
3232 return GetSelection();
3235 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */