1 /*
2 * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 #include "awt_Toolkit.h"
27 #include "awt_TextField.h"
28 #include "awt_TextComponent.h"
29 #include "awt_Canvas.h"
30
31 /* IMPORTANT! Read the README.JNI file for notes on JNI converted AWT code.
32 */
33
34 /***********************************************************************/
35 // struct for _SetEchoChar() method
36 struct SetEchoCharStruct {
37 jobject textfield;
38 jchar echoChar;
39 };
40 /************************************************************************
41 * AwtTextField methods
42 */
43
AwtTextField()44 AwtTextField::AwtTextField()
45 {
46 }
47
48 /* Create a new AwtTextField object and window. */
Create(jobject peer,jobject parent)49 AwtTextField* AwtTextField::Create(jobject peer, jobject parent)
50 {
51 return (AwtTextField*) AwtTextComponent::Create(peer, parent, false);
52 }
53
EditSetSel(CHARRANGE & cr)54 void AwtTextField::EditSetSel(CHARRANGE &cr) {
55 SendMessage(EM_EXSETSEL, 0, reinterpret_cast<LPARAM>(&cr));
56
57 // 6417581: force expected drawing
58 if (IS_WINVISTA && cr.cpMin == cr.cpMax) {
59 ::InvalidateRect(GetHWnd(), NULL, TRUE);
60 }
61
62 }
63
WindowProc(UINT message,WPARAM wParam,LPARAM lParam)64 LRESULT AwtTextField::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
65 {
66 if (message == WM_UNDO || message == EM_UNDO || message == EM_CANUNDO) {
67 if (GetWindowLong(GetHWnd(), GWL_STYLE) & ES_READONLY) {
68 return FALSE;
69 }
70 }
71 return AwtTextComponent::WindowProc(message, wParam, lParam);
72 }
73
74 MsgRouting
HandleEvent(MSG * msg,BOOL synthetic)75 AwtTextField::HandleEvent(MSG *msg, BOOL synthetic)
76 {
77 MsgRouting returnVal;
78 BOOL systemBeeperEnabled = FALSE;
79 /*
80 * RichEdit 1.0 control starts internal message loop if the
81 * left mouse button is pressed while the cursor is not over
82 * the current selection or the current selection is empty.
83 * Because of this we don't receive WM_MOUSEMOVE messages
84 * while the left mouse button is pressed. To work around
85 * this behavior we process the relevant mouse messages
86 * by ourselves.
87 * By consuming WM_MOUSEMOVE messages we also don't give
88 * the RichEdit control a chance to recognize a drag gesture
89 * and initiate its own drag-n-drop operation.
90 *
91 * The workaround also allows us to implement synthetic focus mechanism.
92 */
93 if (IsFocusingMouseMessage(msg)) {
94
95 LONG lCurPos = EditGetCharFromPos(msg->pt);
96
97 /*
98 * NOTE: Plain EDIT control always clears selection on mouse
99 * button press. We are clearing the current selection only if
100 * the mouse pointer is not over the selected region.
101 * In this case we sacrifice backward compatibility
102 * to allow dnd of the current selection.
103 */
104 if (msg->message == WM_LBUTTONDBLCLK) {
105 jchar echo = SendMessage(EM_GETPASSWORDCHAR);
106
107 if(echo == 0){
108 SetStartSelectionPos(static_cast<LONG>(SendMessage(
109 EM_FINDWORDBREAK, WB_MOVEWORDLEFT, lCurPos)));
110 SetEndSelectionPos(static_cast<LONG>(SendMessage(
111 EM_FINDWORDBREAK, WB_MOVEWORDRIGHT, lCurPos)));
112 }else{
113 SetStartSelectionPos(0);
114 SetEndSelectionPos(GetTextLength());
115 }
116
117 } else {
118 SetStartSelectionPos(lCurPos);
119 SetEndSelectionPos(lCurPos);
120 }
121 CHARRANGE cr;
122 cr.cpMin = GetStartSelectionPos();
123 cr.cpMax = GetEndSelectionPos();
124 EditSetSel(cr);
125
126 delete msg;
127 return mrConsume;
128 } else if (msg->message == WM_LBUTTONUP) {
129
130 /*
131 * If the left mouse button is pressed on the selected region
132 * we don't clear the current selection. We clear it on button
133 * release instead. This is to allow dnd of the current selection.
134 */
135 if (GetStartSelectionPos() == -1 && GetEndSelectionPos() == -1) {
136 CHARRANGE cr;
137
138 LONG lCurPos = EditGetCharFromPos(msg->pt);
139
140 cr.cpMin = lCurPos;
141 cr.cpMax = lCurPos;
142 EditSetSel(cr);
143 }
144
145 /*
146 * Cleanup the state variables when left mouse button is released.
147 * These state variables are designed to reflect the selection state
148 * while the left mouse button is pressed and be set to -1 otherwise.
149 */
150 SetStartSelectionPos(-1);
151 SetEndSelectionPos(-1);
152 SetLastSelectionPos(-1);
153
154 delete msg;
155 return mrConsume;
156 } else if (msg->message == WM_MOUSEMOVE && (msg->wParam & MK_LBUTTON)) {
157
158 /*
159 * We consume WM_MOUSEMOVE while the left mouse button is pressed,
160 * so we have to simulate autoscrolling when mouse is moved outside
161 * of the client area.
162 */
163 POINT p;
164 RECT r;
165 BOOL bScrollLeft = FALSE;
166 BOOL bScrollRight = FALSE;
167 BOOL bScrollUp = FALSE;
168 BOOL bScrollDown = FALSE;
169
170 p.x = msg->pt.x;
171 p.y = msg->pt.y;
172 VERIFY(::GetClientRect(GetHWnd(), &r));
173
174 if (p.x < 0) {
175 bScrollLeft = TRUE;
176 p.x = 0;
177 } else if (p.x > r.right) {
178 bScrollRight = TRUE;
179 p.x = r.right - 1;
180 }
181 LONG lCurPos = EditGetCharFromPos(p);
182
183 if (GetStartSelectionPos() != -1 &&
184 GetEndSelectionPos() != -1 &&
185 lCurPos != GetLastSelectionPos()) {
186
187 CHARRANGE cr;
188
189 SetLastSelectionPos(lCurPos);
190
191 cr.cpMin = GetStartSelectionPos();
192 cr.cpMax = GetLastSelectionPos();
193
194 EditSetSel(cr);
195 }
196
197 if (bScrollLeft == TRUE || bScrollRight == TRUE) {
198 SCROLLINFO si;
199 memset(&si, 0, sizeof(si));
200 si.cbSize = sizeof(si);
201 si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
202
203 SendMessage(EM_SHOWSCROLLBAR, SB_HORZ, TRUE);
204 VERIFY(::GetScrollInfo(GetHWnd(), SB_HORZ, &si));
205 SendMessage(EM_SHOWSCROLLBAR, SB_HORZ, FALSE);
206
207 if (bScrollLeft == TRUE) {
208 si.nPos = si.nPos - si.nPage / 2;
209 si.nPos = max(si.nMin, si.nPos);
210 } else if (bScrollRight == TRUE) {
211 si.nPos = si.nPos + si.nPage / 2;
212 si.nPos = min(si.nPos, si.nMax);
213 }
214 /*
215 * Okay to use 16-bit position since RichEdit control adjusts
216 * its scrollbars so that their range is always 16-bit.
217 */
218 DASSERT(abs(si.nPos) < 0x8000);
219 SendMessage(WM_HSCROLL,
220 MAKEWPARAM(SB_THUMBPOSITION, LOWORD(si.nPos)));
221 }
222 delete msg;
223 return mrConsume;
224 } else if (msg->message == WM_KEYDOWN) {
225 UINT virtualKey = (UINT) msg->wParam;
226
227 switch(virtualKey){
228 case VK_RETURN:
229 case VK_UP:
230 case VK_DOWN:
231 case VK_LEFT:
232 case VK_RIGHT:
233 case VK_DELETE:
234 case VK_BACK:
235 SystemParametersInfo(SPI_GETBEEP, 0, &systemBeeperEnabled, 0);
236 if(systemBeeperEnabled){
237 // disable system beeper for the RICHEDIT control to be compatible
238 // with the EDIT control behaviour
239 SystemParametersInfo(SPI_SETBEEP, 0, NULL, 0);
240 }
241 break;
242 }
243 } else if (msg->message == WM_SETTINGCHANGE) {
244 if (msg->wParam == SPI_SETBEEP) {
245 SystemParametersInfo(SPI_GETBEEP, 0, &systemBeeperEnabled, 0);
246 if(systemBeeperEnabled){
247 SystemParametersInfo(SPI_SETBEEP, 1, NULL, 0);
248 }
249 }
250 }
251
252 returnVal = AwtTextComponent::HandleEvent(msg, synthetic);
253
254 if(systemBeeperEnabled){
255 SystemParametersInfo(SPI_SETBEEP, 1, NULL, 0);
256 }
257
258 return returnVal;
259 }
260
_SetEchoChar(void * param)261 void AwtTextField::_SetEchoChar(void *param)
262 {
263 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
264
265 SetEchoCharStruct *secs = (SetEchoCharStruct *)param;
266 jobject self = secs->textfield;
267 jchar echo = secs->echoChar;
268
269 AwtTextField *c = NULL;
270
271 PDATA pData;
272 JNI_CHECK_PEER_GOTO(self, ret);
273 c = (AwtTextField *)pData;
274 if (::IsWindow(c->GetHWnd()))
275 {
276 c->SendMessage(EM_SETPASSWORDCHAR, echo);
277 // Fix for 4307281: force redraw so that changes will take effect
278 VERIFY(::InvalidateRect(c->GetHWnd(), NULL, FALSE));
279 }
280 ret:
281 env->DeleteGlobalRef(self);
282
283 delete secs;
284 }
285
286
287 /************************************************************************
288 * WTextFieldPeer native methods
289 */
290
291 extern "C" {
292
293 /*
294 * Class: sun_awt_windows_WTextFieldPeer
295 * Method: create
296 * Signature: (Lsun/awt/windows/WComponentPeer;)V
297 */
298 JNIEXPORT void JNICALL
Java_sun_awt_windows_WTextFieldPeer_create(JNIEnv * env,jobject self,jobject parent)299 Java_sun_awt_windows_WTextFieldPeer_create(JNIEnv *env, jobject self,
300 jobject parent)
301 {
302 TRY;
303
304 AwtToolkit::CreateComponent(self, parent,
305 (AwtToolkit::ComponentFactory)
306 AwtTextField::Create);
307
308 CATCH_BAD_ALLOC;
309 }
310
311 /*
312 * Class: sun_awt_windows_WTextFieldPeer
313 * Method: setEchoChar
314 * Signature: (C)V
315 */
316 JNIEXPORT void JNICALL
Java_sun_awt_windows_WTextFieldPeer_setEchoChar(JNIEnv * env,jobject self,jchar ch)317 Java_sun_awt_windows_WTextFieldPeer_setEchoChar(JNIEnv *env, jobject self,
318 jchar ch)
319 {
320 TRY;
321
322 SetEchoCharStruct *secs = new SetEchoCharStruct;
323 secs->textfield = env->NewGlobalRef(self);
324 secs->echoChar = ch;
325
326 AwtToolkit::GetInstance().SyncCall(AwtTextField::_SetEchoChar, secs);
327 // global ref and secs are deleted in _SetEchoChar()
328
329 CATCH_BAD_ALLOC;
330 }
331
332 } /* extern "C" */
333