blob: c8c1af18a449c98b69be3b09648620be88565c9e [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_vcl.hxx"
#include <tools/rc.h>
#include <vcl/decoview.hxx>
#include <vcl/event.hxx>
#include <vcl/cursor.hxx>
#include <vcl/virdev.hxx>
#include <vcl/menu.hxx>
#include <vcl/cmdevt.h>
#include <vcl/edit.hxx>
#include <vcl/svapp.hxx>
#include <vcl/msgbox.hxx>
#include <window.h>
#include <svdata.hxx>
#include <svids.hrc>
#include <subedit.hxx>
#include <controldata.hxx>
#include <vos/mutex.hxx>
#include <com/sun/star/i18n/XBreakIterator.hpp>
#include <com/sun/star/i18n/CharacterIteratorMode.hpp>
#include <com/sun/star/i18n/WordType.hpp>
#include <cppuhelper/weak.hxx>
#include <com/sun/star/datatransfer/XTransferable.hpp>
#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#ifndef _COM_SUN_STAR_DATATRANSFER_DND_DNDCONSTANS_HPP_
#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
#endif
#include <com/sun/star/datatransfer/dnd/XDragGestureRecognizer.hpp>
#include <com/sun/star/datatransfer/dnd/XDropTarget.hpp>
#ifndef _COM_SUN_STAR_I18N_XEXTENDEDINPUTSEQUENCECHECKER_HDL_
#include <com/sun/star/i18n/XExtendedInputSequenceChecker.hpp>
#endif
#include <com/sun/star/i18n/InputSequenceCheckMode.hpp>
#include <com/sun/star/i18n/ScriptType.hpp>
#include <com/sun/star/container/XNameAccess.hpp>
#include <com/sun/star/uno/Any.hxx>
#include <comphelper/processfactory.hxx>
#include <comphelper/configurationhelper.hxx>
#include <sot/exchange.hxx>
#include <sot/formats.hxx>
#include <rtl/memory.h>
#include <vcl/unohelp.hxx>
#include <vcl/unohelp2.hxx>
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;
using namespace ::rtl;
// - Redo
// - Bei Tracking-Cancel DefaultSelection wieder herstellen
// =======================================================================
static FncGetSpecialChars pImplFncGetSpecialChars = NULL;
// =======================================================================
#define EDIT_ALIGN_LEFT 1
#define EDIT_ALIGN_CENTER 2
#define EDIT_ALIGN_RIGHT 3
#define EDIT_DEL_LEFT 1
#define EDIT_DEL_RIGHT 2
#define EDIT_DELMODE_SIMPLE 11
#define EDIT_DELMODE_RESTOFWORD 12
#define EDIT_DELMODE_RESTOFCONTENT 13
// =======================================================================
struct DDInfo
{
Cursor aCursor;
Selection aDndStartSel;
xub_StrLen nDropPos;
sal_Bool bStarterOfDD;
sal_Bool bDroppedInMe;
sal_Bool bVisCursor;
sal_Bool bIsStringSupported;
DDInfo()
{
aCursor.SetStyle( CURSOR_SHADOW );
nDropPos = 0;
bStarterOfDD = sal_False;
bDroppedInMe = sal_False;
bVisCursor = sal_False;
bIsStringSupported = sal_False;
}
};
// =======================================================================
struct Impl_IMEInfos
{
String aOldTextAfterStartPos;
sal_uInt16* pAttribs;
xub_StrLen nPos;
xub_StrLen nLen;
sal_Bool bCursor;
sal_Bool bWasCursorOverwrite;
Impl_IMEInfos( xub_StrLen nPos, const String& rOldTextAfterStartPos );
~Impl_IMEInfos();
void CopyAttribs( const xub_StrLen* pA, xub_StrLen nL );
void DestroyAttribs();
};
// -----------------------------------------------------------------------
Impl_IMEInfos::Impl_IMEInfos( xub_StrLen nP, const String& rOldTextAfterStartPos )
: aOldTextAfterStartPos( rOldTextAfterStartPos )
{
nPos = nP;
nLen = 0;
bCursor = sal_True;
pAttribs = NULL;
bWasCursorOverwrite = sal_False;
}
// -----------------------------------------------------------------------
Impl_IMEInfos::~Impl_IMEInfos()
{
delete[] pAttribs;
}
// -----------------------------------------------------------------------
void Impl_IMEInfos::CopyAttribs( const xub_StrLen* pA, xub_StrLen nL )
{
nLen = nL;
delete[] pAttribs;
pAttribs = new sal_uInt16[ nL ];
rtl_copyMemory( pAttribs, pA, nL*sizeof(sal_uInt16) );
}
// -----------------------------------------------------------------------
void Impl_IMEInfos::DestroyAttribs()
{
delete[] pAttribs;
pAttribs = NULL;
nLen = 0;
}
// =======================================================================
Edit::Edit( WindowType nType ) :
Control( nType )
{
ImplInitEditData();
}
// -----------------------------------------------------------------------
Edit::Edit( Window* pParent, WinBits nStyle ) :
Control( WINDOW_EDIT )
{
ImplInitEditData();
ImplInit( pParent, nStyle );
}
// -----------------------------------------------------------------------
Edit::Edit( Window* pParent, const ResId& rResId ) :
Control( WINDOW_EDIT )
{
ImplInitEditData();
rResId.SetRT( RSC_EDIT );
WinBits nStyle = ImplInitRes( rResId );
ImplInit( pParent, nStyle );
ImplLoadRes( rResId );
// Derived MultiLineEdit takes care to call Show only after MultiLineEdit
// ctor has already started:
if ( !(nStyle & WB_HIDE) && rResId.GetRT() != RSC_MULTILINEEDIT )
Show();
}
// -----------------------------------------------------------------------
Edit::Edit( Window* pParent, const ResId& rResId, bool bDisableAccessibleLabeledByRelation ) :
Control( WINDOW_EDIT )
{
ImplInitEditData();
rResId.SetRT( RSC_EDIT );
WinBits nStyle = ImplInitRes( rResId );
ImplInit( pParent, nStyle );
ImplLoadRes( rResId );
if ( bDisableAccessibleLabeledByRelation )
ImplGetWindowImpl()->mbDisableAccessibleLabeledByRelation = sal_True;
// Derived MultiLineEdit takes care to call Show only after MultiLineEdit
// ctor has already started:
if ( !(nStyle & WB_HIDE) && rResId.GetRT() != RSC_MULTILINEEDIT )
Show();
}
// -----------------------------------------------------------------------
Edit::~Edit()
{
delete mpDDInfo;
Cursor* pCursor = GetCursor();
if ( pCursor )
{
SetCursor( NULL );
delete pCursor;
}
delete mpIMEInfos;
if ( mpUpdateDataTimer )
delete mpUpdateDataTimer;
if ( mxDnDListener.is() )
{
if ( GetDragGestureRecognizer().is() )
{
uno::Reference< datatransfer::dnd::XDragGestureListener> xDGL( mxDnDListener, uno::UNO_QUERY );
GetDragGestureRecognizer()->removeDragGestureListener( xDGL );
}
if ( GetDropTarget().is() )
{
uno::Reference< datatransfer::dnd::XDropTargetListener> xDTL( mxDnDListener, uno::UNO_QUERY );
GetDropTarget()->removeDropTargetListener( xDTL );
}
uno::Reference< lang::XEventListener> xEL( mxDnDListener, uno::UNO_QUERY );
xEL->disposing( lang::EventObject() ); // #95154# #96585# Empty Source means it's the Client
}
}
// -----------------------------------------------------------------------
void Edit::ImplInitEditData()
{
mpSubEdit = NULL;
mpUpdateDataTimer = NULL;
mnXOffset = 0;
mnAlign = EDIT_ALIGN_LEFT;
mnMaxTextLen = EDIT_NOLIMIT;
meAutocompleteAction = AUTOCOMPLETE_KEYINPUT;
mbModified = sal_False;
mbInternModified = sal_False;
mbReadOnly = sal_False;
mbInsertMode = sal_True;
mbClickedInSelection = sal_False;
mbActivePopup = sal_False;
mbIsSubEdit = sal_False;
mbInMBDown = sal_False;
mpDDInfo = NULL;
mpIMEInfos = NULL;
mcEchoChar = 0;
// --- RTL --- no default mirroring for Edit controls
// note: controls that use a subedit will revert this (SpinField, ComboBox)
EnableRTL( sal_False );
vcl::unohelper::DragAndDropWrapper* pDnDWrapper = new vcl::unohelper::DragAndDropWrapper( this );
mxDnDListener = pDnDWrapper;
}
// -----------------------------------------------------------------------
bool Edit::ImplUseNativeBorder( WinBits nStyle )
{
bool bRet =
IsNativeControlSupported(ImplGetNativeControlType(), HAS_BACKGROUND_TEXTURE)
&& ((nStyle&WB_BORDER) && !(nStyle&WB_NOBORDER));
if( ! bRet && mbIsSubEdit )
{
Window* pWindow = GetParent();
nStyle = pWindow->GetStyle();
bRet = pWindow->IsNativeControlSupported(ImplGetNativeControlType(), HAS_BACKGROUND_TEXTURE)
&& ((nStyle&WB_BORDER) && !(nStyle&WB_NOBORDER));
}
return bRet;
}
void Edit::ImplInit( Window* pParent, WinBits nStyle )
{
nStyle = ImplInitStyle( nStyle );
if ( !(nStyle & (WB_CENTER | WB_RIGHT)) )
nStyle |= WB_LEFT;
Control::ImplInit( pParent, nStyle, NULL );
mbReadOnly = (nStyle & WB_READONLY) != 0;
mnAlign = EDIT_ALIGN_LEFT;
// --- RTL --- hack: right align until keyinput and cursor travelling works
if( IsRTLEnabled() )
mnAlign = EDIT_ALIGN_RIGHT;
if ( nStyle & WB_RIGHT )
mnAlign = EDIT_ALIGN_RIGHT;
else if ( nStyle & WB_CENTER )
mnAlign = EDIT_ALIGN_CENTER;
SetCursor( new Cursor );
SetPointer( Pointer( POINTER_TEXT ) );
ImplInitSettings( sal_True, sal_True, sal_True );
uno::Reference< datatransfer::dnd::XDragGestureListener> xDGL( mxDnDListener, uno::UNO_QUERY );
uno::Reference< datatransfer::dnd::XDragGestureRecognizer > xDGR = GetDragGestureRecognizer();
if ( xDGR.is() )
{
xDGR->addDragGestureListener( xDGL );
uno::Reference< datatransfer::dnd::XDropTargetListener> xDTL( mxDnDListener, uno::UNO_QUERY );
GetDropTarget()->addDropTargetListener( xDTL );
GetDropTarget()->setActive( sal_True );
GetDropTarget()->setDefaultActions( datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE );
}
}
// -----------------------------------------------------------------------
WinBits Edit::ImplInitStyle( WinBits nStyle )
{
if ( !(nStyle & WB_NOTABSTOP) )
nStyle |= WB_TABSTOP;
if ( !(nStyle & WB_NOGROUP) )
nStyle |= WB_GROUP;
return nStyle;
}
// -----------------------------------------------------------------------
sal_Bool Edit::IsCharInput( const KeyEvent& rKeyEvent )
{
// In the future we must use new Unicode functions for this
xub_Unicode cCharCode = rKeyEvent.GetCharCode();
return ((cCharCode >= 32) && (cCharCode != 127) &&
!rKeyEvent.GetKeyCode().IsMod3() &&
!rKeyEvent.GetKeyCode().IsMod2() &&
!rKeyEvent.GetKeyCode().IsMod1() );
}
// -----------------------------------------------------------------------
void Edit::ImplModified()
{
mbModified = sal_True;
Modify();
}
// -----------------------------------------------------------------------
void Edit::ImplInitSettings( sal_Bool bFont, sal_Bool bForeground, sal_Bool bBackground )
{
const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
if ( bFont )
{
Font aFont = rStyleSettings.GetFieldFont();
if ( IsControlFont() )
aFont.Merge( GetControlFont() );
SetZoomedPointFont( aFont );
ImplClearLayoutData();
}
if ( bFont || bForeground )
{
Color aTextColor = rStyleSettings.GetFieldTextColor();
if ( IsControlForeground() )
aTextColor = GetControlForeground();
SetTextColor( aTextColor );
}
if ( bBackground )
{
if ( ImplUseNativeBorder( GetStyle() ) || IsPaintTransparent() )
{
// Transparent background
SetBackground();
SetFillColor();
}
else if ( IsControlBackground() )
{
SetBackground( GetControlBackground() );
SetFillColor( GetControlBackground() );
}
else
{
SetBackground( rStyleSettings.GetFieldColor() );
SetFillColor( rStyleSettings.GetFieldColor() );
}
}
}
// -----------------------------------------------------------------------
long Edit::ImplGetExtraOffset() const
{
// MT 09/2002: nExtraOffsetX should become a member, instead of checking every time,
// but I need an incompatible update for this...
// #94095# Use extra offset only when edit has a border
long nExtraOffset = 0;
if( ( GetStyle() & WB_BORDER ) || ( mbIsSubEdit && ( GetParent()->GetStyle() & WB_BORDER ) ) )
nExtraOffset = 2;
return nExtraOffset;
}
// -----------------------------------------------------------------------
XubString Edit::ImplGetText() const
{
if ( mcEchoChar || (GetStyle() & WB_PASSWORD) )
{
XubString aText;
xub_Unicode cEchoChar;
if ( mcEchoChar )
cEchoChar = mcEchoChar;
else
cEchoChar = '*';
aText.Fill( maText.Len(), cEchoChar );
return aText;
}
else
return maText;
}
// -----------------------------------------------------------------------
void Edit::ImplInvalidateOrRepaint( xub_StrLen nStart, xub_StrLen nEnd )
{
if( IsPaintTransparent() )
{
Invalidate();
// FIXME: this is currently only on aqua
if( ImplGetSVData()->maNWFData.mbNoFocusRects )
Update();
}
else
ImplRepaint( nStart, nEnd );
}
// -----------------------------------------------------------------------
long Edit::ImplGetTextYPosition() const
{
if ( GetStyle() & WB_TOP )
return ImplGetExtraOffset();
else if ( GetStyle() & WB_BOTTOM )
return GetOutputSizePixel().Height() - GetTextHeight() - ImplGetExtraOffset();
return ( GetOutputSizePixel().Height() - GetTextHeight() ) / 2;
}
// -----------------------------------------------------------------------
void Edit::ImplRepaint( xub_StrLen nStart, xub_StrLen nEnd, bool bLayout )
{
if ( !IsReallyVisible() )
return;
XubString aText = ImplGetText();
nStart = 0;
nEnd = aText.Len();
sal_Int32 nDXBuffer[256];
sal_Int32* pDXBuffer = NULL;
sal_Int32* pDX = nDXBuffer;
if( aText.Len() )
{
if( 2*aText.Len() > xub_StrLen(sizeof(nDXBuffer)/sizeof(nDXBuffer[0])) )
{
pDXBuffer = new sal_Int32[2*(aText.Len()+1)];
pDX = pDXBuffer;
}
GetCaretPositions( aText, pDX, nStart, nEnd );
}
long nTH = GetTextHeight();
Point aPos( mnXOffset, ImplGetTextYPosition() );
if( bLayout )
{
long nPos = nStart ? pDX[2*nStart] : 0;
aPos.X() = nPos + mnXOffset + ImplGetExtraOffset();
MetricVector* pVector = &mpControlData->mpLayoutData->m_aUnicodeBoundRects;
String* pDisplayText = &mpControlData->mpLayoutData->m_aDisplayText;
DrawText( aPos, aText, nStart, nEnd - nStart, pVector, pDisplayText );
if( pDXBuffer )
delete [] pDXBuffer;
return;
}
Cursor* pCursor = GetCursor();
sal_Bool bVisCursor = pCursor ? pCursor->IsVisible() : sal_False;
if ( pCursor )
pCursor->Hide();
ImplClearBackground( 0, GetOutputSizePixel().Width() );
const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
if ( IsEnabled() )
ImplInitSettings( sal_False, sal_True, sal_False );
else
SetTextColor( rStyleSettings.GetDisableColor() );
// Set background color of the normal text
if( (GetStyle() & WB_FORCECTRLBACKGROUND) != 0 && IsControlBackground() )
{
// check if we need to set ControlBackground even in NWF case
Push( PUSH_FILLCOLOR | PUSH_LINECOLOR );
SetLineColor();
SetFillColor( GetControlBackground() );
DrawRect( Rectangle( aPos, Size( GetOutputSizePixel().Width() - 2*mnXOffset, nTH ) ) );
Pop();
SetTextFillColor( GetControlBackground() );
}
else if( IsPaintTransparent() || ImplUseNativeBorder( GetStyle() ) )
SetTextFillColor();
else
SetTextFillColor( IsControlBackground() ? GetControlBackground() : rStyleSettings.GetFieldColor() );
sal_Bool bDrawSelection = maSelection.Len() && ( HasFocus() || ( GetStyle() & WB_NOHIDESELECTION ) || mbActivePopup );
long nPos = nStart ? pDX[2*nStart] : 0;
aPos.X() = nPos + mnXOffset + ImplGetExtraOffset();
if ( !bDrawSelection && !mpIMEInfos )
{
DrawText( aPos, aText, nStart, nEnd - nStart );
}
else
{
// save graphics state
Push();
// first calculate higlighted and non highlighted clip regions
Region aHiglightClipRegion;
Region aNormalClipRegion;
Selection aTmpSel( maSelection );
aTmpSel.Justify();
// selection is highlighted
int i;
for( i = 0; i < aText.Len(); i++ )
{
Rectangle aRect( aPos, Size( 10, nTH ) );
aRect.Left() = pDX[2*i] + mnXOffset + ImplGetExtraOffset();
aRect.Right() = pDX[2*i+1] + mnXOffset + ImplGetExtraOffset();
aRect.Justify();
bool bHighlight = false;
if( i >= aTmpSel.Min() && i < aTmpSel.Max() )
bHighlight = true;
if( mpIMEInfos && mpIMEInfos->pAttribs &&
i >= mpIMEInfos->nPos && i < (mpIMEInfos->nPos+mpIMEInfos->nLen ) &&
( mpIMEInfos->pAttribs[i-mpIMEInfos->nPos] & EXTTEXTINPUT_ATTR_HIGHLIGHT) )
bHighlight = true;
if( bHighlight )
aHiglightClipRegion.Union( aRect );
else
aNormalClipRegion.Union( aRect );
}
// draw normal text
Color aNormalTextColor = GetTextColor();
SetClipRegion( aNormalClipRegion );
if( IsPaintTransparent() )
SetTextFillColor();
else
{
// Set background color when part of the text is selected
if ( ImplUseNativeBorder( GetStyle() ) )
{
if( (GetStyle() & WB_FORCECTRLBACKGROUND) != 0 && IsControlBackground() )
SetTextFillColor( GetControlBackground() );
else
SetTextFillColor();
}
else
SetTextFillColor( IsControlBackground() ? GetControlBackground() : rStyleSettings.GetFieldColor() );
}
DrawText( aPos, aText, nStart, nEnd - nStart );
// draw highlighted text
SetClipRegion( aHiglightClipRegion );
SetTextColor( rStyleSettings.GetHighlightTextColor() );
SetTextFillColor( rStyleSettings.GetHighlightColor() );
DrawText( aPos, aText, nStart, nEnd - nStart );
// if IME info exists loop over portions and output different font attributes
if( mpIMEInfos && mpIMEInfos->pAttribs )
{
for( int n = 0; n < 2; n++ )
{
Region aRegion;
if( n == 0 )
{
SetTextColor( aNormalTextColor );
if( IsPaintTransparent() )
SetTextFillColor();
else
SetTextFillColor( IsControlBackground() ? GetControlBackground() : rStyleSettings.GetFieldColor() );
aRegion = aNormalClipRegion;
}
else
{
SetTextColor( rStyleSettings.GetHighlightTextColor() );
SetTextFillColor( rStyleSettings.GetHighlightColor() );
aRegion = aHiglightClipRegion;
}
for( i = 0; i < mpIMEInfos->nLen; )
{
sal_uInt16 nAttr = mpIMEInfos->pAttribs[i];
Region aClip;
int nIndex = i;
while( nIndex < mpIMEInfos->nLen && mpIMEInfos->pAttribs[nIndex] == nAttr) // #112631# check nIndex before using it
{
Rectangle aRect( aPos, Size( 10, nTH ) );
aRect.Left() = pDX[2*(nIndex+mpIMEInfos->nPos)] + mnXOffset + ImplGetExtraOffset();
aRect.Right() = pDX[2*(nIndex+mpIMEInfos->nPos)+1] + mnXOffset + ImplGetExtraOffset();
aRect.Justify();
aClip.Union( aRect );
nIndex++;
}
i = nIndex;
if( aClip.Intersect( aRegion ) && nAttr )
{
Font aFont = GetFont();
if ( nAttr & EXTTEXTINPUT_ATTR_UNDERLINE )
aFont.SetUnderline( UNDERLINE_SINGLE );
else if ( nAttr & EXTTEXTINPUT_ATTR_BOLDUNDERLINE )
aFont.SetUnderline( UNDERLINE_BOLD );
else if ( nAttr & EXTTEXTINPUT_ATTR_DOTTEDUNDERLINE )
aFont.SetUnderline( UNDERLINE_DOTTED );
else if ( nAttr & EXTTEXTINPUT_ATTR_DASHDOTUNDERLINE )
aFont.SetUnderline( UNDERLINE_DOTTED );
else if ( nAttr & EXTTEXTINPUT_ATTR_GRAYWAVELINE )
{
aFont.SetUnderline( UNDERLINE_WAVE );
SetTextLineColor( Color( COL_LIGHTGRAY ) );
}
SetFont( aFont );
if ( nAttr & EXTTEXTINPUT_ATTR_REDTEXT )
SetTextColor( Color( COL_RED ) );
else if ( nAttr & EXTTEXTINPUT_ATTR_HALFTONETEXT )
SetTextColor( Color( COL_LIGHTGRAY ) );
SetClipRegion( aClip );
DrawText( aPos, aText, nStart, nEnd - nStart );
}
}
}
}
// restore graphics state
Pop();
}
if ( bVisCursor && ( !mpIMEInfos || mpIMEInfos->bCursor ) )
pCursor->Show();
if( pDXBuffer )
delete [] pDXBuffer;
}
// -----------------------------------------------------------------------
void Edit::ImplDelete( const Selection& rSelection, sal_uInt8 nDirection, sal_uInt8 nMode )
{
XubString aText = ImplGetText();
// loeschen moeglich?
if ( !rSelection.Len() &&
(((rSelection.Min() == 0) && (nDirection == EDIT_DEL_LEFT)) ||
((rSelection.Max() == aText.Len()) && (nDirection == EDIT_DEL_RIGHT))) )
return;
ImplClearLayoutData();
Selection aSelection( rSelection );
aSelection.Justify();
if ( !aSelection.Len() )
{
uno::Reference < i18n::XBreakIterator > xBI = ImplGetBreakIterator();
if ( nDirection == EDIT_DEL_LEFT )
{
if ( nMode == EDIT_DELMODE_RESTOFWORD )
{
i18n::Boundary aBoundary = xBI->getWordBoundary( maText, aSelection.Min(), GetSettings().GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True );
if ( aBoundary.startPos == aSelection.Min() )
aBoundary = xBI->previousWord( maText, aSelection.Min(), GetSettings().GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES );
aSelection.Min() = aBoundary.startPos;
}
else if ( nMode == EDIT_DELMODE_RESTOFCONTENT )
{
aSelection.Min() = 0;
}
else
{
sal_Int32 nCount = 1;
aSelection.Min() = xBI->previousCharacters( maText, aSelection.Min(), GetSettings().GetLocale(), i18n::CharacterIteratorMode::SKIPCHARACTER, nCount, nCount );
}
}
else
{
if ( nMode == EDIT_DELMODE_RESTOFWORD )
{
i18n::Boundary aBoundary = xBI->nextWord( maText, aSelection.Max(), GetSettings().GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES );
aSelection.Max() = aBoundary.startPos;
}
else if ( nMode == EDIT_DELMODE_RESTOFCONTENT )
{
aSelection.Max() = aText.Len();
}
else
{
sal_Int32 nCount = 1;
aSelection.Max() = xBI->nextCharacters( maText, aSelection.Max(), GetSettings().GetLocale(), i18n::CharacterIteratorMode::SKIPCHARACTER, nCount, nCount );;
}
}
}
maText.Erase( (xub_StrLen)aSelection.Min(), (xub_StrLen)aSelection.Len() );
maSelection.Min() = aSelection.Min();
maSelection.Max() = aSelection.Min();
ImplAlignAndPaint();
mbInternModified = sal_True;
}
// -----------------------------------------------------------------------
String Edit::ImplGetValidString( const String& rString ) const
{
String aValidString( rString );
aValidString.EraseAllChars( _LF );
aValidString.EraseAllChars( _CR );
aValidString.SearchAndReplaceAll( '\t', ' ' );
return aValidString;
}
// -----------------------------------------------------------------------
uno::Reference < i18n::XBreakIterator > Edit::ImplGetBreakIterator() const
{
//!! since we don't want to become incompatible in the next minor update
//!! where this code will get integrated into, xISC will be a local
//!! variable instead of a class member!
uno::Reference < i18n::XBreakIterator > xBI;
// if ( !xBI.is() )
{
uno::Reference< lang::XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory();
uno::Reference < XInterface > xI = xMSF->createInstance( OUString::createFromAscii( "com.sun.star.i18n.BreakIterator" ) );
if ( xI.is() )
{
Any x = xI->queryInterface( ::getCppuType((const uno::Reference< i18n::XBreakIterator >*)0) );
x >>= xBI;
}
}
return xBI;
}
// -----------------------------------------------------------------------
uno::Reference < i18n::XExtendedInputSequenceChecker > Edit::ImplGetInputSequenceChecker() const
{
//!! since we don't want to become incompatible in the next minor update
//!! where this code will get integrated into, xISC will be a local
//!! variable instead of a class member!
uno::Reference < i18n::XExtendedInputSequenceChecker > xISC;
// if ( !xISC.is() )
{
uno::Reference< lang::XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory();
uno::Reference < XInterface > xI = xMSF->createInstance( OUString::createFromAscii( "com.sun.star.i18n.InputSequenceChecker" ) );
if ( xI.is() )
{
Any x = xI->queryInterface( ::getCppuType((const uno::Reference< i18n::XExtendedInputSequenceChecker >*)0) );
x >>= xISC;
}
}
return xISC;
}
// -----------------------------------------------------------------------
void Edit::ShowTruncationWarning( Window* pParent )
{
ResMgr* pResMgr = ImplGetResMgr();
if( pResMgr )
{
WarningBox aBox( pParent, ResId( SV_EDIT_WARNING_BOX, *pResMgr ) );
aBox.Execute();
}
}
// -----------------------------------------------------------------------
bool Edit::ImplTruncateToMaxLen( rtl::OUString& rStr, sal_uInt32 nSelectionLen ) const
{
bool bWasTruncated = false;
const sal_uInt32 nMaxLen = mnMaxTextLen < 65534 ? mnMaxTextLen : 65534;
sal_uInt32 nLenAfter = static_cast<sal_uInt32>(maText.Len()) + rStr.getLength() - nSelectionLen;
if ( nLenAfter > nMaxLen )
{
sal_uInt32 nErasePos = nMaxLen - static_cast<sal_uInt32>(maText.Len()) + nSelectionLen;
rStr = rStr.copy( 0, nErasePos );
bWasTruncated = true;
}
return bWasTruncated;
}
// -----------------------------------------------------------------------
void Edit::ImplInsertText( const XubString& rStr, const Selection* pNewSel, sal_Bool bIsUserInput )
{
Selection aSelection( maSelection );
aSelection.Justify();
rtl::OUString aNewText( ImplGetValidString( rStr ) );
ImplTruncateToMaxLen( aNewText, aSelection.Len() );
ImplClearLayoutData();
if ( aSelection.Len() )
maText.Erase( (xub_StrLen)aSelection.Min(), (xub_StrLen)aSelection.Len() );
else if ( !mbInsertMode && (aSelection.Max() < maText.Len()) )
maText.Erase( (xub_StrLen)aSelection.Max(), 1 );
// take care of input-sequence-checking now
if (bIsUserInput && rStr.Len())
{
DBG_ASSERT( rStr.Len() == 1, "unexpected string length. User input is expected to providse 1 char only!" );
// determine if input-sequence-checking should be applied or not
//
static OUString sModule( OUString::createFromAscii( "/org.openoffice.Office.Common/I18N" ) );
static OUString sRelNode( OUString::createFromAscii( "CTL" ) );
static OUString sCTLSequenceChecking( OUString::createFromAscii( "CTLSequenceChecking" ) );
static OUString sCTLSequenceCheckingRestricted( OUString::createFromAscii( "CTLSequenceCheckingRestricted" ) );
static OUString sCTLSequenceCheckingTypeAndReplace( OUString::createFromAscii( "CTLSequenceCheckingTypeAndReplace" ) );
static OUString sCTLFont( OUString::createFromAscii( "CTLFont" ) );
//
sal_Bool bCTLSequenceChecking = sal_False;
sal_Bool bCTLSequenceCheckingRestricted = sal_False;
sal_Bool bCTLSequenceCheckingTypeAndReplace = sal_False;
sal_Bool bCTLFontEnabled = sal_False;
sal_Bool bIsInputSequenceChecking = sal_False;
//
// get access to the configuration of this office module
try
{
uno::Reference< lang::XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory();
uno::Reference< container::XNameAccess > xModuleCfg( ::comphelper::ConfigurationHelper::openConfig(
xMSF,
sModule,
::comphelper::ConfigurationHelper::E_READONLY ),
uno::UNO_QUERY );
//!! get values from configuration.
//!! we can't use SvtCTLOptions here since vcl must not be linked
//!! against svtools. (It is already the other way around.)
Any aCTLSequenceChecking = ::comphelper::ConfigurationHelper::readRelativeKey( xModuleCfg, sRelNode, sCTLSequenceChecking );
Any aCTLSequenceCheckingRestricted = ::comphelper::ConfigurationHelper::readRelativeKey( xModuleCfg, sRelNode, sCTLSequenceCheckingRestricted );
Any aCTLSequenceCheckingTypeAndReplace = ::comphelper::ConfigurationHelper::readRelativeKey( xModuleCfg, sRelNode, sCTLSequenceCheckingTypeAndReplace );
Any aCTLFontEnabled = ::comphelper::ConfigurationHelper::readRelativeKey( xModuleCfg, sRelNode, sCTLFont );
aCTLSequenceChecking >>= bCTLSequenceChecking;
aCTLSequenceCheckingRestricted >>= bCTLSequenceCheckingRestricted;
aCTLSequenceCheckingTypeAndReplace >>= bCTLSequenceCheckingTypeAndReplace;
aCTLFontEnabled >>= bCTLFontEnabled;
}
catch(...)
{
bIsInputSequenceChecking = sal_False; // continue with inserting the new text
}
//
uno::Reference < i18n::XBreakIterator > xBI( ImplGetBreakIterator(), UNO_QUERY );
bIsInputSequenceChecking = rStr.Len() == 1 &&
bCTLFontEnabled &&
bCTLSequenceChecking &&
aSelection.Min() > 0 && /* first char needs not to be checked */
xBI.is() && i18n::ScriptType::COMPLEX == xBI->getScriptType( rStr, 0 );
uno::Reference < i18n::XExtendedInputSequenceChecker > xISC;
if (bIsInputSequenceChecking && (xISC = ImplGetInputSequenceChecker()).is())
{
sal_Unicode cChar = rStr.GetChar(0);
xub_StrLen nTmpPos = static_cast< xub_StrLen >( aSelection.Min() );
sal_Int16 nCheckMode = bCTLSequenceCheckingRestricted ?
i18n::InputSequenceCheckMode::STRICT : i18n::InputSequenceCheckMode::BASIC;
// the text that needs to be checked is only the one
// before the current cursor position
rtl::OUString aOldText( maText.Copy(0, nTmpPos) );
rtl::OUString aTmpText( aOldText );
if (bCTLSequenceCheckingTypeAndReplace)
{
xISC->correctInputSequence( aTmpText, nTmpPos - 1, cChar, nCheckMode );
// find position of first character that has changed
sal_Int32 nOldLen = aOldText.getLength();
sal_Int32 nTmpLen = aTmpText.getLength();
const sal_Unicode *pOldTxt = aOldText.getStr();
const sal_Unicode *pTmpTxt = aTmpText.getStr();
sal_Int32 nChgPos = 0;
while ( nChgPos < nOldLen && nChgPos < nTmpLen &&
pOldTxt[nChgPos] == pTmpTxt[nChgPos] )
++nChgPos;
xub_StrLen nChgLen = static_cast< xub_StrLen >( nTmpLen - nChgPos );
String aChgText( aTmpText.copy( nChgPos ).getStr(), nChgLen );
// remove text from first pos to be changed to current pos
maText.Erase( static_cast< xub_StrLen >( nChgPos ), static_cast< xub_StrLen >( nTmpPos - nChgPos ) );
if (aChgText.Len())
{
aNewText = aChgText;
aSelection.Min() = nChgPos; // position for new text to be inserted
}
else
aNewText = String::EmptyString();
}
else
{
// should the character be ignored (i.e. not get inserted) ?
if (!xISC->checkInputSequence( aOldText, nTmpPos - 1, cChar, nCheckMode ))
aNewText = String::EmptyString();
}
}
// at this point now we will insert the non-empty text 'normally' some lines below...
}
if ( aNewText.getLength() )
maText.Insert( String( aNewText ), (xub_StrLen)aSelection.Min() );
if ( !pNewSel )
{
maSelection.Min() = aSelection.Min() + aNewText.getLength();
maSelection.Max() = maSelection.Min();
}
else
{
maSelection = *pNewSel;
if ( maSelection.Min() > maText.Len() )
maSelection.Min() = maText.Len();
if ( maSelection.Max() > maText.Len() )
maSelection.Max() = maText.Len();
}
ImplAlignAndPaint();
mbInternModified = sal_True;
}
// -----------------------------------------------------------------------
void Edit::ImplSetText( const XubString& rText, const Selection* pNewSelection )
{
// Der Text wird dadurch geloescht das der alte Text komplett 'selektiert'
// wird, dann InsertText, damit flackerfrei.
if ( ( rText.Len() <= mnMaxTextLen ) && ( (rText != maText) || (pNewSelection && (*pNewSelection != maSelection)) ) )
{
ImplClearLayoutData();
maSelection.Min() = 0;
maSelection.Max() = maText.Len();
if ( mnXOffset || HasPaintEvent() )
{
mnXOffset = 0;
maText = ImplGetValidString( rText );
// #i54929# recalculate mnXOffset before ImplSetSelection,
// else cursor ends up in wrong position
ImplAlign();
if ( pNewSelection )
ImplSetSelection( *pNewSelection, sal_False );
if ( mnXOffset && !pNewSelection )
maSelection.Max() = 0;
Invalidate();
}
else
ImplInsertText( rText, pNewSelection );
ImplCallEventListeners( VCLEVENT_EDIT_MODIFY );
}
}
// -----------------------------------------------------------------------
int Edit::ImplGetNativeControlType()
{
int nCtrl = 0;
Window *pControl = mbIsSubEdit ? GetParent() : this;
switch( pControl->GetType() )
{
case WINDOW_COMBOBOX:
case WINDOW_PATTERNBOX:
case WINDOW_NUMERICBOX:
case WINDOW_METRICBOX:
case WINDOW_CURRENCYBOX:
case WINDOW_DATEBOX:
case WINDOW_TIMEBOX:
case WINDOW_LONGCURRENCYBOX:
nCtrl = CTRL_COMBOBOX;
break;
case WINDOW_MULTILINEEDIT:
if ( GetWindow( WINDOW_BORDER ) != this )
nCtrl = CTRL_MULTILINE_EDITBOX;
else
nCtrl = CTRL_EDITBOX_NOBORDER;
break;
case WINDOW_EDIT:
case WINDOW_PATTERNFIELD:
case WINDOW_METRICFIELD:
case WINDOW_CURRENCYFIELD:
case WINDOW_DATEFIELD:
case WINDOW_TIMEFIELD:
case WINDOW_LONGCURRENCYFIELD:
case WINDOW_NUMERICFIELD:
case WINDOW_SPINFIELD:
if( pControl->GetStyle() & WB_SPIN )
nCtrl = CTRL_SPINBOX;
else
{
if ( GetWindow( WINDOW_BORDER ) != this )
nCtrl = CTRL_EDITBOX;
else
nCtrl = CTRL_EDITBOX_NOBORDER;
}
break;
default:
nCtrl = CTRL_EDITBOX;
}
return nCtrl;
}
void Edit::ImplClearBackground( long nXStart, long nXEnd )
{
/*
* note: at this point the cursor must be switched off already
*/
Point aTmpPoint;
Rectangle aRect( aTmpPoint, GetOutputSizePixel() );
aRect.Left() = nXStart;
aRect.Right() = nXEnd;
if( ImplUseNativeBorder( GetStyle() ) || IsPaintTransparent() )
{
// draw the inner part by painting the whole control using its border window
Window *pControl = this;
Window *pBorder = GetWindow( WINDOW_BORDER );
if( pBorder == this )
{
// we have no border, use parent
pControl = mbIsSubEdit ? GetParent() : this;
pBorder = pControl->GetWindow( WINDOW_BORDER );
if( pBorder == this )
pBorder = GetParent();
}
if( pBorder )
{
// set proper clipping region to not overdraw the whole control
Region aClipRgn = GetPaintRegion();
if( !aClipRgn.IsNull() )
{
// transform clipping region to border window's coordinate system
if( IsRTLEnabled() != pBorder->IsRTLEnabled() && Application::GetSettings().GetLayoutRTL() )
{
// need to mirror in case border is not RTL but edit is (or vice versa)
// mirror
Rectangle aBounds( aClipRgn.GetBoundRect() );
int xNew = GetOutputSizePixel().Width() - aBounds.GetWidth() - aBounds.Left();
aClipRgn.Move( xNew - aBounds.Left(), 0 );
// move offset of border window
Point aBorderOffs;
aBorderOffs = pBorder->ScreenToOutputPixel( OutputToScreenPixel( aBorderOffs ) );
aClipRgn.Move( aBorderOffs.X(), aBorderOffs.Y() );
}
else
{
// normal case
Point aBorderOffs;
aBorderOffs = pBorder->ScreenToOutputPixel( OutputToScreenPixel( aBorderOffs ) );
aClipRgn.Move( aBorderOffs.X(), aBorderOffs.Y() );
}
Region oldRgn( pBorder->GetClipRegion() );
pBorder->SetClipRegion( aClipRgn );
pBorder->Paint( Rectangle() );
pBorder->SetClipRegion( oldRgn );
}
else
pBorder->Paint( Rectangle() );
}
}
else
Erase( aRect );
}
// -----------------------------------------------------------------------
void Edit::ImplShowCursor( sal_Bool bOnlyIfVisible )
{
if ( !IsUpdateMode() || ( bOnlyIfVisible && !IsReallyVisible() ) )
return;
Cursor* pCursor = GetCursor();
XubString aText = ImplGetText();
long nTextPos = 0;
sal_Int32 nDXBuffer[256];
sal_Int32* pDXBuffer = NULL;
sal_Int32* pDX = nDXBuffer;
if( aText.Len() )
{
if( 2*aText.Len() > xub_StrLen(sizeof(nDXBuffer)/sizeof(nDXBuffer[0])) )
{
pDXBuffer = new sal_Int32[2*(aText.Len()+1)];
pDX = pDXBuffer;
}
GetCaretPositions( aText, pDX, 0, aText.Len() );
if( maSelection.Max() < aText.Len() )
nTextPos = pDX[ 2*maSelection.Max() ];
else
nTextPos = pDX[ 2*aText.Len()-1 ];
}
long nCursorWidth = 0;
if ( !mbInsertMode && !maSelection.Len() && (maSelection.Max() < aText.Len()) )
nCursorWidth = GetTextWidth( aText, (xub_StrLen)maSelection.Max(), 1 );
long nCursorPosX = nTextPos + mnXOffset + ImplGetExtraOffset();
// Cursor muss im sichtbaren Bereich landen:
const Size aOutSize = GetOutputSizePixel();
if ( (nCursorPosX < 0) || (nCursorPosX >= aOutSize.Width()) )
{
long nOldXOffset = mnXOffset;
if ( nCursorPosX < 0 )
{
mnXOffset = - nTextPos;
long nMaxX = 0;
mnXOffset += aOutSize.Width() / 5;
if ( mnXOffset > nMaxX )
mnXOffset = nMaxX;
}
else
{
mnXOffset = (aOutSize.Width()-ImplGetExtraOffset()) - nTextPos;
// Etwas mehr?
if ( (aOutSize.Width()-ImplGetExtraOffset()) < nTextPos )
{
long nMaxNegX = (aOutSize.Width()-ImplGetExtraOffset()) - GetTextWidth( aText );
mnXOffset -= aOutSize.Width() / 5;
if ( mnXOffset < nMaxNegX ) // beides negativ...
mnXOffset = nMaxNegX;
}
}
nCursorPosX = nTextPos + mnXOffset + ImplGetExtraOffset();
if ( nCursorPosX == aOutSize.Width() ) // dann nicht sichtbar...
nCursorPosX--;
if ( mnXOffset != nOldXOffset )
ImplInvalidateOrRepaint();
}
const long nTextHeight = GetTextHeight();
const long nCursorPosY = ImplGetTextYPosition();
pCursor->SetPos( Point( nCursorPosX, nCursorPosY ) );
pCursor->SetSize( Size( nCursorWidth, nTextHeight ) );
pCursor->Show();
if( pDXBuffer )
delete [] pDXBuffer;
}
// -----------------------------------------------------------------------
void Edit::ImplAlign()
{
long nTextWidth = GetTextWidth( ImplGetText() );
long nOutWidth = GetOutputSizePixel().Width();
if ( mnAlign == EDIT_ALIGN_LEFT )
{
if( mnXOffset && ( nTextWidth < nOutWidth ) )
mnXOffset = 0;
}
else if ( mnAlign == EDIT_ALIGN_RIGHT )
{
long nMinXOffset = nOutWidth - nTextWidth - 1 - ImplGetExtraOffset();
bool bRTL = IsRTLEnabled();
if( mbIsSubEdit && GetParent() )
bRTL = GetParent()->IsRTLEnabled();
if( bRTL )
{
if( nTextWidth < nOutWidth )
mnXOffset = nMinXOffset;
}
else
{
if( nTextWidth < nOutWidth )
mnXOffset = nMinXOffset;
else if ( mnXOffset < nMinXOffset )
mnXOffset = nMinXOffset;
}
}
else if( mnAlign == EDIT_ALIGN_CENTER )
{
// Mit Abfrage schoener, wenn gescrollt, dann aber nicht zentriert im gescrollten Zustand...
// if ( nTextWidth < nOutWidth )
mnXOffset = (nOutWidth - nTextWidth) / 2;
}
}
// -----------------------------------------------------------------------
void Edit::ImplAlignAndPaint()
{
ImplAlign();
ImplInvalidateOrRepaint( 0, STRING_LEN );
ImplShowCursor();
}
// -----------------------------------------------------------------------
xub_StrLen Edit::ImplGetCharPos( const Point& rWindowPos ) const
{
xub_StrLen nIndex = STRING_LEN;
String aText = ImplGetText();
sal_Int32 nDXBuffer[256];
sal_Int32* pDXBuffer = NULL;
sal_Int32* pDX = nDXBuffer;
if( 2*aText.Len() > xub_StrLen(sizeof(nDXBuffer)/sizeof(nDXBuffer[0])) )
{
pDXBuffer = new sal_Int32[2*(aText.Len()+1)];
pDX = pDXBuffer;
}
GetCaretPositions( aText, pDX, 0, aText.Len() );
long nX = rWindowPos.X() - mnXOffset - ImplGetExtraOffset();
for( int i = 0; i < aText.Len(); i++ )
{
if( (pDX[2*i] >= nX && pDX[2*i+1] <= nX) ||
(pDX[2*i+1] >= nX && pDX[2*i] <= nX))
{
nIndex = sal::static_int_cast<xub_StrLen>(i);
if( pDX[2*i] < pDX[2*i+1] )
{
if( nX > (pDX[2*i]+pDX[2*i+1])/2 )
nIndex++;
}
else
{
if( nX < (pDX[2*i]+pDX[2*i+1])/2 )
nIndex++;
}
break;
}
}
if( nIndex == STRING_LEN )
{
nIndex = 0;
long nDiff = Abs( pDX[0]-nX );
for( int i = 1; i < aText.Len(); i++ )
{
long nNewDiff = Abs( pDX[2*i]-nX );
if( nNewDiff < nDiff )
{
nIndex = sal::static_int_cast<xub_StrLen>(i);
nDiff = nNewDiff;
}
}
if( nIndex == aText.Len()-1 && Abs( pDX[2*nIndex+1] - nX ) < nDiff )
nIndex = STRING_LEN;
}
if( pDXBuffer )
delete [] pDXBuffer;
return nIndex;
}
// -----------------------------------------------------------------------
void Edit::ImplSetCursorPos( xub_StrLen nChar, sal_Bool bSelect )
{
Selection aSelection( maSelection );
aSelection.Max() = nChar;
if ( !bSelect )
aSelection.Min() = aSelection.Max();
ImplSetSelection( aSelection );
}
// -----------------------------------------------------------------------
void Edit::ImplLoadRes( const ResId& rResId )
{
Control::ImplLoadRes( rResId );
xub_StrLen nTextLength = ReadShortRes();
if ( nTextLength )
SetMaxTextLen( nTextLength );
}
// -----------------------------------------------------------------------
void Edit::ImplCopyToSelectionClipboard()
{
if ( GetSelection().Len() )
{
::com::sun::star::uno::Reference<com::sun::star::datatransfer::clipboard::XClipboard> aSelection(GetPrimarySelection());
ImplCopy( aSelection );
}
}
void Edit::ImplCopy( uno::Reference< datatransfer::clipboard::XClipboard >& rxClipboard )
{
::vcl::unohelper::TextDataObject::CopyStringTo( GetSelected(), rxClipboard );
}
// -----------------------------------------------------------------------
void Edit::ImplPaste( uno::Reference< datatransfer::clipboard::XClipboard >& rxClipboard )
{
if ( rxClipboard.is() )
{
uno::Reference< datatransfer::XTransferable > xDataObj;
const sal_uInt32 nRef = Application::ReleaseSolarMutex();
try
{
xDataObj = rxClipboard->getContents();
}
catch( const ::com::sun::star::uno::Exception& )
{
}
Application::AcquireSolarMutex( nRef );
if ( xDataObj.is() )
{
datatransfer::DataFlavor aFlavor;
SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aFlavor );
try
{
uno::Any aData = xDataObj->getTransferData( aFlavor );
::rtl::OUString aText;
aData >>= aText;
if( ImplTruncateToMaxLen( aText, maSelection.Len() ) )
ShowTruncationWarning( const_cast<Edit*>(this) );
ReplaceSelected( aText );
}
catch( const ::com::sun::star::uno::Exception& )
{
}
}
}
}
// -----------------------------------------------------------------------
void Edit::MouseButtonDown( const MouseEvent& rMEvt )
{
if ( mpSubEdit )
{
Control::MouseButtonDown( rMEvt );
return;
}
xub_StrLen nChar = ImplGetCharPos( rMEvt.GetPosPixel() );
Selection aSelection( maSelection );
aSelection.Justify();
if ( rMEvt.GetClicks() < 4 )
{
mbClickedInSelection = sal_False;
if ( rMEvt.GetClicks() == 3 )
{
ImplSetSelection( Selection( 0, 0xFFFF ) );
ImplCopyToSelectionClipboard();
}
else if ( rMEvt.GetClicks() == 2 )
{
uno::Reference < i18n::XBreakIterator > xBI = ImplGetBreakIterator();
i18n::Boundary aBoundary = xBI->getWordBoundary( maText, aSelection.Max(), GetSettings().GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True );
ImplSetSelection( Selection( aBoundary.startPos, aBoundary.endPos ) );
ImplCopyToSelectionClipboard();
}
else if ( !rMEvt.IsShift() && HasFocus() && aSelection.IsInside( nChar ) )
mbClickedInSelection = sal_True;
else if ( rMEvt.IsLeft() )
ImplSetCursorPos( nChar, rMEvt.IsShift() );
if ( !mbClickedInSelection && rMEvt.IsLeft() && ( rMEvt.GetClicks() == 1 ) )
StartTracking( STARTTRACK_SCROLLREPEAT );
}
mbInMBDown = sal_True; // Dann im GetFocus nicht alles selektieren
GrabFocus();
mbInMBDown = sal_False;
}
// -----------------------------------------------------------------------
void Edit::MouseButtonUp( const MouseEvent& rMEvt )
{
if ( mbClickedInSelection && rMEvt.IsLeft() )
{
xub_StrLen nChar = ImplGetCharPos( rMEvt.GetPosPixel() );
ImplSetCursorPos( nChar, sal_False );
mbClickedInSelection = sal_False;
}
else if ( rMEvt.IsMiddle() && !mbReadOnly &&
( GetSettings().GetMouseSettings().GetMiddleButtonAction() == MOUSE_MIDDLE_PASTESELECTION ) )
{
::com::sun::star::uno::Reference<com::sun::star::datatransfer::clipboard::XClipboard> aSelection(Window::GetPrimarySelection());
ImplPaste( aSelection );
ImplModified();
}
}
// -----------------------------------------------------------------------
void Edit::Tracking( const TrackingEvent& rTEvt )
{
if ( rTEvt.IsTrackingEnded() )
{
if ( mbClickedInSelection )
{
xub_StrLen nChar = ImplGetCharPos( rTEvt.GetMouseEvent().GetPosPixel() );
ImplSetCursorPos( nChar, sal_False );
mbClickedInSelection = sal_False;
}
else if ( rTEvt.GetMouseEvent().IsLeft() )
{
ImplCopyToSelectionClipboard();
}
}
else
{
if( !mbClickedInSelection )
{
xub_StrLen nChar = ImplGetCharPos( rTEvt.GetMouseEvent().GetPosPixel() );
ImplSetCursorPos( nChar, sal_True );
}
}
if ( mpUpdateDataTimer && !mbIsSubEdit && mpUpdateDataTimer->IsActive() )
mpUpdateDataTimer->Start();//do not update while the user is still travelling in the control
}
// -----------------------------------------------------------------------
sal_Bool Edit::ImplHandleKeyEvent( const KeyEvent& rKEvt )
{
sal_Bool bDone = sal_False;
sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
KeyFuncType eFunc = rKEvt.GetKeyCode().GetFunction();
mbInternModified = sal_False;
if ( eFunc != KEYFUNC_DONTKNOW )
{
switch ( eFunc )
{
case KEYFUNC_CUT:
{
if ( !mbReadOnly && maSelection.Len() && !(GetStyle() & WB_PASSWORD) )
{
Cut();
ImplModified();
bDone = sal_True;
}
}
break;
case KEYFUNC_COPY:
{
if ( !(GetStyle() & WB_PASSWORD) )
{
Copy();
bDone = sal_True;
}
}
break;
case KEYFUNC_PASTE:
{
if ( !mbReadOnly )
{
Paste();
bDone = sal_True;
}
}
break;
case KEYFUNC_UNDO:
{
if ( !mbReadOnly )
{
Undo();
bDone = sal_True;
}
}
break;
default: // wird dann evtl. unten bearbeitet.
eFunc = KEYFUNC_DONTKNOW;
}
}
if ( !bDone && rKEvt.GetKeyCode().IsMod1() && !rKEvt.GetKeyCode().IsMod2() )
{
if ( nCode == KEY_A )
{
ImplSetSelection( Selection( 0, maText.Len() ) );
bDone = sal_True;
}
else if ( rKEvt.GetKeyCode().IsShift() && (nCode == KEY_S) )
{
if ( pImplFncGetSpecialChars )
{
Selection aSaveSel = GetSelection(); // Falls jemand in Get/LoseFocus die Selektion verbiegt, z.B. URL-Zeile...
XubString aChars = pImplFncGetSpecialChars( this, GetFont() );
SetSelection( aSaveSel );
if ( aChars.Len() )
{
ImplInsertText( aChars );
ImplModified();
}
bDone = sal_True;
}
}
}
if ( eFunc == KEYFUNC_DONTKNOW && ! bDone )
{
switch ( nCode )
{
case com::sun::star::awt::Key::SELECT_ALL:
{
ImplSetSelection( Selection( 0, maText.Len() ) );
bDone = sal_True;
}
break;
case KEY_LEFT:
case KEY_RIGHT:
case KEY_HOME:
case KEY_END:
case com::sun::star::awt::Key::MOVE_WORD_FORWARD:
case com::sun::star::awt::Key::SELECT_WORD_FORWARD:
case com::sun::star::awt::Key::MOVE_WORD_BACKWARD:
case com::sun::star::awt::Key::SELECT_WORD_BACKWARD:
case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE:
case com::sun::star::awt::Key::MOVE_TO_END_OF_LINE:
case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE:
case com::sun::star::awt::Key::SELECT_TO_END_OF_LINE:
case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH:
case com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH:
case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH:
case com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH:
case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT:
case com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT:
case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT:
case com::sun::star::awt::Key::SELECT_TO_END_OF_DOCUMENT:
{
if ( !rKEvt.GetKeyCode().IsMod2() )
{
ImplClearLayoutData();
uno::Reference < i18n::XBreakIterator > xBI = ImplGetBreakIterator();
Selection aSel( maSelection );
bool bWord = rKEvt.GetKeyCode().IsMod1();
bool bSelect = rKEvt.GetKeyCode().IsShift();
bool bGoLeft = (nCode == KEY_LEFT);
bool bGoRight = (nCode == KEY_RIGHT);
bool bGoHome = (nCode == KEY_HOME);
bool bGoEnd = (nCode == KEY_END);
switch( nCode )
{
case com::sun::star::awt::Key::MOVE_WORD_FORWARD:
bGoRight = bWord = true;break;
case com::sun::star::awt::Key::SELECT_WORD_FORWARD:
bGoRight = bSelect = bWord = true;break;
case com::sun::star::awt::Key::MOVE_WORD_BACKWARD:
bGoLeft = bWord = true;break;
case com::sun::star::awt::Key::SELECT_WORD_BACKWARD:
bGoLeft = bSelect = bWord = true;break;
case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE:
case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH:
case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT:
bSelect = true;
// fallthrough intended
case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE:
case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH:
case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT:
bGoHome = true;break;
case com::sun::star::awt::Key::SELECT_TO_END_OF_LINE:
case com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH:
case com::sun::star::awt::Key::SELECT_TO_END_OF_DOCUMENT:
bSelect = true;
// fallthrough intended
case com::sun::star::awt::Key::MOVE_TO_END_OF_LINE:
case com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH:
case com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT:
bGoEnd = true;break;
default:
break;
};
// Range wird in ImplSetSelection geprueft...
if ( bGoLeft && aSel.Max() )
{
if ( bWord )
{
i18n::Boundary aBoundary = xBI->getWordBoundary( maText, aSel.Max(), GetSettings().GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True );
if ( aBoundary.startPos == aSel.Max() )
aBoundary = xBI->previousWord( maText, aSel.Max(), GetSettings().GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES );
aSel.Max() = aBoundary.startPos;
}
else
{
sal_Int32 nCount = 1;
aSel.Max() = xBI->previousCharacters( maText, aSel.Max(), GetSettings().GetLocale(), i18n::CharacterIteratorMode::SKIPCHARACTER, nCount, nCount );
}
}
else if ( bGoRight && ( aSel.Max() < maText.Len() ) )
{
if ( bWord )
{
i18n::Boundary aBoundary = xBI->nextWord( maText, aSel.Max(), GetSettings().GetLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES );
aSel.Max() = aBoundary.startPos;
}
else
{
sal_Int32 nCount = 1;
aSel.Max() = xBI->nextCharacters( maText, aSel.Max(), GetSettings().GetLocale(), i18n::CharacterIteratorMode::SKIPCHARACTER, nCount, nCount );
}
}
else if ( bGoHome )
{
aSel.Max() = 0;
}
else if ( bGoEnd )
{
aSel.Max() = 0xFFFF;
}
if ( !bSelect )
aSel.Min() = aSel.Max();
if ( aSel != GetSelection() )
{
ImplSetSelection( aSel );
ImplCopyToSelectionClipboard();
}
if ( bGoEnd && maAutocompleteHdl.IsSet() && !rKEvt.GetKeyCode().GetModifier() )
{
if ( (maSelection.Min() == maSelection.Max()) && (maSelection.Min() == maText.Len()) )
{
meAutocompleteAction = AUTOCOMPLETE_KEYINPUT;
maAutocompleteHdl.Call( this );
}
}
bDone = sal_True;
}
}
break;
case com::sun::star::awt::Key::DELETE_WORD_BACKWARD:
case com::sun::star::awt::Key::DELETE_WORD_FORWARD:
case com::sun::star::awt::Key::DELETE_TO_BEGIN_OF_LINE:
case com::sun::star::awt::Key::DELETE_TO_END_OF_LINE:
case KEY_BACKSPACE:
case KEY_DELETE:
{
if ( !mbReadOnly && !rKEvt.GetKeyCode().IsMod2() )
{
sal_uInt8 nDel = (nCode == KEY_DELETE) ? EDIT_DEL_RIGHT : EDIT_DEL_LEFT;
sal_uInt8 nMode = rKEvt.GetKeyCode().IsMod1() ? EDIT_DELMODE_RESTOFWORD : EDIT_DELMODE_SIMPLE;
if ( (nMode == EDIT_DELMODE_RESTOFWORD) && rKEvt.GetKeyCode().IsShift() )
nMode = EDIT_DELMODE_RESTOFCONTENT;
switch( nCode )
{
case com::sun::star::awt::Key::DELETE_WORD_BACKWARD:
nDel = EDIT_DEL_LEFT;
nMode = EDIT_DELMODE_RESTOFWORD;
break;
case com::sun::star::awt::Key::DELETE_WORD_FORWARD:
nDel = EDIT_DEL_RIGHT;
nMode = EDIT_DELMODE_RESTOFWORD;
break;
case com::sun::star::awt::Key::DELETE_TO_BEGIN_OF_LINE:
nDel = EDIT_DEL_LEFT;
nMode = EDIT_DELMODE_RESTOFCONTENT;
break;
case com::sun::star::awt::Key::DELETE_TO_END_OF_LINE:
nDel = EDIT_DEL_RIGHT;
nMode = EDIT_DELMODE_RESTOFCONTENT;
break;
default: break;
}
xub_StrLen nOldLen = maText.Len();
ImplDelete( maSelection, nDel, nMode );
if ( maText.Len() != nOldLen )
ImplModified();
bDone = sal_True;
}
}
break;
case KEY_INSERT:
{
if ( !mpIMEInfos && !mbReadOnly && !rKEvt.GetKeyCode().IsMod2() )
{
SetInsertMode( !mbInsertMode );
bDone = sal_True;
}
}
break;
/* #i101255# disable autocomplete tab forward/backward
users expect tab/shif-tab to move the focus to other controls
not suddenly to cycle the autocompletion
case KEY_TAB:
{
if ( !mbReadOnly && maAutocompleteHdl.IsSet() &&
maSelection.Min() && (maSelection.Min() == maText.Len()) &&
!rKEvt.GetKeyCode().IsMod1() && !rKEvt.GetKeyCode().IsMod2() )
{
// Kein Autocomplete wenn alles Selektiert oder Edit leer, weil dann
// keine vernuenftige Tab-Steuerung!
if ( rKEvt.GetKeyCode().IsShift() )
meAutocompleteAction = AUTOCOMPLETE_TABBACKWARD;
else
meAutocompleteAction = AUTOCOMPLETE_TABFORWARD;
maAutocompleteHdl.Call( this );
// Wurde nichts veraendert, dann TAB fuer DialogControl
if ( GetSelection().Len() )
bDone = sal_True;
}
}
break;
*/
default:
{
if ( IsCharInput( rKEvt ) )
{
bDone = sal_True; // Auch bei ReadOnly die Zeichen schlucken.
if ( !mbReadOnly )
{
ImplInsertText( rKEvt.GetCharCode(), 0, sal_True );
if ( maAutocompleteHdl.IsSet() )
{
if ( (maSelection.Min() == maSelection.Max()) && (maSelection.Min() == maText.Len()) )
{
meAutocompleteAction = AUTOCOMPLETE_KEYINPUT;
maAutocompleteHdl.Call( this );
}
}
}
}
}
}
}
if ( mbInternModified )
ImplModified();
return bDone;
}
// -----------------------------------------------------------------------
void Edit::KeyInput( const KeyEvent& rKEvt )
{
if ( mpUpdateDataTimer && !mbIsSubEdit && mpUpdateDataTimer->IsActive() )
mpUpdateDataTimer->Start();//do not update while the user is still travelling in the control
if ( mpSubEdit || !ImplHandleKeyEvent( rKEvt ) )
Control::KeyInput( rKEvt );
}
// -----------------------------------------------------------------------
void Edit::FillLayoutData() const
{
mpControlData->mpLayoutData = new vcl::ControlLayoutData();
const_cast<Edit*>(this)->ImplRepaint( 0, STRING_LEN, true );
}
// -----------------------------------------------------------------------
void Edit::Paint( const Rectangle& )
{
if ( !mpSubEdit )
ImplRepaint();
}
// -----------------------------------------------------------------------
void Edit::Resize()
{
if ( !mpSubEdit && IsReallyVisible() )
{
Control::Resize();
// Wegen vertikaler Zentrierung...
mnXOffset = 0;
ImplAlign();
Invalidate();
ImplShowCursor();
}
}
// -----------------------------------------------------------------------
void Edit::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, sal_uLong nFlags )
{
ImplInitSettings( sal_True, sal_True, sal_True );
Point aPos = pDev->LogicToPixel( rPos );
Size aSize = pDev->LogicToPixel( rSize );
Font aFont = GetDrawPixelFont( pDev );
OutDevType eOutDevType = pDev->GetOutDevType();
pDev->Push();
pDev->SetMapMode();
pDev->SetFont( aFont );
pDev->SetTextFillColor();
// Border/Background
pDev->SetLineColor();
pDev->SetFillColor();
sal_Bool bBorder = !(nFlags & WINDOW_DRAW_NOBORDER ) && (GetStyle() & WB_BORDER);
sal_Bool bBackground = !(nFlags & WINDOW_DRAW_NOBACKGROUND) && IsControlBackground();
if ( bBorder || bBackground )
{
Rectangle aRect( aPos, aSize );
if ( bBorder )
{
ImplDrawFrame( pDev, aRect );
}
if ( bBackground )
{
pDev->SetFillColor( GetControlBackground() );
pDev->DrawRect( aRect );
}
}
// Inhalt
if ( ( nFlags & WINDOW_DRAW_MONO ) || ( eOutDevType == OUTDEV_PRINTER ) )
pDev->SetTextColor( Color( COL_BLACK ) );
else
{
if ( !(nFlags & WINDOW_DRAW_NODISABLE ) && !IsEnabled() )
{
const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
pDev->SetTextColor( rStyleSettings.GetDisableColor() );
}
else
{
pDev->SetTextColor( GetTextColor() );
}
}
XubString aText = ImplGetText();
long nTextHeight = pDev->GetTextHeight();
long nTextWidth = pDev->GetTextWidth( aText );
long nOnePixel = GetDrawPixel( pDev, 1 );
long nOffX = 3*nOnePixel;
long nOffY = (aSize.Height() - nTextHeight) / 2;
// Clipping?
if ( (nOffY < 0) ||
((nOffY+nTextHeight) > aSize.Height()) ||
((nOffX+nTextWidth) > aSize.Width()) )
{
Rectangle aClip( aPos, aSize );
if ( nTextHeight > aSize.Height() )
aClip.Bottom() += nTextHeight-aSize.Height()+1; // Damit HP-Drucker nicht 'weg-optimieren'
pDev->IntersectClipRegion( aClip );
}
if ( GetStyle() & WB_CENTER )
{
aPos.X() += (aSize.Width() - nTextWidth) / 2;
nOffX = 0;
}
else if ( GetStyle() & WB_RIGHT )
{
aPos.X() += aSize.Width() - nTextWidth;
nOffX = -nOffX;
}
pDev->DrawText( Point( aPos.X() + nOffX, aPos.Y() + nOffY ), aText );
pDev->Pop();
if ( GetSubEdit() )
{
GetSubEdit()->Draw( pDev, rPos, rSize, nFlags );
}
}
// -----------------------------------------------------------------------
void Edit::ImplInvalidateOutermostBorder( Window* pWin )
{
// allow control to show focused state
Window *pInvalWin = pWin, *pBorder = pWin;
while( ( pBorder = pInvalWin->GetWindow( WINDOW_BORDER ) ) != pInvalWin && pBorder &&
pInvalWin->ImplGetFrame() == pBorder->ImplGetFrame() )
{
pInvalWin = pBorder;
}
pInvalWin->Invalidate( INVALIDATE_CHILDREN | INVALIDATE_UPDATE );
}
void Edit::GetFocus()
{
if ( mpSubEdit )
mpSubEdit->ImplGrabFocus( GetGetFocusFlags() );
else if ( !mbActivePopup )
{
maUndoText = maText;
sal_uLong nSelOptions = GetSettings().GetStyleSettings().GetSelectionOptions();
if ( !( GetStyle() & (WB_NOHIDESELECTION|WB_READONLY) )
&& ( GetGetFocusFlags() & (GETFOCUS_INIT|GETFOCUS_TAB|GETFOCUS_CURSOR|GETFOCUS_MNEMONIC) ) )
{
if ( nSelOptions & SELECTION_OPTION_SHOWFIRST )
{
maSelection.Min() = maText.Len();
maSelection.Max() = 0;
}
else
{
maSelection.Min() = 0;
maSelection.Max() = maText.Len();
}
if ( mbIsSubEdit )
((Edit*)GetParent())->ImplCallEventListeners( VCLEVENT_EDIT_SELECTIONCHANGED );
else
ImplCallEventListeners( VCLEVENT_EDIT_SELECTIONCHANGED );
}
ImplShowCursor();
// FIXME: this is currently only on aqua
// check for other platforms that need similar handling
if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
IsNativeWidgetEnabled() &&
IsNativeControlSupported( CTRL_EDITBOX, PART_ENTIRE_CONTROL ) )
{
ImplInvalidateOutermostBorder( mbIsSubEdit ? GetParent() : this );
}
else if ( maSelection.Len() )
{
// Selektion malen
if ( !HasPaintEvent() )
ImplInvalidateOrRepaint();
else
Invalidate();
}
SetInputContext( InputContext( GetFont(), !IsReadOnly() ? INPUTCONTEXT_TEXT|INPUTCONTEXT_EXTTEXTINPUT : 0 ) );
}
Control::GetFocus();
}
// -----------------------------------------------------------------------
Window* Edit::GetPreferredKeyInputWindow()
{
if ( mpSubEdit )
return mpSubEdit->GetPreferredKeyInputWindow();
else
return this;
}
// -----------------------------------------------------------------------
void Edit::LoseFocus()
{
if ( mpUpdateDataTimer && !mbIsSubEdit && mpUpdateDataTimer->IsActive() )
{
//notify an update latest when the focus is lost
mpUpdateDataTimer->Stop();
mpUpdateDataTimer->Timeout();
}
if ( !mpSubEdit )
{
// FIXME: this is currently only on aqua
// check for other platforms that need similar handling
if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
IsNativeWidgetEnabled() &&
IsNativeControlSupported( CTRL_EDITBOX, PART_ENTIRE_CONTROL ) )
{
ImplInvalidateOutermostBorder( mbIsSubEdit ? GetParent() : this );
}
if ( !mbActivePopup && !( GetStyle() & WB_NOHIDESELECTION ) && maSelection.Len() )
ImplInvalidateOrRepaint(); // Selektion malen
}
Control::LoseFocus();
}
// -----------------------------------------------------------------------
void Edit::Command( const CommandEvent& rCEvt )
{
if ( rCEvt.GetCommand() == COMMAND_CONTEXTMENU )
{
PopupMenu* pPopup = Edit::CreatePopupMenu();
const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
if ( rStyleSettings.GetOptions() & STYLE_OPTION_HIDEDISABLED )
pPopup->SetMenuFlags( MENU_FLAG_HIDEDISABLEDENTRIES );
if ( !maSelection.Len() )
{
pPopup->EnableItem( SV_MENU_EDIT_CUT, sal_False );
pPopup->EnableItem( SV_MENU_EDIT_COPY, sal_False );
pPopup->EnableItem( SV_MENU_EDIT_DELETE, sal_False );
}
if ( IsReadOnly() )
{
pPopup->EnableItem( SV_MENU_EDIT_CUT, sal_False );
pPopup->EnableItem( SV_MENU_EDIT_PASTE, sal_False );
pPopup->EnableItem( SV_MENU_EDIT_DELETE, sal_False );
pPopup->EnableItem( SV_MENU_EDIT_INSERTSYMBOL, sal_False );
}
else
{
// Paste nur, wenn Text im Clipboard
sal_Bool bData = sal_False;
uno::Reference< datatransfer::clipboard::XClipboard > xClipboard = GetClipboard();
if ( xClipboard.is() )
{
const sal_uInt32 nRef = Application::ReleaseSolarMutex();
uno::Reference< datatransfer::XTransferable > xDataObj = xClipboard->getContents();
Application::AcquireSolarMutex( nRef );
if ( xDataObj.is() )
{
datatransfer::DataFlavor aFlavor;
SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aFlavor );
bData = xDataObj->isDataFlavorSupported( aFlavor );
}
}
pPopup->EnableItem( SV_MENU_EDIT_PASTE, bData );
}
if ( maUndoText == maText )
pPopup->EnableItem( SV_MENU_EDIT_UNDO, sal_False );
if ( ( maSelection.Min() == 0 ) && ( maSelection.Max() == maText.Len() ) )
pPopup->EnableItem( SV_MENU_EDIT_SELECTALL, sal_False );
if ( !pImplFncGetSpecialChars )
{
sal_uInt16 nPos = pPopup->GetItemPos( SV_MENU_EDIT_INSERTSYMBOL );
pPopup->RemoveItem( nPos );
pPopup->RemoveItem( nPos-1 );
}
mbActivePopup = sal_True;
Selection aSaveSel = GetSelection(); // Falls jemand in Get/LoseFocus die Selektion verbiegt, z.B. URL-Zeile...
Point aPos = rCEvt.GetMousePosPixel();
if ( !rCEvt.IsMouseEvent() )
{
// !!! Irgendwann einmal Menu zentriert in der Selektion anzeigen !!!
Size aSize = GetOutputSizePixel();
aPos = Point( aSize.Width()/2, aSize.Height()/2 );
}
sal_uInt16 n = pPopup->Execute( this, aPos );
Edit::DeletePopupMenu( pPopup );
SetSelection( aSaveSel );
switch ( n )
{
case SV_MENU_EDIT_UNDO:
Undo();
ImplModified();
break;
case SV_MENU_EDIT_CUT:
Cut();
ImplModified();
break;
case SV_MENU_EDIT_COPY:
Copy();
break;
case SV_MENU_EDIT_PASTE:
Paste();
ImplModified();
break;
case SV_MENU_EDIT_DELETE:
DeleteSelected();
ImplModified();
break;
case SV_MENU_EDIT_SELECTALL:
ImplSetSelection( Selection( 0, maText.Len() ) );
break;
case SV_MENU_EDIT_INSERTSYMBOL:
{
XubString aChars = pImplFncGetSpecialChars( this, GetFont() );
SetSelection( aSaveSel );
if ( aChars.Len() )
{
ImplInsertText( aChars );
ImplModified();
}
}
break;
}
mbActivePopup = sal_False;
}
else if ( rCEvt.GetCommand() == COMMAND_VOICE )
{
const CommandVoiceData* pData = rCEvt.GetVoiceData();
if ( pData->GetType() == VOICECOMMANDTYPE_DICTATION )
{
switch ( pData->GetCommand() )
{
case DICTATIONCOMMAND_UNKNOWN:
{
ReplaceSelected( pData->GetText() );
}
break;
case DICTATIONCOMMAND_LEFT:
{
ImplHandleKeyEvent( KeyEvent( 0, KeyCode( KEY_LEFT, KEY_MOD1 ) ) );
}
break;
case DICTATIONCOMMAND_RIGHT:
{
ImplHandleKeyEvent( KeyEvent( 0, KeyCode( KEY_RIGHT, KEY_MOD1 ) ) );
}
break;
case DICTATIONCOMMAND_UNDO:
{
Undo();
}
break;
case DICTATIONCOMMAND_DEL:
{
ImplHandleKeyEvent( KeyEvent( 0, KeyCode( KEY_LEFT, KEY_MOD1|KEY_SHIFT ) ) );
DeleteSelected();
}
break;
}
}
}
else if ( rCEvt.GetCommand() == COMMAND_STARTEXTTEXTINPUT )
{
DeleteSelected();
delete mpIMEInfos;
xub_StrLen nPos = (xub_StrLen)maSelection.Max();
mpIMEInfos = new Impl_IMEInfos( nPos, maText.Copy( nPos ) );
mpIMEInfos->bWasCursorOverwrite = !IsInsertMode();
}
else if ( rCEvt.GetCommand() == COMMAND_ENDEXTTEXTINPUT )
{
sal_Bool bInsertMode = !mpIMEInfos->bWasCursorOverwrite;
delete mpIMEInfos;
mpIMEInfos = NULL;
// Font wieder ohne Attribute einstellen, wird jetzt im Repaint nicht
// mehr neu initialisiert
ImplInitSettings( sal_True, sal_False, sal_False );
SetInsertMode( bInsertMode );
ImplModified();
// #i25161# call auto complete handler for ext text commit also
if ( maAutocompleteHdl.IsSet() )
{
if ( (maSelection.Min() == maSelection.Max()) && (maSelection.Min() == maText.Len()) )
{
meAutocompleteAction = AUTOCOMPLETE_KEYINPUT;
maAutocompleteHdl.Call( this );
}
}
}
else if ( rCEvt.GetCommand() == COMMAND_EXTTEXTINPUT )
{
const CommandExtTextInputData* pData = rCEvt.GetExtTextInputData();
maText.Erase( mpIMEInfos->nPos, mpIMEInfos->nLen );
maText.Insert( pData->GetText(), mpIMEInfos->nPos );
if ( mpIMEInfos->bWasCursorOverwrite )
{
sal_uInt16 nOldIMETextLen = mpIMEInfos->nLen;
sal_uInt16 nNewIMETextLen = pData->GetText().Len();
if ( ( nOldIMETextLen > nNewIMETextLen ) &&
( nNewIMETextLen < mpIMEInfos->aOldTextAfterStartPos.Len() ) )
{
// restore old characters
sal_uInt16 nRestore = nOldIMETextLen - nNewIMETextLen;
maText.Insert( mpIMEInfos->aOldTextAfterStartPos.Copy( nNewIMETextLen, nRestore ), mpIMEInfos->nPos + nNewIMETextLen );
}
else if ( ( nOldIMETextLen < nNewIMETextLen ) &&
( nOldIMETextLen < mpIMEInfos->aOldTextAfterStartPos.Len() ) )
{
// overwrite
sal_uInt16 nOverwrite = nNewIMETextLen - nOldIMETextLen;
if ( ( nOldIMETextLen + nOverwrite ) > mpIMEInfos->aOldTextAfterStartPos.Len() )
nOverwrite = mpIMEInfos->aOldTextAfterStartPos.Len() - nOldIMETextLen;
maText.Erase( mpIMEInfos->nPos + nNewIMETextLen, nOverwrite );
}
}
if ( pData->GetTextAttr() )
{
mpIMEInfos->CopyAttribs( pData->GetTextAttr(), pData->GetText().Len() );
mpIMEInfos->bCursor = pData->IsCursorVisible();
}
else
{
mpIMEInfos->DestroyAttribs();
}
ImplAlignAndPaint();
xub_StrLen nCursorPos = mpIMEInfos->nPos + pData->GetCursorPos();
SetSelection( Selection( nCursorPos, nCursorPos ) );
SetInsertMode( !pData->IsCursorOverwrite() );
if ( pData->IsCursorVisible() )
GetCursor()->Show();
else
GetCursor()->Hide();
}
else if ( rCEvt.GetCommand() == COMMAND_CURSORPOS )
{
if ( mpIMEInfos )
{
xub_StrLen nCursorPos = (sal_uInt16)GetSelection().Max();
SetCursorRect( NULL, GetTextWidth(
maText, nCursorPos, mpIMEInfos->nPos+mpIMEInfos->nLen-nCursorPos ) );
}
else
{
SetCursorRect();
}
}
else if ( rCEvt.GetCommand() == COMMAND_SELECTIONCHANGE )
{
const CommandSelectionChangeData *pData = rCEvt.GetSelectionChangeData();
Selection aSelection( pData->GetStart(), pData->GetEnd() );
SetSelection(aSelection);
}
else
Control::Command( rCEvt );
}
// -----------------------------------------------------------------------
void Edit::StateChanged( StateChangedType nType )
{
if ( nType == STATE_CHANGE_INITSHOW )
{
if ( !mpSubEdit )
{
mnXOffset = 0; // Falls vorher GrabFocus, als Groesse noch falsch.
ImplAlign();
if ( !mpSubEdit )
ImplShowCursor( sal_False );
}
// update background (eventual SetPaintTransparent)
ImplInitSettings( sal_False, sal_False, sal_True );
}
else if ( nType == STATE_CHANGE_ENABLE )
{
if ( !mpSubEdit )
{
// Es aendert sich nur die Textfarbe...
ImplInvalidateOrRepaint( 0, 0xFFFF );
}
}
else if ( nType == STATE_CHANGE_STYLE || nType == STATE_CHANGE_MIRRORING )
{
WinBits nStyle = GetStyle();
if( nType == STATE_CHANGE_STYLE )
{
nStyle = ImplInitStyle( GetStyle() );
SetStyle( nStyle );
}
sal_uInt16 nOldAlign = mnAlign;
mnAlign = EDIT_ALIGN_LEFT;
// --- RTL --- hack: right align until keyinput and cursor travelling works
// edits are always RTL disabled
// however the parent edits contain the correct setting
if( mbIsSubEdit && GetParent()->IsRTLEnabled() )
{
if( GetParent()->GetStyle() & WB_LEFT )
mnAlign = EDIT_ALIGN_RIGHT;
if ( nType == STATE_CHANGE_MIRRORING )
SetLayoutMode( TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_TEXTORIGIN_LEFT );
}
else if( mbIsSubEdit && !GetParent()->IsRTLEnabled() )
{
if ( nType == STATE_CHANGE_MIRRORING )
SetLayoutMode( TEXT_LAYOUT_BIDI_LTR | TEXT_LAYOUT_TEXTORIGIN_LEFT );
}
if ( nStyle & WB_RIGHT )
mnAlign = EDIT_ALIGN_RIGHT;
else if ( nStyle & WB_CENTER )
mnAlign = EDIT_ALIGN_CENTER;
if ( maText.Len() && ( mnAlign != nOldAlign ) )
{
ImplAlign();
Invalidate();
}
}
else if ( nType == STATE_CHANGE_ZOOM )
{
if ( !mpSubEdit )
{
ImplInitSettings( sal_True, sal_False, sal_False );
ImplShowCursor( sal_True );
Invalidate();
}
}
else if ( nType == STATE_CHANGE_CONTROLFONT )
{
if ( !mpSubEdit )
{
ImplInitSettings( sal_True, sal_False, sal_False );
ImplShowCursor();
Invalidate();
}
}
else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
{
if ( !mpSubEdit )
{
ImplInitSettings( sal_False, sal_True, sal_False );
Invalidate();
}
}
else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
{
if ( !mpSubEdit )
{
ImplInitSettings( sal_False, sal_False, sal_True );
Invalidate();
}
}
Control::StateChanged( nType );
}
// -----------------------------------------------------------------------
void Edit::DataChanged( const DataChangedEvent& rDCEvt )
{
if ( (rDCEvt.GetType() == DATACHANGED_FONTS) ||
(rDCEvt.GetType() == DATACHANGED_FONTSUBSTITUTION) ||
((rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
(rDCEvt.GetFlags() & SETTINGS_STYLE)) )
{
if ( !mpSubEdit )
{
ImplInitSettings( sal_True, sal_True, sal_True );
ImplShowCursor( sal_True );
Invalidate();
}
}
Control::DataChanged( rDCEvt );
}
// -----------------------------------------------------------------------
void Edit::ImplShowDDCursor()
{
if ( !mpDDInfo->bVisCursor )
{
long nTextWidth = GetTextWidth( maText, 0, mpDDInfo->nDropPos );
long nTextHeight = GetTextHeight();
Rectangle aCursorRect( Point( nTextWidth + mnXOffset, (GetOutputSize().Height()-nTextHeight)/2 ), Size( 2, nTextHeight ) );
mpDDInfo->aCursor.SetWindow( this );
mpDDInfo->aCursor.SetPos( aCursorRect.TopLeft() );
mpDDInfo->aCursor.SetSize( aCursorRect.GetSize() );
mpDDInfo->aCursor.Show();
mpDDInfo->bVisCursor = sal_True;
}
}
// -----------------------------------------------------------------------
void Edit::ImplHideDDCursor()
{
if ( mpDDInfo && mpDDInfo->bVisCursor )
{
mpDDInfo->aCursor.Hide();
mpDDInfo->bVisCursor = sal_False;
}
}
// -----------------------------------------------------------------------
void Edit::Modify()
{
if ( mbIsSubEdit )
{
((Edit*)GetParent())->Modify();
}
else
{
if ( mpUpdateDataTimer )
mpUpdateDataTimer->Start();
if ( ImplCallEventListenersAndHandler( VCLEVENT_EDIT_MODIFY, maModifyHdl, this ) )
// have been destroyed while calling into the handlers
return;
// #i13677# notify edit listeners about caret position change
//ImplCallEventListeners( VCLEVENT_EDIT_SELECTIONCHANGED );
ImplCallEventListeners( VCLEVENT_EDIT_CARETCHANGED );
// FIXME: this is currently only on aqua
// check for other platforms that need similar handling
if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
IsNativeWidgetEnabled() &&
IsNativeControlSupported( CTRL_EDITBOX, PART_ENTIRE_CONTROL ) )
{
ImplInvalidateOutermostBorder( this );
}
}
}
// -----------------------------------------------------------------------
void Edit::UpdateData()
{
maUpdateDataHdl.Call( this );
}
// -----------------------------------------------------------------------
IMPL_LINK( Edit, ImplUpdateDataHdl, Timer*, EMPTYARG )
{
UpdateData();
return 0;
}
// -----------------------------------------------------------------------
void Edit::EnableUpdateData( sal_uLong nTimeout )
{
if ( !nTimeout )
DisableUpdateData();
else
{
if ( !mpUpdateDataTimer )
{
mpUpdateDataTimer = new Timer;
mpUpdateDataTimer->SetTimeoutHdl( LINK( this, Edit, ImplUpdateDataHdl ) );
}
mpUpdateDataTimer->SetTimeout( nTimeout );
}
}
// -----------------------------------------------------------------------
void Edit::SetEchoChar( xub_Unicode c )
{
mcEchoChar = c;
if ( mpSubEdit )
mpSubEdit->SetEchoChar( c );
}
// -----------------------------------------------------------------------
void Edit::SetReadOnly( sal_Bool bReadOnly )
{
if ( mbReadOnly != bReadOnly )
{
mbReadOnly = bReadOnly;
if ( mpSubEdit )
mpSubEdit->SetReadOnly( bReadOnly );
StateChanged( STATE_CHANGE_READONLY );
}
}
// -----------------------------------------------------------------------
void Edit::SetAutocompleteHdl( const Link& rHdl )
{
maAutocompleteHdl = rHdl;
if ( mpSubEdit )
mpSubEdit->SetAutocompleteHdl( rHdl );
}
// -----------------------------------------------------------------------
void Edit::SetInsertMode( sal_Bool bInsert )
{
if ( bInsert != mbInsertMode )
{
mbInsertMode = bInsert;
if ( mpSubEdit )
mpSubEdit->SetInsertMode( bInsert );
else
ImplShowCursor();
}
}
// -----------------------------------------------------------------------
sal_Bool Edit::IsInsertMode() const
{
if ( mpSubEdit )
return mpSubEdit->IsInsertMode();
else
return mbInsertMode;
}
// -----------------------------------------------------------------------
void Edit::SetMaxTextLen( xub_StrLen nMaxLen )
{
mnMaxTextLen = nMaxLen ? nMaxLen : EDIT_NOLIMIT;
if ( mpSubEdit )
mpSubEdit->SetMaxTextLen( mnMaxTextLen );
else
{
if ( maText.Len() > mnMaxTextLen )
ImplDelete( Selection( mnMaxTextLen, maText.Len() ), EDIT_DEL_RIGHT, EDIT_DELMODE_SIMPLE );
}
}
// -----------------------------------------------------------------------
void Edit::SetSelection( const Selection& rSelection )
{
// Wenn von aussen z.B. im MouseButtonDown die Selektion geaendert wird,
// soll nicht gleich ein Tracking() zuschlagen und die Selektion aendern.
if ( IsTracking() )
EndTracking();
else if ( mpSubEdit && mpSubEdit->IsTracking() )
mpSubEdit->EndTracking();
ImplSetSelection( rSelection );
}
// -----------------------------------------------------------------------
void Edit::ImplSetSelection( const Selection& rSelection, sal_Bool bPaint )
{
if ( mpSubEdit )
mpSubEdit->ImplSetSelection( rSelection );
else
{
if ( rSelection != maSelection )
{
Selection aOld( maSelection );
Selection aNew( rSelection );
if ( aNew.Min() > maText.Len() )
aNew.Min() = maText.Len();
if ( aNew.Max() > maText.Len() )
aNew.Max() = maText.Len();
if ( aNew.Min() < 0 )
aNew.Min() = 0;
if ( aNew.Max() < 0 )
aNew.Max() = 0;
if ( aNew != maSelection )
{
ImplClearLayoutData();
Selection aTemp = maSelection;
maSelection = aNew;
if ( bPaint && ( aOld.Len() || aNew.Len() || IsPaintTransparent() ) )
ImplInvalidateOrRepaint( 0, maText.Len() );
ImplShowCursor();
sal_Bool bCaret = sal_False, bSelection = sal_False;
long nB=aNew.Max(), nA=aNew.Min(),oB=aTemp.Max(), oA=aTemp.Min();
long nGap = nB-nA, oGap = oB-oA;
if (nB != oB)
bCaret = sal_True;
if (nGap != 0 || oGap != 0)
bSelection = sal_True;
if (bCaret)
{
if ( mbIsSubEdit )
((Edit*)GetParent())->ImplCallEventListeners( VCLEVENT_EDIT_CARETCHANGED );
else
ImplCallEventListeners( VCLEVENT_EDIT_CARETCHANGED );
}
if (bSelection)
{
if ( mbIsSubEdit )
((Edit*)GetParent())->ImplCallEventListeners( VCLEVENT_EDIT_SELECTIONCHANGED );
else
ImplCallEventListeners( VCLEVENT_EDIT_SELECTIONCHANGED );
}
// #103511# notify combobox listeners of deselection
if( !maSelection && GetParent() && GetParent()->GetType() == WINDOW_COMBOBOX )
((Edit*)GetParent())->ImplCallEventListeners( VCLEVENT_COMBOBOX_DESELECT );
}
}
}
}
// -----------------------------------------------------------------------
const Selection& Edit::GetSelection() const
{
if ( mpSubEdit )
return mpSubEdit->GetSelection();
else
return maSelection;
}
// -----------------------------------------------------------------------
void Edit::ReplaceSelected( const XubString& rStr )
{
if ( mpSubEdit )
mpSubEdit->ReplaceSelected( rStr );
else
ImplInsertText( rStr );
}
// -----------------------------------------------------------------------
void Edit::DeleteSelected()
{
if ( mpSubEdit )
mpSubEdit->DeleteSelected();
else
{
if ( maSelection.Len() )
ImplDelete( maSelection, EDIT_DEL_RIGHT, EDIT_DELMODE_SIMPLE );
}
}
// -----------------------------------------------------------------------
XubString Edit::GetSelected() const
{
if ( mpSubEdit )
return mpSubEdit->GetSelected();
else
{
Selection aSelection( maSelection );
aSelection.Justify();
return maText.Copy( (xub_StrLen)aSelection.Min(), (xub_StrLen)aSelection.Len() );
}
}
// -----------------------------------------------------------------------
void Edit::Cut()
{
if ( !(GetStyle() & WB_PASSWORD ) )
{
Copy();
ReplaceSelected( ImplGetSVEmptyStr() );
}
}
// -----------------------------------------------------------------------
void Edit::Copy()
{
if ( !(GetStyle() & WB_PASSWORD ) )
{
::com::sun::star::uno::Reference<com::sun::star::datatransfer::clipboard::XClipboard> aClipboard(GetClipboard());
ImplCopy( aClipboard );
}
}
// -----------------------------------------------------------------------
void Edit::Paste()
{
::com::sun::star::uno::Reference<com::sun::star::datatransfer::clipboard::XClipboard> aClipboard(GetClipboard());
ImplPaste( aClipboard );
}
// -----------------------------------------------------------------------
void Edit::Undo()
{
if ( mpSubEdit )
mpSubEdit->Undo();
else
{
XubString aText( maText );
ImplDelete( Selection( 0, aText.Len() ), EDIT_DEL_RIGHT, EDIT_DELMODE_SIMPLE );
ImplInsertText( maUndoText );
ImplSetSelection( Selection( 0, maUndoText.Len() ) );
maUndoText = aText;
}
}
// -----------------------------------------------------------------------
void Edit::SetText( const XubString& rStr )
{
if ( mpSubEdit )
mpSubEdit->SetText( rStr ); // Nicht direkt ImplSetText, falls SetText ueberladen
else
{
Selection aNewSel( 0, 0 ); // Damit nicht gescrollt wird
ImplSetText( rStr, &aNewSel );
}
}
// -----------------------------------------------------------------------
void Edit::SetText( const XubString& rStr, const Selection& rSelection )
{
if ( mpSubEdit )
mpSubEdit->SetText( rStr, rSelection );
else
ImplSetText( rStr, &rSelection );
}
// -----------------------------------------------------------------------
XubString Edit::GetText() const
{
if ( mpSubEdit )
return mpSubEdit->GetText();
else
return maText;
}
// -----------------------------------------------------------------------
void Edit::SetModifyFlag()
{
if ( mpSubEdit )
mpSubEdit->mbModified = sal_True;
else
mbModified = sal_True;
}
// -----------------------------------------------------------------------
void Edit::ClearModifyFlag()
{
if ( mpSubEdit )
mpSubEdit->mbModified = sal_False;
else
mbModified = sal_False;
}
// -----------------------------------------------------------------------
void Edit::SetSubEdit( Edit* pEdit )
{
mpSubEdit = pEdit;
if ( mpSubEdit )
{
SetPointer( POINTER_ARROW ); // Nur das SubEdit hat den BEAM...
mpSubEdit->mbIsSubEdit = sal_True;
mpSubEdit->SetReadOnly( mbReadOnly );
}
}
// -----------------------------------------------------------------------
Size Edit::CalcMinimumSize() const
{
Size aSize ( GetTextWidth( GetText() ), GetTextHeight() );
// do not create edit fields in which one cannot enter anything
// a default minimum width should exist for at least 3 characters
Size aMinSize ( CalcSize( 3 ) );
if( aSize.Width() < aMinSize.Width() )
aSize.Width() = aMinSize.Width();
// add some space between text entry and border
aSize.Height() += 4;
aSize = CalcWindowSize( aSize );
// ask NWF what if it has an opinion, too
ImplControlValue aControlValue;
Rectangle aRect( Point( 0, 0 ), aSize );
Rectangle aContent, aBound;
if( const_cast<Edit*>(this)->GetNativeControlRegion(
CTRL_EDITBOX, PART_ENTIRE_CONTROL,
aRect, 0, aControlValue, rtl::OUString(), aBound, aContent) )
{
if( aBound.GetHeight() > aSize.Height() )
aSize.Height() = aBound.GetHeight();
}
return aSize;
}
Size Edit::GetMinimumEditSize()
{
Window* pDefWin = ImplGetDefaultWindow();
Edit aEdit( pDefWin, WB_BORDER );
Size aSize( aEdit.CalcMinimumSize() );
return aSize;
}
// -----------------------------------------------------------------------
Size Edit::GetOptimalSize(WindowSizeType eType) const
{
switch (eType) {
case WINDOWSIZE_MINIMUM:
return CalcMinimumSize();
default:
return Control::GetOptimalSize( eType );
}
}
// -----------------------------------------------------------------------
Size Edit::CalcSize( xub_StrLen nChars ) const
{
// Breite fuer n Zeichen, unabhaengig vom Inhalt.
// Funktioniert nur bei FixedFont richtig, sonst Mittelwert.
Size aSz( GetTextWidth( XubString( 'x' ) ), GetTextHeight() );
aSz.Width() *= nChars;
aSz = CalcWindowSize( aSz );
return aSz;
}
// -----------------------------------------------------------------------
xub_StrLen Edit::GetMaxVisChars() const
{
const Window* pW = mpSubEdit ? mpSubEdit : this;
long nOutWidth = pW->GetOutputSizePixel().Width();
long nCharWidth = GetTextWidth( XubString( 'x' ) );
return nCharWidth ? (xub_StrLen)(nOutWidth/nCharWidth) : 0;
}
// -----------------------------------------------------------------------
xub_StrLen Edit::GetCharPos( const Point& rWindowPos ) const
{
return ImplGetCharPos( rWindowPos );
}
// -----------------------------------------------------------------------
void Edit::SetGetSpecialCharsFunction( FncGetSpecialChars fn )
{
pImplFncGetSpecialChars = fn;
}
// -----------------------------------------------------------------------
FncGetSpecialChars Edit::GetGetSpecialCharsFunction()
{
return pImplFncGetSpecialChars;
}
// -----------------------------------------------------------------------
PopupMenu* Edit::CreatePopupMenu()
{
ResMgr* pResMgr = ImplGetResMgr();
if( ! pResMgr )
return new PopupMenu();
PopupMenu* pPopup = new PopupMenu( ResId( SV_RESID_MENU_EDIT, *pResMgr ) );
pPopup->SetAccelKey( SV_MENU_EDIT_UNDO, KeyCode( KEYFUNC_UNDO ) );
pPopup->SetAccelKey( SV_MENU_EDIT_CUT, KeyCode( KEYFUNC_CUT ) );
pPopup->SetAccelKey( SV_MENU_EDIT_COPY, KeyCode( KEYFUNC_COPY ) );
pPopup->SetAccelKey( SV_MENU_EDIT_PASTE, KeyCode( KEYFUNC_PASTE ) );
pPopup->SetAccelKey( SV_MENU_EDIT_DELETE, KeyCode( KEYFUNC_DELETE ) );
pPopup->SetAccelKey( SV_MENU_EDIT_SELECTALL, KeyCode( KEY_A, sal_False, sal_True, sal_False, sal_False ) );
pPopup->SetAccelKey( SV_MENU_EDIT_INSERTSYMBOL, KeyCode( KEY_S, sal_True, sal_True, sal_False, sal_False ) );
return pPopup;
}
// -----------------------------------------------------------------------
void Edit::DeletePopupMenu( PopupMenu* pMenu )
{
delete pMenu;
}
// ::com::sun::star::datatransfer::dnd::XDragGestureListener
void Edit::dragGestureRecognized( const ::com::sun::star::datatransfer::dnd::DragGestureEvent& rDGE ) throw (::com::sun::star::uno::RuntimeException)
{
vos::OGuard aVclGuard( Application::GetSolarMutex() );
if ( !IsTracking() && maSelection.Len() &&
!(GetStyle() & WB_PASSWORD) && (!mpDDInfo || mpDDInfo->bStarterOfDD == sal_False) ) // Kein Mehrfach D&D
{
Selection aSel( maSelection );
aSel.Justify();
// Nur wenn Maus in der Selektion...
Point aMousePos( rDGE.DragOriginX, rDGE.DragOriginY );
xub_StrLen nChar = ImplGetCharPos( aMousePos );
if ( (nChar >= aSel.Min()) && (nChar < aSel.Max()) )
{
if ( !mpDDInfo )
mpDDInfo = new DDInfo;
mpDDInfo->bStarterOfDD = sal_True;
mpDDInfo->aDndStartSel = aSel;
if ( IsTracking() )
EndTracking(); // Vor D&D Tracking ausschalten
::vcl::unohelper::TextDataObject* pDataObj = new ::vcl::unohelper::TextDataObject( GetSelected() );
sal_Int8 nActions = datatransfer::dnd::DNDConstants::ACTION_COPY;
if ( !IsReadOnly() )
nActions |= datatransfer::dnd::DNDConstants::ACTION_MOVE;
rDGE.DragSource->startDrag( rDGE, nActions, 0 /*cursor*/, 0 /*image*/, pDataObj, mxDnDListener );
if ( GetCursor() )
GetCursor()->Hide();
}
}
}
// ::com::sun::star::datatransfer::dnd::XDragSourceListener
void Edit::dragDropEnd( const ::com::sun::star::datatransfer::dnd::DragSourceDropEvent& rDSDE ) throw (::com::sun::star::uno::RuntimeException)
{
vos::OGuard aVclGuard( Application::GetSolarMutex() );
if ( rDSDE.DropSuccess && ( rDSDE.DropAction & datatransfer::dnd::DNDConstants::ACTION_MOVE ) )
{
Selection aSel( mpDDInfo->aDndStartSel );
if ( mpDDInfo->bDroppedInMe )
{
if ( aSel.Max() > mpDDInfo->nDropPos )
{
long nLen = aSel.Len();
aSel.Min() += nLen;
aSel.Max() += nLen;
}
}
ImplDelete( aSel, EDIT_DEL_RIGHT, EDIT_DELMODE_SIMPLE );
ImplModified();
}
ImplHideDDCursor();
delete mpDDInfo;
mpDDInfo = NULL;
}
// ::com::sun::star::datatransfer::dnd::XDropTargetListener
void Edit::drop( const ::com::sun::star::datatransfer::dnd::DropTargetDropEvent& rDTDE ) throw (::com::sun::star::uno::RuntimeException)
{
vos::OGuard aVclGuard( Application::GetSolarMutex() );
sal_Bool bChanges = sal_False;
if ( !mbReadOnly && mpDDInfo )
{
ImplHideDDCursor();
Selection aSel( maSelection );
aSel.Justify();
if ( aSel.Len() && !mpDDInfo->bStarterOfDD )
ImplDelete( aSel, EDIT_DEL_RIGHT, EDIT_DELMODE_SIMPLE );
mpDDInfo->bDroppedInMe = sal_True;
aSel.Min() = mpDDInfo->nDropPos;
aSel.Max() = mpDDInfo->nDropPos;
ImplSetSelection( aSel );
uno::Reference< datatransfer::XTransferable > xDataObj = rDTDE.Transferable;
if ( xDataObj.is() )
{
datatransfer::DataFlavor aFlavor;
SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aFlavor );
if ( xDataObj->isDataFlavorSupported( aFlavor ) )
{
uno::Any aData = xDataObj->getTransferData( aFlavor );
::rtl::OUString aText;
aData >>= aText;
ImplInsertText( aText );
bChanges = sal_True;
ImplModified();
}
}
if ( !mpDDInfo->bStarterOfDD )
{
delete mpDDInfo;
mpDDInfo = NULL;
}
}
rDTDE.Context->dropComplete( bChanges );
}
void Edit::dragEnter( const ::com::sun::star::datatransfer::dnd::DropTargetDragEnterEvent& rDTDE ) throw (::com::sun::star::uno::RuntimeException)
{
if ( !mpDDInfo )
{
mpDDInfo = new DDInfo;
}
// search for string data type
const Sequence< com::sun::star::datatransfer::DataFlavor >& rFlavors( rDTDE.SupportedDataFlavors );
sal_Int32 nEle = rFlavors.getLength();
mpDDInfo->bIsStringSupported = sal_False;
for( sal_Int32 i = 0; i < nEle; i++ )
{
sal_Int32 nIndex = 0;
rtl::OUString aMimetype = rFlavors[i].MimeType.getToken( 0, ';', nIndex );
if( aMimetype.equalsAscii( "text/plain" ) )
{
mpDDInfo->bIsStringSupported = sal_True;
break;
}
}
}
void Edit::dragExit( const ::com::sun::star::datatransfer::dnd::DropTargetEvent& ) throw (::com::sun::star::uno::RuntimeException)
{
vos::OGuard aVclGuard( Application::GetSolarMutex() );
ImplHideDDCursor();
}
void Edit::dragOver( const ::com::sun::star::datatransfer::dnd::DropTargetDragEvent& rDTDE ) throw (::com::sun::star::uno::RuntimeException)
{
vos::OGuard aVclGuard( Application::GetSolarMutex() );
Point aMousePos( rDTDE.LocationX, rDTDE.LocationY );
xub_StrLen nPrevDropPos = mpDDInfo->nDropPos;
mpDDInfo->nDropPos = ImplGetCharPos( aMousePos );
/*
Size aOutSize = GetOutputSizePixel();
if ( ( aMousePos.X() < 0 ) || ( aMousePos.X() > aOutSize.Width() ) )
{
// Scroll?
// No, I will not receive events in this case....
}
*/
Selection aSel( maSelection );
aSel.Justify();
// Don't accept drop in selection or read-only field...
if ( IsReadOnly() || aSel.IsInside( mpDDInfo->nDropPos ) || ! mpDDInfo->bIsStringSupported )
{
ImplHideDDCursor();
rDTDE.Context->rejectDrag();
}
else
{
// Alten Cursor wegzeichnen...
if ( !mpDDInfo->bVisCursor || ( nPrevDropPos != mpDDInfo->nDropPos ) )
{
ImplHideDDCursor();
ImplShowDDCursor();
}
rDTDE.Context->acceptDrag( rDTDE.DropAction );
}
}
ImplSubEdit::ImplSubEdit( Edit* pParent, WinBits nStyle ) :
Edit( pParent, nStyle )
{
pParent->SetSubEdit( this );
}
// -----------------------------------------------------------------------
void ImplSubEdit::Modify()
{
GetParent()->Modify();
}
XubString Edit::GetSurroundingText() const
{
if ( mpSubEdit )
return mpSubEdit->GetSurroundingText();
else
return maText;
}
Selection Edit::GetSurroundingTextSelection() const
{
return GetSelection();
}