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