Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <tools/rc.h>
21 : #include <vcl/decoview.hxx>
22 : #include <vcl/event.hxx>
23 : #include <vcl/cursor.hxx>
24 : #include <vcl/virdev.hxx>
25 : #include <vcl/menu.hxx>
26 : #include <vcl/edit.hxx>
27 : #include <vcl/layout.hxx>
28 : #include <vcl/svapp.hxx>
29 : #include <vcl/settings.hxx>
30 :
31 : #include <window.h>
32 : #include <svdata.hxx>
33 : #include <svids.hrc>
34 : #include <controldata.hxx>
35 :
36 : #include <osl/mutex.hxx>
37 :
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 <cppuhelper/weak.hxx>
42 : #include <com/sun/star/datatransfer/XTransferable.hpp>
43 : #include <com/sun/star/datatransfer/clipboard/XClipboard.hpp>
44 : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
45 :
46 : #include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
47 : #include <com/sun/star/datatransfer/dnd/XDragGestureRecognizer.hpp>
48 : #include <com/sun/star/datatransfer/dnd/XDropTarget.hpp>
49 :
50 : #include <com/sun/star/i18n/InputSequenceChecker.hpp>
51 : #include <com/sun/star/i18n/InputSequenceCheckMode.hpp>
52 : #include <com/sun/star/i18n/ScriptType.hpp>
53 : #include <com/sun/star/container/XNameAccess.hpp>
54 :
55 : #include <com/sun/star/uno/Any.hxx>
56 :
57 : #include <comphelper/processfactory.hxx>
58 : #include <comphelper/string.hxx>
59 :
60 : #include <sot/exchange.hxx>
61 : #include <sot/formats.hxx>
62 : #include <sal/macros.h>
63 :
64 : #include <vcl/unohelp.hxx>
65 : #include <vcl/unohelp2.hxx>
66 :
67 : #include <officecfg/Office/Common.hxx>
68 : #include <boost/scoped_array.hpp>
69 :
70 : using namespace ::com::sun::star;
71 : using namespace ::com::sun::star::uno;
72 : using namespace ::com::sun::star::lang;
73 :
74 : // - Redo
75 : // - Bei Tracking-Cancel DefaultSelection wieder herstellen
76 :
77 : static FncGetSpecialChars pImplFncGetSpecialChars = NULL;
78 :
79 : #define EDIT_ALIGN_LEFT 1
80 : #define EDIT_ALIGN_CENTER 2
81 : #define EDIT_ALIGN_RIGHT 3
82 :
83 : #define EDIT_DEL_LEFT 1
84 : #define EDIT_DEL_RIGHT 2
85 :
86 : #define EDIT_DELMODE_SIMPLE 11
87 : #define EDIT_DELMODE_RESTOFWORD 12
88 : #define EDIT_DELMODE_RESTOFCONTENT 13
89 :
90 0 : struct DDInfo
91 : {
92 : vcl::Cursor aCursor;
93 : Selection aDndStartSel;
94 : sal_Int32 nDropPos;
95 : bool bStarterOfDD;
96 : bool bDroppedInMe;
97 : bool bVisCursor;
98 : bool bIsStringSupported;
99 :
100 0 : DDInfo()
101 0 : {
102 0 : aCursor.SetStyle( CURSOR_SHADOW );
103 0 : nDropPos = 0;
104 0 : bStarterOfDD = false;
105 0 : bDroppedInMe = false;
106 0 : bVisCursor = false;
107 0 : bIsStringSupported = false;
108 0 : }
109 : };
110 :
111 : struct Impl_IMEInfos
112 : {
113 : OUString aOldTextAfterStartPos;
114 : sal_uInt16* pAttribs;
115 : sal_Int32 nPos;
116 : sal_Int32 nLen;
117 : bool bCursor;
118 : bool bWasCursorOverwrite;
119 :
120 : Impl_IMEInfos(sal_Int32 nPos, const OUString& rOldTextAfterStartPos);
121 : ~Impl_IMEInfos();
122 :
123 : void CopyAttribs(const sal_uInt16* pA, sal_Int32 nL);
124 : void DestroyAttribs();
125 : };
126 :
127 0 : Impl_IMEInfos::Impl_IMEInfos(sal_Int32 nP, const OUString& rOldTextAfterStartPos)
128 0 : : aOldTextAfterStartPos(rOldTextAfterStartPos)
129 : {
130 0 : nPos = nP;
131 0 : nLen = 0;
132 0 : bCursor = true;
133 0 : pAttribs = NULL;
134 0 : bWasCursorOverwrite = false;
135 0 : }
136 :
137 0 : Impl_IMEInfos::~Impl_IMEInfos()
138 : {
139 0 : delete[] pAttribs;
140 0 : }
141 :
142 0 : void Impl_IMEInfos::CopyAttribs(const sal_uInt16* pA, sal_Int32 nL)
143 : {
144 0 : nLen = nL;
145 0 : delete[] pAttribs;
146 0 : pAttribs = new sal_uInt16[ nL ];
147 0 : memcpy( pAttribs, pA, nL*sizeof(sal_uInt16) );
148 0 : }
149 :
150 0 : void Impl_IMEInfos::DestroyAttribs()
151 : {
152 0 : delete[] pAttribs;
153 0 : pAttribs = NULL;
154 0 : nLen = 0;
155 0 : }
156 :
157 5308 : Edit::Edit( WindowType nType ) :
158 5308 : Control( nType )
159 : {
160 5308 : ImplInitEditData();
161 5308 : }
162 :
163 8554 : Edit::Edit( vcl::Window* pParent, WinBits nStyle ) :
164 8554 : Control( WINDOW_EDIT )
165 : {
166 8554 : ImplInitEditData();
167 8554 : ImplInit( pParent, nStyle );
168 8554 : }
169 :
170 0 : Edit::Edit( vcl::Window* pParent, const ResId& rResId ) :
171 0 : Control( WINDOW_EDIT )
172 : {
173 0 : rResId.SetRT( RSC_EDIT );
174 0 : WinBits nStyle = ImplInitRes( rResId );
175 0 : ImplInitEditData();
176 0 : ImplInit( pParent, nStyle );
177 0 : ImplLoadRes( rResId );
178 :
179 0 : if ( !(nStyle & WB_HIDE) )
180 0 : Show();
181 0 : }
182 :
183 2989 : void Edit::SetWidthInChars(sal_Int32 nWidthInChars)
184 : {
185 2989 : if (mnWidthInChars != nWidthInChars)
186 : {
187 0 : mnWidthInChars = nWidthInChars;
188 0 : queue_resize();
189 : }
190 2989 : }
191 :
192 0 : void Edit::setMaxWidthChars(sal_Int32 nWidth)
193 : {
194 0 : if (nWidth != mnMaxWidthChars)
195 : {
196 0 : mnMaxWidthChars = nWidth;
197 0 : queue_resize();
198 : }
199 0 : }
200 :
201 15278 : bool Edit::set_property(const OString &rKey, const OString &rValue)
202 : {
203 15278 : if (rKey == "width-chars")
204 0 : SetWidthInChars(rValue.toInt32());
205 15278 : else if (rKey == "max-width-chars")
206 0 : setMaxWidthChars(rValue.toInt32());
207 15278 : else if (rKey == "max-length")
208 : {
209 1 : sal_Int32 nTextLen = rValue.toInt32();
210 1 : SetMaxTextLen(nTextLen == 0 ? EDIT_NOLIMIT : nTextLen);
211 : }
212 15277 : else if (rKey == "editable")
213 : {
214 0 : bool bReadOnly = !toBool(rValue);
215 0 : SetReadOnly(bReadOnly);
216 : //disable tab to traverse into readonly editables
217 0 : WinBits nBits = GetStyle();
218 0 : nBits &= ~(WB_TABSTOP|WB_NOTABSTOP);
219 0 : if (!bReadOnly)
220 0 : nBits |= WB_TABSTOP;
221 : else
222 0 : nBits |= WB_NOTABSTOP;
223 0 : SetStyle(nBits);
224 : }
225 15277 : else if (rKey == "visibility")
226 : {
227 0 : WinBits nBits = GetStyle();
228 0 : nBits &= ~(WB_PASSWORD);
229 0 : if (!toBool(rValue))
230 0 : nBits |= WB_PASSWORD;
231 0 : SetStyle(nBits);
232 : }
233 15277 : else if (rKey == "placeholder-text")
234 0 : SetPlaceholderText(OStringToOUString(rValue, RTL_TEXTENCODING_UTF8));
235 : else
236 15277 : return Control::set_property(rKey, rValue);
237 1 : return true;
238 : }
239 :
240 26659 : Edit::~Edit()
241 : {
242 10459 : disposeOnce();
243 16200 : }
244 :
245 13853 : void Edit::dispose()
246 : {
247 13853 : delete mpDDInfo;
248 13853 : mpDDInfo = NULL;
249 :
250 13853 : vcl::Cursor* pCursor = GetCursor();
251 13853 : if ( pCursor )
252 : {
253 13853 : SetCursor( NULL );
254 13853 : delete pCursor;
255 : }
256 :
257 13853 : delete mpIMEInfos;
258 13853 : mpIMEInfos = NULL;
259 :
260 13853 : delete mpUpdateDataTimer;
261 13853 : mpUpdateDataTimer = NULL;
262 :
263 13853 : if ( mxDnDListener.is() )
264 : {
265 13853 : if ( GetDragGestureRecognizer().is() )
266 : {
267 13853 : uno::Reference< datatransfer::dnd::XDragGestureListener> xDGL( mxDnDListener, uno::UNO_QUERY );
268 13853 : GetDragGestureRecognizer()->removeDragGestureListener( xDGL );
269 : }
270 13853 : if ( GetDropTarget().is() )
271 : {
272 13853 : uno::Reference< datatransfer::dnd::XDropTargetListener> xDTL( mxDnDListener, uno::UNO_QUERY );
273 13853 : GetDropTarget()->removeDropTargetListener( xDTL );
274 : }
275 :
276 13853 : uno::Reference< lang::XEventListener> xEL( mxDnDListener, uno::UNO_QUERY );
277 13853 : xEL->disposing( lang::EventObject() ); // #95154# #96585# Empty Source means it's the Client
278 13853 : mxDnDListener.clear();
279 : }
280 :
281 13853 : SetType(WINDOW_WINDOW);
282 :
283 13853 : mpSubEdit.disposeAndClear();
284 13853 : Control::dispose();
285 13853 : }
286 :
287 13862 : void Edit::ImplInitEditData()
288 : {
289 13862 : mpSubEdit = VclPtr<Edit>();
290 13862 : mpUpdateDataTimer = NULL;
291 13862 : mpFilterText = NULL;
292 13862 : mnXOffset = 0;
293 13862 : mnAlign = EDIT_ALIGN_LEFT;
294 13862 : mnMaxTextLen = EDIT_NOLIMIT;
295 13862 : mnWidthInChars = -1;
296 13862 : mnMaxWidthChars = -1;
297 13862 : meAutocompleteAction = AUTOCOMPLETE_KEYINPUT;
298 13862 : mbModified = false;
299 13862 : mbInternModified = false;
300 13862 : mbReadOnly = false;
301 13862 : mbInsertMode = true;
302 13862 : mbClickedInSelection = false;
303 13862 : mbActivePopup = false;
304 13862 : mbIsSubEdit = false;
305 13862 : mbInMBDown = false;
306 13862 : mpDDInfo = NULL;
307 13862 : mpIMEInfos = NULL;
308 13862 : mcEchoChar = 0;
309 :
310 : // --- RTL --- no default mirroring for Edit controls
311 : // note: controls that use a subedit will revert this (SpinField, ComboBox)
312 13862 : EnableRTL( false );
313 :
314 13862 : vcl::unohelper::DragAndDropWrapper* pDnDWrapper = new vcl::unohelper::DragAndDropWrapper( this );
315 13862 : mxDnDListener = pDnDWrapper;
316 13862 : }
317 :
318 25642 : bool Edit::ImplUseNativeBorder(vcl::RenderContext& rRenderContext, WinBits nStyle)
319 : {
320 25642 : bool bRet = rRenderContext.IsNativeControlSupported(ImplGetNativeControlType(),
321 25642 : HAS_BACKGROUND_TEXTURE)
322 25642 : && ((nStyle & WB_BORDER) && !(nStyle & WB_NOBORDER));
323 25642 : if (!bRet && mbIsSubEdit)
324 : {
325 14941 : vcl::Window* pWindow = GetParent();
326 14941 : nStyle = pWindow->GetStyle();
327 14941 : bRet = pWindow->IsNativeControlSupported(ImplGetNativeControlType(),
328 14941 : HAS_BACKGROUND_TEXTURE)
329 14941 : && ((nStyle & WB_BORDER) && !(nStyle & WB_NOBORDER));
330 : }
331 25642 : return bRet;
332 : }
333 :
334 13862 : void Edit::ImplInit(vcl::Window* pParent, WinBits nStyle)
335 : {
336 13862 : nStyle = ImplInitStyle(nStyle);
337 :
338 13862 : if (!(nStyle & (WB_CENTER | WB_RIGHT)))
339 13817 : nStyle |= WB_LEFT;
340 :
341 13862 : Control::ImplInit(pParent, nStyle, NULL);
342 :
343 13862 : mbReadOnly = (nStyle & WB_READONLY) != 0;
344 :
345 13862 : mnAlign = EDIT_ALIGN_LEFT;
346 :
347 : // --- RTL --- hack: right align until keyinput and cursor travelling works
348 13862 : if( IsRTLEnabled() )
349 0 : mnAlign = EDIT_ALIGN_RIGHT;
350 :
351 13862 : if ( nStyle & WB_RIGHT )
352 0 : mnAlign = EDIT_ALIGN_RIGHT;
353 13862 : else if ( nStyle & WB_CENTER )
354 45 : mnAlign = EDIT_ALIGN_CENTER;
355 :
356 13862 : SetCursor( new vcl::Cursor );
357 :
358 13862 : SetPointer( Pointer( PointerStyle::Text ) );
359 :
360 13862 : uno::Reference< datatransfer::dnd::XDragGestureListener> xDGL( mxDnDListener, uno::UNO_QUERY );
361 27724 : uno::Reference< datatransfer::dnd::XDragGestureRecognizer > xDGR = GetDragGestureRecognizer();
362 13862 : if ( xDGR.is() )
363 : {
364 13862 : xDGR->addDragGestureListener( xDGL );
365 13862 : uno::Reference< datatransfer::dnd::XDropTargetListener> xDTL( mxDnDListener, uno::UNO_QUERY );
366 13862 : GetDropTarget()->addDropTargetListener( xDTL );
367 13862 : GetDropTarget()->setActive( true );
368 13862 : GetDropTarget()->setDefaultActions( datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE );
369 13862 : }
370 13862 : }
371 :
372 23869 : WinBits Edit::ImplInitStyle( WinBits nStyle )
373 : {
374 23869 : if ( !(nStyle & WB_NOTABSTOP) )
375 23869 : nStyle |= WB_TABSTOP;
376 23869 : if ( !(nStyle & WB_NOGROUP) )
377 23869 : nStyle |= WB_GROUP;
378 :
379 23869 : return nStyle;
380 : }
381 :
382 0 : bool Edit::IsCharInput( const KeyEvent& rKeyEvent )
383 : {
384 : // In the future we must use new Unicode functions for this
385 0 : sal_Unicode cCharCode = rKeyEvent.GetCharCode();
386 0 : return ((cCharCode >= 32) && (cCharCode != 127) &&
387 0 : !rKeyEvent.GetKeyCode().IsMod3() &&
388 0 : !rKeyEvent.GetKeyCode().IsMod2() &&
389 0 : !rKeyEvent.GetKeyCode().IsMod1() );
390 : }
391 :
392 0 : void Edit::ImplModified()
393 : {
394 0 : mbModified = true;
395 0 : Modify();
396 0 : }
397 :
398 5740 : void Edit::ApplySettings(vcl::RenderContext& rRenderContext)
399 : {
400 5740 : Control::ApplySettings(rRenderContext);
401 :
402 5740 : const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
403 :
404 5740 : vcl::Font aFont = rStyleSettings.GetFieldFont();
405 5740 : ApplyControlFont(rRenderContext, aFont);
406 :
407 5740 : ImplClearLayoutData();
408 :
409 5740 : Color aTextColor = rStyleSettings.GetFieldTextColor();
410 5740 : ApplyControlForeground(rRenderContext, aTextColor);
411 :
412 5740 : if (ImplUseNativeBorder(rRenderContext, GetStyle()) || IsPaintTransparent())
413 : {
414 : // Transparent background
415 0 : rRenderContext.SetBackground();
416 0 : rRenderContext.SetFillColor();
417 : }
418 5740 : else if (IsControlBackground())
419 : {
420 8 : rRenderContext.SetBackground(GetControlBackground());
421 8 : rRenderContext.SetFillColor(GetControlBackground());
422 : }
423 : else
424 : {
425 5732 : rRenderContext.SetBackground(rStyleSettings.GetFieldColor());
426 5732 : rRenderContext.SetFillColor(rStyleSettings.GetFieldColor());
427 5740 : }
428 5740 : }
429 :
430 47061 : long Edit::ImplGetExtraXOffset() const
431 : {
432 : // MT 09/2002: nExtraOffsetX should become a member, instead of checking every time,
433 : // but I need an incompatible update for this...
434 : // #94095# Use extra offset only when edit has a border
435 47061 : long nExtraOffset = 0;
436 47061 : if( ( GetStyle() & WB_BORDER ) || ( mbIsSubEdit && ( GetParent()->GetStyle() & WB_BORDER ) ) )
437 46717 : nExtraOffset = 2;
438 :
439 47061 : return nExtraOffset;
440 : }
441 :
442 16453 : long Edit::ImplGetExtraYOffset() const
443 : {
444 16453 : long nExtraOffset = 0;
445 16453 : int eCtrlType = ImplGetNativeControlType();
446 16453 : if (eCtrlType != CTRL_EDITBOX_NOBORDER)
447 : {
448 : // add some space between text entry and border
449 16453 : nExtraOffset = 2;
450 : }
451 16453 : return nExtraOffset;
452 : }
453 :
454 30283 : OUString Edit::ImplGetText() const
455 : {
456 30283 : if ( mcEchoChar || (GetStyle() & WB_PASSWORD) )
457 : {
458 : sal_Unicode cEchoChar;
459 63 : if ( mcEchoChar )
460 63 : cEchoChar = mcEchoChar;
461 : else
462 0 : cEchoChar = '*';
463 63 : OUStringBuffer aText;
464 63 : comphelper::string::padToLength(aText, maText.getLength(), cEchoChar);
465 63 : return aText.makeStringAndClear();
466 : }
467 : else
468 30220 : return maText.toString();
469 : }
470 :
471 17774 : void Edit::ImplInvalidateOrRepaint()
472 : {
473 17774 : if( IsPaintTransparent() )
474 : {
475 0 : Invalidate();
476 : // FIXME: this is currently only on OS X
477 0 : if( ImplGetSVData()->maNWFData.mbNoFocusRects )
478 0 : Update();
479 : }
480 : else
481 17774 : Invalidate();
482 17774 : }
483 :
484 10749 : long Edit::ImplGetTextYPosition() const
485 : {
486 10749 : if ( GetStyle() & WB_TOP )
487 0 : return ImplGetExtraXOffset();
488 10749 : else if ( GetStyle() & WB_BOTTOM )
489 0 : return GetOutputSizePixel().Height() - GetTextHeight() - ImplGetExtraXOffset();
490 10749 : return ( GetOutputSizePixel().Height() - GetTextHeight() ) / 2;
491 : }
492 :
493 5888 : void Edit::ImplRepaint(vcl::RenderContext& rRenderContext, bool bLayout)
494 : {
495 5888 : if (!IsReallyVisible())
496 0 : return;
497 :
498 5888 : OUString aText = ImplGetText();
499 5888 : sal_Int32 nLen = aText.getLength();
500 :
501 : long nDXBuffer[256];
502 11776 : boost::scoped_array<long> pDXBuffer;
503 5888 : long* pDX = nDXBuffer;
504 :
505 5888 : if (!aText.isEmpty())
506 : {
507 4240 : if ((size_t) (2 * aText.getLength()) > SAL_N_ELEMENTS(nDXBuffer))
508 : {
509 0 : pDXBuffer.reset(new long[2 * (aText.getLength() + 1)]);
510 0 : pDX = pDXBuffer.get();
511 : }
512 :
513 4240 : GetCaretPositions(aText, pDX, 0, nLen);
514 : }
515 :
516 5888 : long nTH = GetTextHeight();
517 5888 : Point aPos(mnXOffset, ImplGetTextYPosition());
518 :
519 5888 : if (bLayout)
520 : {
521 0 : aPos.X() = mnXOffset + ImplGetExtraXOffset();
522 :
523 0 : MetricVector* pVector = &mpControlData->mpLayoutData->m_aUnicodeBoundRects;
524 0 : OUString* pDisplayText = &mpControlData->mpLayoutData->m_aDisplayText;
525 :
526 0 : rRenderContext.DrawText(aPos, aText, 0, nLen, pVector, pDisplayText);
527 0 : return;
528 : }
529 :
530 5888 : vcl::Cursor* pCursor = GetCursor();
531 5888 : bool bVisCursor = pCursor && pCursor->IsVisible();
532 5888 : if (pCursor)
533 5888 : pCursor->Hide();
534 :
535 5888 : ImplClearBackground(rRenderContext, 0, GetOutputSizePixel().Width());
536 :
537 5888 : bool bPaintPlaceholderText = aText.isEmpty() && !maPlaceholderText.isEmpty();
538 :
539 5888 : const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
540 :
541 5888 : if (!IsEnabled() || bPaintPlaceholderText)
542 1392 : rRenderContext.SetTextColor(rStyleSettings.GetDisableColor());
543 :
544 : // Set background color of the normal text
545 5888 : if ((GetStyle() & WB_FORCECTRLBACKGROUND) != 0 && IsControlBackground())
546 : {
547 : // check if we need to set ControlBackground even in NWF case
548 0 : rRenderContext.Push(PushFlags::FILLCOLOR | PushFlags::LINECOLOR);
549 0 : rRenderContext.SetLineColor();
550 0 : rRenderContext.SetFillColor(GetControlBackground());
551 0 : rRenderContext.DrawRect(Rectangle(aPos, Size(GetOutputSizePixel().Width() - 2 * mnXOffset, GetOutputSizePixel().Height())));
552 0 : rRenderContext.Pop();
553 :
554 0 : rRenderContext.SetTextFillColor(GetControlBackground());
555 : }
556 5888 : else if (IsPaintTransparent() || ImplUseNativeBorder(rRenderContext, GetStyle()))
557 48 : rRenderContext.SetTextFillColor();
558 : else
559 5840 : rRenderContext.SetTextFillColor(IsControlBackground() ? GetControlBackground() : rStyleSettings.GetFieldColor());
560 :
561 5888 : ImplPaintBorder(rRenderContext, 0, GetOutputSizePixel().Width());
562 :
563 5888 : bool bDrawSelection = maSelection.Len() && (HasFocus() || (GetStyle() & WB_NOHIDESELECTION) || mbActivePopup);
564 :
565 5888 : aPos.X() = mnXOffset + ImplGetExtraXOffset();
566 5888 : if (bPaintPlaceholderText)
567 : {
568 0 : rRenderContext.DrawText(aPos, maPlaceholderText);
569 : }
570 5888 : else if (!bDrawSelection && !mpIMEInfos)
571 : {
572 5783 : rRenderContext.DrawText(aPos, aText, 0, nLen);
573 : }
574 : else
575 : {
576 : // save graphics state
577 105 : rRenderContext.Push();
578 : // first calculate higlighted and non highlighted clip regions
579 105 : vcl::Region aHiglightClipRegion;
580 210 : vcl::Region aNormalClipRegion;
581 105 : Selection aTmpSel(maSelection);
582 105 : aTmpSel.Justify();
583 : // selection is highlighted
584 : int i;
585 1210 : for(i = 0; i < aText.getLength(); i++)
586 : {
587 1105 : Rectangle aRect(aPos, Size(10, nTH));
588 1105 : aRect.Left() = pDX[2 * i] + mnXOffset + ImplGetExtraXOffset();
589 1105 : aRect.Right() = pDX[2 * i + 1] + mnXOffset + ImplGetExtraXOffset();
590 1105 : aRect.Justify();
591 1105 : bool bHighlight = false;
592 1105 : if (i >= aTmpSel.Min() && i < aTmpSel.Max())
593 1105 : bHighlight = true;
594 :
595 1105 : if (mpIMEInfos && mpIMEInfos->pAttribs &&
596 0 : i >= mpIMEInfos->nPos && i < (mpIMEInfos->nPos+mpIMEInfos->nLen) &&
597 0 : (mpIMEInfos->pAttribs[i - mpIMEInfos->nPos] & EXTTEXTINPUT_ATTR_HIGHLIGHT))
598 : {
599 0 : bHighlight = true;
600 : }
601 :
602 1105 : if (bHighlight)
603 1105 : aHiglightClipRegion.Union(aRect);
604 : else
605 0 : aNormalClipRegion.Union(aRect);
606 : }
607 : // draw normal text
608 105 : Color aNormalTextColor = rRenderContext.GetTextColor();
609 105 : rRenderContext.SetClipRegion(aNormalClipRegion);
610 :
611 105 : if (IsPaintTransparent())
612 0 : rRenderContext.SetTextFillColor();
613 : else
614 : {
615 : // Set background color when part of the text is selected
616 105 : if (ImplUseNativeBorder(rRenderContext, GetStyle()))
617 : {
618 0 : if( (GetStyle() & WB_FORCECTRLBACKGROUND) != 0 && IsControlBackground() )
619 0 : rRenderContext.SetTextFillColor(GetControlBackground());
620 : else
621 0 : rRenderContext.SetTextFillColor();
622 : }
623 : else
624 : {
625 105 : rRenderContext.SetTextFillColor(IsControlBackground() ? GetControlBackground() : rStyleSettings.GetFieldColor());
626 : }
627 : }
628 105 : rRenderContext.DrawText(aPos, aText, 0, nLen);
629 :
630 : // draw highlighted text
631 105 : rRenderContext.SetClipRegion(aHiglightClipRegion);
632 105 : rRenderContext.SetTextColor(rStyleSettings.GetHighlightTextColor());
633 105 : rRenderContext.SetTextFillColor(rStyleSettings.GetHighlightColor());
634 105 : rRenderContext.DrawText(aPos, aText, 0, nLen);
635 :
636 : // if IME info exists loop over portions and output different font attributes
637 105 : if (mpIMEInfos && mpIMEInfos->pAttribs)
638 : {
639 0 : for(int n = 0; n < 2; n++)
640 : {
641 0 : vcl::Region aRegion;
642 0 : if (n == 0)
643 : {
644 0 : rRenderContext.SetTextColor(aNormalTextColor);
645 0 : if (IsPaintTransparent())
646 0 : rRenderContext.SetTextFillColor();
647 : else
648 0 : rRenderContext.SetTextFillColor(IsControlBackground() ? GetControlBackground() : rStyleSettings.GetFieldColor());
649 0 : aRegion = aNormalClipRegion;
650 : }
651 : else
652 : {
653 0 : rRenderContext.SetTextColor(rStyleSettings.GetHighlightTextColor());
654 0 : rRenderContext.SetTextFillColor(rStyleSettings.GetHighlightColor());
655 0 : aRegion = aHiglightClipRegion;
656 : }
657 :
658 0 : for(i = 0; i < mpIMEInfos->nLen; )
659 : {
660 0 : sal_uInt16 nAttr = mpIMEInfos->pAttribs[i];
661 0 : vcl::Region aClip;
662 0 : int nIndex = i;
663 0 : while (nIndex < mpIMEInfos->nLen && mpIMEInfos->pAttribs[nIndex] == nAttr) // #112631# check nIndex before using it
664 : {
665 0 : Rectangle aRect( aPos, Size( 10, nTH ) );
666 0 : aRect.Left() = pDX[2 * (nIndex + mpIMEInfos->nPos)] + mnXOffset + ImplGetExtraXOffset();
667 0 : aRect.Right() = pDX[2 * (nIndex + mpIMEInfos->nPos) + 1] + mnXOffset + ImplGetExtraXOffset();
668 0 : aRect.Justify();
669 0 : aClip.Union(aRect);
670 0 : nIndex++;
671 : }
672 0 : i = nIndex;
673 0 : aClip.Intersect(aRegion);
674 0 : if (!aClip.IsEmpty() && nAttr)
675 : {
676 0 : vcl::Font aFont = rRenderContext.GetFont();
677 0 : if (nAttr & EXTTEXTINPUT_ATTR_UNDERLINE)
678 0 : aFont.SetUnderline(UNDERLINE_SINGLE);
679 0 : else if (nAttr & EXTTEXTINPUT_ATTR_BOLDUNDERLINE)
680 0 : aFont.SetUnderline( UNDERLINE_BOLD);
681 0 : else if (nAttr & EXTTEXTINPUT_ATTR_DOTTEDUNDERLINE)
682 0 : aFont.SetUnderline( UNDERLINE_DOTTED);
683 0 : else if (nAttr & EXTTEXTINPUT_ATTR_DASHDOTUNDERLINE)
684 0 : aFont.SetUnderline( UNDERLINE_DASHDOT);
685 0 : else if (nAttr & EXTTEXTINPUT_ATTR_GRAYWAVELINE)
686 : {
687 0 : aFont.SetUnderline(UNDERLINE_WAVE);
688 0 : rRenderContext.SetTextLineColor(Color(COL_LIGHTGRAY));
689 : }
690 0 : rRenderContext.SetFont(aFont);
691 :
692 0 : if (nAttr & EXTTEXTINPUT_ATTR_REDTEXT)
693 0 : rRenderContext.SetTextColor(Color(COL_RED));
694 0 : else if (nAttr & EXTTEXTINPUT_ATTR_HALFTONETEXT)
695 0 : rRenderContext.SetTextColor(Color(COL_LIGHTGRAY));
696 :
697 0 : rRenderContext.SetClipRegion(aClip);
698 0 : rRenderContext.DrawText(aPos, aText, 0, nLen);
699 : }
700 0 : }
701 0 : }
702 : }
703 :
704 : // restore graphics state
705 210 : rRenderContext.Pop();
706 : }
707 :
708 5888 : if (bVisCursor && (!mpIMEInfos || mpIMEInfos->bCursor))
709 9335 : pCursor->Show();
710 : }
711 :
712 19 : void Edit::ImplDelete( const Selection& rSelection, sal_uInt8 nDirection, sal_uInt8 nMode )
713 : {
714 19 : OUString aText = ImplGetText();
715 :
716 : // loeschen moeglich?
717 19 : if ( !rSelection.Len() &&
718 0 : (((rSelection.Min() == 0) && (nDirection == EDIT_DEL_LEFT)) ||
719 0 : ((rSelection.Max() == aText.getLength()) && (nDirection == EDIT_DEL_RIGHT))) )
720 19 : return;
721 :
722 19 : ImplClearLayoutData();
723 :
724 19 : Selection aSelection( rSelection );
725 19 : aSelection.Justify();
726 :
727 19 : if ( !aSelection.Len() )
728 : {
729 0 : uno::Reference < i18n::XBreakIterator > xBI = ImplGetBreakIterator();
730 0 : if ( nDirection == EDIT_DEL_LEFT )
731 : {
732 0 : if ( nMode == EDIT_DELMODE_RESTOFWORD )
733 : {
734 0 : i18n::Boundary aBoundary = xBI->getWordBoundary( maText.toString(), aSelection.Min(),
735 0 : GetSettings().GetLanguageTag().getLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, true );
736 0 : if ( aBoundary.startPos == aSelection.Min() )
737 0 : aBoundary = xBI->previousWord( maText.toString(), aSelection.Min(),
738 0 : GetSettings().GetLanguageTag().getLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES );
739 0 : aSelection.Min() = aBoundary.startPos;
740 : }
741 0 : else if ( nMode == EDIT_DELMODE_RESTOFCONTENT )
742 : {
743 0 : aSelection.Min() = 0;
744 : }
745 : else
746 : {
747 0 : sal_Int32 nCount = 1;
748 0 : aSelection.Min() = xBI->previousCharacters( maText.toString(), aSelection.Min(),
749 0 : GetSettings().GetLanguageTag().getLocale(), i18n::CharacterIteratorMode::SKIPCHARACTER, nCount, nCount );
750 : }
751 : }
752 : else
753 : {
754 0 : if ( nMode == EDIT_DELMODE_RESTOFWORD )
755 : {
756 0 : i18n::Boundary aBoundary = xBI->nextWord( maText.toString(), aSelection.Max(),
757 0 : GetSettings().GetLanguageTag().getLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES );
758 0 : aSelection.Max() = aBoundary.startPos;
759 : }
760 0 : else if ( nMode == EDIT_DELMODE_RESTOFCONTENT )
761 : {
762 0 : aSelection.Max() = aText.getLength();
763 : }
764 : else
765 : {
766 0 : sal_Int32 nCount = 1;
767 0 : aSelection.Max() = xBI->nextCharacters( maText.toString(), aSelection.Max(),
768 0 : GetSettings().GetLanguageTag().getLocale(), i18n::CharacterIteratorMode::SKIPCHARACTER, nCount, nCount );
769 : }
770 0 : }
771 : }
772 :
773 19 : maText.remove( static_cast<sal_Int32>(aSelection.Min()), static_cast<sal_Int32>(aSelection.Len()) );
774 19 : maSelection.Min() = aSelection.Min();
775 19 : maSelection.Max() = aSelection.Min();
776 19 : ImplAlignAndPaint();
777 19 : mbInternModified = true;
778 : }
779 :
780 15719 : OUString Edit::ImplGetValidString( const OUString& rString ) const
781 : {
782 15719 : OUString aValidString( rString );
783 15719 : aValidString = comphelper::string::remove(aValidString, '\n');
784 15719 : aValidString = comphelper::string::remove(aValidString, '\r');
785 15719 : aValidString = aValidString.replace('\t', ' ');
786 15719 : return aValidString;
787 : }
788 :
789 0 : uno::Reference < i18n::XBreakIterator > Edit::ImplGetBreakIterator() const
790 : {
791 : //!! since we don't want to become incompatible in the next minor update
792 : //!! where this code will get integrated into, xISC will be a local
793 : //!! variable instead of a class member!
794 0 : uno::Reference< uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext();
795 0 : return i18n::BreakIterator::create(xContext);
796 : }
797 :
798 0 : uno::Reference < i18n::XExtendedInputSequenceChecker > Edit::ImplGetInputSequenceChecker()
799 : {
800 0 : if ( !mxISC.is() )
801 : {
802 0 : mxISC = i18n::InputSequenceChecker::create(
803 0 : ::comphelper::getProcessComponentContext() );
804 : }
805 0 : return mxISC;
806 : }
807 :
808 0 : void Edit::ShowTruncationWarning( vcl::Window* pParent )
809 : {
810 0 : ResMgr* pResMgr = ImplGetResMgr();
811 0 : if( pResMgr )
812 : {
813 0 : ScopedVclPtrInstance< MessageDialog > aBox( pParent, ResId(SV_EDIT_WARNING_STR, *pResMgr), VCL_MESSAGE_WARNING );
814 0 : aBox->Execute();
815 : }
816 0 : }
817 :
818 14161 : bool Edit::ImplTruncateToMaxLen( OUString& rStr, sal_Int32 nSelectionLen ) const
819 : {
820 14161 : bool bWasTruncated = false;
821 14161 : if (maText.getLength() - nSelectionLen > mnMaxTextLen - rStr.getLength())
822 : {
823 0 : sal_Int32 nErasePos = mnMaxTextLen - maText.getLength() + nSelectionLen;
824 0 : rStr = rStr.copy( 0, nErasePos );
825 0 : bWasTruncated = true;
826 : }
827 14161 : return bWasTruncated;
828 : }
829 :
830 14161 : void Edit::ImplInsertText( const OUString& rStr, const Selection* pNewSel, bool bIsUserInput )
831 : {
832 14161 : Selection aSelection( maSelection );
833 14161 : aSelection.Justify();
834 :
835 14161 : OUString aNewText( ImplGetValidString( rStr ) );
836 14161 : ImplTruncateToMaxLen( aNewText, aSelection.Len() );
837 :
838 14161 : ImplClearLayoutData();
839 :
840 14161 : if ( aSelection.Len() )
841 8353 : maText.remove( static_cast<sal_Int32>(aSelection.Min()), static_cast<sal_Int32>(aSelection.Len()) );
842 5808 : else if ( !mbInsertMode && (aSelection.Max() < maText.getLength()) )
843 0 : maText.remove( static_cast<sal_Int32>(aSelection.Max()), 1 );
844 :
845 : // take care of input-sequence-checking now
846 14161 : if (bIsUserInput && !rStr.isEmpty())
847 : {
848 : DBG_ASSERT( rStr.getLength() == 1, "unexpected string length. User input is expected to providse 1 char only!" );
849 :
850 : // determine if input-sequence-checking should be applied or not
851 :
852 0 : uno::Reference < i18n::XBreakIterator > xBI( ImplGetBreakIterator(), UNO_QUERY );
853 0 : bool bIsInputSequenceChecking = rStr.getLength() == 1 &&
854 0 : officecfg::Office::Common::I18N::CTL::CTLFont::get() &&
855 0 : officecfg::Office::Common::I18N::CTL::CTLSequenceChecking::get() &&
856 0 : aSelection.Min() > 0 && /* first char needs not to be checked */
857 0 : xBI.is() && i18n::ScriptType::COMPLEX == xBI->getScriptType( rStr, 0 );
858 :
859 0 : uno::Reference < i18n::XExtendedInputSequenceChecker > xISC;
860 0 : if (bIsInputSequenceChecking && (xISC = ImplGetInputSequenceChecker()).is())
861 : {
862 0 : sal_Unicode cChar = rStr[0];
863 0 : sal_Int32 nTmpPos = static_cast< sal_Int32 >( aSelection.Min() );
864 0 : sal_Int16 nCheckMode = officecfg::Office::Common::I18N::CTL::CTLSequenceCheckingRestricted::get()?
865 0 : i18n::InputSequenceCheckMode::STRICT : i18n::InputSequenceCheckMode::BASIC;
866 :
867 : // the text that needs to be checked is only the one
868 : // before the current cursor position
869 0 : OUString aOldText( maText.getStr(), nTmpPos);
870 0 : OUString aTmpText( aOldText );
871 0 : if (officecfg::Office::Common::I18N::CTL::CTLSequenceCheckingTypeAndReplace::get())
872 : {
873 0 : xISC->correctInputSequence( aTmpText, nTmpPos - 1, cChar, nCheckMode );
874 :
875 : // find position of first character that has changed
876 0 : sal_Int32 nOldLen = aOldText.getLength();
877 0 : sal_Int32 nTmpLen = aTmpText.getLength();
878 0 : const sal_Unicode *pOldTxt = aOldText.getStr();
879 0 : const sal_Unicode *pTmpTxt = aTmpText.getStr();
880 0 : sal_Int32 nChgPos = 0;
881 0 : while ( nChgPos < nOldLen && nChgPos < nTmpLen &&
882 0 : pOldTxt[nChgPos] == pTmpTxt[nChgPos] )
883 0 : ++nChgPos;
884 :
885 0 : OUString aChgText( aTmpText.copy( nChgPos ) );
886 :
887 : // remove text from first pos to be changed to current pos
888 0 : maText.remove( nChgPos, nTmpPos - nChgPos );
889 :
890 0 : if (!aChgText.isEmpty())
891 : {
892 0 : aNewText = aChgText;
893 0 : aSelection.Min() = nChgPos; // position for new text to be inserted
894 : }
895 : else
896 0 : aNewText.clear();
897 : }
898 : else
899 : {
900 : // should the character be ignored (i.e. not get inserted) ?
901 0 : if (!xISC->checkInputSequence( aOldText, nTmpPos - 1, cChar, nCheckMode ))
902 0 : aNewText.clear();
903 0 : }
904 0 : }
905 :
906 : // at this point now we will insert the non-empty text 'normally' some lines below...
907 : }
908 :
909 14161 : if ( !aNewText.isEmpty() )
910 13101 : maText.insert( static_cast<sal_Int32>(aSelection.Min()), aNewText );
911 :
912 14161 : if ( !pNewSel )
913 : {
914 0 : maSelection.Min() = aSelection.Min() + aNewText.getLength();
915 0 : maSelection.Max() = maSelection.Min();
916 : }
917 : else
918 : {
919 14161 : maSelection = *pNewSel;
920 14161 : if ( maSelection.Min() > maText.getLength() )
921 20 : maSelection.Min() = maText.getLength();
922 14161 : if ( maSelection.Max() > maText.getLength() )
923 20 : maSelection.Max() = maText.getLength();
924 : }
925 :
926 14161 : ImplAlignAndPaint();
927 14161 : mbInternModified = true;
928 14161 : }
929 :
930 46065 : void Edit::ImplSetText( const OUString& rText, const Selection* pNewSelection )
931 : {
932 : // we delete text by "selecting" the old text completely then calling InsertText; this is flicker free
933 107770 : if ( ( rText.getLength() <= mnMaxTextLen ) &&
934 76255 : ( (rText != maText.getStr()) || (pNewSelection && (*pNewSelection != maSelection)) ) )
935 : {
936 15719 : ImplClearLayoutData();
937 15719 : maSelection.Min() = 0;
938 15719 : maSelection.Max() = maText.getLength();
939 15719 : if ( mnXOffset || HasPaintEvent() )
940 : {
941 1558 : mnXOffset = 0;
942 1558 : maText = ImplGetValidString( rText );
943 :
944 : // #i54929# recalculate mnXOffset before ImplSetSelection,
945 : // else cursor ends up in wrong position
946 1558 : ImplAlign();
947 :
948 1558 : if ( pNewSelection )
949 1558 : ImplSetSelection( *pNewSelection, false );
950 :
951 1558 : if ( mnXOffset && !pNewSelection )
952 0 : maSelection.Max() = 0;
953 :
954 1558 : Invalidate();
955 : }
956 : else
957 14161 : ImplInsertText( rText, pNewSelection );
958 :
959 15719 : CallEventListeners( VCLEVENT_EDIT_MODIFY );
960 : }
961 46065 : }
962 :
963 73489 : int Edit::ImplGetNativeControlType() const
964 : {
965 73489 : int nCtrl = 0;
966 73489 : const vcl::Window* pControl = mbIsSubEdit ? GetParent() : this;
967 :
968 73489 : switch (pControl->GetType())
969 : {
970 : case WINDOW_COMBOBOX:
971 : case WINDOW_PATTERNBOX:
972 : case WINDOW_NUMERICBOX:
973 : case WINDOW_METRICBOX:
974 : case WINDOW_CURRENCYBOX:
975 : case WINDOW_DATEBOX:
976 : case WINDOW_TIMEBOX:
977 : case WINDOW_LONGCURRENCYBOX:
978 37335 : nCtrl = CTRL_COMBOBOX;
979 37335 : break;
980 :
981 : case WINDOW_MULTILINEEDIT:
982 252 : if ( GetWindow( GetWindowType::Border ) != this )
983 156 : nCtrl = CTRL_MULTILINE_EDITBOX;
984 : else
985 96 : nCtrl = CTRL_EDITBOX_NOBORDER;
986 252 : break;
987 :
988 : case WINDOW_EDIT:
989 : case WINDOW_PATTERNFIELD:
990 : case WINDOW_METRICFIELD:
991 : case WINDOW_CURRENCYFIELD:
992 : case WINDOW_DATEFIELD:
993 : case WINDOW_TIMEFIELD:
994 : case WINDOW_LONGCURRENCYFIELD:
995 : case WINDOW_NUMERICFIELD:
996 : case WINDOW_SPINFIELD:
997 35902 : if (pControl->GetStyle() & WB_SPIN)
998 28745 : nCtrl = CTRL_SPINBOX;
999 : else
1000 : {
1001 7157 : if (GetWindow(GetWindowType::Border) != this)
1002 6225 : nCtrl = CTRL_EDITBOX;
1003 : else
1004 932 : nCtrl = CTRL_EDITBOX_NOBORDER;
1005 : }
1006 35902 : break;
1007 :
1008 : default:
1009 0 : nCtrl = CTRL_EDITBOX;
1010 : }
1011 73489 : return nCtrl;
1012 : }
1013 :
1014 5888 : void Edit::ImplClearBackground(vcl::RenderContext& rRenderContext, long nXStart, long nXEnd )
1015 : {
1016 : /*
1017 : * note: at this point the cursor must be switched off already
1018 : */
1019 5888 : Point aTmpPoint;
1020 5888 : Rectangle aRect(aTmpPoint, GetOutputSizePixel());
1021 5888 : aRect.Left() = nXStart;
1022 5888 : aRect.Right() = nXEnd;
1023 :
1024 5888 : if( !(ImplUseNativeBorder(rRenderContext, GetStyle()) || IsPaintTransparent()))
1025 5840 : rRenderContext.Erase(aRect);
1026 5888 : }
1027 :
1028 5888 : void Edit::ImplPaintBorder(vcl::RenderContext& rRenderContext, long nXStart, long nXEnd)
1029 : {
1030 : // this is not needed when double-buffering
1031 5888 : if (SupportsDoubleBuffering())
1032 5888 : return;
1033 :
1034 5888 : Point aTmpPoint;
1035 5888 : Rectangle aRect(aTmpPoint, GetOutputSizePixel());
1036 5888 : aRect.Left() = nXStart;
1037 5888 : aRect.Right() = nXEnd;
1038 :
1039 5888 : if (ImplUseNativeBorder(rRenderContext, GetStyle()) || IsPaintTransparent())
1040 : {
1041 : // draw the inner part by painting the whole control using its border window
1042 48 : vcl::Window* pBorder = GetWindow(GetWindowType::Border);
1043 48 : if (pBorder == this)
1044 : {
1045 : // we have no border, use parent
1046 48 : vcl::Window* pControl = mbIsSubEdit ? GetParent() : this;
1047 48 : pBorder = pControl->GetWindow(GetWindowType::Border);
1048 48 : if (pBorder == this)
1049 48 : pBorder = GetParent();
1050 : }
1051 :
1052 48 : if (pBorder)
1053 : {
1054 : // set proper clipping region to not overdraw the whole control
1055 48 : vcl::Region aClipRgn = GetPaintRegion();
1056 48 : if (!aClipRgn.IsNull())
1057 : {
1058 : // transform clipping region to border window's coordinate system
1059 48 : if (IsRTLEnabled() != pBorder->IsRTLEnabled() && AllSettings::GetLayoutRTL())
1060 : {
1061 : // need to mirror in case border is not RTL but edit is (or vice versa)
1062 :
1063 : // mirror
1064 0 : Rectangle aBounds(aClipRgn.GetBoundRect());
1065 0 : int xNew = rRenderContext.GetOutputSizePixel().Width() - aBounds.GetWidth() - aBounds.Left();
1066 0 : aClipRgn.Move(xNew - aBounds.Left(), 0);
1067 :
1068 : // move offset of border window
1069 0 : Point aBorderOffs;
1070 0 : aBorderOffs = pBorder->ScreenToOutputPixel(OutputToScreenPixel(aBorderOffs));
1071 0 : aClipRgn.Move(aBorderOffs.X(), aBorderOffs.Y());
1072 : }
1073 : else
1074 : {
1075 : // normal case
1076 48 : Point aBorderOffs;
1077 48 : aBorderOffs = pBorder->ScreenToOutputPixel(OutputToScreenPixel(aBorderOffs));
1078 48 : aClipRgn.Move(aBorderOffs.X(), aBorderOffs.Y());
1079 : }
1080 :
1081 48 : vcl::Region oldRgn(pBorder->GetClipRegion());
1082 48 : pBorder->SetClipRegion(aClipRgn);
1083 :
1084 48 : pBorder->Paint(*pBorder, Rectangle()); // FIXME
1085 :
1086 48 : pBorder->SetClipRegion(oldRgn);
1087 : }
1088 : else
1089 : {
1090 0 : pBorder->Paint(*pBorder, Rectangle()); // FIXME
1091 48 : }
1092 : }
1093 : }
1094 : }
1095 :
1096 22582 : void Edit::ImplShowCursor( bool bOnlyIfVisible )
1097 : {
1098 22582 : if ( !IsUpdateMode() || ( bOnlyIfVisible && !IsReallyVisible() ) )
1099 40303 : return;
1100 :
1101 4861 : vcl::Cursor* pCursor = GetCursor();
1102 4861 : OUString aText = ImplGetText();
1103 :
1104 4861 : long nTextPos = 0;
1105 :
1106 : long nDXBuffer[256];
1107 9722 : boost::scoped_array<long> pDXBuffer;
1108 4861 : long* pDX = nDXBuffer;
1109 :
1110 4861 : if( !aText.isEmpty() )
1111 : {
1112 4322 : if( (size_t) (2*aText.getLength()) > SAL_N_ELEMENTS(nDXBuffer) )
1113 : {
1114 0 : pDXBuffer.reset(new long[2*(aText.getLength()+1)]);
1115 0 : pDX = pDXBuffer.get();
1116 : }
1117 :
1118 4322 : GetCaretPositions( aText, pDX, 0, aText.getLength() );
1119 :
1120 4322 : if( maSelection.Max() < aText.getLength() )
1121 4305 : nTextPos = pDX[ 2*maSelection.Max() ];
1122 : else
1123 17 : nTextPos = pDX[ 2*aText.getLength()-1 ];
1124 : }
1125 :
1126 4861 : long nCursorWidth = 0;
1127 4861 : if ( !mbInsertMode && !maSelection.Len() && (maSelection.Max() < aText.getLength()) )
1128 0 : nCursorWidth = GetTextWidth(aText, maSelection.Max(), 1);
1129 4861 : long nCursorPosX = nTextPos + mnXOffset + ImplGetExtraXOffset();
1130 :
1131 : // cursor should land in visible area
1132 4861 : const Size aOutSize = GetOutputSizePixel();
1133 4861 : if ( (nCursorPosX < 0) || (nCursorPosX >= aOutSize.Width()) )
1134 : {
1135 4 : long nOldXOffset = mnXOffset;
1136 :
1137 4 : if ( nCursorPosX < 0 )
1138 : {
1139 0 : mnXOffset = - nTextPos;
1140 0 : long nMaxX = 0;
1141 0 : mnXOffset += aOutSize.Width() / 5;
1142 0 : if ( mnXOffset > nMaxX )
1143 0 : mnXOffset = nMaxX;
1144 : }
1145 : else
1146 : {
1147 4 : mnXOffset = (aOutSize.Width()-ImplGetExtraXOffset()) - nTextPos;
1148 : // Etwas mehr?
1149 4 : if ( (aOutSize.Width()-ImplGetExtraXOffset()) < nTextPos )
1150 : {
1151 4 : long nMaxNegX = (aOutSize.Width()-ImplGetExtraXOffset()) - GetTextWidth( aText );
1152 4 : mnXOffset -= aOutSize.Width() / 5;
1153 4 : if ( mnXOffset < nMaxNegX ) // beides negativ...
1154 2 : mnXOffset = nMaxNegX;
1155 : }
1156 : }
1157 :
1158 4 : nCursorPosX = nTextPos + mnXOffset + ImplGetExtraXOffset();
1159 4 : if ( nCursorPosX == aOutSize.Width() ) // dann nicht sichtbar...
1160 4 : nCursorPosX--;
1161 :
1162 4 : if ( mnXOffset != nOldXOffset )
1163 4 : ImplInvalidateOrRepaint();
1164 : }
1165 :
1166 4861 : const long nTextHeight = GetTextHeight();
1167 4861 : const long nCursorPosY = ImplGetTextYPosition();
1168 4861 : if (pCursor)
1169 : {
1170 4861 : pCursor->SetPos( Point( nCursorPosX, nCursorPosY ) );
1171 4861 : pCursor->SetSize( Size( nCursorWidth, nTextHeight ) );
1172 4861 : pCursor->Show();
1173 4861 : }
1174 : }
1175 :
1176 19515 : void Edit::ImplAlign()
1177 : {
1178 19515 : long nTextWidth = GetTextWidth( ImplGetText() );
1179 19515 : long nOutWidth = GetOutputSizePixel().Width();
1180 :
1181 19515 : if ( mnAlign == EDIT_ALIGN_LEFT )
1182 : {
1183 19399 : if( mnXOffset && ( nTextWidth < nOutWidth ) )
1184 5 : mnXOffset = 0;
1185 :
1186 : }
1187 116 : else if ( mnAlign == EDIT_ALIGN_RIGHT )
1188 : {
1189 30 : long nMinXOffset = nOutWidth - nTextWidth - 1 - ImplGetExtraXOffset();
1190 30 : bool bRTL = IsRTLEnabled();
1191 30 : if( mbIsSubEdit && GetParent() )
1192 30 : bRTL = GetParent()->IsRTLEnabled();
1193 30 : if( bRTL )
1194 : {
1195 22 : if( nTextWidth < nOutWidth )
1196 22 : mnXOffset = nMinXOffset;
1197 : }
1198 : else
1199 : {
1200 8 : if( nTextWidth < nOutWidth )
1201 8 : mnXOffset = nMinXOffset;
1202 0 : else if ( mnXOffset < nMinXOffset )
1203 0 : mnXOffset = nMinXOffset;
1204 : }
1205 : }
1206 86 : else if( mnAlign == EDIT_ALIGN_CENTER )
1207 : {
1208 : // would be nicer with check while scrolling but then it's not centred in scrolled state
1209 86 : mnXOffset = (nOutWidth - nTextWidth) / 2;
1210 : }
1211 19515 : }
1212 :
1213 14180 : void Edit::ImplAlignAndPaint()
1214 : {
1215 14180 : ImplAlign();
1216 14180 : ImplInvalidateOrRepaint();
1217 14180 : ImplShowCursor();
1218 14180 : }
1219 :
1220 0 : sal_Int32 Edit::ImplGetCharPos( const Point& rWindowPos ) const
1221 : {
1222 0 : sal_Int32 nIndex = EDIT_NOLIMIT;
1223 0 : OUString aText = ImplGetText();
1224 :
1225 : long nDXBuffer[256];
1226 0 : boost::scoped_array<long> pDXBuffer;
1227 0 : long* pDX = nDXBuffer;
1228 0 : if( (size_t) (2*aText.getLength()) > SAL_N_ELEMENTS(nDXBuffer) )
1229 : {
1230 0 : pDXBuffer.reset(new long[2*(aText.getLength()+1)]);
1231 0 : pDX = pDXBuffer.get();
1232 : }
1233 :
1234 0 : GetCaretPositions( aText, pDX, 0, aText.getLength() );
1235 0 : long nX = rWindowPos.X() - mnXOffset - ImplGetExtraXOffset();
1236 0 : for( sal_Int32 i = 0; i < aText.getLength(); i++ )
1237 : {
1238 0 : if( (pDX[2*i] >= nX && pDX[2*i+1] <= nX) ||
1239 0 : (pDX[2*i+1] >= nX && pDX[2*i] <= nX))
1240 : {
1241 0 : nIndex = i;
1242 0 : if( pDX[2*i] < pDX[2*i+1] )
1243 : {
1244 0 : if( nX > (pDX[2*i]+pDX[2*i+1])/2 )
1245 0 : nIndex++;
1246 : }
1247 : else
1248 : {
1249 0 : if( nX < (pDX[2*i]+pDX[2*i+1])/2 )
1250 0 : nIndex++;
1251 : }
1252 0 : break;
1253 : }
1254 : }
1255 0 : if( nIndex == EDIT_NOLIMIT )
1256 : {
1257 0 : nIndex = 0;
1258 0 : long nDiff = std::abs( pDX[0]-nX );
1259 0 : for( sal_Int32 i = 1; i < aText.getLength(); i++ )
1260 : {
1261 0 : long nNewDiff = std::abs( pDX[2*i]-nX );
1262 :
1263 0 : if( nNewDiff < nDiff )
1264 : {
1265 0 : nIndex = i;
1266 0 : nDiff = nNewDiff;
1267 : }
1268 : }
1269 0 : if( nIndex == aText.getLength()-1 && std::abs( pDX[2*nIndex+1] - nX ) < nDiff )
1270 0 : nIndex = EDIT_NOLIMIT;
1271 : }
1272 :
1273 0 : return nIndex;
1274 : }
1275 :
1276 0 : void Edit::ImplSetCursorPos( sal_Int32 nChar, bool bSelect )
1277 : {
1278 0 : Selection aSelection( maSelection );
1279 0 : aSelection.Max() = nChar;
1280 0 : if ( !bSelect )
1281 0 : aSelection.Min() = aSelection.Max();
1282 0 : ImplSetSelection( aSelection );
1283 0 : }
1284 :
1285 505 : void Edit::ImplLoadRes( const ResId& rResId )
1286 : {
1287 505 : Control::ImplLoadRes( rResId );
1288 :
1289 505 : sal_uInt16 nTextLength = ReadShortRes();
1290 505 : if ( nTextLength )
1291 0 : SetMaxTextLen( nTextLength );
1292 505 : }
1293 :
1294 0 : void Edit::ImplCopyToSelectionClipboard()
1295 : {
1296 0 : if ( GetSelection().Len() )
1297 : {
1298 0 : ::com::sun::star::uno::Reference<com::sun::star::datatransfer::clipboard::XClipboard> aSelection(GetPrimarySelection());
1299 0 : ImplCopy( aSelection );
1300 : }
1301 0 : }
1302 :
1303 0 : void Edit::ImplCopy( uno::Reference< datatransfer::clipboard::XClipboard >& rxClipboard )
1304 : {
1305 0 : vcl::unohelper::TextDataObject::CopyStringTo( GetSelected(), rxClipboard );
1306 0 : }
1307 :
1308 0 : void Edit::ImplPaste( uno::Reference< datatransfer::clipboard::XClipboard >& rxClipboard )
1309 : {
1310 0 : if ( rxClipboard.is() )
1311 : {
1312 0 : uno::Reference< datatransfer::XTransferable > xDataObj;
1313 :
1314 : try
1315 : {
1316 0 : SolarMutexReleaser aReleaser;
1317 0 : xDataObj = rxClipboard->getContents();
1318 : }
1319 0 : catch( const ::com::sun::star::uno::Exception& )
1320 : {
1321 : }
1322 :
1323 0 : if ( xDataObj.is() )
1324 : {
1325 0 : datatransfer::DataFlavor aFlavor;
1326 0 : SotExchange::GetFormatDataFlavor( SotClipboardFormatId::STRING, aFlavor );
1327 : try
1328 : {
1329 0 : uno::Any aData = xDataObj->getTransferData( aFlavor );
1330 0 : OUString aText;
1331 0 : aData >>= aText;
1332 0 : if( ImplTruncateToMaxLen( aText, maSelection.Len() ) )
1333 0 : ShowTruncationWarning( this );
1334 0 : ReplaceSelected( aText );
1335 : }
1336 0 : catch( const ::com::sun::star::uno::Exception& )
1337 : {
1338 0 : }
1339 0 : }
1340 : }
1341 0 : }
1342 :
1343 0 : void Edit::MouseButtonDown( const MouseEvent& rMEvt )
1344 : {
1345 0 : if ( mpSubEdit )
1346 : {
1347 0 : Control::MouseButtonDown( rMEvt );
1348 0 : return;
1349 : }
1350 :
1351 0 : sal_Int32 nCharPos = ImplGetCharPos( rMEvt.GetPosPixel() );
1352 0 : Selection aSelection( maSelection );
1353 0 : aSelection.Justify();
1354 :
1355 0 : if ( rMEvt.GetClicks() < 4 )
1356 : {
1357 0 : mbClickedInSelection = false;
1358 0 : if ( rMEvt.GetClicks() == 3 )
1359 : {
1360 0 : ImplSetSelection( Selection( 0, EDIT_NOLIMIT) );
1361 0 : ImplCopyToSelectionClipboard();
1362 :
1363 : }
1364 0 : else if ( rMEvt.GetClicks() == 2 )
1365 : {
1366 0 : uno::Reference < i18n::XBreakIterator > xBI = ImplGetBreakIterator();
1367 0 : i18n::Boundary aBoundary = xBI->getWordBoundary( maText.toString(), aSelection.Max(),
1368 0 : GetSettings().GetLanguageTag().getLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, true );
1369 0 : ImplSetSelection( Selection( aBoundary.startPos, aBoundary.endPos ) );
1370 0 : ImplCopyToSelectionClipboard();
1371 : }
1372 0 : else if ( !rMEvt.IsShift() && HasFocus() && aSelection.IsInside( nCharPos ) )
1373 0 : mbClickedInSelection = true;
1374 0 : else if ( rMEvt.IsLeft() )
1375 0 : ImplSetCursorPos( nCharPos, rMEvt.IsShift() );
1376 :
1377 0 : if ( !mbClickedInSelection && rMEvt.IsLeft() && ( rMEvt.GetClicks() == 1 ) )
1378 0 : StartTracking( StartTrackingFlags::ScrollRepeat );
1379 : }
1380 :
1381 0 : mbInMBDown = true; // then do not select all in GetFocus
1382 0 : GrabFocus();
1383 0 : mbInMBDown = false;
1384 : }
1385 :
1386 0 : void Edit::MouseButtonUp( const MouseEvent& rMEvt )
1387 : {
1388 0 : if ( mbClickedInSelection && rMEvt.IsLeft() )
1389 : {
1390 0 : sal_Int32 nCharPos = ImplGetCharPos( rMEvt.GetPosPixel() );
1391 0 : ImplSetCursorPos( nCharPos, false );
1392 0 : mbClickedInSelection = false;
1393 : }
1394 0 : else if ( rMEvt.IsMiddle() && !mbReadOnly &&
1395 0 : ( GetSettings().GetMouseSettings().GetMiddleButtonAction() == MouseMiddleButtonAction::PasteSelection ) )
1396 : {
1397 0 : ::com::sun::star::uno::Reference<com::sun::star::datatransfer::clipboard::XClipboard> aSelection(Window::GetPrimarySelection());
1398 0 : ImplPaste( aSelection );
1399 0 : ImplModified();
1400 : }
1401 0 : }
1402 :
1403 0 : void Edit::Tracking( const TrackingEvent& rTEvt )
1404 : {
1405 0 : if ( rTEvt.IsTrackingEnded() )
1406 : {
1407 0 : if ( mbClickedInSelection )
1408 : {
1409 0 : sal_Int32 nCharPos = ImplGetCharPos( rTEvt.GetMouseEvent().GetPosPixel() );
1410 0 : ImplSetCursorPos( nCharPos, false );
1411 0 : mbClickedInSelection = false;
1412 : }
1413 0 : else if ( rTEvt.GetMouseEvent().IsLeft() )
1414 : {
1415 0 : ImplCopyToSelectionClipboard();
1416 : }
1417 : }
1418 : else
1419 : {
1420 0 : if( !mbClickedInSelection )
1421 : {
1422 0 : sal_Int32 nCharPos = ImplGetCharPos( rTEvt.GetMouseEvent().GetPosPixel() );
1423 0 : ImplSetCursorPos( nCharPos, true );
1424 : }
1425 : }
1426 :
1427 0 : if ( mpUpdateDataTimer && !mbIsSubEdit && mpUpdateDataTimer->IsActive() )
1428 0 : mpUpdateDataTimer->Start();//do not update while the user is still travelling in the control
1429 0 : }
1430 :
1431 0 : bool Edit::ImplHandleKeyEvent( const KeyEvent& rKEvt )
1432 : {
1433 0 : bool bDone = false;
1434 0 : sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
1435 0 : KeyFuncType eFunc = rKEvt.GetKeyCode().GetFunction();
1436 :
1437 0 : mbInternModified = false;
1438 :
1439 0 : if ( eFunc != KeyFuncType::DONTKNOW )
1440 : {
1441 0 : switch ( eFunc )
1442 : {
1443 : case KeyFuncType::CUT:
1444 : {
1445 0 : if ( !mbReadOnly && maSelection.Len() && !(GetStyle() & WB_PASSWORD) )
1446 : {
1447 0 : Cut();
1448 0 : ImplModified();
1449 0 : bDone = true;
1450 : }
1451 : }
1452 0 : break;
1453 :
1454 : case KeyFuncType::COPY:
1455 : {
1456 0 : if ( !(GetStyle() & WB_PASSWORD) )
1457 : {
1458 0 : Copy();
1459 0 : bDone = true;
1460 : }
1461 : }
1462 0 : break;
1463 :
1464 : case KeyFuncType::PASTE:
1465 : {
1466 0 : if ( !mbReadOnly )
1467 : {
1468 0 : Paste();
1469 0 : bDone = true;
1470 : }
1471 : }
1472 0 : break;
1473 :
1474 : case KeyFuncType::UNDO:
1475 : {
1476 0 : if ( !mbReadOnly )
1477 : {
1478 0 : Undo();
1479 0 : bDone = true;
1480 : }
1481 : }
1482 0 : break;
1483 :
1484 : default:
1485 0 : eFunc = KeyFuncType::DONTKNOW;
1486 : }
1487 : }
1488 :
1489 0 : if ( !bDone && rKEvt.GetKeyCode().IsMod1() && !rKEvt.GetKeyCode().IsMod2() )
1490 : {
1491 0 : if ( nCode == KEY_A )
1492 : {
1493 0 : ImplSetSelection( Selection( 0, maText.getLength() ) );
1494 0 : bDone = true;
1495 : }
1496 0 : else if ( rKEvt.GetKeyCode().IsShift() && (nCode == KEY_S) )
1497 : {
1498 0 : if ( pImplFncGetSpecialChars )
1499 : {
1500 0 : Selection aSaveSel = GetSelection(); // if someone changes the selection in Get/LoseFocus, e.g. URL bar
1501 0 : OUString aChars = pImplFncGetSpecialChars( this, GetFont() );
1502 0 : SetSelection( aSaveSel );
1503 0 : if ( !aChars.isEmpty() )
1504 : {
1505 0 : ImplInsertText( aChars );
1506 0 : ImplModified();
1507 : }
1508 0 : bDone = true;
1509 : }
1510 : }
1511 : }
1512 :
1513 0 : if ( eFunc == KeyFuncType::DONTKNOW && ! bDone )
1514 : {
1515 0 : switch ( nCode )
1516 : {
1517 : case com::sun::star::awt::Key::SELECT_ALL:
1518 : {
1519 0 : ImplSetSelection( Selection( 0, maText.getLength() ) );
1520 0 : bDone = true;
1521 : }
1522 0 : break;
1523 :
1524 : case KEY_LEFT:
1525 : case KEY_RIGHT:
1526 : case KEY_HOME:
1527 : case KEY_END:
1528 : case com::sun::star::awt::Key::MOVE_WORD_FORWARD:
1529 : case com::sun::star::awt::Key::SELECT_WORD_FORWARD:
1530 : case com::sun::star::awt::Key::MOVE_WORD_BACKWARD:
1531 : case com::sun::star::awt::Key::SELECT_WORD_BACKWARD:
1532 : case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE:
1533 : case com::sun::star::awt::Key::MOVE_TO_END_OF_LINE:
1534 : case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE:
1535 : case com::sun::star::awt::Key::SELECT_TO_END_OF_LINE:
1536 : case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH:
1537 : case com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH:
1538 : case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH:
1539 : case com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH:
1540 : case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT:
1541 : case com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT:
1542 : case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT:
1543 : case com::sun::star::awt::Key::SELECT_TO_END_OF_DOCUMENT:
1544 : {
1545 0 : if ( !rKEvt.GetKeyCode().IsMod2() )
1546 : {
1547 0 : ImplClearLayoutData();
1548 0 : uno::Reference < i18n::XBreakIterator > xBI = ImplGetBreakIterator();
1549 :
1550 0 : Selection aSel( maSelection );
1551 0 : bool bWord = rKEvt.GetKeyCode().IsMod1();
1552 0 : bool bSelect = rKEvt.GetKeyCode().IsShift();
1553 0 : bool bGoLeft = (nCode == KEY_LEFT);
1554 0 : bool bGoRight = (nCode == KEY_RIGHT);
1555 0 : bool bGoHome = (nCode == KEY_HOME);
1556 0 : bool bGoEnd = (nCode == KEY_END);
1557 :
1558 0 : switch( nCode )
1559 : {
1560 : case com::sun::star::awt::Key::MOVE_WORD_FORWARD:
1561 0 : bGoRight = bWord = true;break;
1562 : case com::sun::star::awt::Key::SELECT_WORD_FORWARD:
1563 0 : bGoRight = bSelect = bWord = true;break;
1564 : case com::sun::star::awt::Key::MOVE_WORD_BACKWARD:
1565 0 : bGoLeft = bWord = true;break;
1566 : case com::sun::star::awt::Key::SELECT_WORD_BACKWARD:
1567 0 : bGoLeft = bSelect = bWord = true;break;
1568 : case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE:
1569 : case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH:
1570 : case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT:
1571 0 : bSelect = true;
1572 : // fallthrough intended
1573 : case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE:
1574 : case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH:
1575 : case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT:
1576 0 : bGoHome = true;break;
1577 : case com::sun::star::awt::Key::SELECT_TO_END_OF_LINE:
1578 : case com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH:
1579 : case com::sun::star::awt::Key::SELECT_TO_END_OF_DOCUMENT:
1580 0 : bSelect = true;
1581 : // fallthrough intended
1582 : case com::sun::star::awt::Key::MOVE_TO_END_OF_LINE:
1583 : case com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH:
1584 : case com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT:
1585 0 : bGoEnd = true;break;
1586 : default:
1587 0 : break;
1588 : };
1589 :
1590 : // Range wird in ImplSetSelection geprueft...
1591 0 : if ( bGoLeft && aSel.Max() )
1592 : {
1593 0 : if ( bWord )
1594 : {
1595 0 : i18n::Boundary aBoundary = xBI->getWordBoundary( maText.toString(), aSel.Max(),
1596 0 : GetSettings().GetLanguageTag().getLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES, true );
1597 0 : if ( aBoundary.startPos == aSel.Max() )
1598 0 : aBoundary = xBI->previousWord( maText.toString(), aSel.Max(),
1599 0 : GetSettings().GetLanguageTag().getLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES );
1600 0 : aSel.Max() = aBoundary.startPos;
1601 : }
1602 : else
1603 : {
1604 0 : sal_Int32 nCount = 1;
1605 0 : aSel.Max() = xBI->previousCharacters( maText.toString(), aSel.Max(),
1606 0 : GetSettings().GetLanguageTag().getLocale(), i18n::CharacterIteratorMode::SKIPCHARACTER, nCount, nCount );
1607 : }
1608 : }
1609 0 : else if ( bGoRight && ( aSel.Max() < maText.getLength() ) )
1610 : {
1611 0 : if ( bWord )
1612 : {
1613 0 : i18n::Boundary aBoundary = xBI->nextWord( maText.toString(), aSel.Max(),
1614 0 : GetSettings().GetLanguageTag().getLocale(), i18n::WordType::ANYWORD_IGNOREWHITESPACES );
1615 0 : aSel.Max() = aBoundary.startPos;
1616 : }
1617 : else
1618 : {
1619 0 : sal_Int32 nCount = 1;
1620 0 : aSel.Max() = xBI->nextCharacters( maText.toString(), aSel.Max(),
1621 0 : GetSettings().GetLanguageTag().getLocale(), i18n::CharacterIteratorMode::SKIPCHARACTER, nCount, nCount );
1622 : }
1623 : }
1624 0 : else if ( bGoHome )
1625 : {
1626 0 : aSel.Max() = 0;
1627 : }
1628 0 : else if ( bGoEnd )
1629 : {
1630 0 : aSel.Max() = EDIT_NOLIMIT;
1631 : }
1632 :
1633 0 : if ( !bSelect )
1634 0 : aSel.Min() = aSel.Max();
1635 :
1636 0 : if ( aSel != GetSelection() )
1637 : {
1638 0 : ImplSetSelection( aSel );
1639 0 : ImplCopyToSelectionClipboard();
1640 : }
1641 :
1642 0 : if ( bGoEnd && !autocompleteSignal.empty() && !rKEvt.GetKeyCode().GetModifier() )
1643 : {
1644 0 : if ( (maSelection.Min() == maSelection.Max()) && (maSelection.Min() == maText.getLength()) )
1645 : {
1646 0 : meAutocompleteAction = AUTOCOMPLETE_KEYINPUT;
1647 0 : autocompleteSignal( this );
1648 : }
1649 : }
1650 :
1651 0 : bDone = true;
1652 : }
1653 : }
1654 0 : break;
1655 :
1656 : case com::sun::star::awt::Key::DELETE_WORD_BACKWARD:
1657 : case com::sun::star::awt::Key::DELETE_WORD_FORWARD:
1658 : case com::sun::star::awt::Key::DELETE_TO_BEGIN_OF_LINE:
1659 : case com::sun::star::awt::Key::DELETE_TO_END_OF_LINE:
1660 : case KEY_BACKSPACE:
1661 : case KEY_DELETE:
1662 : {
1663 0 : if ( !mbReadOnly && !rKEvt.GetKeyCode().IsMod2() )
1664 : {
1665 0 : sal_uInt8 nDel = (nCode == KEY_DELETE) ? EDIT_DEL_RIGHT : EDIT_DEL_LEFT;
1666 0 : sal_uInt8 nMode = rKEvt.GetKeyCode().IsMod1() ? EDIT_DELMODE_RESTOFWORD : EDIT_DELMODE_SIMPLE;
1667 0 : if ( (nMode == EDIT_DELMODE_RESTOFWORD) && rKEvt.GetKeyCode().IsShift() )
1668 0 : nMode = EDIT_DELMODE_RESTOFCONTENT;
1669 0 : switch( nCode )
1670 : {
1671 : case com::sun::star::awt::Key::DELETE_WORD_BACKWARD:
1672 0 : nDel = EDIT_DEL_LEFT;
1673 0 : nMode = EDIT_DELMODE_RESTOFWORD;
1674 0 : break;
1675 : case com::sun::star::awt::Key::DELETE_WORD_FORWARD:
1676 0 : nDel = EDIT_DEL_RIGHT;
1677 0 : nMode = EDIT_DELMODE_RESTOFWORD;
1678 0 : break;
1679 : case com::sun::star::awt::Key::DELETE_TO_BEGIN_OF_LINE:
1680 0 : nDel = EDIT_DEL_LEFT;
1681 0 : nMode = EDIT_DELMODE_RESTOFCONTENT;
1682 0 : break;
1683 : case com::sun::star::awt::Key::DELETE_TO_END_OF_LINE:
1684 0 : nDel = EDIT_DEL_RIGHT;
1685 0 : nMode = EDIT_DELMODE_RESTOFCONTENT;
1686 0 : break;
1687 0 : default: break;
1688 : }
1689 0 : sal_Int32 nOldLen = maText.getLength();
1690 0 : ImplDelete( maSelection, nDel, nMode );
1691 0 : if ( maText.getLength() != nOldLen )
1692 0 : ImplModified();
1693 0 : bDone = true;
1694 : }
1695 : }
1696 0 : break;
1697 :
1698 : case KEY_INSERT:
1699 : {
1700 0 : if ( !mpIMEInfos && !mbReadOnly && !rKEvt.GetKeyCode().IsMod2() )
1701 : {
1702 0 : SetInsertMode( !mbInsertMode );
1703 0 : bDone = true;
1704 : }
1705 : }
1706 0 : break;
1707 :
1708 : /* #i101255# disable autocomplete tab forward/backward
1709 : users expect tab/shif-tab to move the focus to other controls
1710 : not suddenly to cycle the autocompletion
1711 : case KEY_TAB:
1712 : {
1713 : if ( !mbReadOnly && !autocompleteSignal.empty() &&
1714 : maSelection.Min() && (maSelection.Min() == maText.Len()) &&
1715 : !rKEvt.GetKeyCode().IsMod1() && !rKEvt.GetKeyCode().IsMod2() )
1716 : {
1717 : // Kein Autocomplete wenn alles Selektiert oder Edit leer, weil dann
1718 : // keine vernuenftige Tab-Steuerung!
1719 : if ( rKEvt.GetKeyCode().IsShift() )
1720 : meAutocompleteAction = AUTOCOMPLETE_TABBACKWARD;
1721 : else
1722 : meAutocompleteAction = AUTOCOMPLETE_TABFORWARD;
1723 :
1724 : autocompleteSignal( this );
1725 :
1726 : // Wurde nichts veraendert, dann TAB fuer DialogControl
1727 : if ( GetSelection().Len() )
1728 : bDone = true;
1729 : }
1730 : }
1731 : break;
1732 : */
1733 :
1734 : default:
1735 : {
1736 0 : if ( IsCharInput( rKEvt ) )
1737 : {
1738 0 : bDone = true; // read characters also when in ReadOnly
1739 0 : if ( !mbReadOnly )
1740 : {
1741 0 : ImplInsertText(OUString(rKEvt.GetCharCode()), 0, true);
1742 0 : if ( !autocompleteSignal.empty() )
1743 : {
1744 0 : if ( (maSelection.Min() == maSelection.Max()) && (maSelection.Min() == maText.getLength()) )
1745 : {
1746 0 : meAutocompleteAction = AUTOCOMPLETE_KEYINPUT;
1747 0 : autocompleteSignal( this );
1748 : }
1749 : }
1750 : }
1751 : }
1752 : }
1753 : }
1754 : }
1755 :
1756 0 : if ( mbInternModified )
1757 0 : ImplModified();
1758 :
1759 0 : return bDone;
1760 : }
1761 :
1762 0 : void Edit::KeyInput( const KeyEvent& rKEvt )
1763 : {
1764 0 : if ( mpUpdateDataTimer && !mbIsSubEdit && mpUpdateDataTimer->IsActive() )
1765 0 : mpUpdateDataTimer->Start();//do not update while the user is still travelling in the control
1766 :
1767 0 : if ( mpSubEdit || !ImplHandleKeyEvent( rKEvt ) )
1768 0 : Control::KeyInput( rKEvt );
1769 0 : }
1770 :
1771 0 : void Edit::FillLayoutData() const
1772 : {
1773 0 : mpControlData->mpLayoutData = new vcl::ControlLayoutData();
1774 0 : const_cast<Edit*>(this)->Invalidate();
1775 0 : }
1776 :
1777 9699 : void Edit::Paint(vcl::RenderContext& rRenderContext, const Rectangle&)
1778 : {
1779 9699 : if (!mpSubEdit)
1780 5888 : ImplRepaint(rRenderContext);
1781 9699 : }
1782 :
1783 12955 : void Edit::Resize()
1784 : {
1785 12955 : if ( !mpSubEdit && IsReallyVisible() )
1786 : {
1787 86 : Control::Resize();
1788 : // Wegen vertikaler Zentrierung...
1789 86 : mnXOffset = 0;
1790 86 : ImplAlign();
1791 86 : Invalidate();
1792 86 : ImplShowCursor();
1793 : }
1794 12955 : }
1795 :
1796 0 : void Edit::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, DrawFlags nFlags )
1797 : {
1798 0 : Point aPos = pDev->LogicToPixel( rPos );
1799 0 : Size aSize = pDev->LogicToPixel( rSize );
1800 0 : vcl::Font aFont = GetDrawPixelFont( pDev );
1801 0 : OutDevType eOutDevType = pDev->GetOutDevType();
1802 :
1803 0 : pDev->Push();
1804 0 : pDev->SetMapMode();
1805 0 : pDev->SetFont( aFont );
1806 0 : pDev->SetTextFillColor();
1807 :
1808 : // Border/Background
1809 0 : pDev->SetLineColor();
1810 0 : pDev->SetFillColor();
1811 0 : bool bBorder = !(nFlags & DrawFlags::NoBorder ) && (GetStyle() & WB_BORDER);
1812 0 : bool bBackground = !(nFlags & DrawFlags::NoBackground) && IsControlBackground();
1813 0 : if ( bBorder || bBackground )
1814 : {
1815 0 : Rectangle aRect( aPos, aSize );
1816 0 : if ( bBorder )
1817 : {
1818 0 : ImplDrawFrame( pDev, aRect );
1819 : }
1820 0 : if ( bBackground )
1821 : {
1822 0 : pDev->SetFillColor( GetControlBackground() );
1823 0 : pDev->DrawRect( aRect );
1824 : }
1825 : }
1826 :
1827 : // Inhalt
1828 0 : if ( ( nFlags & DrawFlags::Mono ) || ( eOutDevType == OUTDEV_PRINTER ) )
1829 0 : pDev->SetTextColor( Color( COL_BLACK ) );
1830 : else
1831 : {
1832 0 : if ( !(nFlags & DrawFlags::NoDisable ) && !IsEnabled() )
1833 : {
1834 0 : const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
1835 0 : pDev->SetTextColor( rStyleSettings.GetDisableColor() );
1836 : }
1837 : else
1838 : {
1839 0 : pDev->SetTextColor( GetTextColor() );
1840 : }
1841 : }
1842 :
1843 0 : OUString aText = ImplGetText();
1844 0 : long nTextHeight = pDev->GetTextHeight();
1845 0 : long nTextWidth = pDev->GetTextWidth( aText );
1846 0 : long nOnePixel = GetDrawPixel( pDev, 1 );
1847 0 : long nOffX = 3*nOnePixel;
1848 0 : long nOffY = (aSize.Height() - nTextHeight) / 2;
1849 :
1850 : // Clipping?
1851 0 : if ( (nOffY < 0) ||
1852 0 : ((nOffY+nTextHeight) > aSize.Height()) ||
1853 0 : ((nOffX+nTextWidth) > aSize.Width()) )
1854 : {
1855 0 : Rectangle aClip( aPos, aSize );
1856 0 : if ( nTextHeight > aSize.Height() )
1857 0 : aClip.Bottom() += nTextHeight-aSize.Height()+1; // prevent HP printers from 'optimizing'
1858 0 : pDev->IntersectClipRegion( aClip );
1859 : }
1860 :
1861 0 : if ( GetStyle() & WB_CENTER )
1862 : {
1863 0 : aPos.X() += (aSize.Width() - nTextWidth) / 2;
1864 0 : nOffX = 0;
1865 : }
1866 0 : else if ( GetStyle() & WB_RIGHT )
1867 : {
1868 0 : aPos.X() += aSize.Width() - nTextWidth;
1869 0 : nOffX = -nOffX;
1870 : }
1871 :
1872 0 : pDev->DrawText( Point( aPos.X() + nOffX, aPos.Y() + nOffY ), aText );
1873 0 : pDev->Pop();
1874 :
1875 0 : if ( GetSubEdit() )
1876 : {
1877 0 : GetSubEdit()->Draw( pDev, rPos, rSize, nFlags );
1878 0 : }
1879 0 : }
1880 :
1881 0 : void Edit::ImplInvalidateOutermostBorder( vcl::Window* pWin )
1882 : {
1883 : // allow control to show focused state
1884 0 : vcl::Window *pInvalWin = pWin, *pBorder = pWin;
1885 0 : while( ( pBorder = pInvalWin->GetWindow( GetWindowType::Border ) ) != pInvalWin && pBorder &&
1886 0 : pInvalWin->ImplGetFrame() == pBorder->ImplGetFrame() )
1887 : {
1888 0 : pInvalWin = pBorder;
1889 : }
1890 :
1891 0 : pInvalWin->Invalidate( InvalidateFlags::Children | InvalidateFlags::Update );
1892 0 : }
1893 :
1894 2 : void Edit::GetFocus()
1895 : {
1896 2 : if ( mpSubEdit )
1897 1 : mpSubEdit->ImplGrabFocus( GetGetFocusFlags() );
1898 1 : else if ( !mbActivePopup )
1899 : {
1900 1 : maUndoText = maText.toString();
1901 :
1902 1 : SelectionOptions nSelOptions = GetSettings().GetStyleSettings().GetSelectionOptions();
1903 3 : if ( !( GetStyle() & (WB_NOHIDESELECTION|WB_READONLY) )
1904 4 : && ( GetGetFocusFlags() & (GetFocusFlags::Init|GetFocusFlags::Tab|GetFocusFlags::CURSOR|GetFocusFlags::Mnemonic) ) )
1905 : {
1906 0 : if ( nSelOptions & SelectionOptions::ShowFirst )
1907 : {
1908 0 : maSelection.Min() = maText.getLength();
1909 0 : maSelection.Max() = 0;
1910 : }
1911 : else
1912 : {
1913 0 : maSelection.Min() = 0;
1914 0 : maSelection.Max() = maText.getLength();
1915 : }
1916 0 : if ( mbIsSubEdit )
1917 0 : static_cast<Edit*>(GetParent())->CallEventListeners( VCLEVENT_EDIT_SELECTIONCHANGED );
1918 : else
1919 0 : CallEventListeners( VCLEVENT_EDIT_SELECTIONCHANGED );
1920 : }
1921 :
1922 1 : ImplShowCursor();
1923 :
1924 : // FIXME: this is currently only on OS X
1925 : // check for other platforms that need similar handling
1926 2 : if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
1927 1 : IsNativeWidgetEnabled() &&
1928 0 : IsNativeControlSupported( CTRL_EDITBOX, PART_ENTIRE_CONTROL ) )
1929 : {
1930 0 : ImplInvalidateOutermostBorder( mbIsSubEdit ? GetParent() : this );
1931 : }
1932 1 : else if ( maSelection.Len() )
1933 : {
1934 : // Selektion malen
1935 0 : if ( !HasPaintEvent() )
1936 0 : ImplInvalidateOrRepaint();
1937 : else
1938 0 : Invalidate();
1939 : }
1940 :
1941 1 : SetInputContext( InputContext( GetFont(), !IsReadOnly() ? InputContextFlags::Text|InputContextFlags::ExtText : InputContextFlags::NONE ) );
1942 : }
1943 :
1944 2 : Control::GetFocus();
1945 2 : }
1946 :
1947 0 : vcl::Window* Edit::GetPreferredKeyInputWindow()
1948 : {
1949 0 : if ( mpSubEdit )
1950 0 : return mpSubEdit->GetPreferredKeyInputWindow();
1951 : else
1952 0 : return this;
1953 : }
1954 :
1955 0 : void Edit::LoseFocus()
1956 : {
1957 0 : if ( mpUpdateDataTimer && !mbIsSubEdit && mpUpdateDataTimer->IsActive() )
1958 : {
1959 : //notify an update latest when the focus is lost
1960 0 : mpUpdateDataTimer->Stop();
1961 0 : mpUpdateDataTimer->Timeout();
1962 : }
1963 :
1964 0 : if ( !mpSubEdit )
1965 : {
1966 : // FIXME: this is currently only on OS X
1967 : // check for other platforms that need similar handling
1968 0 : if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
1969 0 : IsNativeWidgetEnabled() &&
1970 0 : IsNativeControlSupported( CTRL_EDITBOX, PART_ENTIRE_CONTROL ) )
1971 : {
1972 0 : ImplInvalidateOutermostBorder( mbIsSubEdit ? GetParent() : this );
1973 : }
1974 :
1975 0 : if ( !mbActivePopup && !( GetStyle() & WB_NOHIDESELECTION ) && maSelection.Len() )
1976 0 : ImplInvalidateOrRepaint(); // Selektion malen
1977 : }
1978 :
1979 0 : Control::LoseFocus();
1980 0 : }
1981 :
1982 0 : void Edit::Command( const CommandEvent& rCEvt )
1983 : {
1984 0 : if ( rCEvt.GetCommand() == CommandEventId::ContextMenu )
1985 : {
1986 0 : PopupMenu* pPopup = Edit::CreatePopupMenu();
1987 :
1988 0 : if ( !maSelection.Len() )
1989 : {
1990 0 : pPopup->EnableItem( SV_MENU_EDIT_CUT, false );
1991 0 : pPopup->EnableItem( SV_MENU_EDIT_COPY, false );
1992 0 : pPopup->EnableItem( SV_MENU_EDIT_DELETE, false );
1993 : }
1994 :
1995 0 : if ( IsReadOnly() )
1996 : {
1997 0 : pPopup->EnableItem( SV_MENU_EDIT_CUT, false );
1998 0 : pPopup->EnableItem( SV_MENU_EDIT_PASTE, false );
1999 0 : pPopup->EnableItem( SV_MENU_EDIT_DELETE, false );
2000 0 : pPopup->EnableItem( SV_MENU_EDIT_INSERTSYMBOL, false );
2001 : }
2002 : else
2003 : {
2004 : // only paste if text available in clipboard
2005 0 : bool bData = false;
2006 0 : uno::Reference< datatransfer::clipboard::XClipboard > xClipboard = GetClipboard();
2007 :
2008 0 : if ( xClipboard.is() )
2009 : {
2010 0 : uno::Reference< datatransfer::XTransferable > xDataObj;
2011 : {
2012 0 : SolarMutexReleaser aReleaser;
2013 0 : xDataObj = xClipboard->getContents();
2014 : }
2015 0 : if ( xDataObj.is() )
2016 : {
2017 0 : datatransfer::DataFlavor aFlavor;
2018 0 : SotExchange::GetFormatDataFlavor( SotClipboardFormatId::STRING, aFlavor );
2019 0 : bData = xDataObj->isDataFlavorSupported( aFlavor );
2020 0 : }
2021 : }
2022 0 : pPopup->EnableItem( SV_MENU_EDIT_PASTE, bData );
2023 : }
2024 :
2025 0 : if ( maUndoText == maText.getStr() )
2026 0 : pPopup->EnableItem( SV_MENU_EDIT_UNDO, false );
2027 0 : if ( ( maSelection.Min() == 0 ) && ( maSelection.Max() == maText.getLength() ) )
2028 0 : pPopup->EnableItem( SV_MENU_EDIT_SELECTALL, false );
2029 0 : if ( !pImplFncGetSpecialChars )
2030 : {
2031 0 : sal_uInt16 nPos = pPopup->GetItemPos( SV_MENU_EDIT_INSERTSYMBOL );
2032 0 : pPopup->RemoveItem( nPos );
2033 0 : pPopup->RemoveItem( nPos-1 );
2034 : }
2035 :
2036 0 : mbActivePopup = true;
2037 0 : Selection aSaveSel = GetSelection(); // if someone changes selection in Get/LoseFocus, e.g. URL bar
2038 0 : Point aPos = rCEvt.GetMousePosPixel();
2039 0 : if ( !rCEvt.IsMouseEvent() )
2040 : {
2041 : // Show menu eventually centered in selection
2042 0 : Size aSize = GetOutputSizePixel();
2043 0 : aPos = Point( aSize.Width()/2, aSize.Height()/2 );
2044 : }
2045 0 : sal_uInt16 n = pPopup->Execute( this, aPos );
2046 0 : Edit::DeletePopupMenu( pPopup );
2047 0 : SetSelection( aSaveSel );
2048 0 : switch ( n )
2049 : {
2050 : case SV_MENU_EDIT_UNDO:
2051 0 : Undo();
2052 0 : ImplModified();
2053 0 : break;
2054 : case SV_MENU_EDIT_CUT:
2055 0 : Cut();
2056 0 : ImplModified();
2057 0 : break;
2058 : case SV_MENU_EDIT_COPY:
2059 0 : Copy();
2060 0 : break;
2061 : case SV_MENU_EDIT_PASTE:
2062 0 : Paste();
2063 0 : ImplModified();
2064 0 : break;
2065 : case SV_MENU_EDIT_DELETE:
2066 0 : DeleteSelected();
2067 0 : ImplModified();
2068 0 : break;
2069 : case SV_MENU_EDIT_SELECTALL:
2070 0 : ImplSetSelection( Selection( 0, maText.getLength() ) );
2071 0 : break;
2072 : case SV_MENU_EDIT_INSERTSYMBOL:
2073 : {
2074 0 : OUString aChars = pImplFncGetSpecialChars( this, GetFont() );
2075 0 : SetSelection( aSaveSel );
2076 0 : if ( !aChars.isEmpty() )
2077 : {
2078 0 : ImplInsertText( aChars );
2079 0 : ImplModified();
2080 0 : }
2081 : }
2082 0 : break;
2083 : }
2084 0 : mbActivePopup = false;
2085 : }
2086 0 : else if ( rCEvt.GetCommand() == CommandEventId::StartExtTextInput )
2087 : {
2088 0 : DeleteSelected();
2089 0 : delete mpIMEInfos;
2090 0 : sal_Int32 nPos = static_cast<sal_Int32>(maSelection.Max());
2091 0 : mpIMEInfos = new Impl_IMEInfos( nPos, OUString(maText.getStr() + nPos ) );
2092 0 : mpIMEInfos->bWasCursorOverwrite = !IsInsertMode();
2093 : }
2094 0 : else if ( rCEvt.GetCommand() == CommandEventId::EndExtTextInput )
2095 : {
2096 0 : bool bInsertMode = !mpIMEInfos->bWasCursorOverwrite;
2097 0 : delete mpIMEInfos;
2098 0 : mpIMEInfos = NULL;
2099 :
2100 0 : SetInsertMode(bInsertMode);
2101 0 : ImplModified();
2102 :
2103 0 : Invalidate();
2104 :
2105 : // #i25161# call auto complete handler for ext text commit also
2106 0 : if ( autocompleteSignal.empty() )
2107 : {
2108 0 : if ( (maSelection.Min() == maSelection.Max()) && (maSelection.Min() == maText.getLength()) )
2109 : {
2110 0 : meAutocompleteAction = AUTOCOMPLETE_KEYINPUT;
2111 0 : autocompleteSignal( this );
2112 : }
2113 : }
2114 : }
2115 0 : else if ( rCEvt.GetCommand() == CommandEventId::ExtTextInput )
2116 : {
2117 0 : const CommandExtTextInputData* pData = rCEvt.GetExtTextInputData();
2118 :
2119 0 : maText.remove( mpIMEInfos->nPos, mpIMEInfos->nLen );
2120 0 : maText.insert( mpIMEInfos->nPos, pData->GetText() );
2121 0 : if ( mpIMEInfos->bWasCursorOverwrite )
2122 : {
2123 0 : sal_Int32 nOldIMETextLen = mpIMEInfos->nLen;
2124 0 : sal_Int32 nNewIMETextLen = pData->GetText().getLength();
2125 0 : if ( ( nOldIMETextLen > nNewIMETextLen ) &&
2126 0 : ( nNewIMETextLen < mpIMEInfos->aOldTextAfterStartPos.getLength() ) )
2127 : {
2128 : // restore old characters
2129 0 : sal_Int32 nRestore = nOldIMETextLen - nNewIMETextLen;
2130 0 : maText.insert( mpIMEInfos->nPos + nNewIMETextLen, mpIMEInfos->aOldTextAfterStartPos.copy( nNewIMETextLen, nRestore ) );
2131 : }
2132 0 : else if ( ( nOldIMETextLen < nNewIMETextLen ) &&
2133 0 : ( nOldIMETextLen < mpIMEInfos->aOldTextAfterStartPos.getLength() ) )
2134 : {
2135 : // overwrite
2136 0 : sal_uInt16 nOverwrite = nNewIMETextLen - nOldIMETextLen;
2137 0 : if ( ( nOldIMETextLen + nOverwrite ) > mpIMEInfos->aOldTextAfterStartPos.getLength() )
2138 0 : nOverwrite = mpIMEInfos->aOldTextAfterStartPos.getLength() - nOldIMETextLen;
2139 0 : maText.remove( mpIMEInfos->nPos + nNewIMETextLen, nOverwrite );
2140 : }
2141 : }
2142 :
2143 0 : if ( pData->GetTextAttr() )
2144 : {
2145 0 : mpIMEInfos->CopyAttribs( pData->GetTextAttr(), pData->GetText().getLength() );
2146 0 : mpIMEInfos->bCursor = pData->IsCursorVisible();
2147 : }
2148 : else
2149 : {
2150 0 : mpIMEInfos->DestroyAttribs();
2151 : }
2152 :
2153 0 : ImplAlignAndPaint();
2154 0 : sal_Int32 nCursorPos = mpIMEInfos->nPos + pData->GetCursorPos();
2155 0 : SetSelection( Selection( nCursorPos, nCursorPos ) );
2156 0 : SetInsertMode( !pData->IsCursorOverwrite() );
2157 :
2158 0 : if ( pData->IsCursorVisible() )
2159 0 : GetCursor()->Show();
2160 : else
2161 0 : GetCursor()->Hide();
2162 : }
2163 0 : else if ( rCEvt.GetCommand() == CommandEventId::CursorPos )
2164 : {
2165 0 : if ( mpIMEInfos )
2166 : {
2167 0 : sal_Int32 nCursorPos = GetSelection().Max();
2168 0 : SetCursorRect( NULL, GetTextWidth( maText.toString(), nCursorPos, mpIMEInfos->nPos+mpIMEInfos->nLen-nCursorPos ) );
2169 : }
2170 : else
2171 : {
2172 0 : SetCursorRect();
2173 : }
2174 : }
2175 0 : else if ( rCEvt.GetCommand() == CommandEventId::SelectionChange )
2176 : {
2177 0 : const CommandSelectionChangeData *pData = rCEvt.GetSelectionChangeData();
2178 0 : Selection aSelection( pData->GetStart(), pData->GetEnd() );
2179 0 : SetSelection(aSelection);
2180 : }
2181 0 : else if ( rCEvt.GetCommand() == CommandEventId::QueryCharPosition )
2182 : {
2183 0 : if (mpIMEInfos && mpIMEInfos->nLen > 0)
2184 : {
2185 0 : OUString aText = ImplGetText();
2186 : long nDXBuffer[256];
2187 0 : boost::scoped_array<long> pDXBuffer;
2188 0 : long* pDX = nDXBuffer;
2189 :
2190 0 : if( !aText.isEmpty() )
2191 : {
2192 0 : if( (size_t) (2*aText.getLength()) > SAL_N_ELEMENTS(nDXBuffer) )
2193 : {
2194 0 : pDXBuffer.reset(new long[2*(aText.getLength()+1)]);
2195 0 : pDX = pDXBuffer.get();
2196 : }
2197 :
2198 0 : GetCaretPositions( aText, pDX, 0, aText.getLength() );
2199 : }
2200 0 : long nTH = GetTextHeight();
2201 0 : Point aPos( mnXOffset, ImplGetTextYPosition() );
2202 :
2203 0 : boost::scoped_array<Rectangle> aRects(new Rectangle[ mpIMEInfos->nLen ]);
2204 0 : for ( int nIndex = 0; nIndex < mpIMEInfos->nLen; ++nIndex )
2205 : {
2206 0 : Rectangle aRect( aPos, Size( 10, nTH ) );
2207 0 : aRect.Left() = pDX[2*(nIndex+mpIMEInfos->nPos)] + mnXOffset + ImplGetExtraXOffset();
2208 0 : aRects[ nIndex ] = aRect;
2209 : }
2210 0 : SetCompositionCharRect( aRects.get(), mpIMEInfos->nLen );
2211 : }
2212 : }
2213 : else
2214 0 : Control::Command( rCEvt );
2215 0 : }
2216 :
2217 76326 : void Edit::StateChanged( StateChangedType nType )
2218 : {
2219 76326 : if (nType == StateChangedType::InitShow)
2220 : {
2221 7120 : if (!mpSubEdit)
2222 : {
2223 3679 : mnXOffset = 0; // if GrabFocus before while size was still wrong
2224 3679 : ImplAlign();
2225 3679 : if (!mpSubEdit)
2226 3679 : ImplShowCursor(false);
2227 3679 : Invalidate();
2228 : }
2229 : }
2230 69206 : else if (nType == StateChangedType::Enable)
2231 : {
2232 3897 : if (!mpSubEdit)
2233 : {
2234 : // change text color only
2235 3544 : ImplInvalidateOrRepaint();
2236 : }
2237 : }
2238 65309 : else if (nType == StateChangedType::Style || nType == StateChangedType::Mirroring)
2239 : {
2240 29950 : WinBits nStyle = GetStyle();
2241 29950 : if (nType == StateChangedType::Style)
2242 : {
2243 10007 : nStyle = ImplInitStyle(GetStyle());
2244 10007 : SetStyle(nStyle);
2245 : }
2246 :
2247 29950 : sal_uInt16 nOldAlign = mnAlign;
2248 29950 : mnAlign = EDIT_ALIGN_LEFT;
2249 :
2250 : // --- RTL --- hack: right align until keyinput and cursor travelling works
2251 : // edits are always RTL disabled
2252 : // however the parent edits contain the correct setting
2253 29950 : if (mbIsSubEdit && GetParent()->IsRTLEnabled())
2254 : {
2255 30 : if (GetParent()->GetStyle() & WB_LEFT)
2256 29 : mnAlign = EDIT_ALIGN_RIGHT;
2257 30 : if (nType == StateChangedType::Mirroring)
2258 19 : SetLayoutMode(TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_TEXTORIGIN_LEFT);
2259 : }
2260 29920 : else if (mbIsSubEdit && !GetParent()->IsRTLEnabled())
2261 : {
2262 178 : if (nType == StateChangedType::Mirroring)
2263 134 : SetLayoutMode(TEXT_LAYOUT_TEXTORIGIN_LEFT);
2264 : }
2265 :
2266 29950 : if (nStyle & WB_RIGHT)
2267 0 : mnAlign = EDIT_ALIGN_RIGHT;
2268 29950 : else if (nStyle & WB_CENTER)
2269 155 : mnAlign = EDIT_ALIGN_CENTER;
2270 29950 : if (!maText.isEmpty() && (mnAlign != nOldAlign))
2271 : {
2272 12 : ImplAlign();
2273 12 : Invalidate();
2274 29950 : }
2275 :
2276 : }
2277 35359 : else if (nType == StateChangedType::Zoom)
2278 : {
2279 8 : if (!mpSubEdit)
2280 : {
2281 5 : ImplShowCursor(true);
2282 5 : Invalidate();
2283 : }
2284 : }
2285 35351 : else if (nType == StateChangedType::ControlFont)
2286 : {
2287 1480 : if (!mpSubEdit)
2288 : {
2289 1033 : ImplShowCursor();
2290 1033 : Invalidate();
2291 : }
2292 : }
2293 33871 : else if (nType == StateChangedType::ControlForeground)
2294 : {
2295 7 : if (!mpSubEdit)
2296 : {
2297 5 : Invalidate();
2298 : }
2299 : }
2300 33864 : else if (nType == StateChangedType::ControlBackground)
2301 : {
2302 175 : if (!mpSubEdit)
2303 : {
2304 173 : Invalidate();
2305 : }
2306 : }
2307 :
2308 76326 : Control::StateChanged(nType);
2309 76326 : }
2310 :
2311 3318 : void Edit::DataChanged( const DataChangedEvent& rDCEvt )
2312 : {
2313 13272 : if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) ||
2314 13266 : (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) ||
2315 9954 : ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
2316 13272 : (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) )
2317 : {
2318 3312 : if ( !mpSubEdit )
2319 : {
2320 2477 : ImplShowCursor( true );
2321 2477 : Invalidate();
2322 : }
2323 : }
2324 :
2325 3318 : Control::DataChanged( rDCEvt );
2326 3318 : }
2327 :
2328 0 : void Edit::ImplShowDDCursor()
2329 : {
2330 0 : if (!mpDDInfo->bVisCursor)
2331 : {
2332 0 : long nTextWidth = GetTextWidth( maText.toString(), 0, mpDDInfo->nDropPos );
2333 0 : long nTextHeight = GetTextHeight();
2334 0 : Rectangle aCursorRect( Point( nTextWidth + mnXOffset, (GetOutputSize().Height()-nTextHeight)/2 ), Size( 2, nTextHeight ) );
2335 0 : mpDDInfo->aCursor.SetWindow( this );
2336 0 : mpDDInfo->aCursor.SetPos( aCursorRect.TopLeft() );
2337 0 : mpDDInfo->aCursor.SetSize( aCursorRect.GetSize() );
2338 0 : mpDDInfo->aCursor.Show();
2339 0 : mpDDInfo->bVisCursor = true;
2340 : }
2341 0 : }
2342 :
2343 0 : void Edit::ImplHideDDCursor()
2344 : {
2345 0 : if ( mpDDInfo && mpDDInfo->bVisCursor )
2346 : {
2347 0 : mpDDInfo->aCursor.Hide();
2348 0 : mpDDInfo->bVisCursor = false;
2349 : }
2350 0 : }
2351 :
2352 0 : TextFilter::TextFilter(const OUString &rForbiddenChars)
2353 0 : : sForbiddenChars(rForbiddenChars)
2354 : {
2355 0 : }
2356 :
2357 0 : TextFilter::~TextFilter()
2358 : {
2359 0 : }
2360 :
2361 0 : OUString TextFilter::filter(const OUString &rText)
2362 : {
2363 0 : OUString sTemp(rText);
2364 0 : for (sal_Int32 i = 0; i < sForbiddenChars.getLength(); ++i)
2365 : {
2366 0 : sTemp = comphelper::string::remove(sTemp, sForbiddenChars[i]);
2367 : }
2368 0 : return sTemp;
2369 : }
2370 :
2371 0 : void Edit::filterText()
2372 : {
2373 0 : Selection aSel = GetSelection();
2374 0 : OUString sOrig = GetText();
2375 0 : OUString sNew = mpFilterText->filter(GetText());
2376 0 : if (sOrig != sNew)
2377 : {
2378 0 : sal_Int32 nDiff = sOrig.getLength() - sNew.getLength();
2379 0 : if (nDiff)
2380 : {
2381 0 : aSel.setMin(aSel.getMin() - nDiff);
2382 0 : aSel.setMax(aSel.getMin());
2383 : }
2384 0 : SetText(sNew);
2385 0 : SetSelection(aSel);
2386 0 : }
2387 0 : }
2388 :
2389 373 : void Edit::Modify()
2390 : {
2391 373 : if (mpFilterText)
2392 0 : filterText();
2393 :
2394 373 : if ( mbIsSubEdit )
2395 : {
2396 0 : static_cast<Edit*>(GetParent())->Modify();
2397 : }
2398 : else
2399 : {
2400 373 : if ( mpUpdateDataTimer )
2401 0 : mpUpdateDataTimer->Start();
2402 :
2403 373 : if ( ImplCallEventListenersAndHandler( VCLEVENT_EDIT_MODIFY, maModifyHdl, this ) )
2404 : // have been destroyed while calling into the handlers
2405 373 : return;
2406 :
2407 : // #i13677# notify edit listeners about caret position change
2408 373 : CallEventListeners( VCLEVENT_EDIT_CARETCHANGED );
2409 : // FIXME: this is currently only on OS X
2410 : // check for other platforms that need similar handling
2411 746 : if( ImplGetSVData()->maNWFData.mbNoFocusRects &&
2412 373 : IsNativeWidgetEnabled() &&
2413 0 : IsNativeControlSupported( CTRL_EDITBOX, PART_ENTIRE_CONTROL ) )
2414 : {
2415 0 : ImplInvalidateOutermostBorder( this );
2416 : }
2417 : }
2418 : }
2419 :
2420 0 : void Edit::UpdateData()
2421 : {
2422 0 : maUpdateDataHdl.Call( this );
2423 0 : }
2424 :
2425 0 : IMPL_LINK_NOARG_TYPED(Edit, ImplUpdateDataHdl, Timer *, void)
2426 : {
2427 0 : UpdateData();
2428 0 : }
2429 :
2430 0 : void Edit::EnableUpdateData( sal_uLong nTimeout )
2431 : {
2432 0 : if ( !nTimeout )
2433 0 : DisableUpdateData();
2434 : else
2435 : {
2436 0 : if ( !mpUpdateDataTimer )
2437 : {
2438 0 : mpUpdateDataTimer = new Timer;
2439 0 : mpUpdateDataTimer->SetTimeoutHdl( LINK( this, Edit, ImplUpdateDataHdl ) );
2440 : }
2441 :
2442 0 : mpUpdateDataTimer->SetTimeout( nTimeout );
2443 : }
2444 0 : }
2445 :
2446 56 : void Edit::SetEchoChar( sal_Unicode c )
2447 : {
2448 56 : mcEchoChar = c;
2449 56 : if ( mpSubEdit )
2450 0 : mpSubEdit->SetEchoChar( c );
2451 56 : }
2452 :
2453 5729 : void Edit::SetReadOnly( bool bReadOnly )
2454 : {
2455 5729 : if ( mbReadOnly != bool(bReadOnly) )
2456 : {
2457 367 : mbReadOnly = bReadOnly;
2458 367 : if ( mpSubEdit )
2459 61 : mpSubEdit->SetReadOnly( bReadOnly );
2460 :
2461 367 : CompatStateChanged( StateChangedType::ReadOnly );
2462 : }
2463 5729 : }
2464 :
2465 0 : void Edit::SetInsertMode( bool bInsert )
2466 : {
2467 0 : if ( bInsert != mbInsertMode )
2468 : {
2469 0 : mbInsertMode = bInsert;
2470 0 : if ( mpSubEdit )
2471 0 : mpSubEdit->SetInsertMode( bInsert );
2472 : else
2473 0 : ImplShowCursor();
2474 : }
2475 0 : }
2476 :
2477 0 : bool Edit::IsInsertMode() const
2478 : {
2479 0 : if ( mpSubEdit )
2480 0 : return mpSubEdit->IsInsertMode();
2481 : else
2482 0 : return mbInsertMode;
2483 : }
2484 :
2485 214 : void Edit::SetMaxTextLen(sal_Int32 nMaxLen)
2486 : {
2487 214 : mnMaxTextLen = nMaxLen > 0 ? nMaxLen : EDIT_NOLIMIT;
2488 :
2489 214 : if ( mpSubEdit )
2490 42 : mpSubEdit->SetMaxTextLen( mnMaxTextLen );
2491 : else
2492 : {
2493 172 : if ( maText.getLength() > mnMaxTextLen )
2494 19 : ImplDelete( Selection( mnMaxTextLen, maText.getLength() ), EDIT_DEL_RIGHT, EDIT_DELMODE_SIMPLE );
2495 : }
2496 214 : }
2497 :
2498 1054 : void Edit::SetSelection( const Selection& rSelection )
2499 : {
2500 : // If the selection was changed from outside, e.g. by MouseButtonDown, don't call Tracking()
2501 : // directly afterwards which would change the selection again
2502 1054 : if ( IsTracking() )
2503 0 : EndTracking();
2504 1054 : else if ( mpSubEdit && mpSubEdit->IsTracking() )
2505 0 : mpSubEdit->EndTracking();
2506 :
2507 1054 : ImplSetSelection( rSelection );
2508 1054 : }
2509 :
2510 3609 : void Edit::ImplSetSelection( const Selection& rSelection, bool bPaint )
2511 : {
2512 3609 : if ( mpSubEdit )
2513 997 : mpSubEdit->ImplSetSelection( rSelection );
2514 : else
2515 : {
2516 2612 : if ( rSelection != maSelection )
2517 : {
2518 1127 : Selection aOld( maSelection );
2519 1127 : Selection aNew( rSelection );
2520 :
2521 1127 : if ( aNew.Min() > maText.getLength() )
2522 5 : aNew.Min() = maText.getLength();
2523 1127 : if ( aNew.Max() > maText.getLength() )
2524 2 : aNew.Max() = maText.getLength();
2525 1127 : if ( aNew.Min() < 0 )
2526 0 : aNew.Min() = 0;
2527 1127 : if ( aNew.Max() < 0 )
2528 5 : aNew.Max() = 0;
2529 :
2530 1127 : if ( aNew != maSelection )
2531 : {
2532 1121 : ImplClearLayoutData();
2533 1121 : Selection aTemp = maSelection;
2534 1121 : maSelection = aNew;
2535 :
2536 1121 : if ( bPaint && ( aOld.Len() || aNew.Len() || IsPaintTransparent() ) )
2537 46 : ImplInvalidateOrRepaint();
2538 1121 : ImplShowCursor();
2539 :
2540 1121 : bool bCaret = false, bSelection = false;
2541 1121 : long nB=aNew.Max(), nA=aNew.Min(),oB=aTemp.Max(), oA=aTemp.Min();
2542 1121 : long nGap = nB-nA, oGap = oB-oA;
2543 1121 : if (nB != oB)
2544 1121 : bCaret = true;
2545 1121 : if (nGap != 0 || oGap != 0)
2546 1106 : bSelection = true;
2547 :
2548 1121 : if (bSelection)
2549 : {
2550 1106 : if ( mbIsSubEdit )
2551 1022 : static_cast<Edit*>(GetParent())->CallEventListeners( VCLEVENT_EDIT_SELECTIONCHANGED );
2552 : else
2553 84 : CallEventListeners( VCLEVENT_EDIT_SELECTIONCHANGED );
2554 : }
2555 :
2556 1121 : if (bCaret)
2557 : {
2558 1121 : if ( mbIsSubEdit )
2559 1024 : static_cast<Edit*>(GetParent())->CallEventListeners( VCLEVENT_EDIT_CARETCHANGED );
2560 : else
2561 97 : CallEventListeners( VCLEVENT_EDIT_CARETCHANGED );
2562 : }
2563 :
2564 : // #103511# notify combobox listeners of deselection
2565 1121 : if( !maSelection && GetParent() && GetParent()->GetType() == WINDOW_COMBOBOX )
2566 998 : static_cast<Edit*>(GetParent())->CallEventListeners( VCLEVENT_COMBOBOX_DESELECT );
2567 : }
2568 : }
2569 : }
2570 3609 : }
2571 :
2572 76430 : const Selection& Edit::GetSelection() const
2573 : {
2574 76430 : if ( mpSubEdit )
2575 37839 : return mpSubEdit->GetSelection();
2576 : else
2577 38591 : return maSelection;
2578 : }
2579 :
2580 0 : void Edit::ReplaceSelected( const OUString& rStr )
2581 : {
2582 0 : if ( mpSubEdit )
2583 0 : mpSubEdit->ReplaceSelected( rStr );
2584 : else
2585 0 : ImplInsertText( rStr );
2586 0 : }
2587 :
2588 0 : void Edit::DeleteSelected()
2589 : {
2590 0 : if ( mpSubEdit )
2591 0 : mpSubEdit->DeleteSelected();
2592 : else
2593 : {
2594 0 : if ( maSelection.Len() )
2595 0 : ImplDelete( maSelection, EDIT_DEL_RIGHT, EDIT_DELMODE_SIMPLE );
2596 : }
2597 0 : }
2598 :
2599 17 : OUString Edit::GetSelected() const
2600 : {
2601 17 : if ( mpSubEdit )
2602 2 : return mpSubEdit->GetSelected();
2603 : else
2604 : {
2605 15 : Selection aSelection( maSelection );
2606 15 : aSelection.Justify();
2607 15 : return OUString( maText.getStr() + aSelection.Min(), aSelection.Len() );
2608 : }
2609 : }
2610 :
2611 0 : void Edit::Cut()
2612 : {
2613 0 : if ( !(GetStyle() & WB_PASSWORD ) )
2614 : {
2615 0 : Copy();
2616 0 : ReplaceSelected( OUString() );
2617 : }
2618 0 : }
2619 :
2620 0 : void Edit::Copy()
2621 : {
2622 0 : if ( !(GetStyle() & WB_PASSWORD ) )
2623 : {
2624 0 : ::com::sun::star::uno::Reference<com::sun::star::datatransfer::clipboard::XClipboard> aClipboard(GetClipboard());
2625 0 : ImplCopy( aClipboard );
2626 : }
2627 0 : }
2628 :
2629 0 : void Edit::Paste()
2630 : {
2631 0 : ::com::sun::star::uno::Reference<com::sun::star::datatransfer::clipboard::XClipboard> aClipboard(GetClipboard());
2632 0 : ImplPaste( aClipboard );
2633 0 : }
2634 :
2635 0 : void Edit::Undo()
2636 : {
2637 0 : if ( mpSubEdit )
2638 0 : mpSubEdit->Undo();
2639 : else
2640 : {
2641 0 : OUString aText( maText.toString() );
2642 0 : ImplDelete( Selection( 0, aText.getLength() ), EDIT_DEL_RIGHT, EDIT_DELMODE_SIMPLE );
2643 0 : ImplInsertText( maUndoText );
2644 0 : ImplSetSelection( Selection( 0, maUndoText.getLength() ) );
2645 0 : maUndoText = aText;
2646 : }
2647 0 : }
2648 :
2649 16657 : void Edit::SetText( const OUString& rStr )
2650 : {
2651 16657 : if ( mpSubEdit )
2652 8030 : mpSubEdit->SetText( rStr ); // not directly ImplSetText if SetText overridden
2653 : else
2654 : {
2655 8627 : Selection aNewSel( 0, 0 ); // prevent scrolling
2656 8627 : ImplSetText( rStr, &aNewSel );
2657 : }
2658 16657 : }
2659 :
2660 74278 : void Edit::SetText( const OUString& rStr, const Selection& rSelection )
2661 : {
2662 74278 : if ( mpSubEdit )
2663 36840 : mpSubEdit->SetText( rStr, rSelection );
2664 : else
2665 37438 : ImplSetText( rStr, &rSelection );
2666 74278 : }
2667 :
2668 179974 : OUString Edit::GetText() const
2669 : {
2670 179974 : if ( mpSubEdit )
2671 80095 : return mpSubEdit->GetText();
2672 : else
2673 99879 : return maText.toString();
2674 : }
2675 :
2676 0 : void Edit::SetPlaceholderText( const OUString& rStr )
2677 : {
2678 0 : if ( mpSubEdit )
2679 0 : mpSubEdit->SetPlaceholderText( rStr );
2680 0 : else if ( maPlaceholderText != rStr )
2681 : {
2682 0 : maPlaceholderText = rStr;
2683 0 : if ( GetText().isEmpty() )
2684 0 : Invalidate();
2685 : }
2686 0 : }
2687 :
2688 0 : OUString Edit::GetPlaceholderText() const
2689 : {
2690 0 : if ( mpSubEdit )
2691 0 : return mpSubEdit->GetPlaceholderText();
2692 :
2693 0 : return maPlaceholderText;
2694 : }
2695 :
2696 373 : void Edit::SetModifyFlag()
2697 : {
2698 373 : if ( mpSubEdit )
2699 105 : mpSubEdit->mbModified = true;
2700 : else
2701 268 : mbModified = true;
2702 373 : }
2703 :
2704 1 : void Edit::ClearModifyFlag()
2705 : {
2706 1 : if ( mpSubEdit )
2707 0 : mpSubEdit->mbModified = false;
2708 : else
2709 1 : mbModified = false;
2710 1 : }
2711 :
2712 5182 : void Edit::SetSubEdit(Edit* pEdit)
2713 : {
2714 5182 : mpSubEdit.disposeAndClear();
2715 5182 : mpSubEdit.set(pEdit);
2716 :
2717 5182 : if (mpSubEdit)
2718 : {
2719 5182 : SetPointer(PointerStyle::Arrow); // Nur das SubEdit hat den BEAM...
2720 5182 : mpSubEdit->mbIsSubEdit = true;
2721 :
2722 5182 : mpSubEdit->SetReadOnly(mbReadOnly);
2723 5182 : mpSubEdit->autocompleteSignal.connect(autocompleteSignal);
2724 : }
2725 5182 : }
2726 :
2727 16453 : Size Edit::CalcMinimumSizeForText(const OUString &rString) const
2728 : {
2729 16453 : int eCtrlType = ImplGetNativeControlType();
2730 :
2731 16453 : Size aSize;
2732 16453 : if (mnWidthInChars != -1)
2733 : {
2734 : //CalcSize calls CalcWindowSize, but we will call that also in this
2735 : //function, so undo the first one with CalcOutputSize
2736 0 : aSize = CalcOutputSize(CalcSize(mnWidthInChars));
2737 : }
2738 : else
2739 : {
2740 16453 : OUString aString;
2741 16453 : if (mnMaxWidthChars != -1 && mnMaxWidthChars < rString.getLength())
2742 0 : aString = rString.copy(0, mnMaxWidthChars);
2743 : else
2744 16453 : aString = rString;
2745 :
2746 16453 : aSize.Height() = GetTextHeight();
2747 16453 : aSize.Width() = GetTextWidth(aString);
2748 16453 : aSize.Width() += ImplGetExtraXOffset() * 2;
2749 :
2750 : // do not create edit fields in which one cannot enter anything
2751 : // a default minimum width should exist for at least 3 characters
2752 :
2753 : //CalcSize calls CalcWindowSize, but we will call that also in this
2754 : //function, so undo the first one with CalcOutputSize
2755 16453 : Size aMinSize(CalcOutputSize(CalcSize(3)));
2756 16453 : if (aSize.Width() < aMinSize.Width())
2757 6102 : aSize.Width() = aMinSize.Width();
2758 : }
2759 :
2760 16453 : aSize.Height() += ImplGetExtraYOffset() * 2;
2761 :
2762 16453 : aSize = CalcWindowSize( aSize );
2763 :
2764 : // ask NWF what if it has an opinion, too
2765 16453 : ImplControlValue aControlValue;
2766 16453 : Rectangle aRect( Point( 0, 0 ), aSize );
2767 16453 : Rectangle aContent, aBound;
2768 32906 : if (GetNativeControlRegion(eCtrlType, PART_ENTIRE_CONTROL, aRect, ControlState::NONE,
2769 32906 : aControlValue, OUString(), aBound, aContent))
2770 : {
2771 0 : if (aBound.GetHeight() > aSize.Height())
2772 0 : aSize.Height() = aBound.GetHeight();
2773 : }
2774 16453 : return aSize;
2775 : }
2776 :
2777 347 : Size Edit::CalcMinimumSize() const
2778 : {
2779 347 : return CalcMinimumSizeForText(GetText());
2780 : }
2781 :
2782 338 : Size Edit::GetMinimumEditSize()
2783 : {
2784 338 : vcl::Window* pDefWin = ImplGetDefaultWindow();
2785 338 : ScopedVclPtrInstance< Edit > aEdit( pDefWin, WB_BORDER );
2786 338 : Size aSize( aEdit->CalcMinimumSize() );
2787 338 : return aSize;
2788 : }
2789 :
2790 0 : Size Edit::GetOptimalSize() const
2791 : {
2792 0 : return CalcMinimumSize();
2793 : }
2794 :
2795 16454 : Size Edit::CalcSize(sal_Int32 nChars) const
2796 : {
2797 : // width for N characters, independent from content.
2798 : // works only correct for fixed fonts, average otherwise
2799 16454 : Size aSz( GetTextWidth( OUString('x') ), GetTextHeight() );
2800 16454 : aSz.Width() *= nChars;
2801 16454 : aSz.Width() += ImplGetExtraXOffset() * 2;
2802 16454 : aSz = CalcWindowSize( aSz );
2803 16454 : return aSz;
2804 : }
2805 :
2806 13 : sal_Int32 Edit::GetMaxVisChars() const
2807 : {
2808 13 : const vcl::Window* pW = mpSubEdit ? mpSubEdit : this;
2809 13 : sal_Int32 nOutWidth = pW->GetOutputSizePixel().Width();
2810 13 : sal_Int32 nCharWidth = GetTextWidth( OUString('x') );
2811 13 : return nCharWidth ? nOutWidth/nCharWidth : 0;
2812 : }
2813 :
2814 0 : sal_Int32 Edit::GetCharPos( const Point& rWindowPos ) const
2815 : {
2816 0 : return ImplGetCharPos( rWindowPos );
2817 : }
2818 :
2819 208 : void Edit::SetGetSpecialCharsFunction( FncGetSpecialChars fn )
2820 : {
2821 208 : pImplFncGetSpecialChars = fn;
2822 208 : }
2823 :
2824 0 : FncGetSpecialChars Edit::GetGetSpecialCharsFunction()
2825 : {
2826 0 : return pImplFncGetSpecialChars;
2827 : }
2828 :
2829 0 : PopupMenu* Edit::CreatePopupMenu()
2830 : {
2831 0 : ResMgr* pResMgr = ImplGetResMgr();
2832 0 : if( ! pResMgr )
2833 0 : return new PopupMenu();
2834 :
2835 0 : PopupMenu* pPopup = new PopupMenu( ResId( SV_RESID_MENU_EDIT, *pResMgr ) );
2836 0 : const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
2837 0 : if ( rStyleSettings.GetHideDisabledMenuItems() )
2838 0 : pPopup->SetMenuFlags( MenuFlags::HideDisabledEntries );
2839 : else
2840 0 : pPopup->SetMenuFlags ( MenuFlags::AlwaysShowDisabledEntries );
2841 0 : if ( rStyleSettings.GetAcceleratorsInContextMenus() )
2842 : {
2843 0 : pPopup->SetAccelKey( SV_MENU_EDIT_UNDO, vcl::KeyCode( KeyFuncType::UNDO ) );
2844 0 : pPopup->SetAccelKey( SV_MENU_EDIT_CUT, vcl::KeyCode( KeyFuncType::CUT ) );
2845 0 : pPopup->SetAccelKey( SV_MENU_EDIT_COPY, vcl::KeyCode( KeyFuncType::COPY ) );
2846 0 : pPopup->SetAccelKey( SV_MENU_EDIT_PASTE, vcl::KeyCode( KeyFuncType::PASTE ) );
2847 0 : pPopup->SetAccelKey( SV_MENU_EDIT_DELETE, vcl::KeyCode( KeyFuncType::DELETE ) );
2848 0 : pPopup->SetAccelKey( SV_MENU_EDIT_SELECTALL, vcl::KeyCode( KEY_A, false, true, false, false ) );
2849 0 : pPopup->SetAccelKey( SV_MENU_EDIT_INSERTSYMBOL, vcl::KeyCode( KEY_S, true, true, false, false ) );
2850 : }
2851 0 : return pPopup;
2852 : }
2853 :
2854 0 : void Edit::DeletePopupMenu( PopupMenu* pMenu )
2855 : {
2856 0 : delete pMenu;
2857 0 : }
2858 :
2859 : // ::com::sun::star::datatransfer::dnd::XDragGestureListener
2860 0 : void Edit::dragGestureRecognized( const ::com::sun::star::datatransfer::dnd::DragGestureEvent& rDGE ) throw (::com::sun::star::uno::RuntimeException, std::exception)
2861 : {
2862 0 : SolarMutexGuard aVclGuard;
2863 :
2864 0 : if ( !IsTracking() && maSelection.Len() &&
2865 0 : !(GetStyle() & WB_PASSWORD) && (!mpDDInfo || !mpDDInfo->bStarterOfDD) ) // Kein Mehrfach D&D
2866 : {
2867 0 : Selection aSel( maSelection );
2868 0 : aSel.Justify();
2869 :
2870 : // Nur wenn Maus in der Selektion...
2871 0 : Point aMousePos( rDGE.DragOriginX, rDGE.DragOriginY );
2872 0 : sal_Int32 nCharPos = ImplGetCharPos( aMousePos );
2873 0 : if ( (nCharPos >= aSel.Min()) && (nCharPos < aSel.Max()) )
2874 : {
2875 0 : if ( !mpDDInfo )
2876 0 : mpDDInfo = new DDInfo;
2877 :
2878 0 : mpDDInfo->bStarterOfDD = true;
2879 0 : mpDDInfo->aDndStartSel = aSel;
2880 :
2881 0 : if ( IsTracking() )
2882 0 : EndTracking(); // Vor D&D Tracking ausschalten
2883 :
2884 0 : vcl::unohelper::TextDataObject* pDataObj = new vcl::unohelper::TextDataObject( GetSelected() );
2885 0 : sal_Int8 nActions = datatransfer::dnd::DNDConstants::ACTION_COPY;
2886 0 : if ( !IsReadOnly() )
2887 0 : nActions |= datatransfer::dnd::DNDConstants::ACTION_MOVE;
2888 0 : rDGE.DragSource->startDrag( rDGE, nActions, 0 /*cursor*/, 0 /*image*/, pDataObj, mxDnDListener );
2889 0 : if ( GetCursor() )
2890 0 : GetCursor()->Hide();
2891 :
2892 : }
2893 0 : }
2894 0 : }
2895 :
2896 : // ::com::sun::star::datatransfer::dnd::XDragSourceListener
2897 0 : void Edit::dragDropEnd( const ::com::sun::star::datatransfer::dnd::DragSourceDropEvent& rDSDE ) throw (::com::sun::star::uno::RuntimeException, std::exception)
2898 : {
2899 0 : SolarMutexGuard aVclGuard;
2900 :
2901 0 : if ( rDSDE.DropSuccess && ( rDSDE.DropAction & datatransfer::dnd::DNDConstants::ACTION_MOVE ) )
2902 : {
2903 0 : Selection aSel( mpDDInfo->aDndStartSel );
2904 0 : if ( mpDDInfo->bDroppedInMe )
2905 : {
2906 0 : if ( aSel.Max() > mpDDInfo->nDropPos )
2907 : {
2908 0 : long nLen = aSel.Len();
2909 0 : aSel.Min() += nLen;
2910 0 : aSel.Max() += nLen;
2911 : }
2912 : }
2913 0 : ImplDelete( aSel, EDIT_DEL_RIGHT, EDIT_DELMODE_SIMPLE );
2914 0 : ImplModified();
2915 : }
2916 :
2917 0 : ImplHideDDCursor();
2918 0 : delete mpDDInfo;
2919 0 : mpDDInfo = NULL;
2920 0 : }
2921 :
2922 : // ::com::sun::star::datatransfer::dnd::XDropTargetListener
2923 0 : void Edit::drop( const ::com::sun::star::datatransfer::dnd::DropTargetDropEvent& rDTDE ) throw (::com::sun::star::uno::RuntimeException, std::exception)
2924 : {
2925 0 : SolarMutexGuard aVclGuard;
2926 :
2927 0 : bool bChanges = false;
2928 0 : if ( !mbReadOnly && mpDDInfo )
2929 : {
2930 0 : ImplHideDDCursor();
2931 :
2932 0 : Selection aSel( maSelection );
2933 0 : aSel.Justify();
2934 :
2935 0 : if ( aSel.Len() && !mpDDInfo->bStarterOfDD )
2936 0 : ImplDelete( aSel, EDIT_DEL_RIGHT, EDIT_DELMODE_SIMPLE );
2937 :
2938 0 : mpDDInfo->bDroppedInMe = true;
2939 :
2940 0 : aSel.Min() = mpDDInfo->nDropPos;
2941 0 : aSel.Max() = mpDDInfo->nDropPos;
2942 0 : ImplSetSelection( aSel );
2943 :
2944 0 : uno::Reference< datatransfer::XTransferable > xDataObj = rDTDE.Transferable;
2945 0 : if ( xDataObj.is() )
2946 : {
2947 0 : datatransfer::DataFlavor aFlavor;
2948 0 : SotExchange::GetFormatDataFlavor( SotClipboardFormatId::STRING, aFlavor );
2949 0 : if ( xDataObj->isDataFlavorSupported( aFlavor ) )
2950 : {
2951 0 : uno::Any aData = xDataObj->getTransferData( aFlavor );
2952 0 : OUString aText;
2953 0 : aData >>= aText;
2954 0 : ImplInsertText( aText );
2955 0 : bChanges = true;
2956 0 : ImplModified();
2957 0 : }
2958 : }
2959 :
2960 0 : if ( !mpDDInfo->bStarterOfDD )
2961 : {
2962 0 : delete mpDDInfo;
2963 0 : mpDDInfo = NULL;
2964 0 : }
2965 : }
2966 :
2967 0 : rDTDE.Context->dropComplete( bChanges );
2968 0 : }
2969 :
2970 0 : void Edit::dragEnter( const ::com::sun::star::datatransfer::dnd::DropTargetDragEnterEvent& rDTDE ) throw (::com::sun::star::uno::RuntimeException, std::exception)
2971 : {
2972 0 : if ( !mpDDInfo )
2973 : {
2974 0 : mpDDInfo = new DDInfo;
2975 : }
2976 : // search for string data type
2977 0 : const Sequence< com::sun::star::datatransfer::DataFlavor >& rFlavors( rDTDE.SupportedDataFlavors );
2978 0 : sal_Int32 nEle = rFlavors.getLength();
2979 0 : mpDDInfo->bIsStringSupported = false;
2980 0 : for( sal_Int32 i = 0; i < nEle; i++ )
2981 : {
2982 0 : sal_Int32 nIndex = 0;
2983 0 : OUString aMimetype = rFlavors[i].MimeType.getToken( 0, ';', nIndex );
2984 0 : if ( aMimetype == "text/plain" )
2985 : {
2986 0 : mpDDInfo->bIsStringSupported = true;
2987 0 : break;
2988 : }
2989 0 : }
2990 0 : }
2991 :
2992 0 : void Edit::dragExit( const ::com::sun::star::datatransfer::dnd::DropTargetEvent& ) throw (::com::sun::star::uno::RuntimeException, std::exception)
2993 : {
2994 0 : SolarMutexGuard aVclGuard;
2995 :
2996 0 : ImplHideDDCursor();
2997 0 : }
2998 :
2999 0 : void Edit::dragOver( const ::com::sun::star::datatransfer::dnd::DropTargetDragEvent& rDTDE ) throw (::com::sun::star::uno::RuntimeException, std::exception)
3000 : {
3001 0 : SolarMutexGuard aVclGuard;
3002 :
3003 0 : Point aMousePos( rDTDE.LocationX, rDTDE.LocationY );
3004 :
3005 0 : sal_Int32 nPrevDropPos = mpDDInfo->nDropPos;
3006 0 : mpDDInfo->nDropPos = ImplGetCharPos( aMousePos );
3007 :
3008 : /*
3009 : Size aOutSize = GetOutputSizePixel();
3010 : if ( ( aMousePos.X() < 0 ) || ( aMousePos.X() > aOutSize.Width() ) )
3011 : {
3012 : // Scroll?
3013 : // No, I will not receive events in this case....
3014 : }
3015 : */
3016 :
3017 0 : Selection aSel( maSelection );
3018 0 : aSel.Justify();
3019 :
3020 : // Don't accept drop in selection or read-only field...
3021 0 : if ( IsReadOnly() || aSel.IsInside( mpDDInfo->nDropPos ) || ! mpDDInfo->bIsStringSupported )
3022 : {
3023 0 : ImplHideDDCursor();
3024 0 : rDTDE.Context->rejectDrag();
3025 : }
3026 : else
3027 : {
3028 : // Alten Cursor wegzeichnen...
3029 0 : if ( !mpDDInfo->bVisCursor || ( nPrevDropPos != mpDDInfo->nDropPos ) )
3030 : {
3031 0 : ImplHideDDCursor();
3032 0 : ImplShowDDCursor();
3033 : }
3034 0 : rDTDE.Context->acceptDrag( rDTDE.DropAction );
3035 0 : }
3036 0 : }
3037 :
3038 0 : OUString Edit::GetSurroundingText() const
3039 : {
3040 0 : if (mpSubEdit)
3041 0 : return mpSubEdit->GetSurroundingText();
3042 0 : return maText.toString();
3043 : }
3044 :
3045 0 : Selection Edit::GetSurroundingTextSelection() const
3046 : {
3047 0 : return GetSelection();
3048 801 : }
3049 :
3050 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|