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