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 uno::Reference
< datatransfer::dnd::XDragGestureListener
> xDGL( mxDnDListener
, uno::UNO_QUERY
);
244 GetDragGestureRecognizer()->removeDragGestureListener( xDGL
);
246 if ( GetDropTarget().is() )
248 uno::Reference
< datatransfer::dnd::XDropTargetListener
> xDTL( mxDnDListener
, uno::UNO_QUERY
);
249 GetDropTarget()->removeDropTargetListener( xDTL
);
252 mxDnDListener
->disposing( lang::EventObject() ); // #95154# #96585# Empty Source means it's the Client
253 mxDnDListener
.clear();
256 SetType(WindowType::WINDOW
);
258 mpSubEdit
.disposeAndClear();
262 void Edit::ImplInitEditData()
264 mpSubEdit
= VclPtr
<Edit
>();
265 mpFilterText
= nullptr;
267 mnAlign
= EDIT_ALIGN_LEFT
;
268 mnMaxTextLen
= EDIT_NOLIMIT
;
270 mnMaxWidthChars
= -1;
271 mbInternModified
= false;
274 mbClickedInSelection
= false;
275 mbActivePopup
= false;
277 mbForceControlBackground
= false;
280 mpIMEInfos
= nullptr;
283 // no default mirroring for Edit controls
284 // note: controls that use a subedit will revert this (SpinField, ComboBox)
287 mxDnDListener
= new vcl::unohelper::DragAndDropWrapper( this );
290 bool Edit::ImplUseNativeBorder(vcl::RenderContext
const & rRenderContext
, WinBits nStyle
) const
292 bool bRet
= rRenderContext
.IsNativeControlSupported(ImplGetNativeControlType(),
293 ControlPart::HasBackgroundTexture
)
294 && ((nStyle
& WB_BORDER
) && !(nStyle
& WB_NOBORDER
));
295 if (!bRet
&& mbIsSubEdit
)
297 vcl::Window
* pWindow
= GetParent();
298 nStyle
= pWindow
->GetStyle();
299 bRet
= pWindow
->IsNativeControlSupported(ImplGetNativeControlType(),
300 ControlPart::HasBackgroundTexture
)
301 && ((nStyle
& WB_BORDER
) && !(nStyle
& WB_NOBORDER
));
306 void Edit::ImplInit(vcl::Window
* pParent
, WinBits nStyle
)
308 nStyle
= ImplInitStyle(nStyle
);
310 if (!(nStyle
& (WB_CENTER
| WB_RIGHT
)))
313 Control::ImplInit(pParent
, nStyle
, nullptr);
315 mbReadOnly
= (nStyle
& WB_READONLY
) != 0;
317 mnAlign
= EDIT_ALIGN_LEFT
;
319 // hack: right align until keyinput and cursor travelling works
321 mnAlign
= EDIT_ALIGN_RIGHT
;
323 if ( nStyle
& WB_RIGHT
)
324 mnAlign
= EDIT_ALIGN_RIGHT
;
325 else if ( nStyle
& WB_CENTER
)
326 mnAlign
= EDIT_ALIGN_CENTER
;
328 SetCursor( new vcl::Cursor
);
330 SetPointer( PointerStyle::Text
);
331 ApplySettings(*GetOutDev());
333 uno::Reference
< datatransfer::dnd::XDragGestureListener
> xDGL( mxDnDListener
, uno::UNO_QUERY
);
334 uno::Reference
< datatransfer::dnd::XDragGestureRecognizer
> xDGR
= GetDragGestureRecognizer();
337 xDGR
->addDragGestureListener( xDGL
);
338 uno::Reference
< datatransfer::dnd::XDropTargetListener
> xDTL( mxDnDListener
, uno::UNO_QUERY
);
339 GetDropTarget()->addDropTargetListener( xDTL
);
340 GetDropTarget()->setActive( true );
341 GetDropTarget()->setDefaultActions( datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE
);
345 WinBits
Edit::ImplInitStyle( WinBits nStyle
)
347 if ( !(nStyle
& WB_NOTABSTOP
) )
348 nStyle
|= WB_TABSTOP
;
349 if ( !(nStyle
& WB_NOGROUP
) )
355 bool Edit::IsCharInput( const KeyEvent
& rKeyEvent
)
357 // In the future we must use new Unicode functions for this
358 sal_Unicode cCharCode
= rKeyEvent
.GetCharCode();
359 return ((cCharCode
>= 32) && (cCharCode
!= 127) &&
360 !rKeyEvent
.GetKeyCode().IsMod3() &&
361 !rKeyEvent
.GetKeyCode().IsMod2() &&
362 !rKeyEvent
.GetKeyCode().IsMod1() );
365 void Edit::ApplySettings(vcl::RenderContext
& rRenderContext
)
367 Control::ApplySettings(rRenderContext
);
369 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
371 const vcl::Font
& aFont
= rStyleSettings
.GetFieldFont();
372 ApplyControlFont(rRenderContext
, aFont
);
374 ImplClearLayoutData();
376 Color aTextColor
= rStyleSettings
.GetFieldTextColor();
377 ApplyControlForeground(rRenderContext
, aTextColor
);
379 if (IsControlBackground())
381 rRenderContext
.SetBackground(GetControlBackground());
382 rRenderContext
.SetFillColor(GetControlBackground());
384 if (ImplUseNativeBorder(rRenderContext
, GetStyle()))
386 // indicates that no non-native drawing of background should take place
387 mpWindowImpl
->mnNativeBackground
= ControlPart::Entire
;
390 else if (ImplUseNativeBorder(rRenderContext
, GetStyle()))
392 // Transparent background
393 rRenderContext
.SetBackground();
394 rRenderContext
.SetFillColor();
398 rRenderContext
.SetBackground(rStyleSettings
.GetFieldColor());
399 rRenderContext
.SetFillColor(rStyleSettings
.GetFieldColor());
403 tools::Long
Edit::ImplGetExtraXOffset() const
405 // MT 09/2002: nExtraOffsetX should become a member, instead of checking every time,
406 // but I need an incompatible update for this...
407 // #94095# Use extra offset only when edit has a border
408 tools::Long nExtraOffset
= 0;
409 if( ( GetStyle() & WB_BORDER
) || ( mbIsSubEdit
&& ( GetParent()->GetStyle() & WB_BORDER
) ) )
415 tools::Long
Edit::ImplGetExtraYOffset() const
417 tools::Long nExtraOffset
= 0;
418 ControlType eCtrlType
= ImplGetNativeControlType();
419 if (eCtrlType
!= ControlType::EditboxNoBorder
)
421 // add some space between text entry and border
427 OUString
Edit::ImplGetText() const
429 if ( mcEchoChar
|| mbPassword
)
431 sal_Unicode cEchoChar
;
433 cEchoChar
= mcEchoChar
;
435 cEchoChar
= u
'\x2022';
436 OUStringBuffer
aText(maText
.getLength());
437 comphelper::string::padToLength(aText
, maText
.getLength(), cEchoChar
);
438 return aText
.makeStringAndClear();
441 return maText
.toString();
444 void Edit::ImplInvalidateOrRepaint()
446 if( IsPaintTransparent() )
449 // FIXME: this is currently only on macOS
450 if( ImplGetSVData()->maNWFData
.mbNoFocusRects
)
457 tools::Long
Edit::ImplGetTextYPosition() const
459 if ( GetStyle() & WB_TOP
)
460 return ImplGetExtraXOffset();
461 else if ( GetStyle() & WB_BOTTOM
)
462 return GetOutputSizePixel().Height() - GetTextHeight() - ImplGetExtraXOffset();
463 return ( GetOutputSizePixel().Height() - GetTextHeight() ) / 2;
466 void Edit::ImplRepaint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRectangle
)
468 if (!IsReallyVisible())
471 ApplySettings(rRenderContext
);
473 const OUString aText
= ImplGetText();
474 const sal_Int32 nLen
= aText
.getLength();
476 sal_Int32 nDXBuffer
[256];
477 std::unique_ptr
<sal_Int32
[]> pDXBuffer
;
478 sal_Int32
* pDX
= nDXBuffer
;
482 if (o3tl::make_unsigned(2 * nLen
) > SAL_N_ELEMENTS(nDXBuffer
))
484 pDXBuffer
.reset(new sal_Int32
[2 * (nLen
+ 1)]);
485 pDX
= pDXBuffer
.get();
488 GetOutDev()->GetCaretPositions(aText
, pDX
, 0, nLen
);
491 tools::Long nTH
= GetTextHeight();
492 Point
aPos(mnXOffset
, ImplGetTextYPosition());
494 vcl::Cursor
* pCursor
= GetCursor();
495 bool bVisCursor
= pCursor
&& pCursor
->IsVisible();
499 ImplClearBackground(rRenderContext
, rRectangle
, 0, GetOutputSizePixel().Width()-1);
501 bool bPaintPlaceholderText
= aText
.isEmpty() && !maPlaceholderText
.isEmpty();
503 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
505 if (!IsEnabled() || bPaintPlaceholderText
)
506 rRenderContext
.SetTextColor(rStyleSettings
.GetDisableColor());
508 // Set background color of the normal text
509 if (mbForceControlBackground
&& IsControlBackground())
511 // check if we need to set ControlBackground even in NWF case
512 rRenderContext
.Push(vcl::PushFlags::FILLCOLOR
| vcl::PushFlags::LINECOLOR
);
513 rRenderContext
.SetLineColor();
514 rRenderContext
.SetFillColor(GetControlBackground());
515 rRenderContext
.DrawRect(tools::Rectangle(aPos
, Size(GetOutputSizePixel().Width() - 2 * mnXOffset
, GetOutputSizePixel().Height())));
516 rRenderContext
.Pop();
518 rRenderContext
.SetTextFillColor(GetControlBackground());
520 else if (IsPaintTransparent() || ImplUseNativeBorder(rRenderContext
, GetStyle()))
521 rRenderContext
.SetTextFillColor();
523 rRenderContext
.SetTextFillColor(IsControlBackground() ? GetControlBackground() : rStyleSettings
.GetFieldColor());
525 ImplPaintBorder(rRenderContext
);
527 bool bDrawSelection
= maSelection
.Len() && (HasFocus() || (GetStyle() & WB_NOHIDESELECTION
) || mbActivePopup
);
529 aPos
.setX( mnXOffset
+ ImplGetExtraXOffset() );
530 if (bPaintPlaceholderText
)
532 rRenderContext
.DrawText(aPos
, maPlaceholderText
);
534 else if (!bDrawSelection
&& !mpIMEInfos
)
536 rRenderContext
.DrawText(aPos
, aText
, 0, nLen
);
540 // save graphics state
541 rRenderContext
.Push();
542 // first calculate highlighted and non highlighted clip regions
543 vcl::Region aHighlightClipRegion
;
544 vcl::Region aNormalClipRegion
;
545 Selection
aTmpSel(maSelection
);
547 // selection is highlighted
548 for(sal_Int32 i
= 0; i
< nLen
; ++i
)
550 tools::Rectangle
aRect(aPos
, Size(10, nTH
));
551 aRect
.SetLeft( pDX
[2 * i
] + mnXOffset
+ ImplGetExtraXOffset() );
552 aRect
.SetRight( pDX
[2 * i
+ 1] + mnXOffset
+ ImplGetExtraXOffset() );
554 bool bHighlight
= false;
555 if (i
>= aTmpSel
.Min() && i
< aTmpSel
.Max())
558 if (mpIMEInfos
&& mpIMEInfos
->pAttribs
&&
559 i
>= mpIMEInfos
->nPos
&& i
< (mpIMEInfos
->nPos
+mpIMEInfos
->nLen
) &&
560 (mpIMEInfos
->pAttribs
[i
- mpIMEInfos
->nPos
] & ExtTextInputAttr::Highlight
))
566 aHighlightClipRegion
.Union(aRect
);
568 aNormalClipRegion
.Union(aRect
);
571 Color aNormalTextColor
= rRenderContext
.GetTextColor();
572 rRenderContext
.SetClipRegion(aNormalClipRegion
);
574 if (IsPaintTransparent())
575 rRenderContext
.SetTextFillColor();
578 // Set background color when part of the text is selected
579 if (ImplUseNativeBorder(rRenderContext
, GetStyle()))
581 if( mbForceControlBackground
&& IsControlBackground() )
582 rRenderContext
.SetTextFillColor(GetControlBackground());
584 rRenderContext
.SetTextFillColor();
588 rRenderContext
.SetTextFillColor(IsControlBackground() ? GetControlBackground() : rStyleSettings
.GetFieldColor());
591 rRenderContext
.DrawText(aPos
, aText
, 0, nLen
);
593 // draw highlighted text
594 rRenderContext
.SetClipRegion(aHighlightClipRegion
);
595 rRenderContext
.SetTextColor(rStyleSettings
.GetHighlightTextColor());
596 rRenderContext
.SetTextFillColor(rStyleSettings
.GetHighlightColor());
597 rRenderContext
.DrawText(aPos
, aText
, 0, nLen
);
599 // if IME info exists loop over portions and output different font attributes
600 if (mpIMEInfos
&& mpIMEInfos
->pAttribs
)
602 for(int n
= 0; n
< 2; n
++)
607 rRenderContext
.SetTextColor(aNormalTextColor
);
608 if (IsPaintTransparent())
609 rRenderContext
.SetTextFillColor();
611 rRenderContext
.SetTextFillColor(IsControlBackground() ? GetControlBackground() : rStyleSettings
.GetFieldColor());
612 aRegion
= aNormalClipRegion
;
616 rRenderContext
.SetTextColor(rStyleSettings
.GetHighlightTextColor());
617 rRenderContext
.SetTextFillColor(rStyleSettings
.GetHighlightColor());
618 aRegion
= aHighlightClipRegion
;
621 for(int i
= 0; i
< mpIMEInfos
->nLen
; )
623 ExtTextInputAttr nAttr
= mpIMEInfos
->pAttribs
[i
];
626 while (nIndex
< mpIMEInfos
->nLen
&& mpIMEInfos
->pAttribs
[nIndex
] == nAttr
) // #112631# check nIndex before using it
628 tools::Rectangle
aRect( aPos
, Size( 10, nTH
) );
629 aRect
.SetLeft( pDX
[2 * (nIndex
+ mpIMEInfos
->nPos
)] + mnXOffset
+ ImplGetExtraXOffset() );
630 aRect
.SetRight( pDX
[2 * (nIndex
+ mpIMEInfos
->nPos
) + 1] + mnXOffset
+ ImplGetExtraXOffset() );
636 aClip
.Intersect(aRegion
);
637 if (!aClip
.IsEmpty() && nAttr
!= ExtTextInputAttr::NONE
)
639 vcl::Font aFont
= rRenderContext
.GetFont();
640 if (nAttr
& ExtTextInputAttr::Underline
)
641 aFont
.SetUnderline(LINESTYLE_SINGLE
);
642 else if (nAttr
& ExtTextInputAttr::DoubleUnderline
)
643 aFont
.SetUnderline(LINESTYLE_DOUBLE
);
644 else if (nAttr
& ExtTextInputAttr::BoldUnderline
)
645 aFont
.SetUnderline( LINESTYLE_BOLD
);
646 else if (nAttr
& ExtTextInputAttr::DottedUnderline
)
647 aFont
.SetUnderline( LINESTYLE_DOTTED
);
648 else if (nAttr
& ExtTextInputAttr::DashDotUnderline
)
649 aFont
.SetUnderline( LINESTYLE_DASHDOT
);
650 else if (nAttr
& ExtTextInputAttr::GrayWaveline
)
652 aFont
.SetUnderline(LINESTYLE_WAVE
);
653 rRenderContext
.SetTextLineColor(COL_LIGHTGRAY
);
655 rRenderContext
.SetFont(aFont
);
657 if (nAttr
& ExtTextInputAttr::RedText
)
658 rRenderContext
.SetTextColor(COL_RED
);
659 else if (nAttr
& ExtTextInputAttr::HalfToneText
)
660 rRenderContext
.SetTextColor(COL_LIGHTGRAY
);
662 rRenderContext
.SetClipRegion(aClip
);
663 rRenderContext
.DrawText(aPos
, aText
, 0, nLen
);
669 // restore graphics state
670 rRenderContext
.Pop();
673 if (bVisCursor
&& (!mpIMEInfos
|| mpIMEInfos
->bCursor
))
677 void Edit::ImplDelete( const Selection
& rSelection
, sal_uInt8 nDirection
, sal_uInt8 nMode
)
679 const sal_Int32 nTextLen
= ImplGetText().getLength();
681 // deleting possible?
682 if ( !rSelection
.Len() &&
683 (((rSelection
.Min() == 0) && (nDirection
== EDIT_DEL_LEFT
)) ||
684 ((rSelection
.Max() == nTextLen
) && (nDirection
== EDIT_DEL_RIGHT
))) )
687 ImplClearLayoutData();
689 Selection
aSelection( rSelection
);
690 aSelection
.Normalize();
692 if ( !aSelection
.Len() )
694 uno::Reference
< i18n::XBreakIterator
> xBI
= ImplGetBreakIterator();
695 if ( nDirection
== EDIT_DEL_LEFT
)
697 if ( nMode
== EDIT_DELMODE_RESTOFWORD
)
699 const OUString sText
= maText
.toString();
700 i18n::Boundary aBoundary
= xBI
->getWordBoundary( sText
, aSelection
.Min(),
701 GetSettings().GetLanguageTag().getLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES
, true );
702 auto startPos
= aBoundary
.startPos
;
703 if ( startPos
== aSelection
.Min() )
705 aBoundary
= xBI
->previousWord( sText
, aSelection
.Min(),
706 GetSettings().GetLanguageTag().getLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES
);
707 startPos
= std::max(aBoundary
.startPos
, sal_Int32(0));
709 aSelection
.Min() = startPos
;
711 else if ( nMode
== EDIT_DELMODE_RESTOFCONTENT
)
713 aSelection
.Min() = 0;
717 sal_Int32 nCount
= 1;
718 aSelection
.Min() = xBI
->previousCharacters( maText
.toString(), aSelection
.Min(),
719 GetSettings().GetLanguageTag().getLocale(), i18n::CharacterIteratorMode::SKIPCHARACTER
, nCount
, nCount
);
724 if ( nMode
== EDIT_DELMODE_RESTOFWORD
)
726 i18n::Boundary aBoundary
= xBI
->nextWord( maText
.toString(), aSelection
.Max(),
727 GetSettings().GetLanguageTag().getLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES
);
728 aSelection
.Max() = aBoundary
.startPos
;
730 else if ( nMode
== EDIT_DELMODE_RESTOFCONTENT
)
732 aSelection
.Max() = nTextLen
;
736 sal_Int32 nCount
= 1;
737 aSelection
.Max() = xBI
->nextCharacters( maText
.toString(), aSelection
.Max(),
738 GetSettings().GetLanguageTag().getLocale(), i18n::CharacterIteratorMode::SKIPCHARACTER
, nCount
, nCount
);
743 const auto nSelectionMin
= aSelection
.Min();
744 maText
.remove( nSelectionMin
, aSelection
.Len() );
745 maSelection
.Min() = nSelectionMin
;
746 maSelection
.Max() = nSelectionMin
;
748 mbInternModified
= true;
751 OUString
Edit::ImplGetValidString( const OUString
& rString
)
753 OUString aValidString
= rString
.replaceAll("\n", "").replaceAll("\r", "");
754 aValidString
= aValidString
.replace('\t', ' ');
758 uno::Reference
<i18n::XBreakIterator
> const& Edit::ImplGetBreakIterator()
760 if (!mxBreakIterator
)
761 mxBreakIterator
= i18n::BreakIterator::create(::comphelper::getProcessComponentContext());
762 return mxBreakIterator
;
765 uno::Reference
<i18n::XExtendedInputSequenceChecker
> const& Edit::ImplGetInputSequenceChecker()
768 mxISC
= i18n::InputSequenceChecker::create(::comphelper::getProcessComponentContext());
772 void Edit::ShowTruncationWarning(weld::Widget
* pParent
)
774 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(pParent
, VclMessageType::Warning
,
775 VclButtonsType::Ok
, VclResId(SV_EDIT_WARNING_STR
)));
779 bool Edit::ImplTruncateToMaxLen( OUString
& rStr
, sal_Int32 nSelectionLen
) const
781 bool bWasTruncated
= false;
782 if (maText
.getLength() - nSelectionLen
> mnMaxTextLen
- rStr
.getLength())
784 sal_Int32 nErasePos
= mnMaxTextLen
- maText
.getLength() + nSelectionLen
;
785 rStr
= rStr
.copy( 0, nErasePos
);
786 bWasTruncated
= true;
788 return bWasTruncated
;
791 void Edit::ImplInsertText( const OUString
& rStr
, const Selection
* pNewSel
, bool bIsUserInput
)
793 Selection
aSelection( maSelection
);
794 aSelection
.Normalize();
796 OUString
aNewText( ImplGetValidString( rStr
) );
798 // as below, if there's no selection, but we're in overwrite mode and not beyond
799 // the end of the existing text then that's like a selection of 1
800 auto nSelectionLen
= aSelection
.Len();
801 if (!nSelectionLen
&& !mbInsertMode
&& aSelection
.Max() < maText
.getLength())
803 ImplTruncateToMaxLen( aNewText
, nSelectionLen
);
805 ImplClearLayoutData();
807 if ( aSelection
.Len() )
808 maText
.remove( aSelection
.Min(), aSelection
.Len() );
809 else if (!mbInsertMode
&& aSelection
.Max() < maText
.getLength())
810 maText
.remove( aSelection
.Max(), 1 );
812 // take care of input-sequence-checking now
813 if (bIsUserInput
&& !rStr
.isEmpty())
815 SAL_WARN_IF( rStr
.getLength() != 1, "vcl", "unexpected string length. User input is expected to provide 1 char only!" );
817 // determine if input-sequence-checking should be applied or not
819 uno::Reference
< i18n::XBreakIterator
> xBI
= ImplGetBreakIterator();
820 bool bIsInputSequenceChecking
= rStr
.getLength() == 1 &&
821 officecfg::Office::Common::I18N::CTL::CTLFont::get() &&
822 officecfg::Office::Common::I18N::CTL::CTLSequenceChecking::get() &&
823 aSelection
.Min() > 0 && /* first char needs not to be checked */
824 xBI
.is() && i18n::ScriptType::COMPLEX
== xBI
->getScriptType( rStr
, 0 );
826 if (bIsInputSequenceChecking
)
828 uno::Reference
< i18n::XExtendedInputSequenceChecker
> xISC
= ImplGetInputSequenceChecker();
831 sal_Unicode cChar
= rStr
[0];
832 sal_Int32 nTmpPos
= aSelection
.Min();
833 sal_Int16 nCheckMode
= officecfg::Office::Common::I18N::CTL::CTLSequenceCheckingRestricted::get()?
834 i18n::InputSequenceCheckMode::STRICT
: i18n::InputSequenceCheckMode::BASIC
;
836 // the text that needs to be checked is only the one
837 // before the current cursor position
838 const OUString
aOldText( maText
.subView(0, nTmpPos
) );
839 OUString
aTmpText( aOldText
);
840 if (officecfg::Office::Common::I18N::CTL::CTLSequenceCheckingTypeAndReplace::get())
842 xISC
->correctInputSequence( aTmpText
, nTmpPos
- 1, cChar
, nCheckMode
);
844 // find position of first character that has changed
845 sal_Int32 nOldLen
= aOldText
.getLength();
846 sal_Int32 nTmpLen
= aTmpText
.getLength();
847 const sal_Unicode
*pOldTxt
= aOldText
.getStr();
848 const sal_Unicode
*pTmpTxt
= aTmpText
.getStr();
849 sal_Int32 nChgPos
= 0;
850 while ( nChgPos
< nOldLen
&& nChgPos
< nTmpLen
&&
851 pOldTxt
[nChgPos
] == pTmpTxt
[nChgPos
] )
854 const OUString
aChgText( aTmpText
.copy( nChgPos
) );
856 // remove text from first pos to be changed to current pos
857 maText
.remove( nChgPos
, nTmpPos
- nChgPos
);
859 if (!aChgText
.isEmpty())
862 aSelection
.Min() = nChgPos
; // position for new text to be inserted
869 // should the character be ignored (i.e. not get inserted) ?
870 if (!xISC
->checkInputSequence( aOldText
, nTmpPos
- 1, cChar
, nCheckMode
))
876 // at this point now we will insert the non-empty text 'normally' some lines below...
879 if ( !aNewText
.isEmpty() )
880 maText
.insert( aSelection
.Min(), aNewText
);
884 maSelection
.Min() = aSelection
.Min() + aNewText
.getLength();
885 maSelection
.Max() = maSelection
.Min();
889 maSelection
= *pNewSel
;
890 if ( maSelection
.Min() > maText
.getLength() )
891 maSelection
.Min() = maText
.getLength();
892 if ( maSelection
.Max() > maText
.getLength() )
893 maSelection
.Max() = maText
.getLength();
897 mbInternModified
= true;
900 void Edit::ImplSetText( const OUString
& rText
, const Selection
* pNewSelection
)
902 // we delete text by "selecting" the old text completely then calling InsertText; this is flicker free
903 if ( ( rText
.getLength() > mnMaxTextLen
) ||
904 ( std::u16string_view(rText
) == std::u16string_view(maText
)
905 && (!pNewSelection
|| (*pNewSelection
== maSelection
)) ) )
908 ImplClearLayoutData();
909 maSelection
.Min() = 0;
910 maSelection
.Max() = maText
.getLength();
911 if ( mnXOffset
|| HasPaintEvent() )
914 maText
= ImplGetValidString( rText
);
916 // #i54929# recalculate mnXOffset before ImplSetSelection,
917 // else cursor ends up in wrong position
921 ImplSetSelection( *pNewSelection
, false );
923 if ( mnXOffset
&& !pNewSelection
)
924 maSelection
.Max() = 0;
929 ImplInsertText( rText
, pNewSelection
);
931 CallEventListeners( VclEventId::EditModify
);
934 ControlType
Edit::ImplGetNativeControlType() const
936 ControlType nCtrl
= ControlType::Generic
;
937 const vcl::Window
* pControl
= mbIsSubEdit
? GetParent() : this;
939 switch (pControl
->GetType())
941 case WindowType::COMBOBOX
:
942 case WindowType::PATTERNBOX
:
943 case WindowType::NUMERICBOX
:
944 case WindowType::METRICBOX
:
945 case WindowType::CURRENCYBOX
:
946 case WindowType::DATEBOX
:
947 case WindowType::TIMEBOX
:
948 case WindowType::LONGCURRENCYBOX
:
949 nCtrl
= ControlType::Combobox
;
952 case WindowType::MULTILINEEDIT
:
953 if ( GetWindow( GetWindowType::Border
) != this )
954 nCtrl
= ControlType::MultilineEditbox
;
956 nCtrl
= ControlType::EditboxNoBorder
;
959 case WindowType::EDIT
:
960 case WindowType::PATTERNFIELD
:
961 case WindowType::METRICFIELD
:
962 case WindowType::CURRENCYFIELD
:
963 case WindowType::DATEFIELD
:
964 case WindowType::TIMEFIELD
:
965 case WindowType::SPINFIELD
:
966 case WindowType::FORMATTEDFIELD
:
967 if (pControl
->GetStyle() & WB_SPIN
)
968 nCtrl
= ControlType::Spinbox
;
971 if (GetWindow(GetWindowType::Border
) != this)
972 nCtrl
= ControlType::Editbox
;
974 nCtrl
= ControlType::EditboxNoBorder
;
979 nCtrl
= ControlType::Editbox
;
984 void Edit::ImplClearBackground(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRectangle
, tools::Long nXStart
, tools::Long nXEnd
)
987 * note: at this point the cursor must be switched off already
989 tools::Rectangle
aRect(Point(), GetOutputSizePixel());
990 aRect
.SetLeft( nXStart
);
991 aRect
.SetRight( nXEnd
);
993 if( !(ImplUseNativeBorder(rRenderContext
, GetStyle()) || IsPaintTransparent()))
994 rRenderContext
.Erase(aRect
);
995 else if (SupportsDoubleBuffering() && mbIsSubEdit
)
997 // ImplPaintBorder() is a NOP, we have a native border, and this is a sub-edit of a control.
998 // That means we have to draw the parent native widget to paint the edit area to clear our background.
999 vcl::PaintBufferGuard
g(ImplGetWindowImpl()->mpFrameData
, GetParent());
1000 GetParent()->Paint(rRenderContext
, rRectangle
);
1004 void Edit::ImplPaintBorder(vcl::RenderContext
const & rRenderContext
)
1006 // this is not needed when double-buffering
1007 if (SupportsDoubleBuffering())
1010 if (!(ImplUseNativeBorder(rRenderContext
, GetStyle()) || IsPaintTransparent()))
1013 // draw the inner part by painting the whole control using its border window
1014 vcl::Window
* pBorder
= GetWindow(GetWindowType::Border
);
1015 if (pBorder
== this)
1017 // we have no border, use parent
1018 vcl::Window
* pControl
= mbIsSubEdit
? GetParent() : this;
1019 pBorder
= pControl
->GetWindow(GetWindowType::Border
);
1020 if (pBorder
== this)
1021 pBorder
= GetParent();
1027 // set proper clipping region to not overdraw the whole control
1028 vcl::Region aClipRgn
= GetPaintRegion();
1029 if (!aClipRgn
.IsNull())
1031 // transform clipping region to border window's coordinate system
1032 if (IsRTLEnabled() != pBorder
->IsRTLEnabled() && AllSettings::GetLayoutRTL())
1034 // need to mirror in case border is not RTL but edit is (or vice versa)
1037 tools::Rectangle
aBounds(aClipRgn
.GetBoundRect());
1038 int xNew
= GetOutputSizePixel().Width() - aBounds
.GetWidth() - aBounds
.Left();
1039 aClipRgn
.Move(xNew
- aBounds
.Left(), 0);
1041 // move offset of border window
1042 Point aBorderOffs
= pBorder
->ScreenToOutputPixel(OutputToScreenPixel(Point()));
1043 aClipRgn
.Move(aBorderOffs
.X(), aBorderOffs
.Y());
1048 Point aBorderOffs
= pBorder
->ScreenToOutputPixel(OutputToScreenPixel(Point()));
1049 aClipRgn
.Move(aBorderOffs
.X(), aBorderOffs
.Y());
1052 vcl::Region
oldRgn(pBorder
->GetOutDev()->GetClipRegion());
1053 pBorder
->GetOutDev()->SetClipRegion(aClipRgn
);
1055 pBorder
->Paint(*pBorder
->GetOutDev(), tools::Rectangle());
1057 pBorder
->GetOutDev()->SetClipRegion(oldRgn
);
1061 pBorder
->Paint(*pBorder
->GetOutDev(), tools::Rectangle());
1065 void Edit::ImplShowCursor( bool bOnlyIfVisible
)
1067 if ( !IsUpdateMode() || ( bOnlyIfVisible
&& !IsReallyVisible() ) )
1070 vcl::Cursor
* pCursor
= GetCursor();
1071 OUString aText
= ImplGetText();
1073 tools::Long nTextPos
= 0;
1075 sal_Int32 nDXBuffer
[256];
1076 std::unique_ptr
<sal_Int32
[]> pDXBuffer
;
1077 sal_Int32
* pDX
= nDXBuffer
;
1079 if( !aText
.isEmpty() )
1081 if( o3tl::make_unsigned(2*aText
.getLength()) > SAL_N_ELEMENTS(nDXBuffer
) )
1083 pDXBuffer
.reset(new sal_Int32
[2*(aText
.getLength()+1)]);
1084 pDX
= pDXBuffer
.get();
1087 GetOutDev()->GetCaretPositions( aText
, pDX
, 0, aText
.getLength() );
1089 if( maSelection
.Max() < aText
.getLength() )
1090 nTextPos
= pDX
[ 2*maSelection
.Max() ];
1092 nTextPos
= pDX
[ 2*aText
.getLength()-1 ];
1095 tools::Long nCursorWidth
= 0;
1096 if ( !mbInsertMode
&& !maSelection
.Len() && (maSelection
.Max() < aText
.getLength()) )
1097 nCursorWidth
= GetTextWidth(aText
, maSelection
.Max(), 1);
1098 tools::Long nCursorPosX
= nTextPos
+ mnXOffset
+ ImplGetExtraXOffset();
1100 // cursor should land in visible area
1101 const Size aOutSize
= GetOutputSizePixel();
1102 if ( (nCursorPosX
< 0) || (nCursorPosX
>= aOutSize
.Width()) )
1104 tools::Long nOldXOffset
= mnXOffset
;
1106 if ( nCursorPosX
< 0 )
1108 mnXOffset
= - nTextPos
;
1109 tools::Long nMaxX
= 0;
1110 mnXOffset
+= aOutSize
.Width() / 5;
1111 if ( mnXOffset
> nMaxX
)
1116 mnXOffset
= (aOutSize
.Width()-ImplGetExtraXOffset()) - nTextPos
;
1118 if ( (aOutSize
.Width()-ImplGetExtraXOffset()) < nTextPos
)
1120 tools::Long nMaxNegX
= (aOutSize
.Width()-ImplGetExtraXOffset()) - GetTextWidth( aText
);
1121 mnXOffset
-= aOutSize
.Width() / 5;
1122 if ( mnXOffset
< nMaxNegX
) // both negative...
1123 mnXOffset
= nMaxNegX
;
1127 nCursorPosX
= nTextPos
+ mnXOffset
+ ImplGetExtraXOffset();
1128 if ( nCursorPosX
== aOutSize
.Width() ) // then invisible...
1131 if ( mnXOffset
!= nOldXOffset
)
1132 ImplInvalidateOrRepaint();
1135 const tools::Long nTextHeight
= GetTextHeight();
1136 const tools::Long nCursorPosY
= ImplGetTextYPosition();
1139 pCursor
->SetPos( Point( nCursorPosX
, nCursorPosY
) );
1140 pCursor
->SetSize( Size( nCursorWidth
, nTextHeight
) );
1145 void Edit::ImplAlign()
1147 if (mnAlign
== EDIT_ALIGN_LEFT
&& !mnXOffset
)
1149 // short circuit common case and avoid slow GetTextWidth() calc
1153 tools::Long nTextWidth
= GetTextWidth( ImplGetText() );
1154 tools::Long nOutWidth
= GetOutputSizePixel().Width();
1156 if ( mnAlign
== EDIT_ALIGN_LEFT
)
1158 if (nTextWidth
< nOutWidth
)
1161 else if ( mnAlign
== EDIT_ALIGN_RIGHT
)
1163 tools::Long nMinXOffset
= nOutWidth
- nTextWidth
- 1 - ImplGetExtraXOffset();
1164 bool bRTL
= IsRTLEnabled();
1165 if( mbIsSubEdit
&& GetParent() )
1166 bRTL
= GetParent()->IsRTLEnabled();
1169 if( nTextWidth
< nOutWidth
)
1170 mnXOffset
= nMinXOffset
;
1174 if( nTextWidth
< nOutWidth
)
1175 mnXOffset
= nMinXOffset
;
1176 else if ( mnXOffset
< nMinXOffset
)
1177 mnXOffset
= nMinXOffset
;
1180 else if( mnAlign
== EDIT_ALIGN_CENTER
)
1182 // would be nicer with check while scrolling but then it's not centred in scrolled state
1183 mnXOffset
= (nOutWidth
- nTextWidth
) / 2;
1187 void Edit::ImplAlignAndPaint()
1190 ImplInvalidateOrRepaint();
1194 sal_Int32
Edit::ImplGetCharPos( const Point
& rWindowPos
) const
1196 sal_Int32 nIndex
= EDIT_NOLIMIT
;
1197 OUString aText
= ImplGetText();
1199 sal_Int32 nDXBuffer
[256];
1200 std::unique_ptr
<sal_Int32
[]> pDXBuffer
;
1201 sal_Int32
* pDX
= nDXBuffer
;
1202 if( o3tl::make_unsigned(2*aText
.getLength()) > SAL_N_ELEMENTS(nDXBuffer
) )
1204 pDXBuffer
.reset(new sal_Int32
[2*(aText
.getLength()+1)]);
1205 pDX
= pDXBuffer
.get();
1208 GetOutDev()->GetCaretPositions( aText
, pDX
, 0, aText
.getLength() );
1209 tools::Long nX
= rWindowPos
.X() - mnXOffset
- ImplGetExtraXOffset();
1210 for (sal_Int32 i
= 0; i
< aText
.getLength(); aText
.iterateCodePoints(&i
))
1212 if( (pDX
[2*i
] >= nX
&& pDX
[2*i
+1] <= nX
) ||
1213 (pDX
[2*i
+1] >= nX
&& pDX
[2*i
] <= nX
))
1216 if( pDX
[2*i
] < pDX
[2*i
+1] )
1218 if( nX
> (pDX
[2*i
]+pDX
[2*i
+1])/2 )
1219 aText
.iterateCodePoints(&nIndex
);
1223 if( nX
< (pDX
[2*i
]+pDX
[2*i
+1])/2 )
1224 aText
.iterateCodePoints(&nIndex
);
1229 if( nIndex
== EDIT_NOLIMIT
)
1232 sal_Int32 nFinalIndex
= 0;
1233 tools::Long nDiff
= std::abs( pDX
[0]-nX
);
1235 if (!aText
.isEmpty())
1237 aText
.iterateCodePoints(&i
); //skip the first character
1239 while (i
< aText
.getLength())
1241 tools::Long nNewDiff
= std::abs( pDX
[2*i
]-nX
);
1243 if( nNewDiff
< nDiff
)
1251 aText
.iterateCodePoints(&i
);
1253 if (nIndex
== nFinalIndex
&& std::abs( pDX
[2*nIndex
+1] - nX
) < nDiff
)
1254 nIndex
= EDIT_NOLIMIT
;
1260 void Edit::ImplSetCursorPos( sal_Int32 nChar
, bool bSelect
)
1262 Selection
aSelection( maSelection
);
1263 aSelection
.Max() = nChar
;
1265 aSelection
.Min() = aSelection
.Max();
1266 ImplSetSelection( aSelection
);
1269 void Edit::ImplCopyToSelectionClipboard()
1271 if ( GetSelection().Len() )
1273 css::uno::Reference
<css::datatransfer::clipboard::XClipboard
> aSelection(GetSystemPrimarySelection());
1274 ImplCopy( aSelection
);
1278 void Edit::ImplCopy( uno::Reference
< datatransfer::clipboard::XClipboard
> const & rxClipboard
)
1280 vcl::unohelper::TextDataObject::CopyStringTo( GetSelected(), rxClipboard
);
1283 void Edit::ImplPaste( uno::Reference
< datatransfer::clipboard::XClipboard
> const & rxClipboard
)
1285 if ( !rxClipboard
.is() )
1288 uno::Reference
< datatransfer::XTransferable
> xDataObj
;
1292 SolarMutexReleaser aReleaser
;
1293 xDataObj
= rxClipboard
->getContents();
1295 catch( const css::uno::Exception
& )
1299 if ( !xDataObj
.is() )
1302 datatransfer::DataFlavor aFlavor
;
1303 SotExchange::GetFormatDataFlavor( SotClipboardFormatId::STRING
, aFlavor
);
1306 uno::Any aData
= xDataObj
->getTransferData( aFlavor
);
1310 // tdf#127588 - extend selection to the entire field or paste the text
1311 // from the clipboard to the current position if there is no selection
1312 if (mnMaxTextLen
< EDIT_NOLIMIT
&& maSelection
.Len() == 0)
1314 const sal_Int32 aTextLen
= aText
.getLength();
1315 if (aTextLen
== mnMaxTextLen
)
1317 maSelection
.Min() = 0;
1318 maSelection
.Max() = mnMaxTextLen
;
1320 maSelection
.Max() = std::min
<sal_Int32
>(maSelection
.Min() + aTextLen
, mnMaxTextLen
);
1323 Selection
aSelection(maSelection
);
1324 aSelection
.Normalize();
1325 if (ImplTruncateToMaxLen(aText
, aSelection
.Len()))
1326 ShowTruncationWarning(GetFrameWeld());
1328 ReplaceSelected( aText
);
1330 catch( const css::uno::Exception
& )
1335 void Edit::MouseButtonDown( const MouseEvent
& rMEvt
)
1339 Control::MouseButtonDown( rMEvt
);
1343 sal_Int32 nCharPos
= ImplGetCharPos( rMEvt
.GetPosPixel() );
1344 Selection
aSelection( maSelection
);
1345 aSelection
.Normalize();
1347 if ( rMEvt
.GetClicks() < 4 )
1349 mbClickedInSelection
= false;
1350 if ( rMEvt
.GetClicks() == 3 )
1352 ImplSetSelection( Selection( 0, EDIT_NOLIMIT
) );
1353 ImplCopyToSelectionClipboard();
1356 else if ( rMEvt
.GetClicks() == 2 )
1358 uno::Reference
< i18n::XBreakIterator
> xBI
= ImplGetBreakIterator();
1359 i18n::Boundary aBoundary
= xBI
->getWordBoundary( maText
.toString(), aSelection
.Max(),
1360 GetSettings().GetLanguageTag().getLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES
, true );
1361 ImplSetSelection( Selection( aBoundary
.startPos
, aBoundary
.endPos
) );
1362 ImplCopyToSelectionClipboard();
1364 else if ( !rMEvt
.IsShift() && HasFocus() && aSelection
.Contains( nCharPos
) )
1365 mbClickedInSelection
= true;
1366 else if ( rMEvt
.IsLeft() )
1367 ImplSetCursorPos( nCharPos
, rMEvt
.IsShift() );
1369 if ( !mbClickedInSelection
&& rMEvt
.IsLeft() && ( rMEvt
.GetClicks() == 1 ) )
1370 StartTracking( StartTrackingFlags::ScrollRepeat
);
1376 void Edit::MouseButtonUp( const MouseEvent
& rMEvt
)
1378 if ( mbClickedInSelection
&& rMEvt
.IsLeft() )
1380 sal_Int32 nCharPos
= ImplGetCharPos( rMEvt
.GetPosPixel() );
1381 ImplSetCursorPos( nCharPos
, false );
1382 mbClickedInSelection
= false;
1384 else if ( rMEvt
.IsMiddle() && !mbReadOnly
&&
1385 ( GetSettings().GetMouseSettings().GetMiddleButtonAction() == MouseMiddleButtonAction::PasteSelection
) )
1387 css::uno::Reference
<css::datatransfer::clipboard::XClipboard
> aSelection(GetSystemPrimarySelection());
1388 ImplPaste( aSelection
);
1393 void Edit::Tracking( const TrackingEvent
& rTEvt
)
1395 if ( rTEvt
.IsTrackingEnded() )
1397 if ( mbClickedInSelection
)
1399 sal_Int32 nCharPos
= ImplGetCharPos( rTEvt
.GetMouseEvent().GetPosPixel() );
1400 ImplSetCursorPos( nCharPos
, false );
1401 mbClickedInSelection
= false;
1403 else if ( rTEvt
.GetMouseEvent().IsLeft() )
1405 ImplCopyToSelectionClipboard();
1410 if( !mbClickedInSelection
)
1412 sal_Int32 nCharPos
= ImplGetCharPos( rTEvt
.GetMouseEvent().GetPosPixel() );
1413 ImplSetCursorPos( nCharPos
, true );
1418 bool Edit::ImplHandleKeyEvent( const KeyEvent
& rKEvt
)
1421 sal_uInt16 nCode
= rKEvt
.GetKeyCode().GetCode();
1422 KeyFuncType eFunc
= rKEvt
.GetKeyCode().GetFunction();
1424 mbInternModified
= false;
1426 if ( eFunc
!= KeyFuncType::DONTKNOW
)
1430 case KeyFuncType::CUT
:
1432 if ( !mbReadOnly
&& maSelection
.Len() && !mbPassword
)
1441 case KeyFuncType::COPY
:
1451 case KeyFuncType::PASTE
:
1461 case KeyFuncType::UNDO
:
1472 eFunc
= KeyFuncType::DONTKNOW
;
1476 if ( !bDone
&& rKEvt
.GetKeyCode().IsMod1() && !rKEvt
.GetKeyCode().IsMod2() )
1478 if ( nCode
== KEY_A
)
1480 ImplSetSelection( Selection( 0, maText
.getLength() ) );
1483 else if ( rKEvt
.GetKeyCode().IsShift() && (nCode
== KEY_S
) )
1485 if ( pImplFncGetSpecialChars
)
1487 Selection aSaveSel
= GetSelection(); // if someone changes the selection in Get/LoseFocus, e.g. URL bar
1488 OUString aChars
= pImplFncGetSpecialChars( GetFrameWeld(), GetFont() );
1489 SetSelection( aSaveSel
);
1490 if ( !aChars
.isEmpty() )
1492 ImplInsertText( aChars
);
1500 if ( eFunc
== KeyFuncType::DONTKNOW
&& ! bDone
)
1504 case css::awt::Key::SELECT_ALL
:
1506 ImplSetSelection( Selection( 0, maText
.getLength() ) );
1515 case css::awt::Key::MOVE_WORD_FORWARD
:
1516 case css::awt::Key::SELECT_WORD_FORWARD
:
1517 case css::awt::Key::MOVE_WORD_BACKWARD
:
1518 case css::awt::Key::SELECT_WORD_BACKWARD
:
1519 case css::awt::Key::MOVE_TO_BEGIN_OF_LINE
:
1520 case css::awt::Key::MOVE_TO_END_OF_LINE
:
1521 case css::awt::Key::SELECT_TO_BEGIN_OF_LINE
:
1522 case css::awt::Key::SELECT_TO_END_OF_LINE
:
1523 case css::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH
:
1524 case css::awt::Key::MOVE_TO_END_OF_PARAGRAPH
:
1525 case css::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH
:
1526 case css::awt::Key::SELECT_TO_END_OF_PARAGRAPH
:
1527 case css::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT
:
1528 case css::awt::Key::MOVE_TO_END_OF_DOCUMENT
:
1529 case css::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT
:
1530 case css::awt::Key::SELECT_TO_END_OF_DOCUMENT
:
1532 if ( !rKEvt
.GetKeyCode().IsMod2() )
1534 ImplClearLayoutData();
1535 uno::Reference
< i18n::XBreakIterator
> xBI
= ImplGetBreakIterator();
1537 Selection
aSel( maSelection
);
1538 bool bWord
= rKEvt
.GetKeyCode().IsMod1();
1539 bool bSelect
= rKEvt
.GetKeyCode().IsShift();
1540 bool bGoLeft
= (nCode
== KEY_LEFT
);
1541 bool bGoRight
= (nCode
== KEY_RIGHT
);
1542 bool bGoHome
= (nCode
== KEY_HOME
);
1543 bool bGoEnd
= (nCode
== KEY_END
);
1547 case css::awt::Key::MOVE_WORD_FORWARD
:
1548 bGoRight
= bWord
= true;break;
1549 case css::awt::Key::SELECT_WORD_FORWARD
:
1550 bGoRight
= bSelect
= bWord
= true;break;
1551 case css::awt::Key::MOVE_WORD_BACKWARD
:
1552 bGoLeft
= bWord
= true;break;
1553 case css::awt::Key::SELECT_WORD_BACKWARD
:
1554 bGoLeft
= bSelect
= bWord
= true;break;
1555 case css::awt::Key::SELECT_TO_BEGIN_OF_LINE
:
1556 case css::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH
:
1557 case css::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT
:
1560 case css::awt::Key::MOVE_TO_BEGIN_OF_LINE
:
1561 case css::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH
:
1562 case css::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT
:
1563 bGoHome
= true;break;
1564 case css::awt::Key::SELECT_TO_END_OF_LINE
:
1565 case css::awt::Key::SELECT_TO_END_OF_PARAGRAPH
:
1566 case css::awt::Key::SELECT_TO_END_OF_DOCUMENT
:
1569 case css::awt::Key::MOVE_TO_END_OF_LINE
:
1570 case css::awt::Key::MOVE_TO_END_OF_PARAGRAPH
:
1571 case css::awt::Key::MOVE_TO_END_OF_DOCUMENT
:
1572 bGoEnd
= true;break;
1577 // range is checked in ImplSetSelection ...
1578 if ( bGoLeft
&& aSel
.Max() )
1582 const OUString sText
= maText
.toString();
1583 i18n::Boundary aBoundary
= xBI
->getWordBoundary( sText
, aSel
.Max(),
1584 GetSettings().GetLanguageTag().getLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES
, true );
1585 if ( aBoundary
.startPos
== aSel
.Max() )
1586 aBoundary
= xBI
->previousWord( sText
, aSel
.Max(),
1587 GetSettings().GetLanguageTag().getLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES
);
1588 aSel
.Max() = aBoundary
.startPos
;
1592 sal_Int32 nCount
= 1;
1593 aSel
.Max() = xBI
->previousCharacters( maText
.toString(), aSel
.Max(),
1594 GetSettings().GetLanguageTag().getLocale(), i18n::CharacterIteratorMode::SKIPCHARACTER
, nCount
, nCount
);
1597 else if ( bGoRight
&& ( aSel
.Max() < maText
.getLength() ) )
1601 i18n::Boundary aBoundary
= xBI
->nextWord( maText
.toString(), aSel
.Max(),
1602 GetSettings().GetLanguageTag().getLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES
);
1603 aSel
.Max() = aBoundary
.startPos
;
1607 sal_Int32 nCount
= 1;
1608 aSel
.Max() = xBI
->nextCharacters( maText
.toString(), aSel
.Max(),
1609 GetSettings().GetLanguageTag().getLocale(), i18n::CharacterIteratorMode::SKIPCHARACTER
, nCount
, nCount
);
1618 aSel
.Max() = EDIT_NOLIMIT
;
1622 aSel
.Min() = aSel
.Max();
1624 if ( aSel
!= GetSelection() )
1626 ImplSetSelection( aSel
);
1627 ImplCopyToSelectionClipboard();
1630 if (bGoEnd
&& maAutocompleteHdl
.IsSet() && !rKEvt
.GetKeyCode().GetModifier())
1632 if ( (maSelection
.Min() == maSelection
.Max()) && (maSelection
.Min() == maText
.getLength()) )
1634 maAutocompleteHdl
.Call(*this);
1643 case css::awt::Key::DELETE_WORD_BACKWARD
:
1644 case css::awt::Key::DELETE_WORD_FORWARD
:
1645 case css::awt::Key::DELETE_TO_BEGIN_OF_LINE
:
1646 case css::awt::Key::DELETE_TO_END_OF_LINE
:
1650 if ( !mbReadOnly
&& !rKEvt
.GetKeyCode().IsMod2() )
1652 sal_uInt8 nDel
= (nCode
== KEY_DELETE
) ? EDIT_DEL_RIGHT
: EDIT_DEL_LEFT
;
1653 sal_uInt8 nMode
= rKEvt
.GetKeyCode().IsMod1() ? EDIT_DELMODE_RESTOFWORD
: EDIT_DELMODE_SIMPLE
;
1654 if ( (nMode
== EDIT_DELMODE_RESTOFWORD
) && rKEvt
.GetKeyCode().IsShift() )
1655 nMode
= EDIT_DELMODE_RESTOFCONTENT
;
1658 case css::awt::Key::DELETE_WORD_BACKWARD
:
1659 nDel
= EDIT_DEL_LEFT
;
1660 nMode
= EDIT_DELMODE_RESTOFWORD
;
1662 case css::awt::Key::DELETE_WORD_FORWARD
:
1663 nDel
= EDIT_DEL_RIGHT
;
1664 nMode
= EDIT_DELMODE_RESTOFWORD
;
1666 case css::awt::Key::DELETE_TO_BEGIN_OF_LINE
:
1667 nDel
= EDIT_DEL_LEFT
;
1668 nMode
= EDIT_DELMODE_RESTOFCONTENT
;
1670 case css::awt::Key::DELETE_TO_END_OF_LINE
:
1671 nDel
= EDIT_DEL_RIGHT
;
1672 nMode
= EDIT_DELMODE_RESTOFCONTENT
;
1676 sal_Int32 nOldLen
= maText
.getLength();
1677 ImplDelete( maSelection
, nDel
, nMode
);
1678 if ( maText
.getLength() != nOldLen
)
1687 if ( !mpIMEInfos
&& !mbReadOnly
&& !rKEvt
.GetKeyCode().IsMod2() )
1689 SetInsertMode( !mbInsertMode
);
1696 if (maActivateHdl
.IsSet() && !rKEvt
.GetKeyCode().GetModifier())
1697 bDone
= maActivateHdl
.Call(*this);
1702 if ( IsCharInput( rKEvt
) )
1704 bDone
= true; // read characters also when in ReadOnly
1707 ImplInsertText(OUString(rKEvt
.GetCharCode()), nullptr, true);
1708 if (maAutocompleteHdl
.IsSet())
1710 if ( (maSelection
.Min() == maSelection
.Max()) && (maSelection
.Min() == maText
.getLength()) )
1712 maAutocompleteHdl
.Call(*this);
1721 if ( mbInternModified
)
1727 void Edit::KeyInput( const KeyEvent
& rKEvt
)
1729 if ( mpSubEdit
|| !ImplHandleKeyEvent( rKEvt
) )
1730 Control::KeyInput( rKEvt
);
1733 void Edit::FillLayoutData() const
1735 mxLayoutData
.emplace();
1736 const_cast<Edit
*>(this)->Invalidate();
1739 void Edit::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRectangle
)
1742 ImplRepaint(rRenderContext
, rRectangle
);
1747 if ( !mpSubEdit
&& IsReallyVisible() )
1750 // because of vertical centering...
1758 void Edit::Draw( OutputDevice
* pDev
, const Point
& rPos
, SystemTextColorFlags nFlags
)
1760 ApplySettings(*pDev
);
1762 Point aPos
= pDev
->LogicToPixel( rPos
);
1763 Size aSize
= GetSizePixel();
1764 vcl::Font aFont
= GetDrawPixelFont( pDev
);
1768 pDev
->SetFont( aFont
);
1769 pDev
->SetTextFillColor();
1771 // Border/Background
1772 pDev
->SetLineColor();
1773 pDev
->SetFillColor();
1774 bool bBorder
= (GetStyle() & WB_BORDER
);
1775 bool bBackground
= IsControlBackground();
1776 if ( bBorder
|| bBackground
)
1778 tools::Rectangle
aRect( aPos
, aSize
);
1781 ImplDrawFrame( pDev
, aRect
);
1785 pDev
->SetFillColor( GetControlBackground() );
1786 pDev
->DrawRect( aRect
);
1791 if ( nFlags
& SystemTextColorFlags::Mono
)
1792 pDev
->SetTextColor( COL_BLACK
);
1797 const StyleSettings
& rStyleSettings
= GetSettings().GetStyleSettings();
1798 pDev
->SetTextColor( rStyleSettings
.GetDisableColor() );
1802 pDev
->SetTextColor( GetTextColor() );
1806 const tools::Long nOnePixel
= GetDrawPixel( pDev
, 1 );
1807 const tools::Long nOffX
= 3*nOnePixel
;
1808 DrawTextFlags nTextStyle
= DrawTextFlags::VCenter
;
1809 tools::Rectangle
aTextRect( aPos
, aSize
);
1811 if ( GetStyle() & WB_CENTER
)
1812 nTextStyle
|= DrawTextFlags::Center
;
1813 else if ( GetStyle() & WB_RIGHT
)
1814 nTextStyle
|= DrawTextFlags::Right
;
1816 nTextStyle
|= DrawTextFlags::Left
;
1818 aTextRect
.AdjustLeft(nOffX
);
1819 aTextRect
.AdjustRight( -nOffX
);
1821 OUString aText
= ImplGetText();
1822 tools::Long nTextHeight
= pDev
->GetTextHeight();
1823 tools::Long nTextWidth
= pDev
->GetTextWidth( aText
);
1824 tools::Long nOffY
= (aSize
.Height() - nTextHeight
) / 2;
1828 ((nOffY
+nTextHeight
) > aSize
.Height()) ||
1829 ((nOffX
+nTextWidth
) > aSize
.Width()) )
1831 tools::Rectangle
aClip( aPos
, aSize
);
1832 if ( nTextHeight
> aSize
.Height() )
1833 aClip
.AdjustBottom(nTextHeight
-aSize
.Height()+1 ); // prevent HP printers from 'optimizing'
1834 pDev
->IntersectClipRegion( aClip
);
1837 pDev
->DrawText( aTextRect
, aText
, nTextStyle
);
1842 Size
aOrigSize(GetSubEdit()->GetSizePixel());
1843 GetSubEdit()->SetSizePixel(GetSizePixel());
1844 GetSubEdit()->Draw(pDev
, rPos
, nFlags
);
1845 GetSubEdit()->SetSizePixel(aOrigSize
);
1849 void Edit::ImplInvalidateOutermostBorder( vcl::Window
* pWin
)
1851 // allow control to show focused state
1852 vcl::Window
*pInvalWin
= pWin
;
1855 vcl::Window
* pBorder
= pInvalWin
->GetWindow( GetWindowType::Border
);
1856 if (pBorder
== pInvalWin
|| !pBorder
||
1857 pInvalWin
->ImplGetFrame() != pBorder
->ImplGetFrame() )
1859 pInvalWin
= pBorder
;
1862 pInvalWin
->Invalidate( InvalidateFlags::Children
| InvalidateFlags::Update
);
1865 void Edit::GetFocus()
1868 mpSubEdit
->ImplGrabFocus( GetGetFocusFlags() );
1869 else if ( !mbActivePopup
)
1871 maUndoText
= maText
.toString();
1872 SelectionOptions nSelOptions
= GetSettings().GetStyleSettings().GetSelectionOptions();
1873 if ( !( GetStyle() & (WB_NOHIDESELECTION
|WB_READONLY
) )
1874 && ( GetGetFocusFlags() & (GetFocusFlags::Init
|GetFocusFlags::Tab
|GetFocusFlags::CURSOR
|GetFocusFlags::Mnemonic
) ) )
1876 if ( nSelOptions
& SelectionOptions::ShowFirst
)
1878 maSelection
.Min() = maText
.getLength();
1879 maSelection
.Max() = 0;
1883 maSelection
.Min() = 0;
1884 maSelection
.Max() = maText
.getLength();
1887 static_cast<Edit
*>(GetParent())->CallEventListeners( VclEventId::EditSelectionChanged
);
1889 CallEventListeners( VclEventId::EditSelectionChanged
);
1894 if (IsNativeWidgetEnabled() &&
1895 IsNativeControlSupported( ControlType::Editbox
, ControlPart::Entire
))
1897 ImplInvalidateOutermostBorder( mbIsSubEdit
? GetParent() : this );
1899 else if ( maSelection
.Len() )
1901 // paint the selection
1902 if ( !HasPaintEvent() )
1903 ImplInvalidateOrRepaint();
1908 SetInputContext( InputContext( GetFont(), !IsReadOnly() ? InputContextFlags::Text
|InputContextFlags::ExtText
: InputContextFlags::NONE
) );
1911 Control::GetFocus();
1914 void Edit::LoseFocus()
1918 if (IsNativeWidgetEnabled() &&
1919 IsNativeControlSupported(ControlType::Editbox
, ControlPart::Entire
))
1921 ImplInvalidateOutermostBorder( mbIsSubEdit
? GetParent() : this );
1924 if ( !mbActivePopup
&& !( GetStyle() & WB_NOHIDESELECTION
) && maSelection
.Len() )
1925 ImplInvalidateOrRepaint(); // paint the selection
1928 Control::LoseFocus();
1931 bool Edit::PreNotify(NotifyEvent
& rNEvt
)
1933 if (rNEvt
.GetType() == NotifyEventType::MOUSEMOVE
)
1935 const MouseEvent
* pMouseEvt
= rNEvt
.GetMouseEvent();
1936 if (pMouseEvt
&& !pMouseEvt
->GetButtons() && !pMouseEvt
->IsSynthetic() && !pMouseEvt
->IsModifierChanged())
1938 // trigger redraw if mouse over state has changed
1939 if (pMouseEvt
->IsLeaveWindow() || pMouseEvt
->IsEnterWindow())
1941 if (IsNativeWidgetEnabled() &&
1942 IsNativeControlSupported(ControlType::Editbox
, ControlPart::Entire
))
1944 ImplInvalidateOutermostBorder(this);
1950 return Control::PreNotify(rNEvt
);
1953 void Edit::Command( const CommandEvent
& rCEvt
)
1955 if ( rCEvt
.GetCommand() == CommandEventId::ContextMenu
)
1957 VclPtr
<PopupMenu
> pPopup
= Edit::CreatePopupMenu();
1959 bool bEnableCut
= true;
1960 bool bEnableCopy
= true;
1961 bool bEnableDelete
= true;
1962 bool bEnablePaste
= true;
1963 bool bEnableSpecialChar
= true;
1965 if ( !maSelection
.Len() )
1968 bEnableCopy
= false;
1969 bEnableDelete
= false;
1975 bEnablePaste
= false;
1976 bEnableDelete
= false;
1977 bEnableSpecialChar
= false;
1981 // only paste if text available in clipboard
1983 uno::Reference
< datatransfer::clipboard::XClipboard
> xClipboard
= GetClipboard();
1985 if ( xClipboard
.is() )
1987 uno::Reference
< datatransfer::XTransferable
> xDataObj
;
1989 SolarMutexReleaser aReleaser
;
1990 xDataObj
= xClipboard
->getContents();
1992 if ( xDataObj
.is() )
1994 datatransfer::DataFlavor aFlavor
;
1995 SotExchange::GetFormatDataFlavor( SotClipboardFormatId::STRING
, aFlavor
);
1996 bData
= xDataObj
->isDataFlavorSupported( aFlavor
);
1999 bEnablePaste
= bData
;
2002 pPopup
->EnableItem(pPopup
->GetItemId(u
"cut"), bEnableCut
);
2003 pPopup
->EnableItem(pPopup
->GetItemId(u
"copy"), bEnableCopy
);
2004 pPopup
->EnableItem(pPopup
->GetItemId(u
"delete"), bEnableDelete
);
2005 pPopup
->EnableItem(pPopup
->GetItemId(u
"paste"), bEnablePaste
);
2006 pPopup
->EnableItem(pPopup
->GetItemId(u
"specialchar"), bEnableSpecialChar
);
2008 pPopup
->GetItemId(u
"undo"),
2009 std::u16string_view(maUndoText
) != std::u16string_view(maText
));
2010 bool bAllSelected
= maSelection
.Min() == 0 && maSelection
.Max() == maText
.getLength();
2011 pPopup
->EnableItem(pPopup
->GetItemId(u
"selectall"), !bAllSelected
);
2012 pPopup
->ShowItem(pPopup
->GetItemId(u
"specialchar"), pImplFncGetSpecialChars
!= nullptr);
2014 mbActivePopup
= true;
2015 Selection aSaveSel
= GetSelection(); // if someone changes selection in Get/LoseFocus, e.g. URL bar
2016 Point aPos
= rCEvt
.GetMousePosPixel();
2017 if ( !rCEvt
.IsMouseEvent() )
2019 // Show menu eventually centered in selection
2020 Size aSize
= GetOutputSizePixel();
2021 aPos
= Point( aSize
.Width()/2, aSize
.Height()/2 );
2023 sal_uInt16 n
= pPopup
->Execute( this, aPos
);
2024 SetSelection( aSaveSel
);
2025 OUString sCommand
= pPopup
->GetItemIdent(n
);
2026 if (sCommand
== "undo")
2031 else if (sCommand
== "cut")
2036 else if (sCommand
== "copy")
2040 else if (sCommand
== "paste")
2045 else if (sCommand
== "delete")
2050 else if (sCommand
== "selectall")
2052 ImplSetSelection( Selection( 0, maText
.getLength() ) );
2054 else if (sCommand
== "specialchar" && pImplFncGetSpecialChars
)
2056 OUString aChars
= pImplFncGetSpecialChars(GetFrameWeld(), GetFont());
2057 if (!isDisposed()) // destroyed while the insert special character dialog was still open
2059 SetSelection( aSaveSel
);
2060 if (!aChars
.isEmpty())
2062 ImplInsertText( aChars
);
2068 mbActivePopup
= false;
2070 else if ( rCEvt
.GetCommand() == CommandEventId::StartExtTextInput
)
2073 sal_Int32 nPos
= maSelection
.Max();
2074 mpIMEInfos
.reset(new Impl_IMEInfos( nPos
, maText
.copy(nPos
).makeStringAndClear() ));
2075 mpIMEInfos
->bWasCursorOverwrite
= !IsInsertMode();
2077 else if ( rCEvt
.GetCommand() == CommandEventId::EndExtTextInput
)
2079 bool bInsertMode
= !mpIMEInfos
->bWasCursorOverwrite
;
2082 SetInsertMode(bInsertMode
);
2087 // #i25161# call auto complete handler for ext text commit also
2088 if (maAutocompleteHdl
.IsSet())
2090 if ( (maSelection
.Min() == maSelection
.Max()) && (maSelection
.Min() == maText
.getLength()) )
2092 maAutocompleteHdl
.Call(*this);
2096 else if ( rCEvt
.GetCommand() == CommandEventId::ExtTextInput
)
2098 const CommandExtTextInputData
* pData
= rCEvt
.GetExtTextInputData();
2100 maText
.remove( mpIMEInfos
->nPos
, mpIMEInfos
->nLen
);
2101 maText
.insert( mpIMEInfos
->nPos
, pData
->GetText() );
2102 if ( mpIMEInfos
->bWasCursorOverwrite
)
2104 const sal_Int32 nOldIMETextLen
= mpIMEInfos
->nLen
;
2105 const sal_Int32 nNewIMETextLen
= pData
->GetText().getLength();
2106 if ( ( nOldIMETextLen
> nNewIMETextLen
) &&
2107 ( nNewIMETextLen
< mpIMEInfos
->aOldTextAfterStartPos
.getLength() ) )
2109 // restore old characters
2110 const sal_Int32 nRestore
= nOldIMETextLen
- nNewIMETextLen
;
2111 maText
.insert( mpIMEInfos
->nPos
+ nNewIMETextLen
, mpIMEInfos
->aOldTextAfterStartPos
.subView( nNewIMETextLen
, nRestore
) );
2113 else if ( ( nOldIMETextLen
< nNewIMETextLen
) &&
2114 ( nOldIMETextLen
< mpIMEInfos
->aOldTextAfterStartPos
.getLength() ) )
2116 const sal_Int32 nOverwrite
= ( nNewIMETextLen
> mpIMEInfos
->aOldTextAfterStartPos
.getLength()
2117 ? mpIMEInfos
->aOldTextAfterStartPos
.getLength() : nNewIMETextLen
) - nOldIMETextLen
;
2118 maText
.remove( mpIMEInfos
->nPos
+ nNewIMETextLen
, nOverwrite
);
2122 if ( pData
->GetTextAttr() )
2124 mpIMEInfos
->CopyAttribs( pData
->GetTextAttr(), pData
->GetText().getLength() );
2125 mpIMEInfos
->bCursor
= pData
->IsCursorVisible();
2129 mpIMEInfos
->DestroyAttribs();
2132 ImplAlignAndPaint();
2133 sal_Int32 nCursorPos
= mpIMEInfos
->nPos
+ pData
->GetCursorPos();
2134 SetSelection( Selection( nCursorPos
, nCursorPos
) );
2135 SetInsertMode( !pData
->IsCursorOverwrite() );
2137 if ( pData
->IsCursorVisible() )
2138 GetCursor()->Show();
2140 GetCursor()->Hide();
2142 else if ( rCEvt
.GetCommand() == CommandEventId::CursorPos
)
2146 sal_Int32 nCursorPos
= GetSelection().Max();
2147 SetCursorRect( nullptr, GetTextWidth( maText
.toString(), nCursorPos
, mpIMEInfos
->nPos
+mpIMEInfos
->nLen
-nCursorPos
) );
2154 else if ( rCEvt
.GetCommand() == CommandEventId::SelectionChange
)
2156 const CommandSelectionChangeData
*pData
= rCEvt
.GetSelectionChangeData();
2157 Selection
aSelection( pData
->GetStart(), pData
->GetEnd() );
2158 SetSelection(aSelection
);
2160 else if ( rCEvt
.GetCommand() == CommandEventId::QueryCharPosition
)
2162 if (mpIMEInfos
&& mpIMEInfos
->nLen
> 0)
2164 OUString aText
= ImplGetText();
2165 std::vector
<sal_Int32
> aDX(2*(aText
.getLength()+1));
2167 GetOutDev()->GetCaretPositions( aText
, aDX
.data(), 0, aText
.getLength() );
2169 tools::Long nTH
= GetTextHeight();
2170 Point
aPos( mnXOffset
, ImplGetTextYPosition() );
2172 std::vector
<tools::Rectangle
> aRects(mpIMEInfos
->nLen
);
2173 for ( int nIndex
= 0; nIndex
< mpIMEInfos
->nLen
; ++nIndex
)
2175 tools::Rectangle
aRect( aPos
, Size( 10, nTH
) );
2176 aRect
.SetLeft( aDX
[2*(nIndex
+mpIMEInfos
->nPos
)] + mnXOffset
+ ImplGetExtraXOffset() );
2177 aRects
[ nIndex
] = aRect
;
2179 SetCompositionCharRect(aRects
.data(), mpIMEInfos
->nLen
);
2183 Control::Command( rCEvt
);
2186 void Edit::StateChanged( StateChangedType nType
)
2188 if (nType
== StateChangedType::InitShow
)
2192 mnXOffset
= 0; // if GrabFocus before while size was still wrong
2195 ImplShowCursor(false);
2199 else if (nType
== StateChangedType::Enable
)
2203 // change text color only
2204 ImplInvalidateOrRepaint();
2207 else if (nType
== StateChangedType::Style
|| nType
== StateChangedType::Mirroring
)
2209 WinBits nStyle
= GetStyle();
2210 if (nType
== StateChangedType::Style
)
2212 nStyle
= ImplInitStyle(GetStyle());
2216 sal_uInt16 nOldAlign
= mnAlign
;
2217 mnAlign
= EDIT_ALIGN_LEFT
;
2219 // hack: right align until keyinput and cursor travelling works
2220 // edits are always RTL disabled
2221 // however the parent edits contain the correct setting
2222 if (mbIsSubEdit
&& GetParent()->IsRTLEnabled())
2224 if (GetParent()->GetStyle() & WB_LEFT
)
2225 mnAlign
= EDIT_ALIGN_RIGHT
;
2226 if (nType
== StateChangedType::Mirroring
)
2227 GetOutDev()->SetLayoutMode(vcl::text::ComplexTextLayoutFlags::BiDiRtl
| vcl::text::ComplexTextLayoutFlags::TextOriginLeft
);
2229 else if (mbIsSubEdit
&& !GetParent()->IsRTLEnabled())
2231 if (nType
== StateChangedType::Mirroring
)
2232 GetOutDev()->SetLayoutMode(vcl::text::ComplexTextLayoutFlags::TextOriginLeft
);
2235 if (nStyle
& WB_RIGHT
)
2236 mnAlign
= EDIT_ALIGN_RIGHT
;
2237 else if (nStyle
& WB_CENTER
)
2238 mnAlign
= EDIT_ALIGN_CENTER
;
2239 if (!maText
.isEmpty() && (mnAlign
!= nOldAlign
))
2246 else if ((nType
== StateChangedType::Zoom
) || (nType
== StateChangedType::ControlFont
))
2250 ApplySettings(*GetOutDev());
2255 else if ((nType
== StateChangedType::ControlForeground
) || (nType
== StateChangedType::ControlBackground
))
2259 ApplySettings(*GetOutDev());
2264 Control::StateChanged(nType
);
2267 void Edit::DataChanged( const DataChangedEvent
& rDCEvt
)
2269 if ( (rDCEvt
.GetType() == DataChangedEventType::FONTS
) ||
2270 (rDCEvt
.GetType() == DataChangedEventType::FONTSUBSTITUTION
) ||
2271 ((rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
2272 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
)) )
2276 ApplySettings(*GetOutDev());
2282 Control::DataChanged( rDCEvt
);
2285 void Edit::ImplShowDDCursor()
2287 if (!mpDDInfo
->bVisCursor
)
2289 tools::Long nTextWidth
= GetTextWidth( maText
.toString(), 0, mpDDInfo
->nDropPos
);
2290 tools::Long nTextHeight
= GetTextHeight();
2291 tools::Rectangle
aCursorRect( Point( nTextWidth
+ mnXOffset
, (GetOutDev()->GetOutputSize().Height()-nTextHeight
)/2 ), Size( 2, nTextHeight
) );
2292 mpDDInfo
->aCursor
.SetWindow( this );
2293 mpDDInfo
->aCursor
.SetPos( aCursorRect
.TopLeft() );
2294 mpDDInfo
->aCursor
.SetSize( aCursorRect
.GetSize() );
2295 mpDDInfo
->aCursor
.Show();
2296 mpDDInfo
->bVisCursor
= true;
2300 void Edit::ImplHideDDCursor()
2302 if ( mpDDInfo
&& mpDDInfo
->bVisCursor
)
2304 mpDDInfo
->aCursor
.Hide();
2305 mpDDInfo
->bVisCursor
= false;
2309 TextFilter::TextFilter(OUString _aForbiddenChars
)
2310 : sForbiddenChars(std::move(_aForbiddenChars
))
2314 TextFilter::~TextFilter()
2318 OUString
TextFilter::filter(const OUString
&rText
)
2320 OUString
sTemp(rText
);
2321 for (sal_Int32 i
= 0; i
< sForbiddenChars
.getLength(); ++i
)
2323 sTemp
= sTemp
.replaceAll(OUStringChar(sForbiddenChars
[i
]), "");
2328 void Edit::filterText()
2330 Selection aSel
= GetSelection();
2331 const OUString sOrig
= GetText();
2332 const OUString sNew
= mpFilterText
->filter(GetText());
2335 sal_Int32 nDiff
= sOrig
.getLength() - sNew
.getLength();
2338 aSel
.setMin(aSel
.getMin() - nDiff
);
2339 aSel
.setMax(aSel
.getMin());
2353 static_cast<Edit
*>(GetParent())->Modify();
2357 if ( ImplCallEventListenersAndHandler( VclEventId::EditModify
, [this] () { maModifyHdl
.Call(*this); } ) )
2358 // have been destroyed while calling into the handlers
2361 // #i13677# notify edit listeners about caret position change
2362 CallEventListeners( VclEventId::EditCaretChanged
);
2363 // FIXME: this is currently only on macOS
2364 // check for other platforms that need similar handling
2365 if( ImplGetSVData()->maNWFData
.mbNoFocusRects
&&
2366 IsNativeWidgetEnabled() &&
2367 IsNativeControlSupported( ControlType::Editbox
, ControlPart::Entire
) )
2369 ImplInvalidateOutermostBorder( this );
2374 void Edit::SetEchoChar( sal_Unicode c
)
2378 mpSubEdit
->SetEchoChar( c
);
2381 void Edit::SetReadOnly( bool bReadOnly
)
2383 if ( mbReadOnly
!= bReadOnly
)
2385 mbReadOnly
= bReadOnly
;
2387 mpSubEdit
->SetReadOnly( bReadOnly
);
2389 CompatStateChanged( StateChangedType::ReadOnly
);
2393 void Edit::SetInsertMode( bool bInsert
)
2395 if ( bInsert
!= mbInsertMode
)
2397 mbInsertMode
= bInsert
;
2399 mpSubEdit
->SetInsertMode( bInsert
);
2405 bool Edit::IsInsertMode() const
2408 return mpSubEdit
->IsInsertMode();
2410 return mbInsertMode
;
2413 void Edit::SetMaxTextLen(sal_Int32 nMaxLen
)
2415 mnMaxTextLen
= nMaxLen
> 0 ? nMaxLen
: EDIT_NOLIMIT
;
2418 mpSubEdit
->SetMaxTextLen( mnMaxTextLen
);
2421 if ( maText
.getLength() > mnMaxTextLen
)
2422 ImplDelete( Selection( mnMaxTextLen
, maText
.getLength() ), EDIT_DEL_RIGHT
, EDIT_DELMODE_SIMPLE
);
2426 void Edit::SetSelection( const Selection
& rSelection
)
2428 // If the selection was changed from outside, e.g. by MouseButtonDown, don't call Tracking()
2429 // directly afterwards which would change the selection again
2432 else if ( mpSubEdit
&& mpSubEdit
->IsTracking() )
2433 mpSubEdit
->EndTracking();
2435 ImplSetSelection( rSelection
);
2438 void Edit::ImplSetSelection( const Selection
& rSelection
, bool bPaint
)
2441 mpSubEdit
->ImplSetSelection( rSelection
);
2444 if ( rSelection
!= maSelection
)
2446 Selection
aOld( maSelection
);
2447 Selection
aNew( rSelection
);
2449 if ( aNew
.Min() > maText
.getLength() )
2450 aNew
.Min() = maText
.getLength();
2451 if ( aNew
.Max() > maText
.getLength() )
2452 aNew
.Max() = maText
.getLength();
2453 if ( aNew
.Min() < 0 )
2455 if ( aNew
.Max() < 0 )
2458 if ( aNew
!= maSelection
)
2460 ImplClearLayoutData();
2461 Selection aTemp
= maSelection
;
2464 if ( bPaint
&& ( aOld
.Len() || aNew
.Len() || IsPaintTransparent() ) )
2465 ImplInvalidateOrRepaint();
2468 bool bCaret
= false, bSelection
= false;
2469 tools::Long nB
=aNew
.Max(), nA
=aNew
.Min(),oB
=aTemp
.Max(), oA
=aTemp
.Min();
2470 tools::Long nGap
= nB
-nA
, oGap
= oB
-oA
;
2473 if (nGap
!= 0 || oGap
!= 0)
2479 static_cast<Edit
*>(GetParent())->CallEventListeners( VclEventId::EditSelectionChanged
);
2481 CallEventListeners( VclEventId::EditSelectionChanged
);
2487 static_cast<Edit
*>(GetParent())->CallEventListeners( VclEventId::EditCaretChanged
);
2489 CallEventListeners( VclEventId::EditCaretChanged
);
2492 // #103511# notify combobox listeners of deselection
2493 if( !maSelection
&& GetParent() && GetParent()->GetType() == WindowType::COMBOBOX
)
2494 static_cast<Edit
*>(GetParent())->CallEventListeners( VclEventId::ComboboxDeselect
);
2500 const Selection
& Edit::GetSelection() const
2503 return mpSubEdit
->GetSelection();
2508 void Edit::ReplaceSelected( const OUString
& rStr
)
2511 mpSubEdit
->ReplaceSelected( rStr
);
2513 ImplInsertText( rStr
);
2516 void Edit::DeleteSelected()
2519 mpSubEdit
->DeleteSelected();
2522 if ( maSelection
.Len() )
2523 ImplDelete( maSelection
, EDIT_DEL_RIGHT
, EDIT_DELMODE_SIMPLE
);
2527 OUString
Edit::GetSelected() const
2530 return mpSubEdit
->GetSelected();
2533 Selection
aSelection( maSelection
);
2534 aSelection
.Normalize();
2535 return OUString( maText
.getStr() + aSelection
.Min(), aSelection
.Len() );
2544 ReplaceSelected( OUString() );
2552 css::uno::Reference
<css::datatransfer::clipboard::XClipboard
> aClipboard(GetClipboard());
2553 ImplCopy( aClipboard
);
2559 css::uno::Reference
<css::datatransfer::clipboard::XClipboard
> aClipboard(GetClipboard());
2560 ImplPaste( aClipboard
);
2569 const OUString
aText( maText
.toString() );
2570 ImplDelete( Selection( 0, aText
.getLength() ), EDIT_DEL_RIGHT
, EDIT_DELMODE_SIMPLE
);
2571 ImplInsertText( maUndoText
);
2572 ImplSetSelection( Selection( 0, maUndoText
.getLength() ) );
2577 void Edit::SetText( const OUString
& rStr
)
2580 mpSubEdit
->SetText( rStr
); // not directly ImplSetText if SetText overridden
2583 Selection
aNewSel( 0, 0 ); // prevent scrolling
2584 ImplSetText( rStr
, &aNewSel
);
2588 void Edit::SetText( const OUString
& rStr
, const Selection
& rSelection
)
2591 mpSubEdit
->SetText( rStr
, rSelection
);
2593 ImplSetText( rStr
, &rSelection
);
2596 OUString
Edit::GetText() const
2599 return mpSubEdit
->GetText();
2601 return maText
.toString();
2604 void Edit::SetCursorAtLast(){
2605 ImplSetCursorPos( GetText().getLength(), false );
2608 void Edit::SetPlaceholderText( const OUString
& rStr
)
2611 mpSubEdit
->SetPlaceholderText( rStr
);
2612 else if ( maPlaceholderText
!= rStr
)
2614 maPlaceholderText
= rStr
;
2615 if ( GetText().isEmpty() )
2620 void Edit::SetModifyFlag()
2624 void Edit::SetSubEdit(Edit
* pEdit
)
2626 mpSubEdit
.disposeAndClear();
2627 mpSubEdit
.set(pEdit
);
2631 SetPointer(PointerStyle::Arrow
); // Only SubEdit has the BEAM...
2632 mpSubEdit
->mbIsSubEdit
= true;
2634 mpSubEdit
->SetReadOnly(mbReadOnly
);
2635 mpSubEdit
->maAutocompleteHdl
= maAutocompleteHdl
;
2639 Size
Edit::CalcMinimumSizeForText(const OUString
&rString
) const
2641 ControlType eCtrlType
= ImplGetNativeControlType();
2644 if (mnWidthInChars
!= -1)
2646 //CalcSize calls CalcWindowSize, but we will call that also in this
2647 //function, so undo the first one with CalcOutputSize
2648 aSize
= CalcOutputSize(CalcSize(mnWidthInChars
));
2653 if (mnMaxWidthChars
!= -1 && mnMaxWidthChars
< rString
.getLength())
2654 aString
= rString
.copy(0, mnMaxWidthChars
);
2658 aSize
.setHeight( GetTextHeight() );
2659 aSize
.setWidth( GetTextWidth(aString
) );
2660 aSize
.AdjustWidth(ImplGetExtraXOffset() * 2 );
2662 // do not create edit fields in which one cannot enter anything
2663 // a default minimum width should exist for at least 3 characters
2665 //CalcSize calls CalcWindowSize, but we will call that also in this
2666 //function, so undo the first one with CalcOutputSize
2667 Size
aMinSize(CalcOutputSize(CalcSize(3)));
2668 if (aSize
.Width() < aMinSize
.Width())
2669 aSize
.setWidth( aMinSize
.Width() );
2672 aSize
.AdjustHeight(ImplGetExtraYOffset() * 2 );
2674 aSize
= CalcWindowSize( aSize
);
2676 // ask NWF what if it has an opinion, too
2677 ImplControlValue aControlValue
;
2678 tools::Rectangle
aRect( Point( 0, 0 ), aSize
);
2679 tools::Rectangle aContent
, aBound
;
2680 if (GetNativeControlRegion(eCtrlType
, ControlPart::Entire
, aRect
, ControlState::NONE
,
2681 aControlValue
, aBound
, aContent
))
2683 if (aBound
.GetHeight() > aSize
.Height())
2684 aSize
.setHeight( aBound
.GetHeight() );
2689 Size
Edit::CalcMinimumSize() const
2691 return CalcMinimumSizeForText(GetText());
2694 Size
Edit::GetOptimalSize() const
2696 return CalcMinimumSize();
2699 Size
Edit::CalcSize(sal_Int32 nChars
) const
2701 // width for N characters, independent from content.
2702 // works only correct for fixed fonts, average otherwise
2703 float fUnitWidth
= std::max(approximate_char_width(), approximate_digit_width());
2704 Size
aSz(fUnitWidth
* nChars
, GetTextHeight());
2705 aSz
.AdjustWidth(ImplGetExtraXOffset() * 2 );
2706 aSz
= CalcWindowSize( aSz
);
2710 sal_Int32
Edit::GetMaxVisChars() const
2712 const vcl::Window
* pW
= mpSubEdit
? mpSubEdit
: this;
2713 sal_Int32 nOutWidth
= pW
->GetOutputSizePixel().Width();
2714 float fUnitWidth
= std::max(approximate_char_width(), approximate_digit_width());
2715 return nOutWidth
/ fUnitWidth
;
2720 void SetGetSpecialCharsFunction( FncGetSpecialChars fn
)
2722 pImplFncGetSpecialChars
= fn
;
2725 FncGetSpecialChars
GetGetSpecialCharsFunction()
2727 return pImplFncGetSpecialChars
;
2731 VclPtr
<PopupMenu
> Edit::CreatePopupMenu()
2734 mpUIBuilder
.reset(new VclBuilder(nullptr, AllSettings::GetUIRootDir(), "vcl/ui/editmenu.ui", ""));
2735 VclPtr
<PopupMenu
> pPopup
= mpUIBuilder
->get_menu(u
"menu");
2736 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
2737 if (rStyleSettings
.GetHideDisabledMenuItems())
2738 pPopup
->SetMenuFlags( MenuFlags::HideDisabledEntries
);
2740 pPopup
->SetMenuFlags ( MenuFlags::AlwaysShowDisabledEntries
);
2741 if (rStyleSettings
.GetContextMenuShortcuts())
2743 pPopup
->SetAccelKey(pPopup
->GetItemId(u
"undo"), vcl::KeyCode( KeyFuncType::UNDO
));
2744 pPopup
->SetAccelKey(pPopup
->GetItemId(u
"cut"), vcl::KeyCode( KeyFuncType::CUT
));
2745 pPopup
->SetAccelKey(pPopup
->GetItemId(u
"copy"), vcl::KeyCode( KeyFuncType::COPY
));
2746 pPopup
->SetAccelKey(pPopup
->GetItemId(u
"paste"), vcl::KeyCode( KeyFuncType::PASTE
));
2747 pPopup
->SetAccelKey(pPopup
->GetItemId(u
"delete"), vcl::KeyCode( KeyFuncType::DELETE
));
2748 pPopup
->SetAccelKey(pPopup
->GetItemId(u
"selectall"), vcl::KeyCode( KEY_A
, false, true, false, false));
2749 pPopup
->SetAccelKey(pPopup
->GetItemId(u
"specialchar"), vcl::KeyCode( KEY_S
, true, true, false, false));
2754 // css::datatransfer::dnd::XDragGestureListener
2755 void Edit::dragGestureRecognized( const css::datatransfer::dnd::DragGestureEvent
& rDGE
)
2757 SolarMutexGuard aVclGuard
;
2759 if ( !(!IsTracking() && maSelection
.Len() &&
2760 !mbPassword
&& (!mpDDInfo
|| !mpDDInfo
->bStarterOfDD
)) ) // no repeated D&D
2763 Selection
aSel( maSelection
);
2766 // only if mouse in the selection...
2767 Point
aMousePos( rDGE
.DragOriginX
, rDGE
.DragOriginY
);
2768 sal_Int32 nCharPos
= ImplGetCharPos( aMousePos
);
2769 if ( (nCharPos
< aSel
.Min()) || (nCharPos
>= aSel
.Max()) )
2773 mpDDInfo
.reset(new DDInfo
);
2775 mpDDInfo
->bStarterOfDD
= true;
2776 mpDDInfo
->aDndStartSel
= aSel
;
2779 EndTracking(); // before D&D disable tracking
2781 rtl::Reference
<vcl::unohelper::TextDataObject
> pDataObj
= new vcl::unohelper::TextDataObject( GetSelected() );
2782 sal_Int8 nActions
= datatransfer::dnd::DNDConstants::ACTION_COPY
;
2783 if ( !IsReadOnly() )
2784 nActions
|= datatransfer::dnd::DNDConstants::ACTION_MOVE
;
2785 rDGE
.DragSource
->startDrag( rDGE
, nActions
, 0 /*cursor*/, 0 /*image*/, pDataObj
, mxDnDListener
);
2787 GetCursor()->Hide();
2790 // css::datatransfer::dnd::XDragSourceListener
2791 void Edit::dragDropEnd( const css::datatransfer::dnd::DragSourceDropEvent
& rDSDE
)
2793 SolarMutexGuard aVclGuard
;
2795 if (rDSDE
.DropSuccess
&& (rDSDE
.DropAction
& datatransfer::dnd::DNDConstants::ACTION_MOVE
) && mpDDInfo
)
2797 Selection
aSel( mpDDInfo
->aDndStartSel
);
2798 if ( mpDDInfo
->bDroppedInMe
)
2800 if ( aSel
.Max() > mpDDInfo
->nDropPos
)
2802 tools::Long nLen
= aSel
.Len();
2807 ImplDelete( aSel
, EDIT_DEL_RIGHT
, EDIT_DELMODE_SIMPLE
);
2815 // css::datatransfer::dnd::XDropTargetListener
2816 void Edit::drop( const css::datatransfer::dnd::DropTargetDropEvent
& rDTDE
)
2818 SolarMutexGuard aVclGuard
;
2820 bool bChanges
= false;
2821 if ( !mbReadOnly
&& mpDDInfo
)
2825 Selection
aSel( maSelection
);
2828 if ( aSel
.Len() && !mpDDInfo
->bStarterOfDD
)
2829 ImplDelete( aSel
, EDIT_DEL_RIGHT
, EDIT_DELMODE_SIMPLE
);
2831 mpDDInfo
->bDroppedInMe
= true;
2833 aSel
.Min() = mpDDInfo
->nDropPos
;
2834 aSel
.Max() = mpDDInfo
->nDropPos
;
2835 ImplSetSelection( aSel
);
2837 uno::Reference
< datatransfer::XTransferable
> xDataObj
= rDTDE
.Transferable
;
2838 if ( xDataObj
.is() )
2840 datatransfer::DataFlavor aFlavor
;
2841 SotExchange::GetFormatDataFlavor( SotClipboardFormatId::STRING
, aFlavor
);
2842 if ( xDataObj
->isDataFlavorSupported( aFlavor
) )
2844 uno::Any aData
= xDataObj
->getTransferData( aFlavor
);
2847 ImplInsertText( aText
);
2853 if ( !mpDDInfo
->bStarterOfDD
)
2859 rDTDE
.Context
->dropComplete( bChanges
);
2862 void Edit::dragEnter( const css::datatransfer::dnd::DropTargetDragEnterEvent
& rDTDE
)
2866 mpDDInfo
.reset(new DDInfo
);
2868 // search for string data type
2869 const Sequence
< css::datatransfer::DataFlavor
>& rFlavors( rDTDE
.SupportedDataFlavors
);
2870 mpDDInfo
->bIsStringSupported
= std::any_of(rFlavors
.begin(), rFlavors
.end(),
2871 [](const css::datatransfer::DataFlavor
& rFlavor
) {
2872 sal_Int32 nIndex
= 0;
2873 const std::u16string_view aMimetype
= o3tl::getToken(rFlavor
.MimeType
, 0, ';', nIndex
);
2874 return aMimetype
== u
"text/plain";
2878 void Edit::dragExit( const css::datatransfer::dnd::DropTargetEvent
& )
2880 SolarMutexGuard aVclGuard
;
2885 void Edit::dragOver( const css::datatransfer::dnd::DropTargetDragEvent
& rDTDE
)
2887 SolarMutexGuard aVclGuard
;
2889 Point
aMousePos( rDTDE
.LocationX
, rDTDE
.LocationY
);
2891 sal_Int32 nPrevDropPos
= mpDDInfo
->nDropPos
;
2892 mpDDInfo
->nDropPos
= ImplGetCharPos( aMousePos
);
2895 Size aOutSize = GetOutputSizePixel();
2896 if ( ( aMousePos.X() < 0 ) || ( aMousePos.X() > aOutSize.Width() ) )
2899 // No, I will not receive events in this case...
2903 Selection
aSel( maSelection
);
2906 // Don't accept drop in selection or read-only field...
2907 if ( IsReadOnly() || aSel
.Contains( mpDDInfo
->nDropPos
) || ! mpDDInfo
->bIsStringSupported
)
2910 rDTDE
.Context
->rejectDrag();
2914 // draw the old cursor away...
2915 if ( !mpDDInfo
->bVisCursor
|| ( nPrevDropPos
!= mpDDInfo
->nDropPos
) )
2920 rDTDE
.Context
->acceptDrag( rDTDE
.DropAction
);
2924 OUString
Edit::GetSurroundingText() const
2927 return mpSubEdit
->GetSurroundingText();
2928 return maText
.toString();
2931 Selection
Edit::GetSurroundingTextSelection() const
2933 return GetSelection();
2936 bool Edit::DeleteSurroundingText(const Selection
& rSelection
)
2938 SetSelection(rSelection
);
2940 // maybe we should update mpIMEInfos here
2944 FactoryFunction
Edit::GetUITestFactory() const
2946 return EditUIObject::create
;
2950 void Edit::DumpAsPropertyTree(tools::JsonWriter
& rJsonWriter
)
2952 Control::DumpAsPropertyTree(rJsonWriter
);
2954 if (!maPlaceholderText
.isEmpty())
2955 rJsonWriter
.put("placeholder", maPlaceholderText
);
2958 rJsonWriter
.put("password", true);
2961 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */