1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <vcl/builder.hxx>
22 #include <vcl/event.hxx>
23 #include <vcl/cursor.hxx>
24 #include <vcl/menu.hxx>
25 #include <vcl/toolkit/edit.hxx>
26 #include <vcl/weld.hxx>
27 #include <vcl/specialchars.hxx>
28 #include <vcl/svapp.hxx>
29 #include <vcl/settings.hxx>
30 #include <vcl/transfer.hxx>
31 #include <vcl/uitest/uiobject.hxx>
32 #include <vcl/ptrstyle.hxx>
36 #include <strings.hrc>
38 #include <com/sun/star/i18n/BreakIterator.hpp>
39 #include <com/sun/star/i18n/CharacterIteratorMode.hpp>
40 #include <com/sun/star/i18n/WordType.hpp>
41 #include <com/sun/star/datatransfer/XTransferable.hpp>
42 #include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
44 #include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
45 #include <com/sun/star/datatransfer/dnd/XDragGestureRecognizer.hpp>
46 #include <com/sun/star/datatransfer/dnd/XDropTarget.hpp>
48 #include <com/sun/star/i18n/InputSequenceChecker.hpp>
49 #include <com/sun/star/i18n/InputSequenceCheckMode.hpp>
50 #include <com/sun/star/i18n/ScriptType.hpp>
52 #include <com/sun/star/uno/Any.hxx>
54 #include <comphelper/processfactory.hxx>
55 #include <comphelper/string.hxx>
57 #include <sot/exchange.hxx>
58 #include <sot/formats.hxx>
59 #include <sal/macros.h>
60 #include <sal/log.hxx>
62 #include <i18nlangtag/languagetag.hxx>
63 #include <vcl/unohelp2.hxx>
64 #include <o3tl/safeint.hxx>
65 #include <o3tl/string_view.hxx>
66 #include <officecfg/Office/Common.hxx>
67 #include <tools/json_writer.hxx>
71 #include <string_view>
73 using namespace ::com::sun::star
;
74 using namespace ::com::sun::star::uno
;
75 using namespace ::com::sun::star::lang
;
78 // - if Tracking-Cancel recreate DefaultSelection
80 static FncGetSpecialChars pImplFncGetSpecialChars
= nullptr;
82 #define EDIT_ALIGN_LEFT 1
83 #define EDIT_ALIGN_CENTER 2
84 #define EDIT_ALIGN_RIGHT 3
86 #define EDIT_DEL_LEFT 1
87 #define EDIT_DEL_RIGHT 2
89 #define EDIT_DELMODE_SIMPLE 11
90 #define EDIT_DELMODE_RESTOFWORD 12
91 #define EDIT_DELMODE_RESTOFCONTENT 13
96 Selection aDndStartSel
;
101 bool bIsStringSupported
;
105 aCursor
.SetStyle( CURSOR_SHADOW
);
107 bStarterOfDD
= false;
108 bDroppedInMe
= false;
110 bIsStringSupported
= false;
116 OUString aOldTextAfterStartPos
;
117 std::unique_ptr
<ExtTextInputAttr
[]>
122 bool bWasCursorOverwrite
;
124 Impl_IMEInfos(sal_Int32 nPos
, OUString aOldTextAfterStartPos
);
126 void CopyAttribs(const ExtTextInputAttr
* pA
, sal_Int32 nL
);
127 void DestroyAttribs();
130 Impl_IMEInfos::Impl_IMEInfos(sal_Int32 nP
, OUString _aOldTextAfterStartPos
)
131 : aOldTextAfterStartPos(std::move(_aOldTextAfterStartPos
)),
135 bWasCursorOverwrite(false)
139 void Impl_IMEInfos::CopyAttribs(const ExtTextInputAttr
* pA
, sal_Int32 nL
)
142 pAttribs
.reset(new ExtTextInputAttr
[ nL
]);
143 memcpy( pAttribs
.get(), pA
, nL
*sizeof(ExtTextInputAttr
) );
146 void Impl_IMEInfos::DestroyAttribs()
152 Edit::Edit( WindowType nType
)
158 Edit::Edit( vcl::Window
* pParent
, WinBits nStyle
)
159 : Control( WindowType::EDIT
)
162 ImplInit( pParent
, nStyle
);
165 void Edit::SetWidthInChars(sal_Int32 nWidthInChars
)
167 if (mnWidthInChars
!= nWidthInChars
)
169 mnWidthInChars
= nWidthInChars
;
174 void Edit::setMaxWidthChars(sal_Int32 nWidth
)
176 if (nWidth
!= mnMaxWidthChars
)
178 mnMaxWidthChars
= nWidth
;
183 bool Edit::set_property(const OUString
&rKey
, const OUString
&rValue
)
185 if (rKey
== "width-chars")
186 SetWidthInChars(rValue
.toInt32());
187 else if (rKey
== "max-width-chars")
188 setMaxWidthChars(rValue
.toInt32());
189 else if (rKey
== "max-length")
191 sal_Int32 nTextLen
= rValue
.toInt32();
192 SetMaxTextLen(nTextLen
== 0 ? EDIT_NOLIMIT
: nTextLen
);
194 else if (rKey
== "editable")
196 SetReadOnly(!toBool(rValue
));
198 else if (rKey
== "overwrite-mode")
200 SetInsertMode(!toBool(rValue
));
202 else if (rKey
== "visibility")
208 else if (rKey
== "placeholder-text")
209 SetPlaceholderText(rValue
);
210 else if (rKey
== "shadow-type")
212 if (GetStyle() & WB_BORDER
)
213 SetBorderStyle(rValue
== "none" ? WindowBorderStyle::MONO
: WindowBorderStyle::NORMAL
);
216 return Control::set_property(rKey
, rValue
);
230 vcl::Cursor
* pCursor
= GetCursor();
233 SetCursor( nullptr );
239 if ( mxDnDListener
.is() )
241 if ( GetDragGestureRecognizer().is() )
243 GetDragGestureRecognizer()->removeDragGestureListener( mxDnDListener
);
245 if ( GetDropTarget().is() )
247 GetDropTarget()->removeDropTargetListener( mxDnDListener
);
250 mxDnDListener
->disposing( lang::EventObject() ); // #95154# #96585# Empty Source means it's the Client
251 mxDnDListener
.clear();
254 SetType(WindowType::WINDOW
);
256 mpSubEdit
.disposeAndClear();
260 void Edit::ImplInitEditData()
262 mpSubEdit
= VclPtr
<Edit
>();
263 mpFilterText
= nullptr;
265 mnAlign
= EDIT_ALIGN_LEFT
;
266 mnMaxTextLen
= EDIT_NOLIMIT
;
268 mnMaxWidthChars
= -1;
269 mbInternModified
= false;
272 mbClickedInSelection
= false;
273 mbActivePopup
= false;
275 mbForceControlBackground
= false;
278 mpIMEInfos
= nullptr;
281 // no default mirroring for Edit controls
282 // note: controls that use a subedit will revert this (SpinField, ComboBox)
285 mxDnDListener
= new vcl::unohelper::DragAndDropWrapper( this );
288 bool Edit::ImplUseNativeBorder(vcl::RenderContext
const & rRenderContext
, WinBits nStyle
) const
290 bool bRet
= rRenderContext
.IsNativeControlSupported(ImplGetNativeControlType(),
291 ControlPart::HasBackgroundTexture
)
292 && ((nStyle
& WB_BORDER
) && !(nStyle
& WB_NOBORDER
));
293 if (!bRet
&& mbIsSubEdit
)
295 vcl::Window
* pWindow
= GetParent();
296 nStyle
= pWindow
->GetStyle();
297 bRet
= pWindow
->IsNativeControlSupported(ImplGetNativeControlType(),
298 ControlPart::HasBackgroundTexture
)
299 && ((nStyle
& WB_BORDER
) && !(nStyle
& WB_NOBORDER
));
304 void Edit::ImplInit(vcl::Window
* pParent
, WinBits nStyle
)
306 nStyle
= ImplInitStyle(nStyle
);
308 if (!(nStyle
& (WB_CENTER
| WB_RIGHT
)))
311 Control::ImplInit(pParent
, nStyle
, nullptr);
313 mbReadOnly
= (nStyle
& WB_READONLY
) != 0;
315 mnAlign
= EDIT_ALIGN_LEFT
;
317 // hack: right align until keyinput and cursor travelling works
319 mnAlign
= EDIT_ALIGN_RIGHT
;
321 if ( nStyle
& WB_RIGHT
)
322 mnAlign
= EDIT_ALIGN_RIGHT
;
323 else if ( nStyle
& WB_CENTER
)
324 mnAlign
= EDIT_ALIGN_CENTER
;
326 SetCursor( new vcl::Cursor
);
328 SetPointer( PointerStyle::Text
);
329 ApplySettings(*GetOutDev());
331 uno::Reference
< datatransfer::dnd::XDragGestureRecognizer
> xDGR
= GetDragGestureRecognizer();
334 xDGR
->addDragGestureListener( mxDnDListener
);
335 GetDropTarget()->addDropTargetListener( mxDnDListener
);
336 GetDropTarget()->setActive( true );
337 GetDropTarget()->setDefaultActions( datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE
);
341 WinBits
Edit::ImplInitStyle( WinBits nStyle
)
343 if ( !(nStyle
& WB_NOTABSTOP
) )
344 nStyle
|= WB_TABSTOP
;
345 if ( !(nStyle
& WB_NOGROUP
) )
351 bool Edit::IsCharInput( const KeyEvent
& rKeyEvent
)
353 // In the future we must use new Unicode functions for this
354 sal_Unicode cCharCode
= rKeyEvent
.GetCharCode();
355 return ((cCharCode
>= 32) && (cCharCode
!= 127) &&
356 !rKeyEvent
.GetKeyCode().IsMod3() &&
357 !rKeyEvent
.GetKeyCode().IsMod2() &&
358 !rKeyEvent
.GetKeyCode().IsMod1() );
361 void Edit::ApplySettings(vcl::RenderContext
& rRenderContext
)
363 Control::ApplySettings(rRenderContext
);
365 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
367 const vcl::Font
& aFont
= rStyleSettings
.GetFieldFont();
368 ApplyControlFont(rRenderContext
, aFont
);
370 ImplClearLayoutData();
372 Color aTextColor
= rStyleSettings
.GetFieldTextColor();
373 ApplyControlForeground(rRenderContext
, aTextColor
);
375 if (IsControlBackground())
377 rRenderContext
.SetBackground(GetControlBackground());
378 rRenderContext
.SetFillColor(GetControlBackground());
380 if (ImplUseNativeBorder(rRenderContext
, GetStyle()))
382 // indicates that no non-native drawing of background should take place
383 mpWindowImpl
->mnNativeBackground
= ControlPart::Entire
;
386 else if (ImplUseNativeBorder(rRenderContext
, GetStyle()))
388 // Transparent background
389 rRenderContext
.SetBackground();
390 rRenderContext
.SetFillColor();
394 rRenderContext
.SetBackground(rStyleSettings
.GetFieldColor());
395 rRenderContext
.SetFillColor(rStyleSettings
.GetFieldColor());
399 tools::Long
Edit::ImplGetExtraXOffset() const
401 // MT 09/2002: nExtraOffsetX should become a member, instead of checking every time,
402 // but I need an incompatible update for this...
403 // #94095# Use extra offset only when edit has a border
404 tools::Long nExtraOffset
= 0;
405 if( ( GetStyle() & WB_BORDER
) || ( mbIsSubEdit
&& ( GetParent()->GetStyle() & WB_BORDER
) ) )
411 tools::Long
Edit::ImplGetExtraYOffset() const
413 tools::Long nExtraOffset
= 0;
414 ControlType eCtrlType
= ImplGetNativeControlType();
415 if (eCtrlType
!= ControlType::EditboxNoBorder
)
417 // add some space between text entry and border
423 OUString
Edit::ImplGetText() const
425 if ( mcEchoChar
|| mbPassword
)
427 sal_Unicode cEchoChar
;
429 cEchoChar
= mcEchoChar
;
431 cEchoChar
= u
'\x2022';
432 OUStringBuffer
aText(maText
.getLength());
433 comphelper::string::padToLength(aText
, maText
.getLength(), cEchoChar
);
434 return aText
.makeStringAndClear();
437 return maText
.toString();
440 void Edit::ImplInvalidateOrRepaint()
442 if( IsPaintTransparent() )
445 // FIXME: this is currently only on macOS
446 if( ImplGetSVData()->maNWFData
.mbNoFocusRects
)
453 tools::Long
Edit::ImplGetTextYPosition() const
455 if ( GetStyle() & WB_TOP
)
456 return ImplGetExtraXOffset();
457 else if ( GetStyle() & WB_BOTTOM
)
458 return GetOutputSizePixel().Height() - GetTextHeight() - ImplGetExtraXOffset();
459 return ( GetOutputSizePixel().Height() - GetTextHeight() ) / 2;
462 void Edit::ImplRepaint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRectangle
)
464 if (!IsReallyVisible())
467 ApplySettings(rRenderContext
);
469 const OUString aText
= ImplGetText();
470 const sal_Int32 nLen
= aText
.getLength();
474 GetOutDev()->GetCaretPositions(aText
, aDX
, 0, nLen
);
476 tools::Long nTH
= GetTextHeight();
477 Point
aPos(mnXOffset
, ImplGetTextYPosition());
479 vcl::Cursor
* pCursor
= GetCursor();
480 bool bVisCursor
= pCursor
&& pCursor
->IsVisible();
484 ImplClearBackground(rRenderContext
, rRectangle
, 0, GetOutputSizePixel().Width()-1);
486 bool bPaintPlaceholderText
= aText
.isEmpty() && !maPlaceholderText
.isEmpty();
488 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
490 if (!IsEnabled() || bPaintPlaceholderText
)
491 rRenderContext
.SetTextColor(rStyleSettings
.GetDisableColor());
493 // Set background color of the normal text
494 if (mbForceControlBackground
&& IsControlBackground())
496 // check if we need to set ControlBackground even in NWF case
497 rRenderContext
.Push(vcl::PushFlags::FILLCOLOR
| vcl::PushFlags::LINECOLOR
);
498 rRenderContext
.SetLineColor();
499 rRenderContext
.SetFillColor(GetControlBackground());
500 rRenderContext
.DrawRect(tools::Rectangle(aPos
, Size(GetOutputSizePixel().Width() - 2 * mnXOffset
, GetOutputSizePixel().Height())));
501 rRenderContext
.Pop();
503 rRenderContext
.SetTextFillColor(GetControlBackground());
505 else if (IsPaintTransparent() || ImplUseNativeBorder(rRenderContext
, GetStyle()))
506 rRenderContext
.SetTextFillColor();
508 rRenderContext
.SetTextFillColor(IsControlBackground() ? GetControlBackground() : rStyleSettings
.GetFieldColor());
510 ImplPaintBorder(rRenderContext
);
512 bool bDrawSelection
= maSelection
.Len() && (HasFocus() || (GetStyle() & WB_NOHIDESELECTION
) || mbActivePopup
);
514 aPos
.setX( mnXOffset
+ ImplGetExtraXOffset() );
515 if (bPaintPlaceholderText
)
517 rRenderContext
.DrawText(aPos
, maPlaceholderText
);
519 else if (!bDrawSelection
&& !mpIMEInfos
)
521 rRenderContext
.DrawText(aPos
, aText
, 0, nLen
);
525 // save graphics state
526 rRenderContext
.Push();
527 // first calculate highlighted and non highlighted clip regions
528 vcl::Region aHighlightClipRegion
;
529 vcl::Region aNormalClipRegion
;
530 Selection
aTmpSel(maSelection
);
532 // selection is highlighted
533 for(sal_Int32 i
= 0; i
< nLen
; ++i
)
535 tools::Rectangle
aRect(aPos
, Size(10, nTH
));
536 aRect
.SetLeft( aDX
[2 * i
] + mnXOffset
+ ImplGetExtraXOffset() );
537 aRect
.SetRight( aDX
[2 * i
+ 1] + mnXOffset
+ ImplGetExtraXOffset() );
539 bool bHighlight
= false;
540 if (i
>= aTmpSel
.Min() && i
< aTmpSel
.Max())
543 if (mpIMEInfos
&& mpIMEInfos
->pAttribs
&&
544 i
>= mpIMEInfos
->nPos
&& i
< (mpIMEInfos
->nPos
+mpIMEInfos
->nLen
) &&
545 (mpIMEInfos
->pAttribs
[i
- mpIMEInfos
->nPos
] & ExtTextInputAttr::Highlight
))
551 aHighlightClipRegion
.Union(aRect
);
553 aNormalClipRegion
.Union(aRect
);
556 Color aNormalTextColor
= rRenderContext
.GetTextColor();
557 rRenderContext
.SetClipRegion(aNormalClipRegion
);
559 if (IsPaintTransparent())
560 rRenderContext
.SetTextFillColor();
563 // Set background color when part of the text is selected
564 if (ImplUseNativeBorder(rRenderContext
, GetStyle()))
566 if( mbForceControlBackground
&& IsControlBackground() )
567 rRenderContext
.SetTextFillColor(GetControlBackground());
569 rRenderContext
.SetTextFillColor();
573 rRenderContext
.SetTextFillColor(IsControlBackground() ? GetControlBackground() : rStyleSettings
.GetFieldColor());
576 rRenderContext
.DrawText(aPos
, aText
, 0, nLen
);
578 // draw highlighted text
579 rRenderContext
.SetClipRegion(aHighlightClipRegion
);
580 rRenderContext
.SetTextColor(rStyleSettings
.GetHighlightTextColor());
581 rRenderContext
.SetTextFillColor(rStyleSettings
.GetHighlightColor());
582 rRenderContext
.DrawText(aPos
, aText
, 0, nLen
);
584 // if IME info exists loop over portions and output different font attributes
585 if (mpIMEInfos
&& mpIMEInfos
->pAttribs
)
587 for(int n
= 0; n
< 2; n
++)
592 rRenderContext
.SetTextColor(aNormalTextColor
);
593 if (IsPaintTransparent())
594 rRenderContext
.SetTextFillColor();
596 rRenderContext
.SetTextFillColor(IsControlBackground() ? GetControlBackground() : rStyleSettings
.GetFieldColor());
597 aRegion
= aNormalClipRegion
;
601 rRenderContext
.SetTextColor(rStyleSettings
.GetHighlightTextColor());
602 rRenderContext
.SetTextFillColor(rStyleSettings
.GetHighlightColor());
603 aRegion
= aHighlightClipRegion
;
606 for(int i
= 0; i
< mpIMEInfos
->nLen
; )
608 ExtTextInputAttr nAttr
= mpIMEInfos
->pAttribs
[i
];
611 while (nIndex
< mpIMEInfos
->nLen
&& mpIMEInfos
->pAttribs
[nIndex
] == nAttr
) // #112631# check nIndex before using it
613 tools::Rectangle
aRect( aPos
, Size( 10, nTH
) );
614 aRect
.SetLeft( aDX
[2 * (nIndex
+ mpIMEInfos
->nPos
)] + mnXOffset
+ ImplGetExtraXOffset() );
615 aRect
.SetRight( aDX
[2 * (nIndex
+ mpIMEInfos
->nPos
) + 1] + mnXOffset
+ ImplGetExtraXOffset() );
621 aClip
.Intersect(aRegion
);
622 if (!aClip
.IsEmpty() && nAttr
!= ExtTextInputAttr::NONE
)
624 vcl::Font aFont
= rRenderContext
.GetFont();
625 if (nAttr
& ExtTextInputAttr::Underline
)
626 aFont
.SetUnderline(LINESTYLE_SINGLE
);
627 else if (nAttr
& ExtTextInputAttr::DoubleUnderline
)
628 aFont
.SetUnderline(LINESTYLE_DOUBLE
);
629 else if (nAttr
& ExtTextInputAttr::BoldUnderline
)
630 aFont
.SetUnderline( LINESTYLE_BOLD
);
631 else if (nAttr
& ExtTextInputAttr::DottedUnderline
)
632 aFont
.SetUnderline( LINESTYLE_DOTTED
);
633 else if (nAttr
& ExtTextInputAttr::DashDotUnderline
)
634 aFont
.SetUnderline( LINESTYLE_DASHDOT
);
635 else if (nAttr
& ExtTextInputAttr::GrayWaveline
)
637 aFont
.SetUnderline(LINESTYLE_WAVE
);
638 rRenderContext
.SetTextLineColor(COL_LIGHTGRAY
);
640 rRenderContext
.SetFont(aFont
);
642 if (nAttr
& ExtTextInputAttr::RedText
)
643 rRenderContext
.SetTextColor(COL_RED
);
644 else if (nAttr
& ExtTextInputAttr::HalfToneText
)
645 rRenderContext
.SetTextColor(COL_LIGHTGRAY
);
647 rRenderContext
.SetClipRegion(aClip
);
648 rRenderContext
.DrawText(aPos
, aText
, 0, nLen
);
654 // restore graphics state
655 rRenderContext
.Pop();
658 if (bVisCursor
&& (!mpIMEInfos
|| mpIMEInfos
->bCursor
))
662 void Edit::ImplDelete( const Selection
& rSelection
, sal_uInt8 nDirection
, sal_uInt8 nMode
)
664 const sal_Int32 nTextLen
= ImplGetText().getLength();
666 // deleting possible?
667 if ( !rSelection
.Len() &&
668 (((rSelection
.Min() == 0) && (nDirection
== EDIT_DEL_LEFT
)) ||
669 ((rSelection
.Max() == nTextLen
) && (nDirection
== EDIT_DEL_RIGHT
))) )
672 ImplClearLayoutData();
674 Selection
aSelection( rSelection
);
675 aSelection
.Normalize();
677 if ( !aSelection
.Len() )
679 uno::Reference
< i18n::XBreakIterator
> xBI
= ImplGetBreakIterator();
680 if ( nDirection
== EDIT_DEL_LEFT
)
682 if ( nMode
== EDIT_DELMODE_RESTOFWORD
)
684 const OUString sText
= maText
.toString();
685 i18n::Boundary aBoundary
= xBI
->getWordBoundary( sText
, aSelection
.Min(),
686 GetSettings().GetLanguageTag().getLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES
, true );
687 auto startPos
= aBoundary
.startPos
;
688 if ( startPos
== aSelection
.Min() )
690 aBoundary
= xBI
->previousWord( sText
, aSelection
.Min(),
691 GetSettings().GetLanguageTag().getLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES
);
692 startPos
= std::max(aBoundary
.startPos
, sal_Int32(0));
694 aSelection
.Min() = startPos
;
696 else if ( nMode
== EDIT_DELMODE_RESTOFCONTENT
)
698 aSelection
.Min() = 0;
702 sal_Int32 nCount
= 1;
703 aSelection
.Min() = xBI
->previousCharacters( maText
.toString(), aSelection
.Min(),
704 GetSettings().GetLanguageTag().getLocale(), i18n::CharacterIteratorMode::SKIPCHARACTER
, nCount
, nCount
);
709 if ( nMode
== EDIT_DELMODE_RESTOFWORD
)
711 i18n::Boundary aBoundary
= xBI
->nextWord( maText
.toString(), aSelection
.Max(),
712 GetSettings().GetLanguageTag().getLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES
);
713 aSelection
.Max() = aBoundary
.startPos
;
715 else if ( nMode
== EDIT_DELMODE_RESTOFCONTENT
)
717 aSelection
.Max() = nTextLen
;
721 sal_Int32 nCount
= 1;
722 aSelection
.Max() = xBI
->nextCharacters( maText
.toString(), aSelection
.Max(),
723 GetSettings().GetLanguageTag().getLocale(), i18n::CharacterIteratorMode::SKIPCHARACTER
, nCount
, nCount
);
728 const auto nSelectionMin
= aSelection
.Min();
729 maText
.remove( nSelectionMin
, aSelection
.Len() );
730 maSelection
.Min() = nSelectionMin
;
731 maSelection
.Max() = nSelectionMin
;
733 mbInternModified
= true;
736 OUString
Edit::ImplGetValidString( const OUString
& rString
)
738 OUString aValidString
= rString
.replaceAll("\n", "").replaceAll("\r", "");
739 aValidString
= aValidString
.replace('\t', ' ');
743 uno::Reference
<i18n::XBreakIterator
> const& Edit::ImplGetBreakIterator()
745 if (!mxBreakIterator
)
746 mxBreakIterator
= i18n::BreakIterator::create(::comphelper::getProcessComponentContext());
747 return mxBreakIterator
;
750 uno::Reference
<i18n::XExtendedInputSequenceChecker
> const& Edit::ImplGetInputSequenceChecker()
753 mxISC
= i18n::InputSequenceChecker::create(::comphelper::getProcessComponentContext());
757 void Edit::ShowTruncationWarning(weld::Widget
* pParent
)
759 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(pParent
, VclMessageType::Warning
,
760 VclButtonsType::Ok
, VclResId(SV_EDIT_WARNING_STR
)));
764 bool Edit::ImplTruncateToMaxLen( OUString
& rStr
, sal_Int32 nSelectionLen
) const
766 bool bWasTruncated
= false;
767 if (maText
.getLength() - nSelectionLen
> mnMaxTextLen
- rStr
.getLength())
769 sal_Int32 nErasePos
= mnMaxTextLen
- maText
.getLength() + nSelectionLen
;
770 rStr
= rStr
.copy( 0, nErasePos
);
771 bWasTruncated
= true;
773 return bWasTruncated
;
776 void Edit::ImplInsertText( const OUString
& rStr
, const Selection
* pNewSel
, bool bIsUserInput
)
778 Selection
aSelection( maSelection
);
779 aSelection
.Normalize();
781 OUString
aNewText( ImplGetValidString( rStr
) );
783 // as below, if there's no selection, but we're in overwrite mode and not beyond
784 // the end of the existing text then that's like a selection of 1
785 auto nSelectionLen
= aSelection
.Len();
786 if (!nSelectionLen
&& !mbInsertMode
&& aSelection
.Max() < maText
.getLength())
788 ImplTruncateToMaxLen( aNewText
, nSelectionLen
);
790 ImplClearLayoutData();
792 if ( aSelection
.Len() )
793 maText
.remove( aSelection
.Min(), aSelection
.Len() );
794 else if (!mbInsertMode
&& aSelection
.Max() < maText
.getLength())
795 maText
.remove( aSelection
.Max(), 1 );
797 // take care of input-sequence-checking now
798 if (bIsUserInput
&& !rStr
.isEmpty())
800 SAL_WARN_IF( rStr
.getLength() != 1, "vcl", "unexpected string length. User input is expected to provide 1 char only!" );
802 // determine if input-sequence-checking should be applied or not
804 uno::Reference
< i18n::XBreakIterator
> xBI
= ImplGetBreakIterator();
805 bool bIsInputSequenceChecking
= rStr
.getLength() == 1 &&
806 officecfg::Office::Common::I18N::CTL::CTLFont::get() &&
807 officecfg::Office::Common::I18N::CTL::CTLSequenceChecking::get() &&
808 aSelection
.Min() > 0 && /* first char needs not to be checked */
809 xBI
.is() && i18n::ScriptType::COMPLEX
== xBI
->getScriptType( rStr
, 0 );
811 if (bIsInputSequenceChecking
)
813 uno::Reference
< i18n::XExtendedInputSequenceChecker
> xISC
= ImplGetInputSequenceChecker();
816 sal_Unicode cChar
= rStr
[0];
817 sal_Int32 nTmpPos
= aSelection
.Min();
818 sal_Int16 nCheckMode
= officecfg::Office::Common::I18N::CTL::CTLSequenceCheckingRestricted::get()?
819 i18n::InputSequenceCheckMode::STRICT
: i18n::InputSequenceCheckMode::BASIC
;
821 // the text that needs to be checked is only the one
822 // before the current cursor position
823 const OUString
aOldText( maText
.subView(0, nTmpPos
) );
824 OUString
aTmpText( aOldText
);
825 if (officecfg::Office::Common::I18N::CTL::CTLSequenceCheckingTypeAndReplace::get())
827 xISC
->correctInputSequence( aTmpText
, nTmpPos
- 1, cChar
, nCheckMode
);
829 // find position of first character that has changed
830 sal_Int32 nOldLen
= aOldText
.getLength();
831 sal_Int32 nTmpLen
= aTmpText
.getLength();
832 const sal_Unicode
*pOldTxt
= aOldText
.getStr();
833 const sal_Unicode
*pTmpTxt
= aTmpText
.getStr();
834 sal_Int32 nChgPos
= 0;
835 while ( nChgPos
< nOldLen
&& nChgPos
< nTmpLen
&&
836 pOldTxt
[nChgPos
] == pTmpTxt
[nChgPos
] )
839 const OUString
aChgText( aTmpText
.copy( nChgPos
) );
841 // remove text from first pos to be changed to current pos
842 maText
.remove( nChgPos
, nTmpPos
- nChgPos
);
844 if (!aChgText
.isEmpty())
847 aSelection
.Min() = nChgPos
; // position for new text to be inserted
854 // should the character be ignored (i.e. not get inserted) ?
855 if (!xISC
->checkInputSequence( aOldText
, nTmpPos
- 1, cChar
, nCheckMode
))
861 // at this point now we will insert the non-empty text 'normally' some lines below...
864 if ( !aNewText
.isEmpty() )
865 maText
.insert( aSelection
.Min(), aNewText
);
869 maSelection
.Min() = aSelection
.Min() + aNewText
.getLength();
870 maSelection
.Max() = maSelection
.Min();
874 maSelection
= *pNewSel
;
875 if ( maSelection
.Min() > maText
.getLength() )
876 maSelection
.Min() = maText
.getLength();
877 if ( maSelection
.Max() > maText
.getLength() )
878 maSelection
.Max() = maText
.getLength();
882 mbInternModified
= true;
885 void Edit::ImplSetText( const OUString
& rText
, const Selection
* pNewSelection
)
887 // we delete text by "selecting" the old text completely then calling InsertText; this is flicker free
888 if ( ( rText
.getLength() > mnMaxTextLen
) ||
889 ( std::u16string_view(rText
) == std::u16string_view(maText
)
890 && (!pNewSelection
|| (*pNewSelection
== maSelection
)) ) )
893 ImplClearLayoutData();
894 maSelection
.Min() = 0;
895 maSelection
.Max() = maText
.getLength();
896 if ( mnXOffset
|| HasPaintEvent() )
899 maText
= ImplGetValidString( rText
);
901 // #i54929# recalculate mnXOffset before ImplSetSelection,
902 // else cursor ends up in wrong position
906 ImplSetSelection( *pNewSelection
, false );
908 if ( mnXOffset
&& !pNewSelection
)
909 maSelection
.Max() = 0;
914 ImplInsertText( rText
, pNewSelection
);
916 CallEventListeners( VclEventId::EditModify
);
919 ControlType
Edit::ImplGetNativeControlType() const
921 ControlType nCtrl
= ControlType::Generic
;
922 const vcl::Window
* pControl
= mbIsSubEdit
? GetParent() : this;
924 switch (pControl
->GetType())
926 case WindowType::COMBOBOX
:
927 case WindowType::PATTERNBOX
:
928 case WindowType::NUMERICBOX
:
929 case WindowType::METRICBOX
:
930 case WindowType::CURRENCYBOX
:
931 case WindowType::DATEBOX
:
932 case WindowType::TIMEBOX
:
933 case WindowType::LONGCURRENCYBOX
:
934 nCtrl
= ControlType::Combobox
;
937 case WindowType::MULTILINEEDIT
:
938 if ( GetWindow( GetWindowType::Border
) != this )
939 nCtrl
= ControlType::MultilineEditbox
;
941 nCtrl
= ControlType::EditboxNoBorder
;
944 case WindowType::EDIT
:
945 case WindowType::PATTERNFIELD
:
946 case WindowType::METRICFIELD
:
947 case WindowType::CURRENCYFIELD
:
948 case WindowType::DATEFIELD
:
949 case WindowType::TIMEFIELD
:
950 case WindowType::SPINFIELD
:
951 case WindowType::FORMATTEDFIELD
:
952 if (pControl
->GetStyle() & WB_SPIN
)
953 nCtrl
= ControlType::Spinbox
;
956 if (GetWindow(GetWindowType::Border
) != this)
957 nCtrl
= ControlType::Editbox
;
959 nCtrl
= ControlType::EditboxNoBorder
;
964 nCtrl
= ControlType::Editbox
;
969 void Edit::ImplClearBackground(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRectangle
, tools::Long nXStart
, tools::Long nXEnd
)
972 * note: at this point the cursor must be switched off already
974 tools::Rectangle
aRect(Point(), GetOutputSizePixel());
975 aRect
.SetLeft( nXStart
);
976 aRect
.SetRight( nXEnd
);
978 if( !(ImplUseNativeBorder(rRenderContext
, GetStyle()) || IsPaintTransparent()))
979 rRenderContext
.Erase(aRect
);
980 else if (SupportsDoubleBuffering() && mbIsSubEdit
)
982 // ImplPaintBorder() is a NOP, we have a native border, and this is a sub-edit of a control.
983 // That means we have to draw the parent native widget to paint the edit area to clear our background.
984 vcl::PaintBufferGuard
g(ImplGetWindowImpl()->mpFrameData
, GetParent());
985 GetParent()->Paint(rRenderContext
, rRectangle
);
989 void Edit::ImplPaintBorder(vcl::RenderContext
const & rRenderContext
)
991 // this is not needed when double-buffering
992 if (SupportsDoubleBuffering())
995 if (!(ImplUseNativeBorder(rRenderContext
, GetStyle()) || IsPaintTransparent()))
998 // draw the inner part by painting the whole control using its border window
999 vcl::Window
* pBorder
= GetWindow(GetWindowType::Border
);
1000 if (pBorder
== this)
1002 // we have no border, use parent
1003 vcl::Window
* pControl
= mbIsSubEdit
? GetParent() : this;
1004 pBorder
= pControl
->GetWindow(GetWindowType::Border
);
1005 if (pBorder
== this)
1006 pBorder
= GetParent();
1012 // set proper clipping region to not overdraw the whole control
1013 vcl::Region aClipRgn
= GetPaintRegion();
1014 if (!aClipRgn
.IsNull())
1016 // transform clipping region to border window's coordinate system
1017 if (IsRTLEnabled() != pBorder
->IsRTLEnabled() && AllSettings::GetLayoutRTL())
1019 // need to mirror in case border is not RTL but edit is (or vice versa)
1022 tools::Rectangle
aBounds(aClipRgn
.GetBoundRect());
1023 int xNew
= GetOutputSizePixel().Width() - aBounds
.GetWidth() - aBounds
.Left();
1024 aClipRgn
.Move(xNew
- aBounds
.Left(), 0);
1026 // move offset of border window
1027 Point aBorderOffs
= pBorder
->ScreenToOutputPixel(OutputToScreenPixel(Point()));
1028 aClipRgn
.Move(aBorderOffs
.X(), aBorderOffs
.Y());
1033 Point aBorderOffs
= pBorder
->ScreenToOutputPixel(OutputToScreenPixel(Point()));
1034 aClipRgn
.Move(aBorderOffs
.X(), aBorderOffs
.Y());
1037 vcl::Region
oldRgn(pBorder
->GetOutDev()->GetClipRegion());
1038 pBorder
->GetOutDev()->SetClipRegion(aClipRgn
);
1040 pBorder
->Paint(*pBorder
->GetOutDev(), tools::Rectangle());
1042 pBorder
->GetOutDev()->SetClipRegion(oldRgn
);
1046 pBorder
->Paint(*pBorder
->GetOutDev(), tools::Rectangle());
1050 void Edit::ImplShowCursor( bool bOnlyIfVisible
)
1052 if ( !IsUpdateMode() || ( bOnlyIfVisible
&& !IsReallyVisible() ) )
1055 vcl::Cursor
* pCursor
= GetCursor();
1056 OUString aText
= ImplGetText();
1058 tools::Long nTextPos
= 0;
1060 if( !aText
.isEmpty() )
1063 GetOutDev()->GetCaretPositions(aText
, aDX
, 0, aText
.getLength());
1065 if( maSelection
.Max() < aText
.getLength() )
1066 nTextPos
= aDX
[ 2*maSelection
.Max() ];
1068 nTextPos
= aDX
[ 2*aText
.getLength()-1 ];
1071 tools::Long nCursorWidth
= 0;
1072 if ( !mbInsertMode
&& !maSelection
.Len() && (maSelection
.Max() < aText
.getLength()) )
1073 nCursorWidth
= GetTextWidth(aText
, maSelection
.Max(), 1);
1074 tools::Long nCursorPosX
= nTextPos
+ mnXOffset
+ ImplGetExtraXOffset();
1076 // cursor should land in visible area
1077 const Size aOutSize
= GetOutputSizePixel();
1078 if ( (nCursorPosX
< 0) || (nCursorPosX
>= aOutSize
.Width()) )
1080 tools::Long nOldXOffset
= mnXOffset
;
1082 if ( nCursorPosX
< 0 )
1084 mnXOffset
= - nTextPos
;
1085 tools::Long nMaxX
= 0;
1086 mnXOffset
+= aOutSize
.Width() / 5;
1087 if ( mnXOffset
> nMaxX
)
1092 mnXOffset
= (aOutSize
.Width()-ImplGetExtraXOffset()) - nTextPos
;
1094 if ( (aOutSize
.Width()-ImplGetExtraXOffset()) < nTextPos
)
1096 tools::Long nMaxNegX
= (aOutSize
.Width()-ImplGetExtraXOffset()) - GetTextWidth( aText
);
1097 mnXOffset
-= aOutSize
.Width() / 5;
1098 if ( mnXOffset
< nMaxNegX
) // both negative...
1099 mnXOffset
= nMaxNegX
;
1103 nCursorPosX
= nTextPos
+ mnXOffset
+ ImplGetExtraXOffset();
1104 if ( nCursorPosX
== aOutSize
.Width() ) // then invisible...
1107 if ( mnXOffset
!= nOldXOffset
)
1108 ImplInvalidateOrRepaint();
1111 const tools::Long nTextHeight
= GetTextHeight();
1112 const tools::Long nCursorPosY
= ImplGetTextYPosition();
1115 pCursor
->SetPos( Point( nCursorPosX
, nCursorPosY
) );
1116 pCursor
->SetSize( Size( nCursorWidth
, nTextHeight
) );
1121 void Edit::ImplAlign()
1123 if (mnAlign
== EDIT_ALIGN_LEFT
&& !mnXOffset
)
1125 // short circuit common case and avoid slow GetTextWidth() calc
1129 tools::Long nTextWidth
= GetTextWidth( ImplGetText() );
1130 tools::Long nOutWidth
= GetOutputSizePixel().Width();
1132 if ( mnAlign
== EDIT_ALIGN_LEFT
)
1134 if (nTextWidth
< nOutWidth
)
1137 else if ( mnAlign
== EDIT_ALIGN_RIGHT
)
1139 tools::Long nMinXOffset
= nOutWidth
- nTextWidth
- 1 - ImplGetExtraXOffset();
1140 bool bRTL
= IsRTLEnabled();
1141 if( mbIsSubEdit
&& GetParent() )
1142 bRTL
= GetParent()->IsRTLEnabled();
1145 if( nTextWidth
< nOutWidth
)
1146 mnXOffset
= nMinXOffset
;
1150 if( nTextWidth
< nOutWidth
)
1151 mnXOffset
= nMinXOffset
;
1152 else if ( mnXOffset
< nMinXOffset
)
1153 mnXOffset
= nMinXOffset
;
1156 else if( mnAlign
== EDIT_ALIGN_CENTER
)
1158 // would be nicer with check while scrolling but then it's not centred in scrolled state
1159 mnXOffset
= (nOutWidth
- nTextWidth
) / 2;
1163 void Edit::ImplAlignAndPaint()
1166 ImplInvalidateOrRepaint();
1170 sal_Int32
Edit::ImplGetCharPos( const Point
& rWindowPos
) const
1172 sal_Int32 nIndex
= EDIT_NOLIMIT
;
1173 OUString aText
= ImplGetText();
1175 if (aText
.isEmpty())
1179 GetOutDev()->GetCaretPositions(aText
, aDX
, 0, aText
.getLength());
1180 tools::Long nX
= rWindowPos
.X() - mnXOffset
- ImplGetExtraXOffset();
1181 for (sal_Int32 i
= 0; i
< aText
.getLength(); aText
.iterateCodePoints(&i
))
1183 if( (aDX
[2*i
] >= nX
&& aDX
[2*i
+1] <= nX
) ||
1184 (aDX
[2*i
+1] >= nX
&& aDX
[2*i
] <= nX
))
1187 if( aDX
[2*i
] < aDX
[2*i
+1] )
1189 if( nX
> (aDX
[2*i
]+aDX
[2*i
+1])/2 )
1190 aText
.iterateCodePoints(&nIndex
);
1194 if( nX
< (aDX
[2*i
]+aDX
[2*i
+1])/2 )
1195 aText
.iterateCodePoints(&nIndex
);
1200 if( nIndex
== EDIT_NOLIMIT
)
1203 sal_Int32 nFinalIndex
= 0;
1204 tools::Long nDiff
= std::abs( aDX
[0]-nX
);
1206 if (!aText
.isEmpty())
1208 aText
.iterateCodePoints(&i
); //skip the first character
1210 while (i
< aText
.getLength())
1212 tools::Long nNewDiff
= std::abs( aDX
[2*i
]-nX
);
1214 if( nNewDiff
< nDiff
)
1222 aText
.iterateCodePoints(&i
);
1224 if (nIndex
== nFinalIndex
&& std::abs( aDX
[2*nIndex
+1] - nX
) < nDiff
)
1225 nIndex
= EDIT_NOLIMIT
;
1231 void Edit::ImplSetCursorPos( sal_Int32 nChar
, bool bSelect
)
1233 Selection
aSelection( maSelection
);
1234 aSelection
.Max() = nChar
;
1236 aSelection
.Min() = aSelection
.Max();
1237 ImplSetSelection( aSelection
);
1240 void Edit::ImplCopyToSelectionClipboard()
1242 if ( GetSelection().Len() )
1244 css::uno::Reference
<css::datatransfer::clipboard::XClipboard
> aSelection(GetSystemPrimarySelection());
1245 ImplCopy( aSelection
);
1249 void Edit::ImplCopy( uno::Reference
< datatransfer::clipboard::XClipboard
> const & rxClipboard
)
1251 vcl::unohelper::TextDataObject::CopyStringTo( GetSelected(), rxClipboard
);
1254 void Edit::ImplPaste( uno::Reference
< datatransfer::clipboard::XClipboard
> const & rxClipboard
)
1256 if ( !rxClipboard
.is() )
1259 uno::Reference
< datatransfer::XTransferable
> xDataObj
;
1263 SolarMutexReleaser aReleaser
;
1264 xDataObj
= rxClipboard
->getContents();
1266 catch( const css::uno::Exception
& )
1270 if ( !xDataObj
.is() )
1273 datatransfer::DataFlavor aFlavor
;
1274 SotExchange::GetFormatDataFlavor( SotClipboardFormatId::STRING
, aFlavor
);
1277 uno::Any aData
= xDataObj
->getTransferData( aFlavor
);
1281 // tdf#127588 - extend selection to the entire field or paste the text
1282 // from the clipboard to the current position if there is no selection
1283 if (mnMaxTextLen
< EDIT_NOLIMIT
&& maSelection
.Len() == 0)
1285 const sal_Int32 aTextLen
= aText
.getLength();
1286 if (aTextLen
== mnMaxTextLen
)
1288 maSelection
.Min() = 0;
1289 maSelection
.Max() = mnMaxTextLen
;
1291 maSelection
.Max() = std::min
<sal_Int32
>(maSelection
.Min() + aTextLen
, mnMaxTextLen
);
1294 Selection
aSelection(maSelection
);
1295 aSelection
.Normalize();
1296 if (ImplTruncateToMaxLen(aText
, aSelection
.Len()))
1297 ShowTruncationWarning(GetFrameWeld());
1299 ReplaceSelected( aText
);
1301 catch( const css::uno::Exception
& )
1306 void Edit::MouseButtonDown( const MouseEvent
& rMEvt
)
1310 Control::MouseButtonDown( rMEvt
);
1314 sal_Int32 nCharPos
= ImplGetCharPos( rMEvt
.GetPosPixel() );
1315 Selection
aSelection( maSelection
);
1316 aSelection
.Normalize();
1318 if ( rMEvt
.GetClicks() < 4 )
1320 mbClickedInSelection
= false;
1321 if ( rMEvt
.GetClicks() == 3 )
1323 ImplSetSelection( Selection( 0, EDIT_NOLIMIT
) );
1324 ImplCopyToSelectionClipboard();
1327 else if ( rMEvt
.GetClicks() == 2 )
1329 uno::Reference
< i18n::XBreakIterator
> xBI
= ImplGetBreakIterator();
1330 i18n::Boundary aBoundary
= xBI
->getWordBoundary( maText
.toString(), aSelection
.Max(),
1331 GetSettings().GetLanguageTag().getLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES
, true );
1332 ImplSetSelection( Selection( aBoundary
.startPos
, aBoundary
.endPos
) );
1333 ImplCopyToSelectionClipboard();
1335 else if ( !rMEvt
.IsShift() && HasFocus() && aSelection
.Contains( nCharPos
) )
1336 mbClickedInSelection
= true;
1337 else if ( rMEvt
.IsLeft() )
1338 ImplSetCursorPos( nCharPos
, rMEvt
.IsShift() );
1340 if ( !mbClickedInSelection
&& rMEvt
.IsLeft() && ( rMEvt
.GetClicks() == 1 ) )
1341 StartTracking( StartTrackingFlags::ScrollRepeat
);
1347 void Edit::MouseButtonUp( const MouseEvent
& rMEvt
)
1349 if ( mbClickedInSelection
&& rMEvt
.IsLeft() )
1351 sal_Int32 nCharPos
= ImplGetCharPos( rMEvt
.GetPosPixel() );
1352 ImplSetCursorPos( nCharPos
, false );
1353 mbClickedInSelection
= false;
1355 else if ( rMEvt
.IsMiddle() && !mbReadOnly
&&
1356 ( GetSettings().GetMouseSettings().GetMiddleButtonAction() == MouseMiddleButtonAction::PasteSelection
) )
1358 css::uno::Reference
<css::datatransfer::clipboard::XClipboard
> aSelection(GetSystemPrimarySelection());
1359 ImplPaste( aSelection
);
1364 void Edit::Tracking( const TrackingEvent
& rTEvt
)
1366 if ( rTEvt
.IsTrackingEnded() )
1368 if ( mbClickedInSelection
)
1370 sal_Int32 nCharPos
= ImplGetCharPos( rTEvt
.GetMouseEvent().GetPosPixel() );
1371 ImplSetCursorPos( nCharPos
, false );
1372 mbClickedInSelection
= false;
1374 else if ( rTEvt
.GetMouseEvent().IsLeft() )
1376 ImplCopyToSelectionClipboard();
1381 if( !mbClickedInSelection
)
1383 sal_Int32 nCharPos
= ImplGetCharPos( rTEvt
.GetMouseEvent().GetPosPixel() );
1384 ImplSetCursorPos( nCharPos
, true );
1389 bool Edit::ImplHandleKeyEvent( const KeyEvent
& rKEvt
)
1392 sal_uInt16 nCode
= rKEvt
.GetKeyCode().GetCode();
1393 KeyFuncType eFunc
= rKEvt
.GetKeyCode().GetFunction();
1395 mbInternModified
= false;
1397 if ( eFunc
!= KeyFuncType::DONTKNOW
)
1401 case KeyFuncType::CUT
:
1403 if ( !mbReadOnly
&& maSelection
.Len() && !mbPassword
)
1412 case KeyFuncType::COPY
:
1422 case KeyFuncType::PASTE
:
1432 case KeyFuncType::UNDO
:
1443 eFunc
= KeyFuncType::DONTKNOW
;
1447 if ( !bDone
&& rKEvt
.GetKeyCode().IsMod1() && !rKEvt
.GetKeyCode().IsMod2() )
1449 if ( nCode
== KEY_A
)
1451 ImplSetSelection( Selection( 0, maText
.getLength() ) );
1454 else if ( rKEvt
.GetKeyCode().IsShift() && (nCode
== KEY_S
) )
1456 if ( pImplFncGetSpecialChars
)
1458 Selection aSaveSel
= GetSelection(); // if someone changes the selection in Get/LoseFocus, e.g. URL bar
1459 OUString aChars
= pImplFncGetSpecialChars( GetFrameWeld(), GetFont() );
1460 SetSelection( aSaveSel
);
1461 if ( !aChars
.isEmpty() )
1463 ImplInsertText( aChars
);
1471 if ( eFunc
== KeyFuncType::DONTKNOW
&& ! bDone
)
1475 case css::awt::Key::SELECT_ALL
:
1477 ImplSetSelection( Selection( 0, maText
.getLength() ) );
1486 case css::awt::Key::MOVE_WORD_FORWARD
:
1487 case css::awt::Key::SELECT_WORD_FORWARD
:
1488 case css::awt::Key::MOVE_WORD_BACKWARD
:
1489 case css::awt::Key::SELECT_WORD_BACKWARD
:
1490 case css::awt::Key::MOVE_TO_BEGIN_OF_LINE
:
1491 case css::awt::Key::MOVE_TO_END_OF_LINE
:
1492 case css::awt::Key::SELECT_TO_BEGIN_OF_LINE
:
1493 case css::awt::Key::SELECT_TO_END_OF_LINE
:
1494 case css::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH
:
1495 case css::awt::Key::MOVE_TO_END_OF_PARAGRAPH
:
1496 case css::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH
:
1497 case css::awt::Key::SELECT_TO_END_OF_PARAGRAPH
:
1498 case css::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT
:
1499 case css::awt::Key::MOVE_TO_END_OF_DOCUMENT
:
1500 case css::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT
:
1501 case css::awt::Key::SELECT_TO_END_OF_DOCUMENT
:
1503 if ( !rKEvt
.GetKeyCode().IsMod2() )
1505 ImplClearLayoutData();
1506 uno::Reference
< i18n::XBreakIterator
> xBI
= ImplGetBreakIterator();
1508 Selection
aSel( maSelection
);
1509 bool bWord
= rKEvt
.GetKeyCode().IsMod1();
1510 bool bSelect
= rKEvt
.GetKeyCode().IsShift();
1511 bool bGoLeft
= (nCode
== KEY_LEFT
);
1512 bool bGoRight
= (nCode
== KEY_RIGHT
);
1513 bool bGoHome
= (nCode
== KEY_HOME
);
1514 bool bGoEnd
= (nCode
== KEY_END
);
1518 case css::awt::Key::MOVE_WORD_FORWARD
:
1519 bGoRight
= bWord
= true;break;
1520 case css::awt::Key::SELECT_WORD_FORWARD
:
1521 bGoRight
= bSelect
= bWord
= true;break;
1522 case css::awt::Key::MOVE_WORD_BACKWARD
:
1523 bGoLeft
= bWord
= true;break;
1524 case css::awt::Key::SELECT_WORD_BACKWARD
:
1525 bGoLeft
= bSelect
= bWord
= true;break;
1526 case css::awt::Key::SELECT_TO_BEGIN_OF_LINE
:
1527 case css::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH
:
1528 case css::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT
:
1531 case css::awt::Key::MOVE_TO_BEGIN_OF_LINE
:
1532 case css::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH
:
1533 case css::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT
:
1534 bGoHome
= true;break;
1535 case css::awt::Key::SELECT_TO_END_OF_LINE
:
1536 case css::awt::Key::SELECT_TO_END_OF_PARAGRAPH
:
1537 case css::awt::Key::SELECT_TO_END_OF_DOCUMENT
:
1540 case css::awt::Key::MOVE_TO_END_OF_LINE
:
1541 case css::awt::Key::MOVE_TO_END_OF_PARAGRAPH
:
1542 case css::awt::Key::MOVE_TO_END_OF_DOCUMENT
:
1543 bGoEnd
= true;break;
1548 // range is checked in ImplSetSelection ...
1549 if ( bGoLeft
&& aSel
.Max() )
1553 const OUString sText
= maText
.toString();
1554 i18n::Boundary aBoundary
= xBI
->getWordBoundary( sText
, aSel
.Max(),
1555 GetSettings().GetLanguageTag().getLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES
, true );
1556 if ( aBoundary
.startPos
== aSel
.Max() )
1557 aBoundary
= xBI
->previousWord( sText
, aSel
.Max(),
1558 GetSettings().GetLanguageTag().getLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES
);
1559 aSel
.Max() = aBoundary
.startPos
;
1563 sal_Int32 nCount
= 1;
1564 aSel
.Max() = xBI
->previousCharacters( maText
.toString(), aSel
.Max(),
1565 GetSettings().GetLanguageTag().getLocale(), i18n::CharacterIteratorMode::SKIPCHARACTER
, nCount
, nCount
);
1568 else if ( bGoRight
&& ( aSel
.Max() < maText
.getLength() ) )
1572 i18n::Boundary aBoundary
= xBI
->nextWord( maText
.toString(), aSel
.Max(),
1573 GetSettings().GetLanguageTag().getLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES
);
1574 aSel
.Max() = aBoundary
.startPos
;
1578 sal_Int32 nCount
= 1;
1579 aSel
.Max() = xBI
->nextCharacters( maText
.toString(), aSel
.Max(),
1580 GetSettings().GetLanguageTag().getLocale(), i18n::CharacterIteratorMode::SKIPCHARACTER
, nCount
, nCount
);
1589 aSel
.Max() = EDIT_NOLIMIT
;
1593 aSel
.Min() = aSel
.Max();
1595 if ( aSel
!= GetSelection() )
1597 ImplSetSelection( aSel
);
1598 ImplCopyToSelectionClipboard();
1601 if (bGoEnd
&& maAutocompleteHdl
.IsSet() && !rKEvt
.GetKeyCode().GetModifier())
1603 if ( (maSelection
.Min() == maSelection
.Max()) && (maSelection
.Min() == maText
.getLength()) )
1605 maAutocompleteHdl
.Call(*this);
1614 case css::awt::Key::DELETE_WORD_BACKWARD
:
1615 case css::awt::Key::DELETE_WORD_FORWARD
:
1616 case css::awt::Key::DELETE_TO_BEGIN_OF_LINE
:
1617 case css::awt::Key::DELETE_TO_END_OF_LINE
:
1621 if ( !mbReadOnly
&& !rKEvt
.GetKeyCode().IsMod2() )
1623 sal_uInt8 nDel
= (nCode
== KEY_DELETE
) ? EDIT_DEL_RIGHT
: EDIT_DEL_LEFT
;
1624 sal_uInt8 nMode
= rKEvt
.GetKeyCode().IsMod1() ? EDIT_DELMODE_RESTOFWORD
: EDIT_DELMODE_SIMPLE
;
1625 if ( (nMode
== EDIT_DELMODE_RESTOFWORD
) && rKEvt
.GetKeyCode().IsShift() )
1626 nMode
= EDIT_DELMODE_RESTOFCONTENT
;
1629 case css::awt::Key::DELETE_WORD_BACKWARD
:
1630 nDel
= EDIT_DEL_LEFT
;
1631 nMode
= EDIT_DELMODE_RESTOFWORD
;
1633 case css::awt::Key::DELETE_WORD_FORWARD
:
1634 nDel
= EDIT_DEL_RIGHT
;
1635 nMode
= EDIT_DELMODE_RESTOFWORD
;
1637 case css::awt::Key::DELETE_TO_BEGIN_OF_LINE
:
1638 nDel
= EDIT_DEL_LEFT
;
1639 nMode
= EDIT_DELMODE_RESTOFCONTENT
;
1641 case css::awt::Key::DELETE_TO_END_OF_LINE
:
1642 nDel
= EDIT_DEL_RIGHT
;
1643 nMode
= EDIT_DELMODE_RESTOFCONTENT
;
1647 sal_Int32 nOldLen
= maText
.getLength();
1648 ImplDelete( maSelection
, nDel
, nMode
);
1649 if ( maText
.getLength() != nOldLen
)
1658 if ( !mpIMEInfos
&& !mbReadOnly
&& !rKEvt
.GetKeyCode().IsMod2() )
1660 SetInsertMode( !mbInsertMode
);
1667 if (maActivateHdl
.IsSet() && !rKEvt
.GetKeyCode().GetModifier())
1668 bDone
= maActivateHdl
.Call(*this);
1673 if ( IsCharInput( rKEvt
) )
1675 bDone
= true; // read characters also when in ReadOnly
1678 ImplInsertText(OUString(rKEvt
.GetCharCode()), nullptr, true);
1679 if (maAutocompleteHdl
.IsSet())
1681 if ( (maSelection
.Min() == maSelection
.Max()) && (maSelection
.Min() == maText
.getLength()) )
1683 maAutocompleteHdl
.Call(*this);
1692 if ( mbInternModified
)
1698 void Edit::KeyInput( const KeyEvent
& rKEvt
)
1700 if ( mpSubEdit
|| !ImplHandleKeyEvent( rKEvt
) )
1701 Control::KeyInput( rKEvt
);
1704 void Edit::FillLayoutData() const
1706 mxLayoutData
.emplace();
1707 const_cast<Edit
*>(this)->Invalidate();
1710 void Edit::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRectangle
)
1713 ImplRepaint(rRenderContext
, rRectangle
);
1718 if ( !mpSubEdit
&& IsReallyVisible() )
1721 // because of vertical centering...
1729 void Edit::Draw( OutputDevice
* pDev
, const Point
& rPos
, SystemTextColorFlags nFlags
)
1731 ApplySettings(*pDev
);
1733 Point aPos
= pDev
->LogicToPixel( rPos
);
1734 Size aSize
= GetSizePixel();
1735 vcl::Font aFont
= GetDrawPixelFont( pDev
);
1739 pDev
->SetFont( aFont
);
1740 pDev
->SetTextFillColor();
1742 // Border/Background
1743 pDev
->SetLineColor();
1744 pDev
->SetFillColor();
1745 bool bBorder
= (GetStyle() & WB_BORDER
);
1746 bool bBackground
= IsControlBackground();
1747 if ( bBorder
|| bBackground
)
1749 tools::Rectangle
aRect( aPos
, aSize
);
1752 ImplDrawFrame( pDev
, aRect
);
1756 pDev
->SetFillColor( GetControlBackground() );
1757 pDev
->DrawRect( aRect
);
1762 if ( nFlags
& SystemTextColorFlags::Mono
)
1763 pDev
->SetTextColor( COL_BLACK
);
1768 const StyleSettings
& rStyleSettings
= GetSettings().GetStyleSettings();
1769 pDev
->SetTextColor( rStyleSettings
.GetDisableColor() );
1773 pDev
->SetTextColor( GetTextColor() );
1777 const tools::Long nOnePixel
= GetDrawPixel( pDev
, 1 );
1778 const tools::Long nOffX
= 3*nOnePixel
;
1779 DrawTextFlags nTextStyle
= DrawTextFlags::VCenter
;
1780 tools::Rectangle
aTextRect( aPos
, aSize
);
1782 if ( GetStyle() & WB_CENTER
)
1783 nTextStyle
|= DrawTextFlags::Center
;
1784 else if ( GetStyle() & WB_RIGHT
)
1785 nTextStyle
|= DrawTextFlags::Right
;
1787 nTextStyle
|= DrawTextFlags::Left
;
1789 aTextRect
.AdjustLeft(nOffX
);
1790 aTextRect
.AdjustRight( -nOffX
);
1792 OUString aText
= ImplGetText();
1793 tools::Long nTextHeight
= pDev
->GetTextHeight();
1794 tools::Long nTextWidth
= pDev
->GetTextWidth( aText
);
1795 tools::Long nOffY
= (aSize
.Height() - nTextHeight
) / 2;
1799 ((nOffY
+nTextHeight
) > aSize
.Height()) ||
1800 ((nOffX
+nTextWidth
) > aSize
.Width()) )
1802 tools::Rectangle
aClip( aPos
, aSize
);
1803 if ( nTextHeight
> aSize
.Height() )
1804 aClip
.AdjustBottom(nTextHeight
-aSize
.Height()+1 ); // prevent HP printers from 'optimizing'
1805 pDev
->IntersectClipRegion( aClip
);
1808 pDev
->DrawText( aTextRect
, aText
, nTextStyle
);
1813 Size
aOrigSize(GetSubEdit()->GetSizePixel());
1814 GetSubEdit()->SetSizePixel(GetSizePixel());
1815 GetSubEdit()->Draw(pDev
, rPos
, nFlags
);
1816 GetSubEdit()->SetSizePixel(aOrigSize
);
1820 void Edit::ImplInvalidateOutermostBorder( vcl::Window
* pWin
)
1822 // allow control to show focused state
1823 vcl::Window
*pInvalWin
= pWin
;
1826 vcl::Window
* pBorder
= pInvalWin
->GetWindow( GetWindowType::Border
);
1827 if (pBorder
== pInvalWin
|| !pBorder
||
1828 pInvalWin
->ImplGetFrame() != pBorder
->ImplGetFrame() )
1830 pInvalWin
= pBorder
;
1833 pInvalWin
->Invalidate( InvalidateFlags::Children
| InvalidateFlags::Update
);
1836 void Edit::GetFocus()
1838 Control::GetFocus();
1841 mpSubEdit
->ImplGrabFocus( GetGetFocusFlags() );
1842 else if ( !mbActivePopup
)
1844 maUndoText
= maText
.toString();
1845 SelectionOptions nSelOptions
= GetSettings().GetStyleSettings().GetSelectionOptions();
1846 if ( !( GetStyle() & (WB_NOHIDESELECTION
|WB_READONLY
) )
1847 && ( GetGetFocusFlags() & (GetFocusFlags::Init
|GetFocusFlags::Tab
|GetFocusFlags::CURSOR
|GetFocusFlags::Mnemonic
) ) )
1849 if ( nSelOptions
& SelectionOptions::ShowFirst
)
1851 maSelection
.Min() = maText
.getLength();
1852 maSelection
.Max() = 0;
1856 maSelection
.Min() = 0;
1857 maSelection
.Max() = maText
.getLength();
1860 static_cast<Edit
*>(GetParent())->CallEventListeners( VclEventId::EditSelectionChanged
);
1862 CallEventListeners( VclEventId::EditSelectionChanged
);
1867 if (IsNativeWidgetEnabled() &&
1868 IsNativeControlSupported( ControlType::Editbox
, ControlPart::Entire
))
1870 ImplInvalidateOutermostBorder( mbIsSubEdit
? GetParent() : this );
1872 else if ( maSelection
.Len() )
1874 // paint the selection
1875 if ( !HasPaintEvent() )
1876 ImplInvalidateOrRepaint();
1881 SetInputContext( InputContext( GetFont(), !IsReadOnly() ? InputContextFlags::Text
|InputContextFlags::ExtText
: InputContextFlags::NONE
) );
1885 void Edit::LoseFocus()
1889 if (IsNativeWidgetEnabled() &&
1890 IsNativeControlSupported(ControlType::Editbox
, ControlPart::Entire
))
1892 ImplInvalidateOutermostBorder( mbIsSubEdit
? GetParent() : this );
1895 if ( !mbActivePopup
&& !( GetStyle() & WB_NOHIDESELECTION
) && maSelection
.Len() )
1896 ImplInvalidateOrRepaint(); // paint the selection
1899 Control::LoseFocus();
1902 bool Edit::PreNotify(NotifyEvent
& rNEvt
)
1904 if (rNEvt
.GetType() == NotifyEventType::MOUSEMOVE
)
1906 const MouseEvent
* pMouseEvt
= rNEvt
.GetMouseEvent();
1907 if (pMouseEvt
&& !pMouseEvt
->GetButtons() && !pMouseEvt
->IsSynthetic() && !pMouseEvt
->IsModifierChanged())
1909 // trigger redraw if mouse over state has changed
1910 if (pMouseEvt
->IsLeaveWindow() || pMouseEvt
->IsEnterWindow())
1912 if (IsNativeWidgetEnabled() &&
1913 IsNativeControlSupported(ControlType::Editbox
, ControlPart::Entire
))
1915 ImplInvalidateOutermostBorder(this);
1921 return Control::PreNotify(rNEvt
);
1924 void Edit::Command( const CommandEvent
& rCEvt
)
1926 if ( rCEvt
.GetCommand() == CommandEventId::ContextMenu
)
1928 VclPtr
<PopupMenu
> pPopup
= Edit::CreatePopupMenu();
1930 bool bEnableCut
= true;
1931 bool bEnableCopy
= true;
1932 bool bEnableDelete
= true;
1933 bool bEnablePaste
= true;
1934 bool bEnableSpecialChar
= true;
1936 if ( !maSelection
.Len() )
1939 bEnableCopy
= false;
1940 bEnableDelete
= false;
1946 bEnablePaste
= false;
1947 bEnableDelete
= false;
1948 bEnableSpecialChar
= false;
1952 // only paste if text available in clipboard
1954 uno::Reference
< datatransfer::clipboard::XClipboard
> xClipboard
= GetClipboard();
1956 if ( xClipboard
.is() )
1958 uno::Reference
< datatransfer::XTransferable
> xDataObj
;
1960 SolarMutexReleaser aReleaser
;
1961 xDataObj
= xClipboard
->getContents();
1963 if ( xDataObj
.is() )
1965 datatransfer::DataFlavor aFlavor
;
1966 SotExchange::GetFormatDataFlavor( SotClipboardFormatId::STRING
, aFlavor
);
1967 bData
= xDataObj
->isDataFlavorSupported( aFlavor
);
1970 bEnablePaste
= bData
;
1973 pPopup
->EnableItem(pPopup
->GetItemId(u
"cut"), bEnableCut
);
1974 pPopup
->EnableItem(pPopup
->GetItemId(u
"copy"), bEnableCopy
);
1975 pPopup
->EnableItem(pPopup
->GetItemId(u
"delete"), bEnableDelete
);
1976 pPopup
->EnableItem(pPopup
->GetItemId(u
"paste"), bEnablePaste
);
1977 pPopup
->SetItemText(pPopup
->GetItemId(u
"specialchar"),
1978 BuilderUtils::convertMnemonicMarkup(VclResId(STR_SPECIAL_CHARACTER_MENU_ENTRY
)));
1979 pPopup
->EnableItem(pPopup
->GetItemId(u
"specialchar"), bEnableSpecialChar
);
1981 pPopup
->GetItemId(u
"undo"),
1982 std::u16string_view(maUndoText
) != std::u16string_view(maText
));
1983 bool bAllSelected
= maSelection
.Min() == 0 && maSelection
.Max() == maText
.getLength();
1984 pPopup
->EnableItem(pPopup
->GetItemId(u
"selectall"), !bAllSelected
);
1985 pPopup
->ShowItem(pPopup
->GetItemId(u
"specialchar"), pImplFncGetSpecialChars
!= nullptr);
1987 mbActivePopup
= true;
1988 Selection aSaveSel
= GetSelection(); // if someone changes selection in Get/LoseFocus, e.g. URL bar
1989 Point aPos
= rCEvt
.GetMousePosPixel();
1990 if ( !rCEvt
.IsMouseEvent() )
1992 // Show menu eventually centered in selection
1993 Size aSize
= GetOutputSizePixel();
1994 aPos
= Point( aSize
.Width()/2, aSize
.Height()/2 );
1996 sal_uInt16 n
= pPopup
->Execute( this, aPos
);
1997 SetSelection( aSaveSel
);
1998 OUString sCommand
= pPopup
->GetItemIdent(n
);
1999 if (sCommand
== "undo")
2004 else if (sCommand
== "cut")
2009 else if (sCommand
== "copy")
2013 else if (sCommand
== "paste")
2018 else if (sCommand
== "delete")
2023 else if (sCommand
== "selectall")
2025 ImplSetSelection( Selection( 0, maText
.getLength() ) );
2027 else if (sCommand
== "specialchar" && pImplFncGetSpecialChars
)
2029 OUString aChars
= pImplFncGetSpecialChars(GetFrameWeld(), GetFont());
2030 if (!isDisposed()) // destroyed while the insert special character dialog was still open
2032 SetSelection( aSaveSel
);
2033 if (!aChars
.isEmpty())
2035 ImplInsertText( aChars
);
2041 mbActivePopup
= false;
2043 else if ( rCEvt
.GetCommand() == CommandEventId::StartExtTextInput
)
2046 sal_Int32 nPos
= maSelection
.Max();
2047 mpIMEInfos
.reset(new Impl_IMEInfos( nPos
, maText
.copy(nPos
).makeStringAndClear() ));
2048 mpIMEInfos
->bWasCursorOverwrite
= !IsInsertMode();
2050 else if ( rCEvt
.GetCommand() == CommandEventId::EndExtTextInput
)
2052 bool bInsertMode
= !mpIMEInfos
->bWasCursorOverwrite
;
2055 SetInsertMode(bInsertMode
);
2060 // #i25161# call auto complete handler for ext text commit also
2061 if (maAutocompleteHdl
.IsSet())
2063 if ( (maSelection
.Min() == maSelection
.Max()) && (maSelection
.Min() == maText
.getLength()) )
2065 maAutocompleteHdl
.Call(*this);
2069 else if ( rCEvt
.GetCommand() == CommandEventId::ExtTextInput
)
2071 const CommandExtTextInputData
* pData
= rCEvt
.GetExtTextInputData();
2073 maText
.remove( mpIMEInfos
->nPos
, mpIMEInfos
->nLen
);
2074 maText
.insert( mpIMEInfos
->nPos
, pData
->GetText() );
2075 if ( mpIMEInfos
->bWasCursorOverwrite
)
2077 const sal_Int32 nOldIMETextLen
= mpIMEInfos
->nLen
;
2078 const sal_Int32 nNewIMETextLen
= pData
->GetText().getLength();
2079 if ( ( nOldIMETextLen
> nNewIMETextLen
) &&
2080 ( nNewIMETextLen
< mpIMEInfos
->aOldTextAfterStartPos
.getLength() ) )
2082 // restore old characters
2083 const sal_Int32 nRestore
= nOldIMETextLen
- nNewIMETextLen
;
2084 maText
.insert( mpIMEInfos
->nPos
+ nNewIMETextLen
, mpIMEInfos
->aOldTextAfterStartPos
.subView( nNewIMETextLen
, nRestore
) );
2086 else if ( ( nOldIMETextLen
< nNewIMETextLen
) &&
2087 ( nOldIMETextLen
< mpIMEInfos
->aOldTextAfterStartPos
.getLength() ) )
2089 const sal_Int32 nOverwrite
= ( nNewIMETextLen
> mpIMEInfos
->aOldTextAfterStartPos
.getLength()
2090 ? mpIMEInfos
->aOldTextAfterStartPos
.getLength() : nNewIMETextLen
) - nOldIMETextLen
;
2091 maText
.remove( mpIMEInfos
->nPos
+ nNewIMETextLen
, nOverwrite
);
2095 if ( pData
->GetTextAttr() )
2097 mpIMEInfos
->CopyAttribs( pData
->GetTextAttr(), pData
->GetText().getLength() );
2098 mpIMEInfos
->bCursor
= pData
->IsCursorVisible();
2102 mpIMEInfos
->DestroyAttribs();
2105 ImplAlignAndPaint();
2106 sal_Int32 nCursorPos
= mpIMEInfos
->nPos
+ pData
->GetCursorPos();
2107 SetSelection( Selection( nCursorPos
, nCursorPos
) );
2108 SetInsertMode( !pData
->IsCursorOverwrite() );
2110 if ( pData
->IsCursorVisible() )
2111 GetCursor()->Show();
2113 GetCursor()->Hide();
2115 else if ( rCEvt
.GetCommand() == CommandEventId::CursorPos
)
2119 sal_Int32 nCursorPos
= GetSelection().Max();
2120 SetCursorRect( nullptr, GetTextWidth( maText
.toString(), nCursorPos
, mpIMEInfos
->nPos
+mpIMEInfos
->nLen
-nCursorPos
) );
2127 else if ( rCEvt
.GetCommand() == CommandEventId::SelectionChange
)
2129 const CommandSelectionChangeData
*pData
= rCEvt
.GetSelectionChangeData();
2130 Selection
aSelection( pData
->GetStart(), pData
->GetEnd() );
2131 SetSelection(aSelection
);
2133 else if ( rCEvt
.GetCommand() == CommandEventId::QueryCharPosition
)
2135 if (mpIMEInfos
&& mpIMEInfos
->nLen
> 0)
2137 OUString aText
= ImplGetText();
2139 GetOutDev()->GetCaretPositions(aText
, aDX
, 0, aText
.getLength());
2141 tools::Long nTH
= GetTextHeight();
2142 Point
aPos( mnXOffset
, ImplGetTextYPosition() );
2144 std::vector
<tools::Rectangle
> aRects(mpIMEInfos
->nLen
);
2145 for ( int nIndex
= 0; nIndex
< mpIMEInfos
->nLen
; ++nIndex
)
2147 tools::Rectangle
aRect( aPos
, Size( 10, nTH
) );
2148 aRect
.SetLeft( aDX
[2*(nIndex
+mpIMEInfos
->nPos
)] + mnXOffset
+ ImplGetExtraXOffset() );
2149 aRects
[ nIndex
] = aRect
;
2151 SetCompositionCharRect(aRects
.data(), mpIMEInfos
->nLen
);
2155 Control::Command( rCEvt
);
2158 void Edit::StateChanged( StateChangedType nType
)
2160 if (nType
== StateChangedType::InitShow
)
2164 mnXOffset
= 0; // if GrabFocus before while size was still wrong
2167 ImplShowCursor(false);
2171 else if (nType
== StateChangedType::Enable
)
2175 // change text color only
2176 ImplInvalidateOrRepaint();
2179 else if (nType
== StateChangedType::Style
|| nType
== StateChangedType::Mirroring
)
2181 WinBits nStyle
= GetStyle();
2182 if (nType
== StateChangedType::Style
)
2184 nStyle
= ImplInitStyle(GetStyle());
2188 sal_uInt16 nOldAlign
= mnAlign
;
2189 mnAlign
= EDIT_ALIGN_LEFT
;
2191 // hack: right align until keyinput and cursor travelling works
2192 // edits are always RTL disabled
2193 // however the parent edits contain the correct setting
2194 if (mbIsSubEdit
&& GetParent()->IsRTLEnabled())
2196 if (GetParent()->GetStyle() & WB_LEFT
)
2197 mnAlign
= EDIT_ALIGN_RIGHT
;
2198 if (nType
== StateChangedType::Mirroring
)
2199 GetOutDev()->SetLayoutMode(vcl::text::ComplexTextLayoutFlags::BiDiRtl
| vcl::text::ComplexTextLayoutFlags::TextOriginLeft
);
2201 else if (mbIsSubEdit
&& !GetParent()->IsRTLEnabled())
2203 if (nType
== StateChangedType::Mirroring
)
2204 GetOutDev()->SetLayoutMode(vcl::text::ComplexTextLayoutFlags::TextOriginLeft
);
2207 if (nStyle
& WB_RIGHT
)
2208 mnAlign
= EDIT_ALIGN_RIGHT
;
2209 else if (nStyle
& WB_CENTER
)
2210 mnAlign
= EDIT_ALIGN_CENTER
;
2211 if (!maText
.isEmpty() && (mnAlign
!= nOldAlign
))
2218 else if ((nType
== StateChangedType::Zoom
) || (nType
== StateChangedType::ControlFont
))
2222 ApplySettings(*GetOutDev());
2227 else if ((nType
== StateChangedType::ControlForeground
) || (nType
== StateChangedType::ControlBackground
))
2231 ApplySettings(*GetOutDev());
2236 Control::StateChanged(nType
);
2239 void Edit::DataChanged( const DataChangedEvent
& rDCEvt
)
2241 if ( (rDCEvt
.GetType() == DataChangedEventType::FONTS
) ||
2242 (rDCEvt
.GetType() == DataChangedEventType::FONTSUBSTITUTION
) ||
2243 ((rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
2244 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
)) )
2248 ApplySettings(*GetOutDev());
2254 Control::DataChanged( rDCEvt
);
2257 void Edit::ImplShowDDCursor()
2259 if (!mpDDInfo
->bVisCursor
)
2261 tools::Long nTextWidth
= GetTextWidth( maText
.toString(), 0, mpDDInfo
->nDropPos
);
2262 tools::Long nTextHeight
= GetTextHeight();
2263 tools::Rectangle
aCursorRect( Point( nTextWidth
+ mnXOffset
, (GetOutDev()->GetOutputSize().Height()-nTextHeight
)/2 ), Size( 2, nTextHeight
) );
2264 mpDDInfo
->aCursor
.SetWindow( this );
2265 mpDDInfo
->aCursor
.SetPos( aCursorRect
.TopLeft() );
2266 mpDDInfo
->aCursor
.SetSize( aCursorRect
.GetSize() );
2267 mpDDInfo
->aCursor
.Show();
2268 mpDDInfo
->bVisCursor
= true;
2272 void Edit::ImplHideDDCursor()
2274 if ( mpDDInfo
&& mpDDInfo
->bVisCursor
)
2276 mpDDInfo
->aCursor
.Hide();
2277 mpDDInfo
->bVisCursor
= false;
2281 TextFilter::TextFilter(OUString _aForbiddenChars
)
2282 : sForbiddenChars(std::move(_aForbiddenChars
))
2286 TextFilter::~TextFilter()
2290 OUString
TextFilter::filter(const OUString
&rText
)
2292 OUString
sTemp(rText
);
2293 for (sal_Int32 i
= 0; i
< sForbiddenChars
.getLength(); ++i
)
2295 sTemp
= sTemp
.replaceAll(OUStringChar(sForbiddenChars
[i
]), "");
2300 void Edit::filterText()
2302 Selection aSel
= GetSelection();
2303 const OUString sOrig
= GetText();
2304 const OUString sNew
= mpFilterText
->filter(GetText());
2307 sal_Int32 nDiff
= sOrig
.getLength() - sNew
.getLength();
2310 aSel
.setMin(aSel
.getMin() - nDiff
);
2311 aSel
.setMax(aSel
.getMin());
2325 static_cast<Edit
*>(GetParent())->Modify();
2329 if ( ImplCallEventListenersAndHandler( VclEventId::EditModify
, [this] () { maModifyHdl
.Call(*this); } ) )
2330 // have been destroyed while calling into the handlers
2333 // #i13677# notify edit listeners about caret position change
2334 CallEventListeners( VclEventId::EditCaretChanged
);
2335 // FIXME: this is currently only on macOS
2336 // check for other platforms that need similar handling
2337 if( ImplGetSVData()->maNWFData
.mbNoFocusRects
&&
2338 IsNativeWidgetEnabled() &&
2339 IsNativeControlSupported( ControlType::Editbox
, ControlPart::Entire
) )
2341 ImplInvalidateOutermostBorder( this );
2346 void Edit::SetEchoChar( sal_Unicode c
)
2350 mpSubEdit
->SetEchoChar( c
);
2353 void Edit::SetReadOnly( bool bReadOnly
)
2355 if ( mbReadOnly
!= bReadOnly
)
2357 mbReadOnly
= bReadOnly
;
2359 mpSubEdit
->SetReadOnly( bReadOnly
);
2361 CompatStateChanged( StateChangedType::ReadOnly
);
2365 void Edit::SetInsertMode( bool bInsert
)
2367 if ( bInsert
!= mbInsertMode
)
2369 mbInsertMode
= bInsert
;
2371 mpSubEdit
->SetInsertMode( bInsert
);
2377 bool Edit::IsInsertMode() const
2380 return mpSubEdit
->IsInsertMode();
2382 return mbInsertMode
;
2385 void Edit::SetMaxTextLen(sal_Int32 nMaxLen
)
2387 mnMaxTextLen
= nMaxLen
> 0 ? nMaxLen
: EDIT_NOLIMIT
;
2390 mpSubEdit
->SetMaxTextLen( mnMaxTextLen
);
2393 if ( maText
.getLength() > mnMaxTextLen
)
2394 ImplDelete( Selection( mnMaxTextLen
, maText
.getLength() ), EDIT_DEL_RIGHT
, EDIT_DELMODE_SIMPLE
);
2398 void Edit::SetSelection( const Selection
& rSelection
)
2400 // If the selection was changed from outside, e.g. by MouseButtonDown, don't call Tracking()
2401 // directly afterwards which would change the selection again
2404 else if ( mpSubEdit
&& mpSubEdit
->IsTracking() )
2405 mpSubEdit
->EndTracking();
2407 ImplSetSelection( rSelection
);
2410 void Edit::ImplSetSelection( const Selection
& rSelection
, bool bPaint
)
2413 mpSubEdit
->ImplSetSelection( rSelection
);
2416 if ( rSelection
!= maSelection
)
2418 Selection
aOld( maSelection
);
2419 Selection
aNew( rSelection
);
2421 if ( aNew
.Min() > maText
.getLength() )
2422 aNew
.Min() = maText
.getLength();
2423 if ( aNew
.Max() > maText
.getLength() )
2424 aNew
.Max() = maText
.getLength();
2425 if ( aNew
.Min() < 0 )
2427 if ( aNew
.Max() < 0 )
2430 if ( aNew
!= maSelection
)
2432 ImplClearLayoutData();
2433 Selection aTemp
= maSelection
;
2436 if ( bPaint
&& ( aOld
.Len() || aNew
.Len() || IsPaintTransparent() ) )
2437 ImplInvalidateOrRepaint();
2440 bool bCaret
= false, bSelection
= false;
2441 tools::Long nB
=aNew
.Max(), nA
=aNew
.Min(),oB
=aTemp
.Max(), oA
=aTemp
.Min();
2442 tools::Long nGap
= nB
-nA
, oGap
= oB
-oA
;
2445 if (nGap
!= 0 || oGap
!= 0)
2451 static_cast<Edit
*>(GetParent())->CallEventListeners( VclEventId::EditSelectionChanged
);
2453 CallEventListeners( VclEventId::EditSelectionChanged
);
2459 static_cast<Edit
*>(GetParent())->CallEventListeners( VclEventId::EditCaretChanged
);
2461 CallEventListeners( VclEventId::EditCaretChanged
);
2464 // #103511# notify combobox listeners of deselection
2465 if( !maSelection
&& GetParent() && GetParent()->GetType() == WindowType::COMBOBOX
)
2466 static_cast<Edit
*>(GetParent())->CallEventListeners( VclEventId::ComboboxDeselect
);
2472 const Selection
& Edit::GetSelection() const
2475 return mpSubEdit
->GetSelection();
2480 void Edit::ReplaceSelected( const OUString
& rStr
)
2483 mpSubEdit
->ReplaceSelected( rStr
);
2485 ImplInsertText( rStr
);
2488 void Edit::DeleteSelected()
2491 mpSubEdit
->DeleteSelected();
2494 if ( maSelection
.Len() )
2495 ImplDelete( maSelection
, EDIT_DEL_RIGHT
, EDIT_DELMODE_SIMPLE
);
2499 OUString
Edit::GetSelected() const
2502 return mpSubEdit
->GetSelected();
2505 Selection
aSelection( maSelection
);
2506 aSelection
.Normalize();
2507 return OUString( maText
.getStr() + aSelection
.Min(), aSelection
.Len() );
2516 ReplaceSelected( OUString() );
2524 css::uno::Reference
<css::datatransfer::clipboard::XClipboard
> aClipboard(GetClipboard());
2525 ImplCopy( aClipboard
);
2531 css::uno::Reference
<css::datatransfer::clipboard::XClipboard
> aClipboard(GetClipboard());
2532 ImplPaste( aClipboard
);
2541 const OUString
aText( maText
.toString() );
2542 ImplDelete( Selection( 0, aText
.getLength() ), EDIT_DEL_RIGHT
, EDIT_DELMODE_SIMPLE
);
2543 ImplInsertText( maUndoText
);
2544 ImplSetSelection( Selection( 0, maUndoText
.getLength() ) );
2549 void Edit::SetText( const OUString
& rStr
)
2552 mpSubEdit
->SetText( rStr
); // not directly ImplSetText if SetText overridden
2555 Selection
aNewSel( 0, 0 ); // prevent scrolling
2556 ImplSetText( rStr
, &aNewSel
);
2560 void Edit::SetText( const OUString
& rStr
, const Selection
& rSelection
)
2563 mpSubEdit
->SetText( rStr
, rSelection
);
2565 ImplSetText( rStr
, &rSelection
);
2568 OUString
Edit::GetText() const
2571 return mpSubEdit
->GetText();
2573 return maText
.toString();
2576 void Edit::SetCursorAtLast(){
2577 ImplSetCursorPos( GetText().getLength(), false );
2580 void Edit::SetPlaceholderText( const OUString
& rStr
)
2583 mpSubEdit
->SetPlaceholderText( rStr
);
2584 else if ( maPlaceholderText
!= rStr
)
2586 maPlaceholderText
= rStr
;
2587 if ( GetText().isEmpty() )
2592 void Edit::SetModifyFlag()
2596 void Edit::SetSubEdit(Edit
* pEdit
)
2598 mpSubEdit
.disposeAndClear();
2599 mpSubEdit
.set(pEdit
);
2603 SetPointer(PointerStyle::Arrow
); // Only SubEdit has the BEAM...
2604 mpSubEdit
->mbIsSubEdit
= true;
2606 mpSubEdit
->SetReadOnly(mbReadOnly
);
2607 mpSubEdit
->maAutocompleteHdl
= maAutocompleteHdl
;
2611 Size
Edit::CalcMinimumSizeForText(const OUString
&rString
) const
2613 ControlType eCtrlType
= ImplGetNativeControlType();
2616 if (mnWidthInChars
!= -1)
2618 //CalcSize calls CalcWindowSize, but we will call that also in this
2619 //function, so undo the first one with CalcOutputSize
2620 aSize
= CalcOutputSize(CalcSize(mnWidthInChars
));
2625 if (mnMaxWidthChars
!= -1 && mnMaxWidthChars
< rString
.getLength())
2626 aString
= rString
.copy(0, mnMaxWidthChars
);
2630 aSize
.setHeight( GetTextHeight() );
2631 aSize
.setWidth( GetTextWidth(aString
) );
2632 aSize
.AdjustWidth(ImplGetExtraXOffset() * 2 );
2634 // do not create edit fields in which one cannot enter anything
2635 // a default minimum width should exist for at least 3 characters
2637 //CalcSize calls CalcWindowSize, but we will call that also in this
2638 //function, so undo the first one with CalcOutputSize
2639 Size
aMinSize(CalcOutputSize(CalcSize(3)));
2640 if (aSize
.Width() < aMinSize
.Width())
2641 aSize
.setWidth( aMinSize
.Width() );
2644 aSize
.AdjustHeight(ImplGetExtraYOffset() * 2 );
2646 aSize
= CalcWindowSize( aSize
);
2648 // ask NWF what if it has an opinion, too
2649 ImplControlValue aControlValue
;
2650 tools::Rectangle
aRect( Point( 0, 0 ), aSize
);
2651 tools::Rectangle aContent
, aBound
;
2652 if (GetNativeControlRegion(eCtrlType
, ControlPart::Entire
, aRect
, ControlState::NONE
,
2653 aControlValue
, aBound
, aContent
))
2655 if (aBound
.GetHeight() > aSize
.Height())
2656 aSize
.setHeight( aBound
.GetHeight() );
2661 Size
Edit::CalcMinimumSize() const
2663 return CalcMinimumSizeForText(GetText());
2666 Size
Edit::GetOptimalSize() const
2668 return CalcMinimumSize();
2671 Size
Edit::CalcSize(sal_Int32 nChars
) const
2673 // width for N characters, independent from content.
2674 // works only correct for fixed fonts, average otherwise
2675 float fUnitWidth
= std::max(approximate_char_width(), approximate_digit_width());
2676 Size
aSz(fUnitWidth
* nChars
, GetTextHeight());
2677 aSz
.AdjustWidth(ImplGetExtraXOffset() * 2 );
2678 aSz
= CalcWindowSize( aSz
);
2682 sal_Int32
Edit::GetMaxVisChars() const
2684 const vcl::Window
* pW
= mpSubEdit
? mpSubEdit
: this;
2685 sal_Int32 nOutWidth
= pW
->GetOutputSizePixel().Width();
2686 float fUnitWidth
= std::max(approximate_char_width(), approximate_digit_width());
2687 return nOutWidth
/ fUnitWidth
;
2692 void SetGetSpecialCharsFunction( FncGetSpecialChars fn
)
2694 pImplFncGetSpecialChars
= fn
;
2697 FncGetSpecialChars
GetGetSpecialCharsFunction()
2699 return pImplFncGetSpecialChars
;
2703 VclPtr
<PopupMenu
> Edit::CreatePopupMenu()
2706 mpUIBuilder
.reset(new VclBuilder(nullptr, AllSettings::GetUIRootDir(), u
"vcl/ui/editmenu.ui"_ustr
, u
""_ustr
));
2707 VclPtr
<PopupMenu
> pPopup
= mpUIBuilder
->get_menu(u
"menu");
2708 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
2709 if (rStyleSettings
.GetHideDisabledMenuItems())
2710 pPopup
->SetMenuFlags( MenuFlags::HideDisabledEntries
);
2712 pPopup
->SetMenuFlags ( MenuFlags::AlwaysShowDisabledEntries
);
2713 if (rStyleSettings
.GetContextMenuShortcuts())
2715 pPopup
->SetAccelKey(pPopup
->GetItemId(u
"undo"), vcl::KeyCode( KeyFuncType::UNDO
));
2716 pPopup
->SetAccelKey(pPopup
->GetItemId(u
"cut"), vcl::KeyCode( KeyFuncType::CUT
));
2717 pPopup
->SetAccelKey(pPopup
->GetItemId(u
"copy"), vcl::KeyCode( KeyFuncType::COPY
));
2718 pPopup
->SetAccelKey(pPopup
->GetItemId(u
"paste"), vcl::KeyCode( KeyFuncType::PASTE
));
2719 pPopup
->SetAccelKey(pPopup
->GetItemId(u
"delete"), vcl::KeyCode( KeyFuncType::DELETE
));
2720 pPopup
->SetAccelKey(pPopup
->GetItemId(u
"selectall"), vcl::KeyCode( KEY_A
, false, true, false, false));
2721 pPopup
->SetAccelKey(pPopup
->GetItemId(u
"specialchar"), vcl::KeyCode( KEY_S
, true, true, false, false));
2726 // css::datatransfer::dnd::XDragGestureListener
2727 void Edit::dragGestureRecognized( const css::datatransfer::dnd::DragGestureEvent
& rDGE
)
2729 SolarMutexGuard aVclGuard
;
2731 if ( !(!IsTracking() && maSelection
.Len() &&
2732 !mbPassword
&& (!mpDDInfo
|| !mpDDInfo
->bStarterOfDD
)) ) // no repeated D&D
2735 Selection
aSel( maSelection
);
2738 // only if mouse in the selection...
2739 Point
aMousePos( rDGE
.DragOriginX
, rDGE
.DragOriginY
);
2740 sal_Int32 nCharPos
= ImplGetCharPos( aMousePos
);
2741 if ( (nCharPos
< aSel
.Min()) || (nCharPos
>= aSel
.Max()) )
2745 mpDDInfo
.reset(new DDInfo
);
2747 mpDDInfo
->bStarterOfDD
= true;
2748 mpDDInfo
->aDndStartSel
= aSel
;
2751 EndTracking(); // before D&D disable tracking
2753 rtl::Reference
<vcl::unohelper::TextDataObject
> pDataObj
= new vcl::unohelper::TextDataObject( GetSelected() );
2754 sal_Int8 nActions
= datatransfer::dnd::DNDConstants::ACTION_COPY
;
2755 if ( !IsReadOnly() )
2756 nActions
|= datatransfer::dnd::DNDConstants::ACTION_MOVE
;
2757 rDGE
.DragSource
->startDrag( rDGE
, nActions
, 0 /*cursor*/, 0 /*image*/, pDataObj
, mxDnDListener
);
2759 GetCursor()->Hide();
2762 // css::datatransfer::dnd::XDragSourceListener
2763 void Edit::dragDropEnd( const css::datatransfer::dnd::DragSourceDropEvent
& rDSDE
)
2765 SolarMutexGuard aVclGuard
;
2767 if (rDSDE
.DropSuccess
&& (rDSDE
.DropAction
& datatransfer::dnd::DNDConstants::ACTION_MOVE
) && mpDDInfo
)
2769 Selection
aSel( mpDDInfo
->aDndStartSel
);
2770 if ( mpDDInfo
->bDroppedInMe
)
2772 if ( aSel
.Max() > mpDDInfo
->nDropPos
)
2774 tools::Long nLen
= aSel
.Len();
2779 ImplDelete( aSel
, EDIT_DEL_RIGHT
, EDIT_DELMODE_SIMPLE
);
2787 // css::datatransfer::dnd::XDropTargetListener
2788 void Edit::drop( const css::datatransfer::dnd::DropTargetDropEvent
& rDTDE
)
2790 SolarMutexGuard aVclGuard
;
2792 bool bChanges
= false;
2793 if ( !mbReadOnly
&& mpDDInfo
)
2797 Selection
aSel( maSelection
);
2800 if ( aSel
.Len() && !mpDDInfo
->bStarterOfDD
)
2801 ImplDelete( aSel
, EDIT_DEL_RIGHT
, EDIT_DELMODE_SIMPLE
);
2803 mpDDInfo
->bDroppedInMe
= true;
2805 aSel
.Min() = mpDDInfo
->nDropPos
;
2806 aSel
.Max() = mpDDInfo
->nDropPos
;
2807 ImplSetSelection( aSel
);
2809 uno::Reference
< datatransfer::XTransferable
> xDataObj
= rDTDE
.Transferable
;
2810 if ( xDataObj
.is() )
2812 datatransfer::DataFlavor aFlavor
;
2813 SotExchange::GetFormatDataFlavor( SotClipboardFormatId::STRING
, aFlavor
);
2814 if ( xDataObj
->isDataFlavorSupported( aFlavor
) )
2816 uno::Any aData
= xDataObj
->getTransferData( aFlavor
);
2819 ImplInsertText( aText
);
2825 if ( !mpDDInfo
->bStarterOfDD
)
2831 rDTDE
.Context
->dropComplete( bChanges
);
2834 void Edit::dragEnter( const css::datatransfer::dnd::DropTargetDragEnterEvent
& rDTDE
)
2838 mpDDInfo
.reset(new DDInfo
);
2840 // search for string data type
2841 const Sequence
< css::datatransfer::DataFlavor
>& rFlavors( rDTDE
.SupportedDataFlavors
);
2842 mpDDInfo
->bIsStringSupported
= std::any_of(rFlavors
.begin(), rFlavors
.end(),
2843 [](const css::datatransfer::DataFlavor
& rFlavor
) {
2844 sal_Int32 nIndex
= 0;
2845 const std::u16string_view aMimetype
= o3tl::getToken(rFlavor
.MimeType
, 0, ';', nIndex
);
2846 return aMimetype
== u
"text/plain";
2850 void Edit::dragExit( const css::datatransfer::dnd::DropTargetEvent
& )
2852 SolarMutexGuard aVclGuard
;
2857 void Edit::dragOver( const css::datatransfer::dnd::DropTargetDragEvent
& rDTDE
)
2859 SolarMutexGuard aVclGuard
;
2861 Point
aMousePos( rDTDE
.LocationX
, rDTDE
.LocationY
);
2863 sal_Int32 nPrevDropPos
= mpDDInfo
->nDropPos
;
2864 mpDDInfo
->nDropPos
= ImplGetCharPos( aMousePos
);
2867 Size aOutSize = GetOutputSizePixel();
2868 if ( ( aMousePos.X() < 0 ) || ( aMousePos.X() > aOutSize.Width() ) )
2871 // No, I will not receive events in this case...
2875 Selection
aSel( maSelection
);
2878 // Don't accept drop in selection or read-only field...
2879 if ( IsReadOnly() || aSel
.Contains( mpDDInfo
->nDropPos
) || ! mpDDInfo
->bIsStringSupported
)
2882 rDTDE
.Context
->rejectDrag();
2886 // draw the old cursor away...
2887 if ( !mpDDInfo
->bVisCursor
|| ( nPrevDropPos
!= mpDDInfo
->nDropPos
) )
2892 rDTDE
.Context
->acceptDrag( rDTDE
.DropAction
);
2896 OUString
Edit::GetSurroundingText() const
2899 return mpSubEdit
->GetSurroundingText();
2900 return maText
.toString();
2903 Selection
Edit::GetSurroundingTextSelection() const
2905 return GetSelection();
2908 bool Edit::DeleteSurroundingText(const Selection
& rSelection
)
2910 SetSelection(rSelection
);
2912 // maybe we should update mpIMEInfos here
2916 FactoryFunction
Edit::GetUITestFactory() const
2918 return EditUIObject::create
;
2922 void Edit::DumpAsPropertyTree(tools::JsonWriter
& rJsonWriter
)
2924 Control::DumpAsPropertyTree(rJsonWriter
);
2926 if (!maPlaceholderText
.isEmpty())
2927 rJsonWriter
.put("placeholder", maPlaceholderText
);
2930 rJsonWriter
.put("password", true);
2933 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */