Version 4.2.0.1, tag libreoffice-4.2.0.1
[LibreOffice.git] / vcl / source / control / edit.cxx
blob98edce1a5883f2d194442a60f4bd20f17bed311f
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/processfactory.hxx>
59 #include <comphelper/string.hxx>
61 #include <sot/exchange.hxx>
62 #include <sot/formats.hxx>
63 #include <sal/macros.h>
65 #include <vcl/unohelp.hxx>
66 #include <vcl/unohelp2.hxx>
68 #include <officecfg/Office/Common.hxx>
73 using namespace ::com::sun::star;
74 using namespace ::com::sun::star::uno;
75 using namespace ::com::sun::star::lang;
76 using namespace ::rtl;
78 // - Redo
79 // - Bei Tracking-Cancel DefaultSelection wieder herstellen
81 // =======================================================================
83 static FncGetSpecialChars pImplFncGetSpecialChars = NULL;
85 // =======================================================================
87 #define EDIT_ALIGN_LEFT 1
88 #define EDIT_ALIGN_CENTER 2
89 #define EDIT_ALIGN_RIGHT 3
91 #define EDIT_DEL_LEFT 1
92 #define EDIT_DEL_RIGHT 2
94 #define EDIT_DELMODE_SIMPLE 11
95 #define EDIT_DELMODE_RESTOFWORD 12
96 #define EDIT_DELMODE_RESTOFCONTENT 13
98 // =======================================================================
100 struct DDInfo
102 Cursor aCursor;
103 Selection aDndStartSel;
104 xub_StrLen nDropPos;
105 bool bStarterOfDD;
106 bool bDroppedInMe;
107 bool bVisCursor;
108 bool bIsStringSupported;
110 DDInfo()
112 aCursor.SetStyle( CURSOR_SHADOW );
113 nDropPos = 0;
114 bStarterOfDD = false;
115 bDroppedInMe = false;
116 bVisCursor = false;
117 bIsStringSupported = false;
121 // =======================================================================
123 struct Impl_IMEInfos
125 OUString aOldTextAfterStartPos;
126 sal_uInt16* pAttribs;
127 xub_StrLen nPos;
128 xub_StrLen nLen;
129 bool bCursor;
130 bool bWasCursorOverwrite;
132 Impl_IMEInfos( xub_StrLen nPos, const OUString& rOldTextAfterStartPos );
133 ~Impl_IMEInfos();
135 void CopyAttribs( const xub_StrLen* pA, xub_StrLen nL );
136 void DestroyAttribs();
139 // -----------------------------------------------------------------------
141 Impl_IMEInfos::Impl_IMEInfos( xub_StrLen nP, const OUString& rOldTextAfterStartPos )
142 : aOldTextAfterStartPos( rOldTextAfterStartPos )
144 nPos = nP;
145 nLen = 0;
146 bCursor = true;
147 pAttribs = NULL;
148 bWasCursorOverwrite = false;
151 // -----------------------------------------------------------------------
153 Impl_IMEInfos::~Impl_IMEInfos()
155 delete[] pAttribs;
158 // -----------------------------------------------------------------------
160 void Impl_IMEInfos::CopyAttribs( const xub_StrLen* pA, xub_StrLen nL )
162 nLen = nL;
163 delete[] pAttribs;
164 pAttribs = new sal_uInt16[ nL ];
165 memcpy( pAttribs, pA, nL*sizeof(sal_uInt16) );
168 // -----------------------------------------------------------------------
170 void Impl_IMEInfos::DestroyAttribs()
172 delete[] pAttribs;
173 pAttribs = NULL;
174 nLen = 0;
177 // =======================================================================
179 Edit::Edit( WindowType nType ) :
180 Control( nType )
182 ImplInitEditData();
185 // -----------------------------------------------------------------------
187 Edit::Edit( Window* pParent, WinBits nStyle ) :
188 Control( WINDOW_EDIT )
190 ImplInitEditData();
191 ImplInit( pParent, nStyle );
194 Edit::Edit( Window* pParent, const ResId& rResId ) :
195 Control( WINDOW_EDIT )
197 rResId.SetRT( RSC_EDIT );
198 WinBits nStyle = ImplInitRes( rResId );
199 ImplInitEditData();
200 ImplInit( pParent, nStyle );
201 ImplLoadRes( rResId );
203 // Derived MultiLineEdit takes care to call Show only after MultiLineEdit
204 // ctor has already started:
205 if ( !(nStyle & WB_HIDE) && rResId.GetRT() != RSC_MULTILINEEDIT )
206 Show();
209 void Edit::SetWidthInChars(sal_Int32 nWidthInChars)
211 if (mnWidthInChars != nWidthInChars)
213 mnWidthInChars = nWidthInChars;
214 queue_resize();
218 void Edit::setMaxWidthChars(sal_Int32 nWidth)
220 if (nWidth != mnMaxWidthChars)
222 mnMaxWidthChars = nWidth;
223 queue_resize();
227 bool Edit::set_property(const OString &rKey, const OString &rValue)
229 if (rKey == "width-chars")
230 SetWidthInChars(rValue.toInt32());
231 else if (rKey == "max-width-chars")
232 setMaxWidthChars(rValue.toInt32());
233 else if (rKey == "max-length")
235 sal_Int32 nTextLen = rValue.toInt32();
236 SetMaxTextLen(nTextLen == 0 ? EDIT_NOLIMIT : nTextLen);
238 else if (rKey == "editable")
240 bool bReadOnly = !toBool(rValue);
241 SetReadOnly(bReadOnly);
242 //disable tab to traverse into readonly editables
243 WinBits nBits = GetStyle();
244 nBits &= ~(WB_TABSTOP|WB_NOTABSTOP);
245 if (!bReadOnly)
246 nBits |= WB_TABSTOP;
247 else
248 nBits |= WB_NOTABSTOP;
249 SetStyle(nBits);
251 else if (rKey == "visibility")
253 WinBits nBits = GetStyle();
254 nBits &= ~(WB_PASSWORD);
255 if (!toBool(rValue))
256 nBits |= WB_PASSWORD;
257 SetStyle(nBits);
259 else if (rKey == "placeholder-text")
260 SetPlaceholderText(OStringToOUString(rValue, RTL_TEXTENCODING_UTF8));
261 else
262 return Control::set_property(rKey, rValue);
263 return true;
266 // -----------------------------------------------------------------------
268 Edit::~Edit()
270 delete mpDDInfo;
271 Cursor* pCursor = GetCursor();
272 if ( pCursor )
274 SetCursor( NULL );
275 delete pCursor;
278 delete mpIMEInfos;
280 delete mpUpdateDataTimer;
282 if ( mxDnDListener.is() )
284 if ( GetDragGestureRecognizer().is() )
286 uno::Reference< datatransfer::dnd::XDragGestureListener> xDGL( mxDnDListener, uno::UNO_QUERY );
287 GetDragGestureRecognizer()->removeDragGestureListener( xDGL );
289 if ( GetDropTarget().is() )
291 uno::Reference< datatransfer::dnd::XDropTargetListener> xDTL( mxDnDListener, uno::UNO_QUERY );
292 GetDropTarget()->removeDropTargetListener( xDTL );
295 uno::Reference< lang::XEventListener> xEL( mxDnDListener, uno::UNO_QUERY );
296 xEL->disposing( lang::EventObject() ); // #95154# #96585# Empty Source means it's the Client
300 // -----------------------------------------------------------------------
302 void Edit::ImplInitEditData()
304 mpSubEdit = NULL;
305 mpUpdateDataTimer = NULL;
306 mnXOffset = 0;
307 mnAlign = EDIT_ALIGN_LEFT;
308 mnMaxTextLen = EDIT_NOLIMIT;
309 mnWidthInChars = -1;
310 mnMaxWidthChars = -1;
311 meAutocompleteAction = AUTOCOMPLETE_KEYINPUT;
312 mbModified = sal_False;
313 mbInternModified = sal_False;
314 mbReadOnly = sal_False;
315 mbInsertMode = sal_True;
316 mbClickedInSelection = sal_False;
317 mbActivePopup = sal_False;
318 mbIsSubEdit = sal_False;
319 mbInMBDown = sal_False;
320 mpDDInfo = NULL;
321 mpIMEInfos = NULL;
322 mcEchoChar = 0;
324 // --- RTL --- no default mirroring for Edit controls
325 // note: controls that use a subedit will revert this (SpinField, ComboBox)
326 EnableRTL( sal_False );
328 vcl::unohelper::DragAndDropWrapper* pDnDWrapper = new vcl::unohelper::DragAndDropWrapper( this );
329 mxDnDListener = pDnDWrapper;
332 // -----------------------------------------------------------------------
334 bool Edit::ImplUseNativeBorder( WinBits nStyle )
336 bool bRet =
337 IsNativeControlSupported(ImplGetNativeControlType(), HAS_BACKGROUND_TEXTURE)
338 && ((nStyle&WB_BORDER) && !(nStyle&WB_NOBORDER));
339 if( ! bRet && mbIsSubEdit )
341 Window* pWindow = GetParent();
342 nStyle = pWindow->GetStyle();
343 bRet = pWindow->IsNativeControlSupported(ImplGetNativeControlType(), HAS_BACKGROUND_TEXTURE)
344 && ((nStyle&WB_BORDER) && !(nStyle&WB_NOBORDER));
346 return bRet;
349 void Edit::ImplInit( Window* pParent, WinBits nStyle )
351 nStyle = ImplInitStyle( nStyle );
352 if ( !(nStyle & (WB_CENTER | WB_RIGHT)) )
353 nStyle |= WB_LEFT;
355 Control::ImplInit( pParent, nStyle, NULL );
357 mbReadOnly = (nStyle & WB_READONLY) != 0;
359 mnAlign = EDIT_ALIGN_LEFT;
361 // --- RTL --- hack: right align until keyinput and cursor travelling works
362 if( IsRTLEnabled() )
363 mnAlign = EDIT_ALIGN_RIGHT;
365 if ( nStyle & WB_RIGHT )
366 mnAlign = EDIT_ALIGN_RIGHT;
367 else if ( nStyle & WB_CENTER )
368 mnAlign = EDIT_ALIGN_CENTER;
370 SetCursor( new Cursor );
372 SetPointer( Pointer( POINTER_TEXT ) );
373 ImplInitSettings( sal_True, sal_True, sal_True );
375 uno::Reference< datatransfer::dnd::XDragGestureListener> xDGL( mxDnDListener, uno::UNO_QUERY );
376 uno::Reference< datatransfer::dnd::XDragGestureRecognizer > xDGR = GetDragGestureRecognizer();
377 if ( xDGR.is() )
379 xDGR->addDragGestureListener( xDGL );
380 uno::Reference< datatransfer::dnd::XDropTargetListener> xDTL( mxDnDListener, uno::UNO_QUERY );
381 GetDropTarget()->addDropTargetListener( xDTL );
382 GetDropTarget()->setActive( sal_True );
383 GetDropTarget()->setDefaultActions( datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE );
387 // -----------------------------------------------------------------------
389 WinBits Edit::ImplInitStyle( WinBits nStyle )
391 if ( !(nStyle & WB_NOTABSTOP) )
392 nStyle |= WB_TABSTOP;
393 if ( !(nStyle & WB_NOGROUP) )
394 nStyle |= WB_GROUP;
396 return nStyle;
399 // -----------------------------------------------------------------------
401 sal_Bool Edit::IsCharInput( const KeyEvent& rKeyEvent )
403 // In the future we must use new Unicode functions for this
404 sal_Unicode cCharCode = rKeyEvent.GetCharCode();
405 return ((cCharCode >= 32) && (cCharCode != 127) &&
406 !rKeyEvent.GetKeyCode().IsMod3() &&
407 !rKeyEvent.GetKeyCode().IsMod2() &&
408 !rKeyEvent.GetKeyCode().IsMod1() );
411 // -----------------------------------------------------------------------
413 void Edit::ImplModified()
415 mbModified = sal_True;
416 Modify();
419 // -----------------------------------------------------------------------
421 void Edit::ImplInitSettings( sal_Bool bFont, sal_Bool bForeground, sal_Bool bBackground )
423 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
425 if ( bFont )
427 Font aFont = rStyleSettings.GetFieldFont();
428 if ( IsControlFont() )
429 aFont.Merge( GetControlFont() );
430 SetZoomedPointFont( aFont );
431 ImplClearLayoutData();
434 if ( bFont || bForeground )
436 Color aTextColor = rStyleSettings.GetFieldTextColor();
437 if ( IsControlForeground() )
438 aTextColor = GetControlForeground();
439 SetTextColor( aTextColor );
442 if ( bBackground )
444 if ( ImplUseNativeBorder( GetStyle() ) || IsPaintTransparent() )
446 // Transparent background
447 SetBackground();
448 SetFillColor();
450 else if ( IsControlBackground() )
452 SetBackground( GetControlBackground() );
453 SetFillColor( GetControlBackground() );
455 else
457 SetBackground( rStyleSettings.GetFieldColor() );
458 SetFillColor( rStyleSettings.GetFieldColor() );
463 // -----------------------------------------------------------------------
465 long Edit::ImplGetExtraOffset() const
467 // MT 09/2002: nExtraOffsetX should become a member, instead of checking every time,
468 // but I need an incompatible update for this...
469 // #94095# Use extra offset only when edit has a border
470 long nExtraOffset = 0;
471 if( ( GetStyle() & WB_BORDER ) || ( mbIsSubEdit && ( GetParent()->GetStyle() & WB_BORDER ) ) )
472 nExtraOffset = 2;
474 return nExtraOffset;
478 // -----------------------------------------------------------------------
480 OUString Edit::ImplGetText() const
482 if ( mcEchoChar || (GetStyle() & WB_PASSWORD) )
484 sal_Unicode cEchoChar;
485 if ( mcEchoChar )
486 cEchoChar = mcEchoChar;
487 else
488 cEchoChar = '*';
489 OUStringBuffer aText;
490 comphelper::string::padToLength(aText, maText.getLength(), cEchoChar);
491 return aText.makeStringAndClear();
493 else
494 return maText.toString();
497 // -----------------------------------------------------------------------
499 void Edit::ImplInvalidateOrRepaint( sal_Int32 nStart, sal_Int32 nEnd )
501 if( IsPaintTransparent() )
503 Invalidate();
504 // FIXME: this is currently only on aqua
505 if( ImplGetSVData()->maNWFData.mbNoFocusRects )
506 Update();
508 else
509 ImplRepaint( nStart, nEnd );
512 // -----------------------------------------------------------------------
514 long Edit::ImplGetTextYPosition() const
516 if ( GetStyle() & WB_TOP )
517 return ImplGetExtraOffset();
518 else if ( GetStyle() & WB_BOTTOM )
519 return GetOutputSizePixel().Height() - GetTextHeight() - ImplGetExtraOffset();
520 return ( GetOutputSizePixel().Height() - GetTextHeight() ) / 2;
523 // -----------------------------------------------------------------------
525 void Edit::ImplRepaint( sal_Int32 nStart, sal_Int32 nEnd, bool bLayout )
527 if ( !IsReallyVisible() )
528 return;
530 OUString aText = ImplGetText();
531 nStart = 0;
532 nEnd = aText.getLength();
534 sal_Int32 nDXBuffer[256];
535 sal_Int32* pDXBuffer = NULL;
536 sal_Int32* pDX = nDXBuffer;
538 if( !aText.isEmpty() )
540 if( (size_t) (2*aText.getLength()) > SAL_N_ELEMENTS(nDXBuffer) )
542 pDXBuffer = new sal_Int32[2*(aText.getLength()+1)];
543 pDX = pDXBuffer;
546 GetCaretPositions( aText, pDX, nStart, nEnd );
549 long nTH = GetTextHeight();
550 Point aPos( mnXOffset, ImplGetTextYPosition() );
552 if( bLayout )
554 long nPos = nStart ? pDX[2*nStart] : 0;
555 aPos.X() = nPos + mnXOffset + ImplGetExtraOffset();
557 MetricVector* pVector = &mpControlData->mpLayoutData->m_aUnicodeBoundRects;
558 OUString* pDisplayText = &mpControlData->mpLayoutData->m_aDisplayText;
560 DrawText( aPos, aText, nStart, nEnd - nStart, pVector, pDisplayText );
562 if( pDXBuffer )
563 delete [] pDXBuffer;
564 return;
567 Cursor* pCursor = GetCursor();
568 bool bVisCursor = pCursor ? pCursor->IsVisible() : false;
569 if ( pCursor )
570 pCursor->Hide();
572 ImplClearBackground( 0, GetOutputSizePixel().Width() );
574 bool bPaintPlaceholderText = aText.isEmpty() && !maPlaceholderText.isEmpty();
576 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
577 if ( IsEnabled() )
578 ImplInitSettings( sal_False, sal_True, sal_False );
579 if ( !IsEnabled() || bPaintPlaceholderText )
580 SetTextColor( rStyleSettings.GetDisableColor() );
582 // Set background color of the normal text
583 if( (GetStyle() & WB_FORCECTRLBACKGROUND) != 0 && IsControlBackground() )
585 // check if we need to set ControlBackground even in NWF case
586 Push( PUSH_FILLCOLOR | PUSH_LINECOLOR );
587 SetLineColor();
588 SetFillColor( GetControlBackground() );
589 DrawRect( Rectangle( aPos, Size( GetOutputSizePixel().Width() - 2*mnXOffset, GetOutputSizePixel().Height() ) ) );
590 Pop();
592 SetTextFillColor( GetControlBackground() );
594 else if( IsPaintTransparent() || ImplUseNativeBorder( GetStyle() ) )
595 SetTextFillColor();
596 else
597 SetTextFillColor( IsControlBackground() ? GetControlBackground() : rStyleSettings.GetFieldColor() );
599 ImplPaintBorder( 0, GetOutputSizePixel().Width() );
601 bool bDrawSelection = maSelection.Len() && ( HasFocus() || ( GetStyle() & WB_NOHIDESELECTION ) || mbActivePopup );
603 long nPos = nStart ? pDX[2*nStart] : 0;
604 aPos.X() = nPos + mnXOffset + ImplGetExtraOffset();
605 if ( bPaintPlaceholderText )
607 DrawText( aPos, maPlaceholderText );
609 else if ( !bDrawSelection && !mpIMEInfos )
611 DrawText( aPos, aText, nStart, nEnd - nStart );
613 else
615 // save graphics state
616 Push();
617 // first calculate higlighted and non highlighted clip regions
618 Region aHiglightClipRegion;
619 Region aNormalClipRegion;
620 Selection aTmpSel( maSelection );
621 aTmpSel.Justify();
622 // selection is highlighted
623 int i;
624 for( i = 0; i < aText.getLength(); i++ )
626 Rectangle aRect( aPos, Size( 10, nTH ) );
627 aRect.Left() = pDX[2*i] + mnXOffset + ImplGetExtraOffset();
628 aRect.Right() = pDX[2*i+1] + mnXOffset + ImplGetExtraOffset();
629 aRect.Justify();
630 bool bHighlight = false;
631 if( i >= aTmpSel.Min() && i < aTmpSel.Max() )
632 bHighlight = true;
634 if( mpIMEInfos && mpIMEInfos->pAttribs &&
635 i >= mpIMEInfos->nPos && i < (mpIMEInfos->nPos+mpIMEInfos->nLen ) &&
636 ( mpIMEInfos->pAttribs[i-mpIMEInfos->nPos] & EXTTEXTINPUT_ATTR_HIGHLIGHT) )
637 bHighlight = true;
639 if( bHighlight )
640 aHiglightClipRegion.Union( aRect );
641 else
642 aNormalClipRegion.Union( aRect );
644 // draw normal text
645 Color aNormalTextColor = GetTextColor();
646 SetClipRegion( aNormalClipRegion );
648 if( IsPaintTransparent() )
649 SetTextFillColor();
650 else
652 // Set background color when part of the text is selected
653 if ( ImplUseNativeBorder( GetStyle() ) )
655 if( (GetStyle() & WB_FORCECTRLBACKGROUND) != 0 && IsControlBackground() )
656 SetTextFillColor( GetControlBackground() );
657 else
658 SetTextFillColor();
660 else
661 SetTextFillColor( IsControlBackground() ? GetControlBackground() : rStyleSettings.GetFieldColor() );
663 DrawText( aPos, aText, nStart, nEnd - nStart );
665 // draw highlighted text
666 SetClipRegion( aHiglightClipRegion );
667 SetTextColor( rStyleSettings.GetHighlightTextColor() );
668 SetTextFillColor( rStyleSettings.GetHighlightColor() );
669 DrawText( aPos, aText, nStart, nEnd - nStart );
671 // if IME info exists loop over portions and output different font attributes
672 if( mpIMEInfos && mpIMEInfos->pAttribs )
674 for( int n = 0; n < 2; n++ )
676 Region aRegion;
677 if( n == 0 )
679 SetTextColor( aNormalTextColor );
680 if( IsPaintTransparent() )
681 SetTextFillColor();
682 else
683 SetTextFillColor( IsControlBackground() ? GetControlBackground() : rStyleSettings.GetFieldColor() );
684 aRegion = aNormalClipRegion;
686 else
688 SetTextColor( rStyleSettings.GetHighlightTextColor() );
689 SetTextFillColor( rStyleSettings.GetHighlightColor() );
690 aRegion = aHiglightClipRegion;
693 for( i = 0; i < mpIMEInfos->nLen; )
695 sal_uInt16 nAttr = mpIMEInfos->pAttribs[i];
696 Region aClip;
697 int nIndex = i;
698 while( nIndex < mpIMEInfos->nLen && mpIMEInfos->pAttribs[nIndex] == nAttr) // #112631# check nIndex before using it
700 Rectangle aRect( aPos, Size( 10, nTH ) );
701 aRect.Left() = pDX[2*(nIndex+mpIMEInfos->nPos)] + mnXOffset + ImplGetExtraOffset();
702 aRect.Right() = pDX[2*(nIndex+mpIMEInfos->nPos)+1] + mnXOffset + ImplGetExtraOffset();
703 aRect.Justify();
704 aClip.Union( aRect );
705 nIndex++;
707 i = nIndex;
708 aClip.Intersect(aRegion);
709 if( !aClip.IsEmpty() && nAttr )
711 Font aFont = GetFont();
712 if ( nAttr & EXTTEXTINPUT_ATTR_UNDERLINE )
713 aFont.SetUnderline( UNDERLINE_SINGLE );
714 else if ( nAttr & EXTTEXTINPUT_ATTR_BOLDUNDERLINE )
715 aFont.SetUnderline( UNDERLINE_BOLD );
716 else if ( nAttr & EXTTEXTINPUT_ATTR_DOTTEDUNDERLINE )
717 aFont.SetUnderline( UNDERLINE_DOTTED );
718 else if ( nAttr & EXTTEXTINPUT_ATTR_DASHDOTUNDERLINE )
719 aFont.SetUnderline( UNDERLINE_DASHDOT );
720 else if ( nAttr & EXTTEXTINPUT_ATTR_GRAYWAVELINE )
722 aFont.SetUnderline( UNDERLINE_WAVE );
723 SetTextLineColor( Color( COL_LIGHTGRAY ) );
725 SetFont( aFont );
727 if ( nAttr & EXTTEXTINPUT_ATTR_REDTEXT )
728 SetTextColor( Color( COL_RED ) );
729 else if ( nAttr & EXTTEXTINPUT_ATTR_HALFTONETEXT )
730 SetTextColor( Color( COL_LIGHTGRAY ) );
732 SetClipRegion( aClip );
733 DrawText( aPos, aText, nStart, nEnd - nStart );
739 // restore graphics state
740 Pop();
743 if ( bVisCursor && ( !mpIMEInfos || mpIMEInfos->bCursor ) )
744 pCursor->Show();
746 if( pDXBuffer )
747 delete [] pDXBuffer;
750 // -----------------------------------------------------------------------
752 void Edit::ImplDelete( const Selection& rSelection, sal_uInt8 nDirection, sal_uInt8 nMode )
754 OUString aText = ImplGetText();
756 // loeschen moeglich?
757 if ( !rSelection.Len() &&
758 (((rSelection.Min() == 0) && (nDirection == EDIT_DEL_LEFT)) ||
759 ((rSelection.Max() == aText.getLength()) && (nDirection == EDIT_DEL_RIGHT))) )
760 return;
762 ImplClearLayoutData();
764 Selection aSelection( rSelection );
765 aSelection.Justify();
767 if ( !aSelection.Len() )
769 uno::Reference < i18n::XBreakIterator > xBI = ImplGetBreakIterator();
770 if ( nDirection == EDIT_DEL_LEFT )
772 if ( nMode == EDIT_DELMODE_RESTOFWORD )
774 i18n::Boundary aBoundary = xBI->getWordBoundary( maText.toString(), aSelection.Min(),
775 GetSettings().GetLanguageTag().getLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True );
776 if ( aBoundary.startPos == aSelection.Min() )
777 aBoundary = xBI->previousWord( maText.toString(), aSelection.Min(),
778 GetSettings().GetLanguageTag().getLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES );
779 aSelection.Min() = aBoundary.startPos;
781 else if ( nMode == EDIT_DELMODE_RESTOFCONTENT )
783 aSelection.Min() = 0;
785 else
787 sal_Int32 nCount = 1;
788 aSelection.Min() = xBI->previousCharacters( maText.toString(), aSelection.Min(),
789 GetSettings().GetLanguageTag().getLocale(), i18n::CharacterIteratorMode::SKIPCHARACTER, nCount, nCount );
792 else
794 if ( nMode == EDIT_DELMODE_RESTOFWORD )
796 i18n::Boundary aBoundary = xBI->nextWord( maText.toString(), aSelection.Max(),
797 GetSettings().GetLanguageTag().getLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES );
798 aSelection.Max() = aBoundary.startPos;
800 else if ( nMode == EDIT_DELMODE_RESTOFCONTENT )
802 aSelection.Max() = aText.getLength();
804 else
806 sal_Int32 nCount = 1;
807 aSelection.Max() = xBI->nextCharacters( maText.toString(), aSelection.Max(),
808 GetSettings().GetLanguageTag().getLocale(), i18n::CharacterIteratorMode::SKIPCHARACTER, nCount, nCount );
813 maText.remove( static_cast<sal_Int32>(aSelection.Min()), static_cast<sal_Int32>(aSelection.Len()) );
814 maSelection.Min() = aSelection.Min();
815 maSelection.Max() = aSelection.Min();
816 ImplAlignAndPaint();
817 mbInternModified = sal_True;
820 // -----------------------------------------------------------------------
822 OUString Edit::ImplGetValidString( const OUString& rString ) const
824 OUString aValidString( rString );
825 aValidString = comphelper::string::remove(aValidString, '\n');
826 aValidString = comphelper::string::remove(aValidString, '\r');
827 aValidString = aValidString.replace('\t', ' ');
828 return aValidString;
831 // -----------------------------------------------------------------------
832 uno::Reference < i18n::XBreakIterator > Edit::ImplGetBreakIterator() const
834 //!! since we don't want to become incompatible in the next minor update
835 //!! where this code will get integrated into, xISC will be a local
836 //!! variable instead of a class member!
837 uno::Reference< uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
838 return i18n::BreakIterator::create(xContext);
840 // -----------------------------------------------------------------------
842 uno::Reference < i18n::XExtendedInputSequenceChecker > Edit::ImplGetInputSequenceChecker() const
844 //!! since we don't want to become incompatible in the next minor update
845 //!! where this code will get integrated into, xISC will be a local
846 //!! variable instead of a class member!
847 uno::Reference < i18n::XExtendedInputSequenceChecker > xISC;
848 // if ( !xISC.is() )
850 uno::Reference< uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
851 xISC = i18n::InputSequenceChecker::create(xContext);
853 return xISC;
856 // -----------------------------------------------------------------------
858 void Edit::ShowTruncationWarning( Window* pParent )
860 ResMgr* pResMgr = ImplGetResMgr();
861 if( pResMgr )
863 WarningBox aBox( pParent, ResId( SV_EDIT_WARNING_BOX, *pResMgr ) );
864 aBox.Execute();
868 // -----------------------------------------------------------------------
870 bool Edit::ImplTruncateToMaxLen( OUString& rStr, sal_uInt32 nSelectionLen ) const
872 bool bWasTruncated = false;
873 const sal_uInt32 nMaxLen = mnMaxTextLen < 65534 ? mnMaxTextLen : 65534;
874 sal_uInt32 nLenAfter = static_cast<sal_uInt32>(maText.getLength()) + rStr.getLength() - nSelectionLen;
875 if ( nLenAfter > nMaxLen )
877 sal_uInt32 nErasePos = nMaxLen - static_cast<sal_uInt32>(maText.getLength()) + nSelectionLen;
878 rStr = rStr.copy( 0, nErasePos );
879 bWasTruncated = true;
881 return bWasTruncated;
884 // -----------------------------------------------------------------------
886 void Edit::ImplInsertText( const OUString& rStr, const Selection* pNewSel, sal_Bool bIsUserInput )
888 Selection aSelection( maSelection );
889 aSelection.Justify();
891 OUString aNewText( ImplGetValidString( rStr ) );
892 ImplTruncateToMaxLen( aNewText, aSelection.Len() );
894 ImplClearLayoutData();
896 if ( aSelection.Len() )
897 maText.remove( static_cast<sal_Int32>(aSelection.Min()), static_cast<sal_Int32>(aSelection.Len()) );
898 else if ( !mbInsertMode && (aSelection.Max() < maText.getLength()) )
899 maText.remove( static_cast<sal_Int32>(aSelection.Max()), 1 );
901 // take care of input-sequence-checking now
902 if (bIsUserInput && !rStr.isEmpty())
904 DBG_ASSERT( rStr.getLength() == 1, "unexpected string length. User input is expected to providse 1 char only!" );
906 // determine if input-sequence-checking should be applied or not
908 uno::Reference < i18n::XBreakIterator > xBI( ImplGetBreakIterator(), UNO_QUERY );
909 bool bIsInputSequenceChecking = rStr.getLength() == 1 &&
910 officecfg::Office::Common::I18N::CTL::CTLFont::get() &&
911 officecfg::Office::Common::I18N::CTL::CTLSequenceChecking::get() &&
912 aSelection.Min() > 0 && /* first char needs not to be checked */
913 xBI.is() && i18n::ScriptType::COMPLEX == xBI->getScriptType( rStr, 0 );
916 uno::Reference < i18n::XExtendedInputSequenceChecker > xISC;
917 if (bIsInputSequenceChecking && (xISC = ImplGetInputSequenceChecker()).is())
919 sal_Unicode cChar = rStr[0];
920 sal_Int32 nTmpPos = static_cast< sal_Int32 >( aSelection.Min() );
921 sal_Int16 nCheckMode = officecfg::Office::Common::I18N::CTL::CTLSequenceCheckingRestricted::get()?
922 i18n::InputSequenceCheckMode::STRICT : i18n::InputSequenceCheckMode::BASIC;
924 // the text that needs to be checked is only the one
925 // before the current cursor position
926 OUString aOldText( maText.getStr(), nTmpPos);
927 OUString aTmpText( aOldText );
928 if (officecfg::Office::Common::I18N::CTL::CTLSequenceCheckingTypeAndReplace::get())
930 xISC->correctInputSequence( aTmpText, nTmpPos - 1, cChar, nCheckMode );
932 // find position of first character that has changed
933 sal_Int32 nOldLen = aOldText.getLength();
934 sal_Int32 nTmpLen = aTmpText.getLength();
935 const sal_Unicode *pOldTxt = aOldText.getStr();
936 const sal_Unicode *pTmpTxt = aTmpText.getStr();
937 sal_Int32 nChgPos = 0;
938 while ( nChgPos < nOldLen && nChgPos < nTmpLen &&
939 pOldTxt[nChgPos] == pTmpTxt[nChgPos] )
940 ++nChgPos;
942 OUString aChgText( aTmpText.copy( nChgPos ) );
944 // remove text from first pos to be changed to current pos
945 maText.remove( nChgPos, nTmpPos - nChgPos );
947 if (!aChgText.isEmpty())
949 aNewText = aChgText;
950 aSelection.Min() = nChgPos; // position for new text to be inserted
952 else
953 aNewText = "";
955 else
957 // should the character be ignored (i.e. not get inserted) ?
958 if (!xISC->checkInputSequence( aOldText, nTmpPos - 1, cChar, nCheckMode ))
959 aNewText = "";
963 // at this point now we will insert the non-empty text 'normally' some lines below...
966 if ( !aNewText.isEmpty() )
967 maText.insert( static_cast<sal_Int32>(aSelection.Min()), aNewText );
969 if ( !pNewSel )
971 maSelection.Min() = aSelection.Min() + aNewText.getLength();
972 maSelection.Max() = maSelection.Min();
974 else
976 maSelection = *pNewSel;
977 if ( maSelection.Min() > maText.getLength() )
978 maSelection.Min() = maText.getLength();
979 if ( maSelection.Max() > maText.getLength() )
980 maSelection.Max() = maText.getLength();
983 ImplAlignAndPaint();
984 mbInternModified = sal_True;
987 // -----------------------------------------------------------------------
989 void Edit::ImplSetText( const OUString& rText, const Selection* pNewSelection )
991 // we delete text by "selecting" the old text completely then calling InsertText; this is flicker free
992 if ( ( rText.getLength() <= mnMaxTextLen ) &&
993 ( (rText != maText.getStr()) || (pNewSelection && (*pNewSelection != maSelection)) ) )
995 ImplClearLayoutData();
996 maSelection.Min() = 0;
997 maSelection.Max() = maText.getLength();
998 if ( mnXOffset || HasPaintEvent() )
1000 mnXOffset = 0;
1001 maText = ImplGetValidString( rText );
1003 // #i54929# recalculate mnXOffset before ImplSetSelection,
1004 // else cursor ends up in wrong position
1005 ImplAlign();
1007 if ( pNewSelection )
1008 ImplSetSelection( *pNewSelection, sal_False );
1010 if ( mnXOffset && !pNewSelection )
1011 maSelection.Max() = 0;
1013 Invalidate();
1015 else
1016 ImplInsertText( rText, pNewSelection );
1018 ImplCallEventListeners( VCLEVENT_EDIT_MODIFY );
1022 // -----------------------------------------------------------------------
1024 int Edit::ImplGetNativeControlType() const
1026 int nCtrl = 0;
1027 const Window *pControl = mbIsSubEdit ? GetParent() : this;
1029 switch( pControl->GetType() )
1031 case WINDOW_COMBOBOX:
1032 case WINDOW_PATTERNBOX:
1033 case WINDOW_NUMERICBOX:
1034 case WINDOW_METRICBOX:
1035 case WINDOW_CURRENCYBOX:
1036 case WINDOW_DATEBOX:
1037 case WINDOW_TIMEBOX:
1038 case WINDOW_LONGCURRENCYBOX:
1039 nCtrl = CTRL_COMBOBOX;
1040 break;
1042 case WINDOW_MULTILINEEDIT:
1043 if ( GetWindow( WINDOW_BORDER ) != this )
1044 nCtrl = CTRL_MULTILINE_EDITBOX;
1045 else
1046 nCtrl = CTRL_EDITBOX_NOBORDER;
1047 break;
1049 case WINDOW_EDIT:
1050 case WINDOW_PATTERNFIELD:
1051 case WINDOW_METRICFIELD:
1052 case WINDOW_CURRENCYFIELD:
1053 case WINDOW_DATEFIELD:
1054 case WINDOW_TIMEFIELD:
1055 case WINDOW_LONGCURRENCYFIELD:
1056 case WINDOW_NUMERICFIELD:
1057 case WINDOW_SPINFIELD:
1058 if( pControl->GetStyle() & WB_SPIN )
1059 nCtrl = CTRL_SPINBOX;
1060 else
1062 if ( GetWindow( WINDOW_BORDER ) != this )
1063 nCtrl = CTRL_EDITBOX;
1064 else
1065 nCtrl = CTRL_EDITBOX_NOBORDER;
1067 break;
1069 default:
1070 nCtrl = CTRL_EDITBOX;
1072 return nCtrl;
1075 void Edit::ImplClearBackground( long nXStart, long nXEnd )
1078 * note: at this point the cursor must be switched off already
1080 Point aTmpPoint;
1081 Rectangle aRect( aTmpPoint, GetOutputSizePixel() );
1082 aRect.Left() = nXStart;
1083 aRect.Right() = nXEnd;
1085 if( !(ImplUseNativeBorder( GetStyle() ) || IsPaintTransparent()) )
1086 Erase( aRect );
1089 void Edit::ImplPaintBorder( long nXStart, long nXEnd )
1091 Point aTmpPoint;
1092 Rectangle aRect( aTmpPoint, GetOutputSizePixel() );
1093 aRect.Left() = nXStart;
1094 aRect.Right() = nXEnd;
1096 if( ImplUseNativeBorder( GetStyle() ) || IsPaintTransparent() )
1098 // draw the inner part by painting the whole control using its border window
1099 Window *pControl = this;
1100 Window *pBorder = GetWindow( WINDOW_BORDER );
1101 if( pBorder == this )
1103 // we have no border, use parent
1104 pControl = mbIsSubEdit ? GetParent() : this;
1105 pBorder = pControl->GetWindow( WINDOW_BORDER );
1106 if( pBorder == this )
1107 pBorder = GetParent();
1110 if( pBorder )
1112 // set proper clipping region to not overdraw the whole control
1113 Region aClipRgn = GetPaintRegion();
1114 if( !aClipRgn.IsNull() )
1116 // transform clipping region to border window's coordinate system
1117 if( IsRTLEnabled() != pBorder->IsRTLEnabled() && Application::GetSettings().GetLayoutRTL() )
1119 // need to mirror in case border is not RTL but edit is (or vice versa)
1121 // mirror
1122 Rectangle aBounds( aClipRgn.GetBoundRect() );
1123 int xNew = GetOutputSizePixel().Width() - aBounds.GetWidth() - aBounds.Left();
1124 aClipRgn.Move( xNew - aBounds.Left(), 0 );
1126 // move offset of border window
1127 Point aBorderOffs;
1128 aBorderOffs = pBorder->ScreenToOutputPixel( OutputToScreenPixel( aBorderOffs ) );
1129 aClipRgn.Move( aBorderOffs.X(), aBorderOffs.Y() );
1131 else
1133 // normal case
1134 Point aBorderOffs;
1135 aBorderOffs = pBorder->ScreenToOutputPixel( OutputToScreenPixel( aBorderOffs ) );
1136 aClipRgn.Move( aBorderOffs.X(), aBorderOffs.Y() );
1139 Region oldRgn( pBorder->GetClipRegion() );
1140 pBorder->SetClipRegion( aClipRgn );
1142 pBorder->Paint( Rectangle() );
1144 pBorder->SetClipRegion( oldRgn );
1146 else
1147 pBorder->Paint( Rectangle() );
1153 // -----------------------------------------------------------------------
1155 void Edit::ImplShowCursor( sal_Bool bOnlyIfVisible )
1157 if ( !IsUpdateMode() || ( bOnlyIfVisible && !IsReallyVisible() ) )
1158 return;
1160 Cursor* pCursor = GetCursor();
1161 OUString aText = ImplGetText();
1163 long nTextPos = 0;
1165 sal_Int32 nDXBuffer[256];
1166 sal_Int32* pDXBuffer = NULL;
1167 sal_Int32* pDX = nDXBuffer;
1169 if( !aText.isEmpty() )
1171 if( (size_t) (2*aText.getLength()) > SAL_N_ELEMENTS(nDXBuffer) )
1173 pDXBuffer = new sal_Int32[2*(aText.getLength()+1)];
1174 pDX = pDXBuffer;
1177 GetCaretPositions( aText, pDX, 0, aText.getLength() );
1179 if( maSelection.Max() < aText.getLength() )
1180 nTextPos = pDX[ 2*maSelection.Max() ];
1181 else
1182 nTextPos = pDX[ 2*aText.getLength()-1 ];
1185 long nCursorWidth = 0;
1186 if ( !mbInsertMode && !maSelection.Len() && (maSelection.Max() < aText.getLength()) )
1187 nCursorWidth = GetTextWidth( aText, (xub_StrLen)maSelection.Max(), 1 );
1188 long nCursorPosX = nTextPos + mnXOffset + ImplGetExtraOffset();
1190 // cursor should land in visible area
1191 const Size aOutSize = GetOutputSizePixel();
1192 if ( (nCursorPosX < 0) || (nCursorPosX >= aOutSize.Width()) )
1194 long nOldXOffset = mnXOffset;
1196 if ( nCursorPosX < 0 )
1198 mnXOffset = - nTextPos;
1199 long nMaxX = 0;
1200 mnXOffset += aOutSize.Width() / 5;
1201 if ( mnXOffset > nMaxX )
1202 mnXOffset = nMaxX;
1204 else
1206 mnXOffset = (aOutSize.Width()-ImplGetExtraOffset()) - nTextPos;
1207 // Etwas mehr?
1208 if ( (aOutSize.Width()-ImplGetExtraOffset()) < nTextPos )
1210 long nMaxNegX = (aOutSize.Width()-ImplGetExtraOffset()) - GetTextWidth( aText );
1211 mnXOffset -= aOutSize.Width() / 5;
1212 if ( mnXOffset < nMaxNegX ) // beides negativ...
1213 mnXOffset = nMaxNegX;
1217 nCursorPosX = nTextPos + mnXOffset + ImplGetExtraOffset();
1218 if ( nCursorPosX == aOutSize.Width() ) // dann nicht sichtbar...
1219 nCursorPosX--;
1221 if ( mnXOffset != nOldXOffset )
1222 ImplInvalidateOrRepaint();
1225 const long nTextHeight = GetTextHeight();
1226 const long nCursorPosY = ImplGetTextYPosition();
1227 pCursor->SetPos( Point( nCursorPosX, nCursorPosY ) );
1228 pCursor->SetSize( Size( nCursorWidth, nTextHeight ) );
1229 pCursor->Show();
1231 if( pDXBuffer )
1232 delete [] pDXBuffer;
1235 // -----------------------------------------------------------------------
1237 void Edit::ImplAlign()
1239 long nTextWidth = GetTextWidth( ImplGetText() );
1240 long nOutWidth = GetOutputSizePixel().Width();
1242 if ( mnAlign == EDIT_ALIGN_LEFT )
1244 if( mnXOffset && ( nTextWidth < nOutWidth ) )
1245 mnXOffset = 0;
1248 else if ( mnAlign == EDIT_ALIGN_RIGHT )
1250 long nMinXOffset = nOutWidth - nTextWidth - 1 - ImplGetExtraOffset();
1251 bool bRTL = IsRTLEnabled();
1252 if( mbIsSubEdit && GetParent() )
1253 bRTL = GetParent()->IsRTLEnabled();
1254 if( bRTL )
1256 if( nTextWidth < nOutWidth )
1257 mnXOffset = nMinXOffset;
1259 else
1261 if( nTextWidth < nOutWidth )
1262 mnXOffset = nMinXOffset;
1263 else if ( mnXOffset < nMinXOffset )
1264 mnXOffset = nMinXOffset;
1267 else if( mnAlign == EDIT_ALIGN_CENTER )
1269 // would be nicer with check while scrolling but then it's not centred in scrolled state
1270 mnXOffset = (nOutWidth - nTextWidth) / 2;
1275 // -----------------------------------------------------------------------
1277 void Edit::ImplAlignAndPaint()
1279 ImplAlign();
1280 ImplInvalidateOrRepaint( 0, STRING_LEN );
1281 ImplShowCursor();
1284 // -----------------------------------------------------------------------
1286 sal_Int32 Edit::ImplGetCharPos( const Point& rWindowPos ) const
1288 sal_Int32 nIndex = STRING_LEN;
1289 OUString aText = ImplGetText();
1291 sal_Int32 nDXBuffer[256];
1292 sal_Int32* pDXBuffer = NULL;
1293 sal_Int32* pDX = nDXBuffer;
1294 if( (size_t) (2*aText.getLength()) > SAL_N_ELEMENTS(nDXBuffer) )
1296 pDXBuffer = new sal_Int32[2*(aText.getLength()+1)];
1297 pDX = pDXBuffer;
1300 GetCaretPositions( aText, pDX, 0, aText.getLength() );
1301 long nX = rWindowPos.X() - mnXOffset - ImplGetExtraOffset();
1302 for( int i = 0; i < aText.getLength(); i++ )
1304 if( (pDX[2*i] >= nX && pDX[2*i+1] <= nX) ||
1305 (pDX[2*i+1] >= nX && pDX[2*i] <= nX))
1307 nIndex = sal::static_int_cast<xub_StrLen>(i);
1308 if( pDX[2*i] < pDX[2*i+1] )
1310 if( nX > (pDX[2*i]+pDX[2*i+1])/2 )
1311 nIndex++;
1313 else
1315 if( nX < (pDX[2*i]+pDX[2*i+1])/2 )
1316 nIndex++;
1318 break;
1321 if( nIndex == STRING_LEN )
1323 nIndex = 0;
1324 long nDiff = std::abs( pDX[0]-nX );
1325 for( int i = 1; i < aText.getLength(); i++ )
1327 long nNewDiff = std::abs( pDX[2*i]-nX );
1329 if( nNewDiff < nDiff )
1331 nIndex = sal::static_int_cast<xub_StrLen>(i);
1332 nDiff = nNewDiff;
1335 if( nIndex == aText.getLength()-1 && std::abs( pDX[2*nIndex+1] - nX ) < nDiff )
1336 nIndex = STRING_LEN;
1339 if( pDXBuffer )
1340 delete [] pDXBuffer;
1342 return nIndex;
1345 // -----------------------------------------------------------------------
1347 void Edit::ImplSetCursorPos( sal_Int32 nChar, sal_Bool bSelect )
1349 Selection aSelection( maSelection );
1350 aSelection.Max() = nChar;
1351 if ( !bSelect )
1352 aSelection.Min() = aSelection.Max();
1353 ImplSetSelection( aSelection );
1356 // -----------------------------------------------------------------------
1358 void Edit::ImplLoadRes( const ResId& rResId )
1360 Control::ImplLoadRes( rResId );
1362 xub_StrLen nTextLength = ReadShortRes();
1363 if ( nTextLength )
1364 SetMaxTextLen( nTextLength );
1367 // -----------------------------------------------------------------------
1369 void Edit::ImplCopyToSelectionClipboard()
1371 if ( GetSelection().Len() )
1373 ::com::sun::star::uno::Reference<com::sun::star::datatransfer::clipboard::XClipboard> aSelection(GetPrimarySelection());
1374 ImplCopy( aSelection );
1378 void Edit::ImplCopy( uno::Reference< datatransfer::clipboard::XClipboard >& rxClipboard )
1380 ::vcl::unohelper::TextDataObject::CopyStringTo( GetSelected(), rxClipboard );
1383 // -----------------------------------------------------------------------
1385 void Edit::ImplPaste( uno::Reference< datatransfer::clipboard::XClipboard >& rxClipboard )
1387 if ( rxClipboard.is() )
1389 uno::Reference< datatransfer::XTransferable > xDataObj;
1391 const sal_uInt32 nRef = Application::ReleaseSolarMutex();
1395 xDataObj = rxClipboard->getContents();
1397 catch( const ::com::sun::star::uno::Exception& )
1401 Application::AcquireSolarMutex( nRef );
1403 if ( xDataObj.is() )
1405 datatransfer::DataFlavor aFlavor;
1406 SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aFlavor );
1409 uno::Any aData = xDataObj->getTransferData( aFlavor );
1410 OUString aText;
1411 aData >>= aText;
1412 if( ImplTruncateToMaxLen( aText, maSelection.Len() ) )
1413 ShowTruncationWarning( const_cast<Edit*>(this) );
1414 ReplaceSelected( aText );
1416 catch( const ::com::sun::star::uno::Exception& )
1423 // -----------------------------------------------------------------------
1425 void Edit::MouseButtonDown( const MouseEvent& rMEvt )
1427 if ( mpSubEdit )
1429 Control::MouseButtonDown( rMEvt );
1430 return;
1433 xub_StrLen nChar = ImplGetCharPos( rMEvt.GetPosPixel() );
1434 Selection aSelection( maSelection );
1435 aSelection.Justify();
1437 if ( rMEvt.GetClicks() < 4 )
1439 mbClickedInSelection = sal_False;
1440 if ( rMEvt.GetClicks() == 3 )
1442 ImplSetSelection( Selection( 0, 0xFFFF ) );
1443 ImplCopyToSelectionClipboard();
1446 else if ( rMEvt.GetClicks() == 2 )
1448 uno::Reference < i18n::XBreakIterator > xBI = ImplGetBreakIterator();
1449 i18n::Boundary aBoundary = xBI->getWordBoundary( maText.toString(), aSelection.Max(),
1450 GetSettings().GetLanguageTag().getLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True );
1451 ImplSetSelection( Selection( aBoundary.startPos, aBoundary.endPos ) );
1452 ImplCopyToSelectionClipboard();
1454 else if ( !rMEvt.IsShift() && HasFocus() && aSelection.IsInside( nChar ) )
1455 mbClickedInSelection = sal_True;
1456 else if ( rMEvt.IsLeft() )
1457 ImplSetCursorPos( nChar, rMEvt.IsShift() );
1459 if ( !mbClickedInSelection && rMEvt.IsLeft() && ( rMEvt.GetClicks() == 1 ) )
1460 StartTracking( STARTTRACK_SCROLLREPEAT );
1463 mbInMBDown = sal_True; // then do not select all in GetFocus
1464 GrabFocus();
1465 mbInMBDown = sal_False;
1468 // -----------------------------------------------------------------------
1470 void Edit::MouseButtonUp( const MouseEvent& rMEvt )
1472 if ( mbClickedInSelection && rMEvt.IsLeft() )
1474 xub_StrLen nChar = ImplGetCharPos( rMEvt.GetPosPixel() );
1475 ImplSetCursorPos( nChar, sal_False );
1476 mbClickedInSelection = sal_False;
1478 else if ( rMEvt.IsMiddle() && !mbReadOnly &&
1479 ( GetSettings().GetMouseSettings().GetMiddleButtonAction() == MOUSE_MIDDLE_PASTESELECTION ) )
1481 ::com::sun::star::uno::Reference<com::sun::star::datatransfer::clipboard::XClipboard> aSelection(Window::GetPrimarySelection());
1482 ImplPaste( aSelection );
1483 ImplModified();
1487 // -----------------------------------------------------------------------
1489 void Edit::Tracking( const TrackingEvent& rTEvt )
1491 if ( rTEvt.IsTrackingEnded() )
1493 if ( mbClickedInSelection )
1495 xub_StrLen nChar = ImplGetCharPos( rTEvt.GetMouseEvent().GetPosPixel() );
1496 ImplSetCursorPos( nChar, sal_False );
1497 mbClickedInSelection = sal_False;
1499 else if ( rTEvt.GetMouseEvent().IsLeft() )
1501 ImplCopyToSelectionClipboard();
1504 else
1506 if( !mbClickedInSelection )
1508 xub_StrLen nChar = ImplGetCharPos( rTEvt.GetMouseEvent().GetPosPixel() );
1509 ImplSetCursorPos( nChar, sal_True );
1513 if ( mpUpdateDataTimer && !mbIsSubEdit && mpUpdateDataTimer->IsActive() )
1514 mpUpdateDataTimer->Start();//do not update while the user is still travelling in the control
1517 // -----------------------------------------------------------------------
1519 sal_Bool Edit::ImplHandleKeyEvent( const KeyEvent& rKEvt )
1521 sal_Bool bDone = sal_False;
1522 sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
1523 KeyFuncType eFunc = rKEvt.GetKeyCode().GetFunction();
1525 mbInternModified = sal_False;
1527 if ( eFunc != KEYFUNC_DONTKNOW )
1529 switch ( eFunc )
1531 case KEYFUNC_CUT:
1533 if ( !mbReadOnly && maSelection.Len() && !(GetStyle() & WB_PASSWORD) )
1535 Cut();
1536 ImplModified();
1537 bDone = sal_True;
1540 break;
1542 case KEYFUNC_COPY:
1544 if ( !(GetStyle() & WB_PASSWORD) )
1546 Copy();
1547 bDone = sal_True;
1550 break;
1552 case KEYFUNC_PASTE:
1554 if ( !mbReadOnly )
1556 Paste();
1557 bDone = sal_True;
1560 break;
1562 case KEYFUNC_UNDO:
1564 if ( !mbReadOnly )
1566 Undo();
1567 bDone = sal_True;
1570 break;
1572 default:
1573 eFunc = KEYFUNC_DONTKNOW;
1577 if ( !bDone && rKEvt.GetKeyCode().IsMod1() && !rKEvt.GetKeyCode().IsMod2() )
1579 if ( nCode == KEY_A )
1581 ImplSetSelection( Selection( 0, maText.getLength() ) );
1582 bDone = sal_True;
1584 else if ( rKEvt.GetKeyCode().IsShift() && (nCode == KEY_S) )
1586 if ( pImplFncGetSpecialChars )
1588 Selection aSaveSel = GetSelection(); // if someone changes the selection in Get/LoseFocus, e.g. URL bar
1589 OUString aChars = pImplFncGetSpecialChars( this, GetFont() );
1590 SetSelection( aSaveSel );
1591 if ( !aChars.isEmpty() )
1593 ImplInsertText( aChars );
1594 ImplModified();
1596 bDone = sal_True;
1601 if ( eFunc == KEYFUNC_DONTKNOW && ! bDone )
1603 switch ( nCode )
1605 case com::sun::star::awt::Key::SELECT_ALL:
1607 ImplSetSelection( Selection( 0, maText.getLength() ) );
1608 bDone = sal_True;
1610 break;
1612 case KEY_LEFT:
1613 case KEY_RIGHT:
1614 case KEY_HOME:
1615 case KEY_END:
1616 case com::sun::star::awt::Key::MOVE_WORD_FORWARD:
1617 case com::sun::star::awt::Key::SELECT_WORD_FORWARD:
1618 case com::sun::star::awt::Key::MOVE_WORD_BACKWARD:
1619 case com::sun::star::awt::Key::SELECT_WORD_BACKWARD:
1620 case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE:
1621 case com::sun::star::awt::Key::MOVE_TO_END_OF_LINE:
1622 case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE:
1623 case com::sun::star::awt::Key::SELECT_TO_END_OF_LINE:
1624 case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH:
1625 case com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH:
1626 case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH:
1627 case com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH:
1628 case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT:
1629 case com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT:
1630 case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT:
1631 case com::sun::star::awt::Key::SELECT_TO_END_OF_DOCUMENT:
1633 if ( !rKEvt.GetKeyCode().IsMod2() )
1635 ImplClearLayoutData();
1636 uno::Reference < i18n::XBreakIterator > xBI = ImplGetBreakIterator();
1638 Selection aSel( maSelection );
1639 bool bWord = rKEvt.GetKeyCode().IsMod1();
1640 bool bSelect = rKEvt.GetKeyCode().IsShift();
1641 bool bGoLeft = (nCode == KEY_LEFT);
1642 bool bGoRight = (nCode == KEY_RIGHT);
1643 bool bGoHome = (nCode == KEY_HOME);
1644 bool bGoEnd = (nCode == KEY_END);
1646 switch( nCode )
1648 case com::sun::star::awt::Key::MOVE_WORD_FORWARD:
1649 bGoRight = bWord = true;break;
1650 case com::sun::star::awt::Key::SELECT_WORD_FORWARD:
1651 bGoRight = bSelect = bWord = true;break;
1652 case com::sun::star::awt::Key::MOVE_WORD_BACKWARD:
1653 bGoLeft = bWord = true;break;
1654 case com::sun::star::awt::Key::SELECT_WORD_BACKWARD:
1655 bGoLeft = bSelect = bWord = true;break;
1656 case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE:
1657 case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH:
1658 case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT:
1659 bSelect = true;
1660 // fallthrough intended
1661 case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE:
1662 case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH:
1663 case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT:
1664 bGoHome = true;break;
1665 case com::sun::star::awt::Key::SELECT_TO_END_OF_LINE:
1666 case com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH:
1667 case com::sun::star::awt::Key::SELECT_TO_END_OF_DOCUMENT:
1668 bSelect = true;
1669 // fallthrough intended
1670 case com::sun::star::awt::Key::MOVE_TO_END_OF_LINE:
1671 case com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH:
1672 case com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT:
1673 bGoEnd = true;break;
1674 default:
1675 break;
1678 // Range wird in ImplSetSelection geprueft...
1679 if ( bGoLeft && aSel.Max() )
1681 if ( bWord )
1683 i18n::Boundary aBoundary = xBI->getWordBoundary( maText.toString(), aSel.Max(),
1684 GetSettings().GetLanguageTag().getLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True );
1685 if ( aBoundary.startPos == aSel.Max() )
1686 aBoundary = xBI->previousWord( maText.toString(), aSel.Max(),
1687 GetSettings().GetLanguageTag().getLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES );
1688 aSel.Max() = aBoundary.startPos;
1690 else
1692 sal_Int32 nCount = 1;
1693 aSel.Max() = xBI->previousCharacters( maText.toString(), aSel.Max(),
1694 GetSettings().GetLanguageTag().getLocale(), i18n::CharacterIteratorMode::SKIPCHARACTER, nCount, nCount );
1697 else if ( bGoRight && ( aSel.Max() < maText.getLength() ) )
1699 if ( bWord )
1701 i18n::Boundary aBoundary = xBI->nextWord( maText.toString(), aSel.Max(),
1702 GetSettings().GetLanguageTag().getLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES );
1703 aSel.Max() = aBoundary.startPos;
1705 else
1707 sal_Int32 nCount = 1;
1708 aSel.Max() = xBI->nextCharacters( maText.toString(), aSel.Max(),
1709 GetSettings().GetLanguageTag().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.getLength()) )
1734 meAutocompleteAction = AUTOCOMPLETE_KEYINPUT;
1735 maAutocompleteHdl.Call( this );
1739 bDone = sal_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 sal_uInt8 nDel = (nCode == KEY_DELETE) ? EDIT_DEL_RIGHT : EDIT_DEL_LEFT;
1754 sal_uInt8 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 sal_Int32 nOldLen = maText.getLength();
1778 ImplDelete( maSelection, nDel, nMode );
1779 if ( maText.getLength() != nOldLen )
1780 ImplModified();
1781 bDone = sal_True;
1784 break;
1786 case KEY_INSERT:
1788 if ( !mpIMEInfos && !mbReadOnly && !rKEvt.GetKeyCode().IsMod2() )
1790 SetInsertMode( !mbInsertMode );
1791 bDone = sal_True;
1794 break;
1796 /* #i101255# disable autocomplete tab forward/backward
1797 users expect tab/shif-tab to move the focus to other controls
1798 not suddenly to cycle the autocompletion
1799 case KEY_TAB:
1801 if ( !mbReadOnly && maAutocompleteHdl.IsSet() &&
1802 maSelection.Min() && (maSelection.Min() == maText.Len()) &&
1803 !rKEvt.GetKeyCode().IsMod1() && !rKEvt.GetKeyCode().IsMod2() )
1805 // Kein Autocomplete wenn alles Selektiert oder Edit leer, weil dann
1806 // keine vernuenftige Tab-Steuerung!
1807 if ( rKEvt.GetKeyCode().IsShift() )
1808 meAutocompleteAction = AUTOCOMPLETE_TABBACKWARD;
1809 else
1810 meAutocompleteAction = AUTOCOMPLETE_TABFORWARD;
1812 maAutocompleteHdl.Call( this );
1814 // Wurde nichts veraendert, dann TAB fuer DialogControl
1815 if ( GetSelection().Len() )
1816 bDone = sal_True;
1819 break;
1822 default:
1824 if ( IsCharInput( rKEvt ) )
1826 bDone = sal_True; // read characters also when in ReadOnly
1827 if ( !mbReadOnly )
1829 ImplInsertText(OUString(rKEvt.GetCharCode()), 0, sal_True);
1830 if ( maAutocompleteHdl.IsSet() )
1832 if ( (maSelection.Min() == maSelection.Max()) && (maSelection.Min() == maText.getLength()) )
1834 meAutocompleteAction = AUTOCOMPLETE_KEYINPUT;
1835 maAutocompleteHdl.Call( this );
1844 if ( mbInternModified )
1845 ImplModified();
1847 return bDone;
1850 // -----------------------------------------------------------------------
1852 void Edit::KeyInput( const KeyEvent& rKEvt )
1854 if ( mpUpdateDataTimer && !mbIsSubEdit && mpUpdateDataTimer->IsActive() )
1855 mpUpdateDataTimer->Start();//do not update while the user is still travelling in the control
1857 if ( mpSubEdit || !ImplHandleKeyEvent( rKEvt ) )
1858 Control::KeyInput( rKEvt );
1861 // -----------------------------------------------------------------------
1863 void Edit::FillLayoutData() const
1865 mpControlData->mpLayoutData = new vcl::ControlLayoutData();
1866 const_cast<Edit*>(this)->ImplRepaint( 0, STRING_LEN, true );
1869 // -----------------------------------------------------------------------
1871 void Edit::Paint( const Rectangle& )
1873 if ( !mpSubEdit )
1874 ImplRepaint();
1877 // -----------------------------------------------------------------------
1879 void Edit::Resize()
1881 if ( !mpSubEdit && IsReallyVisible() )
1883 Control::Resize();
1884 // Wegen vertikaler Zentrierung...
1885 mnXOffset = 0;
1886 ImplAlign();
1887 Invalidate();
1888 ImplShowCursor();
1892 // -----------------------------------------------------------------------
1894 void Edit::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, sal_uLong nFlags )
1896 ImplInitSettings( sal_True, sal_True, sal_True );
1898 Point aPos = pDev->LogicToPixel( rPos );
1899 Size aSize = pDev->LogicToPixel( rSize );
1900 Font aFont = GetDrawPixelFont( pDev );
1901 OutDevType eOutDevType = pDev->GetOutDevType();
1903 pDev->Push();
1904 pDev->SetMapMode();
1905 pDev->SetFont( aFont );
1906 pDev->SetTextFillColor();
1908 // Border/Background
1909 pDev->SetLineColor();
1910 pDev->SetFillColor();
1911 bool bBorder = !(nFlags & WINDOW_DRAW_NOBORDER ) && (GetStyle() & WB_BORDER);
1912 bool bBackground = !(nFlags & WINDOW_DRAW_NOBACKGROUND) && IsControlBackground();
1913 if ( bBorder || bBackground )
1915 Rectangle aRect( aPos, aSize );
1916 if ( bBorder )
1918 ImplDrawFrame( pDev, aRect );
1920 if ( bBackground )
1922 pDev->SetFillColor( GetControlBackground() );
1923 pDev->DrawRect( aRect );
1927 // Inhalt
1928 if ( ( nFlags & WINDOW_DRAW_MONO ) || ( eOutDevType == OUTDEV_PRINTER ) )
1929 pDev->SetTextColor( Color( COL_BLACK ) );
1930 else
1932 if ( !(nFlags & WINDOW_DRAW_NODISABLE ) && !IsEnabled() )
1934 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
1935 pDev->SetTextColor( rStyleSettings.GetDisableColor() );
1937 else
1939 pDev->SetTextColor( GetTextColor() );
1943 OUString aText = ImplGetText();
1944 long nTextHeight = pDev->GetTextHeight();
1945 long nTextWidth = pDev->GetTextWidth( aText );
1946 long nOnePixel = GetDrawPixel( pDev, 1 );
1947 long nOffX = 3*nOnePixel;
1948 long nOffY = (aSize.Height() - nTextHeight) / 2;
1950 // Clipping?
1951 if ( (nOffY < 0) ||
1952 ((nOffY+nTextHeight) > aSize.Height()) ||
1953 ((nOffX+nTextWidth) > aSize.Width()) )
1955 Rectangle aClip( aPos, aSize );
1956 if ( nTextHeight > aSize.Height() )
1957 aClip.Bottom() += nTextHeight-aSize.Height()+1; // prevent HP printers from 'optimizing'
1958 pDev->IntersectClipRegion( aClip );
1961 if ( GetStyle() & WB_CENTER )
1963 aPos.X() += (aSize.Width() - nTextWidth) / 2;
1964 nOffX = 0;
1966 else if ( GetStyle() & WB_RIGHT )
1968 aPos.X() += aSize.Width() - nTextWidth;
1969 nOffX = -nOffX;
1972 pDev->DrawText( Point( aPos.X() + nOffX, aPos.Y() + nOffY ), aText );
1973 pDev->Pop();
1975 if ( GetSubEdit() )
1977 GetSubEdit()->Draw( pDev, rPos, rSize, nFlags );
1981 // -----------------------------------------------------------------------
1983 void Edit::ImplInvalidateOutermostBorder( Window* pWin )
1985 // allow control to show focused state
1986 Window *pInvalWin = pWin, *pBorder = pWin;
1987 while( ( pBorder = pInvalWin->GetWindow( WINDOW_BORDER ) ) != pInvalWin && pBorder &&
1988 pInvalWin->ImplGetFrame() == pBorder->ImplGetFrame() )
1990 pInvalWin = pBorder;
1993 pInvalWin->Invalidate( INVALIDATE_CHILDREN | INVALIDATE_UPDATE );
1996 void Edit::GetFocus()
1998 if ( mpSubEdit )
1999 mpSubEdit->ImplGrabFocus( GetGetFocusFlags() );
2000 else if ( !mbActivePopup )
2002 maUndoText = maText.toString();
2004 sal_uLong nSelOptions = GetSettings().GetStyleSettings().GetSelectionOptions();
2005 if ( !( GetStyle() & (WB_NOHIDESELECTION|WB_READONLY) )
2006 && ( GetGetFocusFlags() & (GETFOCUS_INIT|GETFOCUS_TAB|GETFOCUS_CURSOR|GETFOCUS_MNEMONIC) ) )
2008 if ( nSelOptions & SELECTION_OPTION_SHOWFIRST )
2010 maSelection.Min() = maText.getLength();
2011 maSelection.Max() = 0;
2013 else
2015 maSelection.Min() = 0;
2016 maSelection.Max() = maText.getLength();
2018 if ( mbIsSubEdit )
2019 ((Edit*)GetParent())->ImplCallEventListeners( VCLEVENT_EDIT_SELECTIONCHANGED );
2020 else
2021 ImplCallEventListeners( VCLEVENT_EDIT_SELECTIONCHANGED );
2024 ImplShowCursor();
2026 // FIXME: this is currently only on aqua
2027 // check for other platforms that need similar handling
2028 if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
2029 IsNativeWidgetEnabled() &&
2030 IsNativeControlSupported( CTRL_EDITBOX, PART_ENTIRE_CONTROL ) )
2032 ImplInvalidateOutermostBorder( mbIsSubEdit ? GetParent() : this );
2034 else if ( maSelection.Len() )
2036 // Selektion malen
2037 if ( !HasPaintEvent() )
2038 ImplInvalidateOrRepaint();
2039 else
2040 Invalidate();
2043 SetInputContext( InputContext( GetFont(), !IsReadOnly() ? INPUTCONTEXT_TEXT|INPUTCONTEXT_EXTTEXTINPUT : 0 ) );
2046 Control::GetFocus();
2049 // -----------------------------------------------------------------------
2051 Window* Edit::GetPreferredKeyInputWindow()
2053 if ( mpSubEdit )
2054 return mpSubEdit->GetPreferredKeyInputWindow();
2055 else
2056 return this;
2059 // -----------------------------------------------------------------------
2061 void Edit::LoseFocus()
2063 if ( mpUpdateDataTimer && !mbIsSubEdit && mpUpdateDataTimer->IsActive() )
2065 //notify an update latest when the focus is lost
2066 mpUpdateDataTimer->Stop();
2067 mpUpdateDataTimer->Timeout();
2070 if ( !mpSubEdit )
2072 // FIXME: this is currently only on aqua
2073 // check for other platforms that need similar handling
2074 if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
2075 IsNativeWidgetEnabled() &&
2076 IsNativeControlSupported( CTRL_EDITBOX, PART_ENTIRE_CONTROL ) )
2078 ImplInvalidateOutermostBorder( mbIsSubEdit ? GetParent() : this );
2081 if ( !mbActivePopup && !( GetStyle() & WB_NOHIDESELECTION ) && maSelection.Len() )
2082 ImplInvalidateOrRepaint(); // Selektion malen
2085 Control::LoseFocus();
2088 // -----------------------------------------------------------------------
2090 void Edit::Command( const CommandEvent& rCEvt )
2092 if ( rCEvt.GetCommand() == COMMAND_CONTEXTMENU )
2094 PopupMenu* pPopup = Edit::CreatePopupMenu();
2096 if ( !maSelection.Len() )
2098 pPopup->EnableItem( SV_MENU_EDIT_CUT, sal_False );
2099 pPopup->EnableItem( SV_MENU_EDIT_COPY, sal_False );
2100 pPopup->EnableItem( SV_MENU_EDIT_DELETE, sal_False );
2103 if ( IsReadOnly() )
2105 pPopup->EnableItem( SV_MENU_EDIT_CUT, sal_False );
2106 pPopup->EnableItem( SV_MENU_EDIT_PASTE, sal_False );
2107 pPopup->EnableItem( SV_MENU_EDIT_DELETE, sal_False );
2108 pPopup->EnableItem( SV_MENU_EDIT_INSERTSYMBOL, sal_False );
2110 else
2112 // Paste nur, wenn Text im Clipboard
2113 sal_Bool bData = sal_False;
2114 uno::Reference< datatransfer::clipboard::XClipboard > xClipboard = GetClipboard();
2115 if ( xClipboard.is() )
2117 const sal_uInt32 nRef = Application::ReleaseSolarMutex();
2118 uno::Reference< datatransfer::XTransferable > xDataObj = xClipboard->getContents();
2119 Application::AcquireSolarMutex( nRef );
2120 if ( xDataObj.is() )
2122 datatransfer::DataFlavor aFlavor;
2123 SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aFlavor );
2124 bData = xDataObj->isDataFlavorSupported( aFlavor );
2127 pPopup->EnableItem( SV_MENU_EDIT_PASTE, bData );
2130 if ( maUndoText == maText.getStr() )
2131 pPopup->EnableItem( SV_MENU_EDIT_UNDO, sal_False );
2132 if ( ( maSelection.Min() == 0 ) && ( maSelection.Max() == maText.getLength() ) )
2133 pPopup->EnableItem( SV_MENU_EDIT_SELECTALL, sal_False );
2134 if ( !pImplFncGetSpecialChars )
2136 sal_uInt16 nPos = pPopup->GetItemPos( SV_MENU_EDIT_INSERTSYMBOL );
2137 pPopup->RemoveItem( nPos );
2138 pPopup->RemoveItem( nPos-1 );
2141 mbActivePopup = sal_True;
2142 Selection aSaveSel = GetSelection(); // if someone changes selection in Get/LoseFocus, e.g. URL bar
2143 Point aPos = rCEvt.GetMousePosPixel();
2144 if ( !rCEvt.IsMouseEvent() )
2146 // Show menu enventually centered in selection
2147 Size aSize = GetOutputSizePixel();
2148 aPos = Point( aSize.Width()/2, aSize.Height()/2 );
2150 sal_uInt16 n = pPopup->Execute( this, aPos );
2151 Edit::DeletePopupMenu( pPopup );
2152 SetSelection( aSaveSel );
2153 switch ( n )
2155 case SV_MENU_EDIT_UNDO:
2156 Undo();
2157 ImplModified();
2158 break;
2159 case SV_MENU_EDIT_CUT:
2160 Cut();
2161 ImplModified();
2162 break;
2163 case SV_MENU_EDIT_COPY:
2164 Copy();
2165 break;
2166 case SV_MENU_EDIT_PASTE:
2167 Paste();
2168 ImplModified();
2169 break;
2170 case SV_MENU_EDIT_DELETE:
2171 DeleteSelected();
2172 ImplModified();
2173 break;
2174 case SV_MENU_EDIT_SELECTALL:
2175 ImplSetSelection( Selection( 0, maText.getLength() ) );
2176 break;
2177 case SV_MENU_EDIT_INSERTSYMBOL:
2179 OUString aChars = pImplFncGetSpecialChars( this, GetFont() );
2180 SetSelection( aSaveSel );
2181 if ( !aChars.isEmpty() )
2183 ImplInsertText( aChars );
2184 ImplModified();
2187 break;
2189 mbActivePopup = sal_False;
2191 else if ( rCEvt.GetCommand() == COMMAND_STARTEXTTEXTINPUT )
2193 DeleteSelected();
2194 delete mpIMEInfos;
2195 sal_Int32 nPos = static_cast<sal_Int32>(maSelection.Max());
2196 mpIMEInfos = new Impl_IMEInfos( nPos, OUString(maText.getStr() + nPos ) );
2197 mpIMEInfos->bWasCursorOverwrite = !IsInsertMode();
2199 else if ( rCEvt.GetCommand() == COMMAND_ENDEXTTEXTINPUT )
2201 sal_Bool bInsertMode = !mpIMEInfos->bWasCursorOverwrite;
2202 delete mpIMEInfos;
2203 mpIMEInfos = NULL;
2205 // set font without attributes, because it will not be re-initialised in Repaint anymore
2206 ImplInitSettings( sal_True, sal_False, sal_False );
2208 SetInsertMode( bInsertMode );
2210 ImplModified();
2212 // #i25161# call auto complete handler for ext text commit also
2213 if ( maAutocompleteHdl.IsSet() )
2215 if ( (maSelection.Min() == maSelection.Max()) && (maSelection.Min() == maText.getLength()) )
2217 meAutocompleteAction = AUTOCOMPLETE_KEYINPUT;
2218 maAutocompleteHdl.Call( this );
2222 else if ( rCEvt.GetCommand() == COMMAND_EXTTEXTINPUT )
2224 const CommandExtTextInputData* pData = rCEvt.GetExtTextInputData();
2226 maText.remove( mpIMEInfos->nPos, mpIMEInfos->nLen );
2227 maText.insert( mpIMEInfos->nPos, pData->GetText() );
2228 if ( mpIMEInfos->bWasCursorOverwrite )
2230 sal_Int32 nOldIMETextLen = mpIMEInfos->nLen;
2231 sal_Int32 nNewIMETextLen = pData->GetText().getLength();
2232 if ( ( nOldIMETextLen > nNewIMETextLen ) &&
2233 ( nNewIMETextLen < mpIMEInfos->aOldTextAfterStartPos.getLength() ) )
2235 // restore old characters
2236 sal_Int32 nRestore = nOldIMETextLen - nNewIMETextLen;
2237 maText.insert( mpIMEInfos->nPos + nNewIMETextLen, mpIMEInfos->aOldTextAfterStartPos.copy( nNewIMETextLen, nRestore ) );
2239 else if ( ( nOldIMETextLen < nNewIMETextLen ) &&
2240 ( nOldIMETextLen < mpIMEInfos->aOldTextAfterStartPos.getLength() ) )
2242 // overwrite
2243 sal_uInt16 nOverwrite = nNewIMETextLen - nOldIMETextLen;
2244 if ( ( nOldIMETextLen + nOverwrite ) > mpIMEInfos->aOldTextAfterStartPos.getLength() )
2245 nOverwrite = mpIMEInfos->aOldTextAfterStartPos.getLength() - nOldIMETextLen;
2246 maText.remove( mpIMEInfos->nPos + nNewIMETextLen, nOverwrite );
2251 if ( pData->GetTextAttr() )
2253 mpIMEInfos->CopyAttribs( pData->GetTextAttr(), pData->GetText().getLength() );
2254 mpIMEInfos->bCursor = pData->IsCursorVisible();
2256 else
2258 mpIMEInfos->DestroyAttribs();
2261 ImplAlignAndPaint();
2262 xub_StrLen nCursorPos = mpIMEInfos->nPos + pData->GetCursorPos();
2263 SetSelection( Selection( nCursorPos, nCursorPos ) );
2264 SetInsertMode( !pData->IsCursorOverwrite() );
2266 if ( pData->IsCursorVisible() )
2267 GetCursor()->Show();
2268 else
2269 GetCursor()->Hide();
2271 else if ( rCEvt.GetCommand() == COMMAND_CURSORPOS )
2273 if ( mpIMEInfos )
2275 xub_StrLen nCursorPos = (sal_uInt16)GetSelection().Max();
2276 SetCursorRect( NULL, GetTextWidth( maText.toString(), nCursorPos, mpIMEInfos->nPos+mpIMEInfos->nLen-nCursorPos ) );
2278 else
2280 SetCursorRect();
2283 else if ( rCEvt.GetCommand() == COMMAND_SELECTIONCHANGE )
2285 const CommandSelectionChangeData *pData = rCEvt.GetSelectionChangeData();
2286 Selection aSelection( pData->GetStart(), pData->GetEnd() );
2287 SetSelection(aSelection);
2289 else if ( rCEvt.GetCommand() == COMMAND_QUERYCHARPOSITION )
2291 if (mpIMEInfos && mpIMEInfos->nLen > 0)
2293 OUString aText = ImplGetText();
2294 sal_Int32 nDXBuffer[256];
2295 sal_Int32* pDXBuffer = NULL;
2296 sal_Int32* pDX = nDXBuffer;
2298 if( !aText.isEmpty() )
2300 if( (size_t) (2*aText.getLength()) > SAL_N_ELEMENTS(nDXBuffer) )
2302 pDXBuffer = new sal_Int32[2*(aText.getLength()+1)];
2303 pDX = pDXBuffer;
2306 GetCaretPositions( aText, pDX, 0, aText.getLength() );
2308 long nTH = GetTextHeight();
2309 Point aPos( mnXOffset, ImplGetTextYPosition() );
2311 Rectangle* aRects = new Rectangle[ mpIMEInfos->nLen ];
2312 for ( int nIndex = 0; nIndex < mpIMEInfos->nLen; ++nIndex )
2314 Rectangle aRect( aPos, Size( 10, nTH ) );
2315 aRect.Left() = pDX[2*(nIndex+mpIMEInfos->nPos)] + mnXOffset + ImplGetExtraOffset();
2316 aRects[ nIndex ] = aRect;
2318 SetCompositionCharRect( aRects, mpIMEInfos->nLen );
2319 delete[] aRects;
2320 delete[] pDXBuffer;
2323 else
2324 Control::Command( rCEvt );
2327 // -----------------------------------------------------------------------
2329 void Edit::StateChanged( StateChangedType nType )
2331 if ( nType == STATE_CHANGE_INITSHOW )
2333 if ( !mpSubEdit )
2335 mnXOffset = 0; // if GrabFocus before while size was still wrong
2336 ImplAlign();
2337 if ( !mpSubEdit )
2338 ImplShowCursor( sal_False );
2340 // update background (eventual SetPaintTransparent)
2341 ImplInitSettings( sal_False, sal_False, sal_True );
2343 else if ( nType == STATE_CHANGE_ENABLE )
2345 if ( !mpSubEdit )
2347 // change text color only
2348 ImplInvalidateOrRepaint( 0, 0xFFFF );
2351 else if ( nType == STATE_CHANGE_STYLE || nType == STATE_CHANGE_MIRRORING )
2353 WinBits nStyle = GetStyle();
2354 if( nType == STATE_CHANGE_STYLE )
2356 nStyle = ImplInitStyle( GetStyle() );
2357 SetStyle( nStyle );
2360 sal_uInt16 nOldAlign = mnAlign;
2361 mnAlign = EDIT_ALIGN_LEFT;
2363 // --- RTL --- hack: right align until keyinput and cursor travelling works
2364 // edits are always RTL disabled
2365 // however the parent edits contain the correct setting
2366 if( mbIsSubEdit && GetParent()->IsRTLEnabled() )
2368 if( GetParent()->GetStyle() & WB_LEFT )
2369 mnAlign = EDIT_ALIGN_RIGHT;
2370 if ( nType == STATE_CHANGE_MIRRORING )
2371 SetLayoutMode( TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_TEXTORIGIN_LEFT );
2373 else if( mbIsSubEdit && !GetParent()->IsRTLEnabled() )
2375 if ( nType == STATE_CHANGE_MIRRORING )
2376 SetLayoutMode( TEXT_LAYOUT_BIDI_LTR | TEXT_LAYOUT_TEXTORIGIN_LEFT );
2379 if ( nStyle & WB_RIGHT )
2380 mnAlign = EDIT_ALIGN_RIGHT;
2381 else if ( nStyle & WB_CENTER )
2382 mnAlign = EDIT_ALIGN_CENTER;
2383 if ( !maText.isEmpty() && ( mnAlign != nOldAlign ) )
2385 ImplAlign();
2386 Invalidate();
2390 else if ( nType == STATE_CHANGE_ZOOM )
2392 if ( !mpSubEdit )
2394 ImplInitSettings( sal_True, sal_False, sal_False );
2395 ImplShowCursor( sal_True );
2396 Invalidate();
2399 else if ( nType == STATE_CHANGE_CONTROLFONT )
2401 if ( !mpSubEdit )
2403 ImplInitSettings( sal_True, sal_False, sal_False );
2404 ImplShowCursor();
2405 Invalidate();
2408 else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
2410 if ( !mpSubEdit )
2412 ImplInitSettings( sal_False, sal_True, sal_False );
2413 Invalidate();
2416 else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
2418 if ( !mpSubEdit )
2420 ImplInitSettings( sal_False, sal_False, sal_True );
2421 Invalidate();
2425 Control::StateChanged( nType );
2428 // -----------------------------------------------------------------------
2430 void Edit::DataChanged( const DataChangedEvent& rDCEvt )
2432 if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
2433 (rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
2434 ((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
2435 (rDCEvt.GetFlags() & SETTINGS_STYLE)) )
2437 if ( !mpSubEdit )
2439 ImplInitSettings( sal_True, sal_True, sal_True );
2440 ImplShowCursor( sal_True );
2441 Invalidate();
2445 Control::DataChanged( rDCEvt );
2448 // -----------------------------------------------------------------------
2450 void Edit::ImplShowDDCursor()
2452 if ( !mpDDInfo->bVisCursor )
2454 long nTextWidth = GetTextWidth( maText.toString(), 0, mpDDInfo->nDropPos );
2455 long nTextHeight = GetTextHeight();
2456 Rectangle aCursorRect( Point( nTextWidth + mnXOffset, (GetOutputSize().Height()-nTextHeight)/2 ), Size( 2, nTextHeight ) );
2457 mpDDInfo->aCursor.SetWindow( this );
2458 mpDDInfo->aCursor.SetPos( aCursorRect.TopLeft() );
2459 mpDDInfo->aCursor.SetSize( aCursorRect.GetSize() );
2460 mpDDInfo->aCursor.Show();
2461 mpDDInfo->bVisCursor = true;
2465 // -----------------------------------------------------------------------
2467 void Edit::ImplHideDDCursor()
2469 if ( mpDDInfo && mpDDInfo->bVisCursor )
2471 mpDDInfo->aCursor.Hide();
2472 mpDDInfo->bVisCursor = false;
2476 // -----------------------------------------------------------------------
2478 void Edit::Modify()
2480 if ( mbIsSubEdit )
2482 ((Edit*)GetParent())->Modify();
2484 else
2486 if ( mpUpdateDataTimer )
2487 mpUpdateDataTimer->Start();
2489 if ( ImplCallEventListenersAndHandler( VCLEVENT_EDIT_MODIFY, maModifyHdl, this ) )
2490 // have been destroyed while calling into the handlers
2491 return;
2493 // #i13677# notify edit listeners about caret position change
2494 ImplCallEventListeners( VCLEVENT_EDIT_SELECTIONCHANGED );
2496 // FIXME: this is currently only on aqua
2497 // check for other platforms that need similar handling
2498 if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
2499 IsNativeWidgetEnabled() &&
2500 IsNativeControlSupported( CTRL_EDITBOX, PART_ENTIRE_CONTROL ) )
2502 ImplInvalidateOutermostBorder( this );
2507 // -----------------------------------------------------------------------
2509 void Edit::UpdateData()
2511 maUpdateDataHdl.Call( this );
2514 // -----------------------------------------------------------------------
2516 IMPL_LINK_NOARG(Edit, ImplUpdateDataHdl)
2518 UpdateData();
2519 return 0;
2522 // -----------------------------------------------------------------------
2524 void Edit::EnableUpdateData( sal_uLong nTimeout )
2526 if ( !nTimeout )
2527 DisableUpdateData();
2528 else
2530 if ( !mpUpdateDataTimer )
2532 mpUpdateDataTimer = new Timer;
2533 mpUpdateDataTimer->SetTimeoutHdl( LINK( this, Edit, ImplUpdateDataHdl ) );
2536 mpUpdateDataTimer->SetTimeout( nTimeout );
2540 // -----------------------------------------------------------------------
2542 void Edit::SetEchoChar( sal_Unicode c )
2544 mcEchoChar = c;
2545 if ( mpSubEdit )
2546 mpSubEdit->SetEchoChar( c );
2549 // -----------------------------------------------------------------------
2551 void Edit::SetReadOnly( sal_Bool bReadOnly )
2553 if ( mbReadOnly != bReadOnly )
2555 mbReadOnly = bReadOnly;
2556 if ( mpSubEdit )
2557 mpSubEdit->SetReadOnly( bReadOnly );
2559 StateChanged( STATE_CHANGE_READONLY );
2563 // -----------------------------------------------------------------------
2565 void Edit::SetAutocompleteHdl( const Link& rHdl )
2567 maAutocompleteHdl = rHdl;
2568 if ( mpSubEdit )
2569 mpSubEdit->SetAutocompleteHdl( rHdl );
2572 // -----------------------------------------------------------------------
2574 void Edit::SetInsertMode( sal_Bool bInsert )
2576 if ( bInsert != mbInsertMode )
2578 mbInsertMode = bInsert;
2579 if ( mpSubEdit )
2580 mpSubEdit->SetInsertMode( bInsert );
2581 else
2582 ImplShowCursor();
2586 // -----------------------------------------------------------------------
2588 sal_Bool Edit::IsInsertMode() const
2590 if ( mpSubEdit )
2591 return mpSubEdit->IsInsertMode();
2592 else
2593 return mbInsertMode;
2596 // -----------------------------------------------------------------------
2598 void Edit::SetMaxTextLen( xub_StrLen nMaxLen )
2600 mnMaxTextLen = nMaxLen ? nMaxLen : EDIT_NOLIMIT;
2602 if ( mpSubEdit )
2603 mpSubEdit->SetMaxTextLen( mnMaxTextLen );
2604 else
2606 if ( maText.getLength() > mnMaxTextLen )
2607 ImplDelete( Selection( mnMaxTextLen, maText.getLength() ), EDIT_DEL_RIGHT, EDIT_DELMODE_SIMPLE );
2611 // -----------------------------------------------------------------------
2613 void Edit::SetSelection( const Selection& rSelection )
2615 // If the selection was changed from outside, e.g. by MouseButtonDown, don't call Tracking()
2616 // directly afterwards which would change the selection again
2617 if ( IsTracking() )
2618 EndTracking();
2619 else if ( mpSubEdit && mpSubEdit->IsTracking() )
2620 mpSubEdit->EndTracking();
2622 ImplSetSelection( rSelection );
2625 // -----------------------------------------------------------------------
2627 void Edit::ImplSetSelection( const Selection& rSelection, sal_Bool bPaint )
2629 if ( mpSubEdit )
2630 mpSubEdit->ImplSetSelection( rSelection );
2631 else
2633 if ( rSelection != maSelection )
2635 Selection aOld( maSelection );
2636 Selection aNew( rSelection );
2638 if ( aNew.Min() > maText.getLength() )
2639 aNew.Min() = maText.getLength();
2640 if ( aNew.Max() > maText.getLength() )
2641 aNew.Max() = maText.getLength();
2642 if ( aNew.Min() < 0 )
2643 aNew.Min() = 0;
2644 if ( aNew.Max() < 0 )
2645 aNew.Max() = 0;
2647 if ( aNew != maSelection )
2649 ImplClearLayoutData();
2650 maSelection = aNew;
2652 if ( bPaint && ( aOld.Len() || aNew.Len() || IsPaintTransparent() ) )
2653 ImplInvalidateOrRepaint( 0, maText.getLength() );
2654 ImplShowCursor();
2655 if ( mbIsSubEdit )
2656 ((Edit*)GetParent())->ImplCallEventListeners( VCLEVENT_EDIT_SELECTIONCHANGED );
2657 else
2658 ImplCallEventListeners( VCLEVENT_EDIT_SELECTIONCHANGED );
2659 // #103511# notify combobox listeners of deselection
2660 if( !maSelection && GetParent() && GetParent()->GetType() == WINDOW_COMBOBOX )
2661 ((Edit*)GetParent())->ImplCallEventListeners( VCLEVENT_COMBOBOX_DESELECT );
2667 // -----------------------------------------------------------------------
2669 const Selection& Edit::GetSelection() const
2671 if ( mpSubEdit )
2672 return mpSubEdit->GetSelection();
2673 else
2674 return maSelection;
2677 // -----------------------------------------------------------------------
2679 void Edit::ReplaceSelected( const OUString& rStr )
2681 if ( mpSubEdit )
2682 mpSubEdit->ReplaceSelected( rStr );
2683 else
2684 ImplInsertText( rStr );
2687 // -----------------------------------------------------------------------
2689 void Edit::DeleteSelected()
2691 if ( mpSubEdit )
2692 mpSubEdit->DeleteSelected();
2693 else
2695 if ( maSelection.Len() )
2696 ImplDelete( maSelection, EDIT_DEL_RIGHT, EDIT_DELMODE_SIMPLE );
2700 // -----------------------------------------------------------------------
2702 OUString Edit::GetSelected() const
2704 if ( mpSubEdit )
2705 return mpSubEdit->GetSelected();
2706 else
2708 Selection aSelection( maSelection );
2709 aSelection.Justify();
2710 return OUString( maText.getStr() + aSelection.Min(), aSelection.Len() );
2714 // -----------------------------------------------------------------------
2716 void Edit::Cut()
2718 if ( !(GetStyle() & WB_PASSWORD ) )
2720 Copy();
2721 ReplaceSelected( OUString() );
2725 // -----------------------------------------------------------------------
2727 void Edit::Copy()
2729 if ( !(GetStyle() & WB_PASSWORD ) )
2731 ::com::sun::star::uno::Reference<com::sun::star::datatransfer::clipboard::XClipboard> aClipboard(GetClipboard());
2732 ImplCopy( aClipboard );
2736 // -----------------------------------------------------------------------
2738 void Edit::Paste()
2740 ::com::sun::star::uno::Reference<com::sun::star::datatransfer::clipboard::XClipboard> aClipboard(GetClipboard());
2741 ImplPaste( aClipboard );
2744 // -----------------------------------------------------------------------
2746 void Edit::Undo()
2748 if ( mpSubEdit )
2749 mpSubEdit->Undo();
2750 else
2752 OUString aText( maText.toString() );
2753 ImplDelete( Selection( 0, aText.getLength() ), EDIT_DEL_RIGHT, EDIT_DELMODE_SIMPLE );
2754 ImplInsertText( maUndoText );
2755 ImplSetSelection( Selection( 0, maUndoText.getLength() ) );
2756 maUndoText = aText;
2760 // -----------------------------------------------------------------------
2762 void Edit::SetText( const OUString& rStr )
2764 if ( mpSubEdit )
2765 mpSubEdit->SetText( rStr ); // not directly ImplSetText if SetText overloaded
2766 else
2768 Selection aNewSel( 0, 0 ); // prevent scrolling
2769 ImplSetText( rStr, &aNewSel );
2773 // -----------------------------------------------------------------------
2775 void Edit::SetText( const OUString& rStr, const Selection& rSelection )
2777 if ( mpSubEdit )
2778 mpSubEdit->SetText( rStr, rSelection );
2779 else
2780 ImplSetText( rStr, &rSelection );
2783 // -----------------------------------------------------------------------
2785 OUString Edit::GetText() const
2787 if ( mpSubEdit )
2788 return mpSubEdit->GetText();
2789 else
2790 return maText.toString();
2793 // -----------------------------------------------------------------------
2795 void Edit::SetPlaceholderText( const OUString& rStr )
2797 if ( mpSubEdit )
2798 mpSubEdit->SetPlaceholderText( rStr );
2799 else if ( maPlaceholderText != rStr )
2801 maPlaceholderText = rStr;
2802 if ( GetText().isEmpty() )
2803 Invalidate();
2807 // -----------------------------------------------------------------------
2809 OUString Edit::GetPlaceholderText() const
2811 if ( mpSubEdit )
2812 return mpSubEdit->GetPlaceholderText();
2814 return maPlaceholderText;
2817 // -----------------------------------------------------------------------
2819 void Edit::SetModifyFlag()
2821 if ( mpSubEdit )
2822 mpSubEdit->mbModified = sal_True;
2823 else
2824 mbModified = sal_True;
2827 // -----------------------------------------------------------------------
2829 void Edit::ClearModifyFlag()
2831 if ( mpSubEdit )
2832 mpSubEdit->mbModified = sal_False;
2833 else
2834 mbModified = sal_False;
2837 // -----------------------------------------------------------------------
2839 void Edit::SetSubEdit( Edit* pEdit )
2841 mpSubEdit = pEdit;
2842 if ( mpSubEdit )
2844 SetPointer( POINTER_ARROW ); // Nur das SubEdit hat den BEAM...
2845 mpSubEdit->mbIsSubEdit = sal_True;
2847 mpSubEdit->SetReadOnly( mbReadOnly );
2851 Size Edit::CalcMinimumSizeForText(const OUString &rString) const
2853 int eCtrlType = ImplGetNativeControlType();
2855 Size aSize;
2856 if (mnWidthInChars != -1)
2858 //CalcSize calls CalcWindowSize, but we will call that also in this
2859 //function, so undo the first one with CalcOutputSize
2860 aSize = CalcOutputSize(CalcSize(mnWidthInChars));
2862 else
2864 OUString aString;
2865 if (mnMaxWidthChars != -1 && mnMaxWidthChars < rString.getLength())
2866 aString = rString.copy(0, mnMaxWidthChars);
2867 else
2868 aString = rString;
2870 aSize.Height() = GetTextHeight();
2871 aSize.Width() = GetTextWidth(aString);
2872 aSize.Width() += ImplGetExtraOffset() * 2;
2874 // do not create edit fields in which one cannot enter anything
2875 // a default minimum width should exist for at least 3 characters
2877 //CalcSize calls CalcWindowSize, but we will call that also in this
2878 //function, so undo the first one with CalcOutputSize
2879 Size aMinSize(CalcOutputSize(CalcSize(3)));
2880 if (aSize.Width() < aMinSize.Width())
2881 aSize.Width() = aMinSize.Width();
2884 if (eCtrlType != CTRL_EDITBOX_NOBORDER)
2886 // add some space between text entry and border
2887 aSize.Height() += 4;
2890 aSize = CalcWindowSize( aSize );
2892 // ask NWF what if it has an opinion, too
2893 ImplControlValue aControlValue;
2894 Rectangle aRect( Point( 0, 0 ), aSize );
2895 Rectangle aContent, aBound;
2896 if( GetNativeControlRegion(
2897 eCtrlType, PART_ENTIRE_CONTROL,
2898 aRect, 0, aControlValue, OUString(), aBound, aContent) )
2900 if( aBound.GetHeight() > aSize.Height() )
2901 aSize.Height() = aBound.GetHeight();
2903 return aSize;
2906 Size Edit::CalcMinimumSize() const
2908 return CalcMinimumSizeForText(GetText());
2911 Size Edit::GetMinimumEditSize()
2913 Window* pDefWin = ImplGetDefaultWindow();
2914 Edit aEdit( pDefWin, WB_BORDER );
2915 Size aSize( aEdit.CalcMinimumSize() );
2916 return aSize;
2919 // -----------------------------------------------------------------------
2921 Size Edit::GetOptimalSize() const
2923 return CalcMinimumSize();
2926 // -----------------------------------------------------------------------
2928 Size Edit::CalcSize( xub_StrLen nChars ) const
2930 // width for N characters, independent from content.
2931 // works only correct for fixed fonts, average otherwise
2932 Size aSz( GetTextWidth( OUString('x') ), GetTextHeight() );
2933 aSz.Width() *= nChars;
2934 aSz.Width() += ImplGetExtraOffset() * 2;
2935 aSz = CalcWindowSize( aSz );
2936 return aSz;
2939 // -----------------------------------------------------------------------
2941 xub_StrLen Edit::GetMaxVisChars() const
2943 const Window* pW = mpSubEdit ? mpSubEdit : this;
2944 long nOutWidth = pW->GetOutputSizePixel().Width();
2945 long nCharWidth = GetTextWidth( OUString('x') );
2946 return nCharWidth ? (xub_StrLen)(nOutWidth/nCharWidth) : 0;
2949 // -----------------------------------------------------------------------
2951 xub_StrLen Edit::GetCharPos( const Point& rWindowPos ) const
2953 return ImplGetCharPos( rWindowPos );
2956 // -----------------------------------------------------------------------
2958 void Edit::SetGetSpecialCharsFunction( FncGetSpecialChars fn )
2960 pImplFncGetSpecialChars = fn;
2963 // -----------------------------------------------------------------------
2965 FncGetSpecialChars Edit::GetGetSpecialCharsFunction()
2967 return pImplFncGetSpecialChars;
2970 // -----------------------------------------------------------------------
2972 PopupMenu* Edit::CreatePopupMenu()
2974 ResMgr* pResMgr = ImplGetResMgr();
2975 if( ! pResMgr )
2976 return new PopupMenu();
2978 PopupMenu* pPopup = new PopupMenu( ResId( SV_RESID_MENU_EDIT, *pResMgr ) );
2979 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
2980 if ( rStyleSettings.GetHideDisabledMenuItems() )
2981 pPopup->SetMenuFlags( MENU_FLAG_HIDEDISABLEDENTRIES );
2982 else
2983 pPopup->SetMenuFlags ( MENU_FLAG_ALWAYSSHOWDISABLEDENTRIES );
2984 if ( rStyleSettings.GetAcceleratorsInContextMenus() )
2986 pPopup->SetAccelKey( SV_MENU_EDIT_UNDO, KeyCode( KEYFUNC_UNDO ) );
2987 pPopup->SetAccelKey( SV_MENU_EDIT_CUT, KeyCode( KEYFUNC_CUT ) );
2988 pPopup->SetAccelKey( SV_MENU_EDIT_COPY, KeyCode( KEYFUNC_COPY ) );
2989 pPopup->SetAccelKey( SV_MENU_EDIT_PASTE, KeyCode( KEYFUNC_PASTE ) );
2990 pPopup->SetAccelKey( SV_MENU_EDIT_DELETE, KeyCode( KEYFUNC_DELETE ) );
2991 pPopup->SetAccelKey( SV_MENU_EDIT_SELECTALL, KeyCode( KEY_A, sal_False, sal_True, sal_False, sal_False ) );
2992 pPopup->SetAccelKey( SV_MENU_EDIT_INSERTSYMBOL, KeyCode( KEY_S, sal_True, sal_True, sal_False, sal_False ) );
2994 return pPopup;
2997 // -----------------------------------------------------------------------
2999 void Edit::DeletePopupMenu( PopupMenu* pMenu )
3001 delete pMenu;
3004 // ::com::sun::star::datatransfer::dnd::XDragGestureListener
3005 void Edit::dragGestureRecognized( const ::com::sun::star::datatransfer::dnd::DragGestureEvent& rDGE ) throw (::com::sun::star::uno::RuntimeException)
3007 SolarMutexGuard aVclGuard;
3009 if ( !IsTracking() && maSelection.Len() &&
3010 !(GetStyle() & WB_PASSWORD) && (!mpDDInfo || mpDDInfo->bStarterOfDD == false) ) // Kein Mehrfach D&D
3012 Selection aSel( maSelection );
3013 aSel.Justify();
3015 // Nur wenn Maus in der Selektion...
3016 Point aMousePos( rDGE.DragOriginX, rDGE.DragOriginY );
3017 xub_StrLen nChar = ImplGetCharPos( aMousePos );
3018 if ( (nChar >= aSel.Min()) && (nChar < aSel.Max()) )
3020 if ( !mpDDInfo )
3021 mpDDInfo = new DDInfo;
3023 mpDDInfo->bStarterOfDD = true;
3024 mpDDInfo->aDndStartSel = aSel;
3027 if ( IsTracking() )
3028 EndTracking(); // Vor D&D Tracking ausschalten
3030 ::vcl::unohelper::TextDataObject* pDataObj = new ::vcl::unohelper::TextDataObject( GetSelected() );
3031 sal_Int8 nActions = datatransfer::dnd::DNDConstants::ACTION_COPY;
3032 if ( !IsReadOnly() )
3033 nActions |= datatransfer::dnd::DNDConstants::ACTION_MOVE;
3034 rDGE.DragSource->startDrag( rDGE, nActions, 0 /*cursor*/, 0 /*image*/, pDataObj, mxDnDListener );
3035 if ( GetCursor() )
3036 GetCursor()->Hide();
3042 // ::com::sun::star::datatransfer::dnd::XDragSourceListener
3043 void Edit::dragDropEnd( const ::com::sun::star::datatransfer::dnd::DragSourceDropEvent& rDSDE ) throw (::com::sun::star::uno::RuntimeException)
3045 SolarMutexGuard aVclGuard;
3047 if ( rDSDE.DropSuccess && ( rDSDE.DropAction & datatransfer::dnd::DNDConstants::ACTION_MOVE ) )
3049 Selection aSel( mpDDInfo->aDndStartSel );
3050 if ( mpDDInfo->bDroppedInMe )
3052 if ( aSel.Max() > mpDDInfo->nDropPos )
3054 long nLen = aSel.Len();
3055 aSel.Min() += nLen;
3056 aSel.Max() += nLen;
3059 ImplDelete( aSel, EDIT_DEL_RIGHT, EDIT_DELMODE_SIMPLE );
3060 ImplModified();
3063 ImplHideDDCursor();
3064 delete mpDDInfo;
3065 mpDDInfo = NULL;
3068 // ::com::sun::star::datatransfer::dnd::XDropTargetListener
3069 void Edit::drop( const ::com::sun::star::datatransfer::dnd::DropTargetDropEvent& rDTDE ) throw (::com::sun::star::uno::RuntimeException)
3071 SolarMutexGuard aVclGuard;
3073 sal_Bool bChanges = sal_False;
3074 if ( !mbReadOnly && mpDDInfo )
3076 ImplHideDDCursor();
3078 Selection aSel( maSelection );
3079 aSel.Justify();
3081 if ( aSel.Len() && !mpDDInfo->bStarterOfDD )
3082 ImplDelete( aSel, EDIT_DEL_RIGHT, EDIT_DELMODE_SIMPLE );
3084 mpDDInfo->bDroppedInMe = true;
3086 aSel.Min() = mpDDInfo->nDropPos;
3087 aSel.Max() = mpDDInfo->nDropPos;
3088 ImplSetSelection( aSel );
3090 uno::Reference< datatransfer::XTransferable > xDataObj = rDTDE.Transferable;
3091 if ( xDataObj.is() )
3093 datatransfer::DataFlavor aFlavor;
3094 SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aFlavor );
3095 if ( xDataObj->isDataFlavorSupported( aFlavor ) )
3097 uno::Any aData = xDataObj->getTransferData( aFlavor );
3098 OUString aText;
3099 aData >>= aText;
3100 ImplInsertText( aText );
3101 bChanges = sal_True;
3102 ImplModified();
3106 if ( !mpDDInfo->bStarterOfDD )
3108 delete mpDDInfo;
3109 mpDDInfo = NULL;
3113 rDTDE.Context->dropComplete( bChanges );
3116 void Edit::dragEnter( const ::com::sun::star::datatransfer::dnd::DropTargetDragEnterEvent& rDTDE ) throw (::com::sun::star::uno::RuntimeException)
3118 if ( !mpDDInfo )
3120 mpDDInfo = new DDInfo;
3122 // search for string data type
3123 const Sequence< com::sun::star::datatransfer::DataFlavor >& rFlavors( rDTDE.SupportedDataFlavors );
3124 sal_Int32 nEle = rFlavors.getLength();
3125 mpDDInfo->bIsStringSupported = false;
3126 for( sal_Int32 i = 0; i < nEle; i++ )
3128 sal_Int32 nIndex = 0;
3129 OUString aMimetype = rFlavors[i].MimeType.getToken( 0, ';', nIndex );
3130 if ( aMimetype == "text/plain" )
3132 mpDDInfo->bIsStringSupported = true;
3133 break;
3138 void Edit::dragExit( const ::com::sun::star::datatransfer::dnd::DropTargetEvent& ) throw (::com::sun::star::uno::RuntimeException)
3140 SolarMutexGuard aVclGuard;
3142 ImplHideDDCursor();
3145 void Edit::dragOver( const ::com::sun::star::datatransfer::dnd::DropTargetDragEvent& rDTDE ) throw (::com::sun::star::uno::RuntimeException)
3147 SolarMutexGuard aVclGuard;
3149 Point aMousePos( rDTDE.LocationX, rDTDE.LocationY );
3151 xub_StrLen nPrevDropPos = mpDDInfo->nDropPos;
3152 mpDDInfo->nDropPos = ImplGetCharPos( aMousePos );
3155 Size aOutSize = GetOutputSizePixel();
3156 if ( ( aMousePos.X() < 0 ) || ( aMousePos.X() > aOutSize.Width() ) )
3158 // Scroll?
3159 // No, I will not receive events in this case....
3163 Selection aSel( maSelection );
3164 aSel.Justify();
3166 // Don't accept drop in selection or read-only field...
3167 if ( IsReadOnly() || aSel.IsInside( mpDDInfo->nDropPos ) || ! mpDDInfo->bIsStringSupported )
3169 ImplHideDDCursor();
3170 rDTDE.Context->rejectDrag();
3172 else
3174 // Alten Cursor wegzeichnen...
3175 if ( !mpDDInfo->bVisCursor || ( nPrevDropPos != mpDDInfo->nDropPos ) )
3177 ImplHideDDCursor();
3178 ImplShowDDCursor();
3180 rDTDE.Context->acceptDrag( rDTDE.DropAction );
3184 OUString Edit::GetSurroundingText() const
3186 if (mpSubEdit)
3187 return mpSubEdit->GetSurroundingText();
3188 return maText.toString();
3191 Selection Edit::GetSurroundingTextSelection() const
3193 return GetSelection();
3196 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */