1 /*
2 * Copyright (c) 1996, 2016, 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_TextComponent.h"
28 #include "awt_TextArea.h"
29 #include "awt_TextField.h"
30 #include "awt_Canvas.h"
31
32 #include "jni.h"
33 #include "awt_Font.h"
34
35
36 /***********************************************************************/
37 // struct for _SetText() method
38 struct SetTextStruct {
39 jobject textcomponent;
40 jstring text;
41 };
42 // struct for _Select() method
43 struct SelectStruct {
44 jobject textcomponent;
45 jint start, end;
46 };
47 // struct for _EnableEditing() method
48 struct EnableEditingStruct {
49 jobject textcomponent;
50 jboolean on;
51 };
52 /************************************************************************
53 * AwtTextComponent fields
54 */
55
56 /************************************************************************
57 * AwtTextComponent methods
58 */
59
60 jmethodID AwtTextComponent::canAccessClipboardMID;
61
AwtTextComponent()62 AwtTextComponent::AwtTextComponent() {
63 m_synthetic = FALSE;
64 m_lStartPos = -1;
65 m_lEndPos = -1;
66 m_lLastPos = -1;
67 m_isLFonly = FALSE;
68 m_EOLchecked = FALSE;
69 m_hEditCtrl = NULL;
70 m_bIgnoreEnChange = FALSE;
71 // javaEventsMask = 0; // accessibility support
72 }
73
GetClassName()74 LPCTSTR AwtTextComponent::GetClassName() {
75 static BOOL richedLibraryLoaded = FALSE;
76 if (!richedLibraryLoaded) {
77 JDK_LoadSystemLibrary("RICHED20.DLL");
78 richedLibraryLoaded = TRUE;
79 }
80 return RICHEDIT_CLASS;
81 }
82
83 /* Create a new AwtTextArea or AwtTextField object and window. */
Create(jobject peer,jobject parent,BOOL isMultiline)84 AwtTextComponent* AwtTextComponent::Create(jobject peer, jobject parent, BOOL isMultiline)
85 {
86 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
87
88 jobject target = NULL;
89 AwtTextComponent* c = NULL;
90
91 try {
92 if (env->EnsureLocalCapacity(1) < 0) {
93 return NULL;
94 }
95
96 PDATA pData;
97 AwtCanvas* awtParent;
98
99 JNI_CHECK_PEER_GOTO(parent, done);
100 awtParent = (AwtCanvas*)pData;
101
102 target = env->GetObjectField(peer, AwtObject::targetID);
103 JNI_CHECK_NULL_GOTO(target, "null target", done);
104
105 if(isMultiline){
106 c = new AwtTextArea();
107 }else{
108 c = new AwtTextField();
109 }
110
111 {
112 /* Adjust style for scrollbar visibility and word wrap */
113 DWORD scroll_style;
114
115 if(isMultiline){
116
117 jint scrollbarVisibility =
118 env->GetIntField(target, AwtTextArea::scrollbarVisibilityID);
119
120 switch (scrollbarVisibility) {
121 case java_awt_TextArea_SCROLLBARS_NONE:
122 scroll_style = ES_AUTOVSCROLL;
123 break;
124 case java_awt_TextArea_SCROLLBARS_VERTICAL_ONLY:
125 scroll_style = WS_VSCROLL | ES_AUTOVSCROLL;
126 break;
127 case java_awt_TextArea_SCROLLBARS_HORIZONTAL_ONLY:
128 scroll_style = WS_HSCROLL | ES_AUTOHSCROLL | ES_AUTOVSCROLL;
129 break;
130 case java_awt_TextArea_SCROLLBARS_BOTH:
131 default:
132 scroll_style = WS_VSCROLL | WS_HSCROLL |
133 ES_AUTOVSCROLL | ES_AUTOHSCROLL;
134 break;
135 }
136 }
137
138 DWORD style = WS_CHILD | WS_CLIPSIBLINGS | ES_LEFT;
139
140 /*
141 * Specify ES_DISABLENOSCROLL - RichEdit control style to disable
142 * scrollbars instead of hiding them when not needed.
143 */
144 style |= isMultiline ? ES_MULTILINE | ES_WANTRETURN | scroll_style
145 | ES_DISABLENOSCROLL : ES_AUTOHSCROLL;
146
147
148 DWORD exStyle = WS_EX_CLIENTEDGE;
149 if (GetRTL()) {
150 exStyle |= WS_EX_RIGHT | WS_EX_LEFTSCROLLBAR;
151 if (GetRTLReadingOrder())
152 exStyle |= WS_EX_RTLREADING;
153 }
154
155
156 jint x = env->GetIntField(target, AwtComponent::xID);
157 jint y = env->GetIntField(target, AwtComponent::yID);
158 jint width = env->GetIntField(target, AwtComponent::widthID);
159 jint height = env->GetIntField(target, AwtComponent::heightID);
160
161 c->CreateHWnd(env, L"", style, exStyle,
162 x, y, width, height,
163 awtParent->GetHWnd(),
164 reinterpret_cast<HMENU>(static_cast<INT_PTR>(
165 awtParent->CreateControlID())),
166 ::GetSysColor(COLOR_WINDOWTEXT),
167 ::GetSysColor(COLOR_WINDOW),
168 peer);
169
170 // Fix for 4753116.
171 // If it is not win95 (we are using Richedit 2.0)
172 // we set plain text mode, in which the control is
173 // similar to a standard edit control:
174 // - The text in a plain text control can have only
175 // one format.
176 // - The user cannot paste rich text formats, such as RTF
177 // or embedded objects into a plain text control.
178 // - Rich text mode controls always have a default
179 // end-of-document marker or carriage return,
180 // to format paragraphs.
181 // kdm@sparc.spb.su
182 c->SendMessage(EM_SETTEXTMODE, TM_PLAINTEXT, 0);
183
184 c->m_backgroundColorSet = TRUE;
185 /* suppress inheriting parent's color. */
186 c->UpdateBackground(env, target);
187 c->SendMessage(EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN,
188 MAKELPARAM(1, 1));
189 /*
190 * Fix for BugTraq Id 4260109.
191 * Set the text limit to the maximum.
192 * Use EM_EXLIMITTEXT for RichEdit controls.
193 * For some reason RichEdit 1.0 becomes read-only if the
194 * specified limit is greater than 0x7FFFFFFD.
195 */
196 c->SendMessage(EM_EXLIMITTEXT, 0, 0x7FFFFFFD);
197
198 /* Unregister RichEdit built-in drop target. */
199 VERIFY(::RevokeDragDrop(c->GetHWnd()) != DRAGDROP_E_INVALIDHWND);
200
201 /* To enforce CF_TEXT format for paste operations. */
202 VERIFY(c->SendMessage(EM_SETOLECALLBACK, 0,
203 (LPARAM)&GetOleCallback()));
204
205 c->SendMessage(EM_SETEVENTMASK, 0, ENM_CHANGE);
206 }
207 } catch (...) {
208 env->DeleteLocalRef(target);
209 throw;
210 }
211
212 done:
213 env->DeleteLocalRef(target);
214
215 return c;
216 }
217
Dispose()218 void AwtTextComponent::Dispose()
219 {
220 if (m_hEditCtrl != NULL) {
221 VERIFY(::DestroyWindow(m_hEditCtrl));
222 m_hEditCtrl = NULL;
223 }
224 AwtComponent::Dispose();
225 }
226
227
228 LRESULT
WindowProc(UINT message,WPARAM wParam,LPARAM lParam)229 AwtTextComponent::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) {
230
231 switch (message) {
232 case WM_PRINTCLIENT:
233 {
234 FORMATRANGE fr;
235 HDC hPrinterDC = (HDC)wParam;
236 int nHorizRes = ::GetDeviceCaps(hPrinterDC, HORZRES);
237 int nVertRes = ::GetDeviceCaps(hPrinterDC, VERTRES);
238 int nLogPixelsX = ::GetDeviceCaps(hPrinterDC, LOGPIXELSX);
239 int nLogPixelsY = ::GetDeviceCaps(hPrinterDC, LOGPIXELSY);
240
241 // Ensure the printer DC is in MM_TEXT mode.
242 ::SetMapMode ( hPrinterDC, MM_TEXT );
243
244 // Rendering to the same DC we are measuring.
245 ::ZeroMemory(&fr, sizeof(fr));
246 fr.hdc = fr.hdcTarget = hPrinterDC;
247 // Set up the page.
248 fr.rcPage.left = fr.rcPage.top = 0;
249 fr.rcPage.right = (nHorizRes/nLogPixelsX) * 1440; // in twips
250 fr.rcPage.bottom = (nVertRes/nLogPixelsY) * 1440;
251 fr.rc.left = fr.rcPage.left;
252 fr.rc.top = fr.rcPage.top;
253 fr.rc.right = fr.rcPage.right;
254 fr.rc.bottom = fr.rcPage.bottom;
255
256 // start printing from the first visible line
257 LRESULT nLine = SendMessage(EM_GETFIRSTVISIBLELINE, 0, 0);
258 LONG startCh = static_cast<LONG>(SendMessage(EM_LINEINDEX,
259 (WPARAM)nLine, 0));
260 fr.chrg.cpMin = startCh;
261 fr.chrg.cpMax = -1;
262
263 SendMessage(EM_FORMATRANGE, TRUE, (LPARAM)&fr);
264 }
265
266 break;
267 }
268
269 return AwtComponent::WindowProc(message, wParam, lParam);
270 }
271
EditGetCharFromPos(POINT & pt)272 LONG AwtTextComponent::EditGetCharFromPos(POINT& pt) {
273 return static_cast<LONG>(SendMessage(EM_CHARFROMPOS, 0,
274 reinterpret_cast<LPARAM>(&pt)));
275 }
276
277 /* Set a suitable font to IME against the component font. */
SetFont(AwtFont * font)278 void AwtTextComponent::SetFont(AwtFont* font)
279 {
280 DASSERT(font != NULL);
281 if (font->GetAscent() < 0) {
282 AwtFont::SetupAscent(font);
283 }
284
285 int index = font->GetInputHFontIndex();
286 if (index < 0)
287 /* In this case, user cannot get any suitable font for input. */
288 index = 0;
289
290 //im --- changed for over the spot composing
291 m_hFont = font->GetHFont(index);
292 SendMessage(WM_SETFONT, (WPARAM)m_hFont, MAKELPARAM(FALSE, 0));
293 SendMessage(EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN,
294 MAKELPARAM(1, 1));
295
296 /*
297 * WM_SETFONT reverts foreground color to the default for
298 * rich edit controls. So we have to restore it manually.
299 */
300 SetColor(GetColor());
301 VERIFY(::InvalidateRect(GetHWnd(), NULL, TRUE));
302 //im --- end
303
304 }
305
RemoveCR(WCHAR * pStr)306 int AwtTextComponent::RemoveCR(WCHAR *pStr)
307 {
308 int i, nLen = 0;
309
310 if (pStr) {
311 /* check to see if there are any CR's */
312 if (wcschr(pStr, L'\r') == NULL) {
313 return static_cast<int>(wcslen(pStr));
314 }
315
316 for (i=0; pStr[i] != 0; i++) {
317 if (m_isLFonly == TRUE) {
318 if (pStr[i] == L'\r') {
319 continue;
320 }
321 } else {
322 if (pStr[i] == L'\r' && pStr[i + 1] != L'\n') {
323 continue;
324 }
325 }
326 pStr[nLen++] = pStr[i];
327 }
328 pStr[nLen] = 0;
329 }
330 return nLen;
331 }
332
333 MsgRouting
WmNotify(UINT notifyCode)334 AwtTextComponent::WmNotify(UINT notifyCode)
335 {
336 if (notifyCode == EN_CHANGE) {
337 /*
338 * Ignore notifications if the text hasn't been changed.
339 * EN_CHANGE sent on character formatting changes as well.
340 */
341 if (m_bIgnoreEnChange == FALSE) {
342 m_bCanUndo = TRUE;
343 DoCallback("valueChanged", "()V");
344 } else {
345 m_bCanUndo = FALSE;
346 }
347 }
348 return mrDoDefault;
349 }
350
IsFocusingMouseMessage(MSG * pMsg)351 BOOL AwtTextComponent::IsFocusingMouseMessage(MSG *pMsg)
352 {
353 return pMsg->message == WM_LBUTTONDOWN || pMsg->message == WM_LBUTTONDBLCLK;
354 }
355
356 MsgRouting
HandleEvent(MSG * msg,BOOL synthetic)357 AwtTextComponent::HandleEvent(MSG *msg, BOOL synthetic)
358 {
359 MsgRouting returnVal;
360
361 if (msg->message == WM_RBUTTONUP ||
362 (msg->message == WM_SYSKEYDOWN && msg->wParam == VK_F10 &&
363 HIBYTE(::GetKeyState(VK_SHIFT)))) {
364 POINT p;
365 if (msg->message == WM_RBUTTONUP) {
366 VERIFY(::GetCursorPos(&p));
367 } else {
368 p.x = -1;
369 p.y = -1;
370 }
371
372 if (!::PostMessage(GetHWnd(), WM_CONTEXTMENU, (WPARAM)GetHWnd(),
373 MAKELPARAM(p.x, p.y))) {
374 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
375 JNU_ThrowInternalError(env, "Message not posted, native event queue may be full.");
376 env->ExceptionDescribe();
377 env->ExceptionClear();
378 }
379 delete msg;
380 return mrConsume;
381 }
382
383 /*
384 * Store the 'synthetic' parameter so that the WM_PASTE security check
385 * happens only for synthetic events.
386 */
387 m_synthetic = synthetic;
388 returnVal = AwtComponent::HandleEvent(msg, synthetic);
389 m_synthetic = FALSE;
390 return returnVal;
391 }
392
393 /*
394 * If this Paste is occurring because of a synthetic Java event (e.g.,
395 * a synthesized <CTRL>-V KeyEvent), then verify that the TextComponent
396 * has permission to access the Clipboard before pasting. If permission
397 * is denied, we should throw a SecurityException, but currently do not
398 * because when we detect the security violation, we are in the Toolkit
399 * thread, not the thread which dispatched the illegal event.
400 */
401 MsgRouting
WmPaste()402 AwtTextComponent::WmPaste()
403 {
404 if (m_synthetic) {
405 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
406 if (env->EnsureLocalCapacity(1) < 0) {
407 return mrConsume;
408 }
409 jobject target = GetTarget(env);
410 jboolean canAccessClipboard =
411 env->CallBooleanMethod (target, AwtTextComponent::canAccessClipboardMID);
412 env->DeleteLocalRef(target);
413 return (canAccessClipboard) ? mrDoDefault : mrConsume;
414 }
415 else {
416 return mrDoDefault;
417 }
418 }
419
420 //im --- override to over the spot composition
SetCompositionWindow(RECT & rc)421 void AwtTextComponent::SetCompositionWindow(RECT& rc)
422 {
423 HWND hwnd = ImmGetHWnd();
424 HIMC hIMC = ImmGetContext(hwnd);
425 // rc is not used for text component.
426 COMPOSITIONFORM cf = { CFS_FORCE_POSITION, {0,0}, {0,0,0,0} };
427 GetCaretPos(&(cf.ptCurrentPos));
428 // the proxy is the native focus owner and it contains the composition window
429 // let's convert the position to a coordinate space relative to proxy
430 ::MapWindowPoints(GetHWnd(), GetProxyFocusOwner(), (LPPOINT)&cf.ptCurrentPos, 1);
431 ImmSetCompositionWindow(hIMC, &cf);
432
433 LOGFONT lf;
434 GetObject(m_hFont, sizeof(LOGFONT), &lf);
435 ImmSetCompositionFont(hIMC, &lf);
436 ImmReleaseContext(hwnd, hIMC);
437 }
438 //im --- end
439
getJavaSelPos(LONG orgPos)440 LONG AwtTextComponent::getJavaSelPos(LONG orgPos)
441 {
442 long wlen;
443 long pos = 0;
444 long cur = 0;
445 LPTSTR wbuf;
446
447 if ((wlen = GetTextLength()) == 0)
448 return 0;
449 wbuf = new TCHAR[wlen + 1];
450 GetText(wbuf, wlen + 1);
451 if (m_isLFonly == TRUE) {
452 wlen = RemoveCR(wbuf);
453 }
454
455 while (cur < orgPos && pos++ < wlen) {
456 if (wbuf[cur] == _T('\r') && wbuf[cur + 1] == _T('\n')) {
457 cur++;
458 }
459 cur++;
460 }
461 delete[] wbuf;
462 return pos;
463 }
464
getWin32SelPos(LONG orgPos)465 LONG AwtTextComponent::getWin32SelPos(LONG orgPos)
466 {
467 long wlen;
468 long pos = 0;
469 long cur = 0;
470 LPTSTR wbuf;
471
472 if ((wlen = GetTextLength()) == 0)
473 return 0;
474 wbuf = new TCHAR[wlen + 1];
475 GetText(wbuf, wlen + 1);
476 if (m_isLFonly == TRUE) {
477 RemoveCR(wbuf);
478 }
479
480 while (cur < orgPos && pos < wlen) {
481 if (wbuf[pos] == _T('\r') && wbuf[pos + 1] == _T('\n')) {
482 pos++;
483 }
484 pos++;
485 cur++;
486 }
487 delete[] wbuf;
488 return pos;
489 }
490
CheckLineSeparator(WCHAR * pStr)491 void AwtTextComponent::CheckLineSeparator(WCHAR *pStr)
492 {
493 if (pStr == NULL) {
494 return;
495 }
496
497 if (GetTextLength() == 0) {
498 m_EOLchecked = FALSE;
499 }
500
501 // check to see if there are any LF's
502 if (m_EOLchecked == TRUE || wcschr(pStr, L'\n') == NULL) {
503 return;
504 }
505
506 for (int i=0; pStr[i] != 0; i++) {
507 if (pStr[i] == L'\n') {
508 if (i > 0 && pStr[i-1] == L'\r') {
509 m_isLFonly = FALSE;
510 } else {
511 m_isLFonly = TRUE;
512 }
513 m_EOLchecked = TRUE;
514 return;
515 }
516 }
517 }
518
SetSelRange(LONG start,LONG end)519 void AwtTextComponent::SetSelRange(LONG start, LONG end)
520 {
521 SendMessage(EM_SETSEL,
522 getWin32SelPos(start),
523 getWin32SelPos(end));
524 // it isn't necessary to wrap this in EM_HIDESELECTION or setting/clearing
525 // ES_NOHIDESEL, as regular edit control honors EM_SCROLLCARET even when not in focus
526 }
527
_GetText(void * param)528 jstring AwtTextComponent::_GetText(void *param)
529 {
530 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
531
532 jobject self = (jobject)param;
533
534 AwtTextComponent *c = NULL;
535 jstring result = NULL;
536
537 PDATA pData;
538 JNI_CHECK_PEER_GOTO(self, ret);
539
540 c = (AwtTextComponent *)pData;
541 if (::IsWindow(c->GetHWnd()))
542 {
543 int len = ::GetWindowTextLength(c->GetHWnd());
544 if (len == 0) {
545 /* Make java null string */
546 jchar *jc = new jchar[0];
547 result = env->NewString(jc, 0);
548 delete [] jc;
549 } else {
550 WCHAR* buf = new WCHAR[len + 1];
551 c->GetText(buf, len + 1);
552 c->RemoveCR(buf);
553 result = JNU_NewStringPlatform(env, buf);
554 delete [] buf;
555 }
556 }
557 ret:
558 env->DeleteGlobalRef(self);
559
560 if (result != NULL)
561 {
562 jstring globalRef = (jstring)env->NewGlobalRef(result);
563 env->DeleteLocalRef(result);
564 return globalRef;
565 }
566 else
567 {
568 return NULL;
569 }
570 }
571
_SetText(void * param)572 void AwtTextComponent::_SetText(void *param)
573 {
574 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
575
576 SetTextStruct *sts = (SetTextStruct *)param;
577 jobject self = sts->textcomponent;
578 jstring text = sts->text;
579
580 AwtTextComponent *c = NULL;
581
582 PDATA pData;
583 JNI_CHECK_PEER_GOTO(self, ret);
584 c = (AwtTextComponent *)pData;
585 if (::IsWindow(c->GetHWnd()))
586 {
587 int length = env->GetStringLength(text);
588 WCHAR* buffer = new WCHAR[length + 1];
589 env->GetStringRegion(text, 0, length, reinterpret_cast<jchar*>(buffer));
590 buffer[length] = 0;
591 c->CheckLineSeparator(buffer);
592 c->RemoveCR(buffer);
593 c->SetText(buffer);
594 delete[] buffer;
595 }
596 ret:
597 env->DeleteGlobalRef(self);
598 env->DeleteGlobalRef(text);
599
600 delete sts;
601 }
602
_GetSelectionStart(void * param)603 jint AwtTextComponent::_GetSelectionStart(void *param)
604 {
605 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
606
607 jobject self = (jobject)param;
608
609 jint result = 0;
610 AwtTextComponent *c = NULL;
611
612 PDATA pData;
613 JNI_CHECK_PEER_GOTO(self, ret);
614 c = (AwtTextComponent *)pData;
615 if (::IsWindow(c->GetHWnd()))
616 {
617 long start;
618 c->SendMessage(EM_GETSEL, (WPARAM)&start);
619 result = c->getJavaSelPos(start);
620 }
621 ret:
622 env->DeleteGlobalRef(self);
623
624 return result;
625 }
626
_GetSelectionEnd(void * param)627 jint AwtTextComponent::_GetSelectionEnd(void *param)
628 {
629 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
630
631 jobject self = (jobject)param;
632
633 jint result = 0;
634 AwtTextComponent *c = NULL;
635
636 PDATA pData;
637 JNI_CHECK_PEER_GOTO(self, ret);
638 c = (AwtTextComponent *)pData;
639 if (::IsWindow(c->GetHWnd()))
640 {
641 long end;
642 c->SendMessage(EM_GETSEL, 0, (LPARAM)&end);
643 result = c->getJavaSelPos(end);
644 }
645 ret:
646 env->DeleteGlobalRef(self);
647
648 return result;
649 }
650
_Select(void * param)651 void AwtTextComponent::_Select(void *param)
652 {
653 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
654
655 SelectStruct *ss = (SelectStruct *)param;
656 jobject self = ss->textcomponent;
657 jint start = ss->start;
658 jint end = ss->end;
659
660 AwtTextComponent *c = NULL;
661
662 PDATA pData;
663 JNI_CHECK_PEER_GOTO(self, ret);
664 c = (AwtTextComponent *)pData;
665 if (::IsWindow(c->GetHWnd()))
666 {
667 c->SetSelRange(start, end);
668 c->SendMessage(EM_SCROLLCARET);
669 }
670 ret:
671 env->DeleteGlobalRef(self);
672
673 delete ss;
674 }
675
_EnableEditing(void * param)676 void AwtTextComponent::_EnableEditing(void *param)
677 {
678 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
679
680 EnableEditingStruct *ees = (EnableEditingStruct *)param;
681 jobject self = ees->textcomponent;
682 jboolean on = ees->on;
683
684 AwtTextComponent *c = NULL;
685
686 PDATA pData;
687 JNI_CHECK_PEER_GOTO(self, ret);
688 c = (AwtTextComponent *)pData;
689 if (::IsWindow(c->GetHWnd()))
690 {
691 c->SendMessage(EM_SETREADONLY, !on);
692 }
693 ret:
694 env->DeleteGlobalRef(self);
695
696 delete ees;
697 }
698
699 /*
700 * Disabled edit control has grayed foreground.
701 * Disabled RichEdit 1.0 control has original foreground.
702 * Thus we have to set grayed foreground manually.
703 */
Enable(BOOL bEnable)704 void AwtTextComponent::Enable(BOOL bEnable)
705 {
706 AwtComponent::Enable(bEnable);
707 SetColor(GetColor());
708 }
709
710
711 /*
712 * WM_CTLCOLOR is not sent by rich edit controls.
713 * Use EM_SETCHARFORMAT and EM_SETBKGNDCOLOR to set
714 * respectively foreground and background color.
715 */
SetColor(COLORREF c)716 void AwtTextComponent::SetColor(COLORREF c) {
717 AwtComponent::SetColor(c);
718
719 CHARFORMAT cf;
720 memset(&cf, 0, sizeof(cf));
721 cf.cbSize = sizeof(cf);
722 cf.dwMask = CFM_COLOR;
723
724 cf.crTextColor = ::IsWindowEnabled(GetHWnd()) ? GetColor() : ::GetSysColor(COLOR_3DSHADOW);
725
726 /*
727 * The documentation for EM_GETCHARFORMAT is not exactly
728 * correct. It appears that wParam has the same meaning
729 * as for EM_SETCHARFORMAT. Our task is to secure that
730 * all the characters in the control have the required
731 * formatting. That's why we use SCF_ALL.
732 */
733 VERIFY(SendMessage(EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&cf));
734 VERIFY(SendMessage(EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM)&cf));
735 }
736
737 /*
738 * In responce to EM_SETBKGNDCOLOR rich edit changes
739 * its bg color and repaints itself so we don't need
740 * to force repaint.
741 */
SetBackgroundColor(COLORREF c)742 void AwtTextComponent::SetBackgroundColor(COLORREF c) {
743 AwtComponent::SetBackgroundColor(c);
744 SendMessage(EM_SETBKGNDCOLOR, (WPARAM)FALSE, (LPARAM)GetBackgroundColor());
745 }
746
EditGetSel(CHARRANGE & cr)747 void AwtTextComponent::EditGetSel(CHARRANGE &cr) {
748 SendMessage(EM_EXGETSEL, 0, reinterpret_cast<LPARAM>(&cr));
749 }
750
751
752 /************************************************************************
753 * WTextComponentPeer native methods
754 */
755
756 extern "C" {
757
758 /*
759 * Class: sun_awt_windows_WTextComponentPeer
760 * Method: getText
761 * Signature: ()Ljava/lang/String;
762 */
763 JNIEXPORT jstring JNICALL
Java_sun_awt_windows_WTextComponentPeer_getText(JNIEnv * env,jobject self)764 Java_sun_awt_windows_WTextComponentPeer_getText(JNIEnv *env, jobject self)
765 {
766 TRY;
767
768 jobject selfGlobalRef = env->NewGlobalRef(self);
769
770 jstring globalRef = (jstring)AwtToolkit::GetInstance().SyncCall(
771 (void*(*)(void*))AwtTextComponent::_GetText,
772 (void *)selfGlobalRef);
773 // selfGlobalRef is deleted in _GetText
774 if (globalRef != NULL)
775 {
776 jstring localRef = (jstring)env->NewLocalRef(globalRef);
777 env->DeleteGlobalRef(globalRef);
778 return localRef;
779 }
780 else
781 {
782 return NULL;
783 }
784
785 CATCH_BAD_ALLOC_RET(NULL);
786 }
787
788 /*
789 * Class: sun_awt_windows_WTextComponentPeer
790 * Method: setText
791 * Signature: (Ljava/lang/String;)V
792 */
793 JNIEXPORT void JNICALL
Java_sun_awt_windows_WTextComponentPeer_setText(JNIEnv * env,jobject self,jstring text)794 Java_sun_awt_windows_WTextComponentPeer_setText(JNIEnv *env, jobject self,
795 jstring text)
796 {
797 TRY;
798
799 SetTextStruct *sts = new SetTextStruct;
800 sts->textcomponent = env->NewGlobalRef(self);
801 sts->text = (jstring)env->NewGlobalRef(text);
802
803 AwtToolkit::GetInstance().SyncCall(AwtTextComponent::_SetText, sts);
804 // global refs and sts are deleted in _SetText
805
806 CATCH_BAD_ALLOC;
807 }
808
809 /*
810 * Class: sun_awt_windows_WTextComponentPeer
811 * Method: getSelectionStart
812 * Signature: ()I
813 */
814 JNIEXPORT jint JNICALL
Java_sun_awt_windows_WTextComponentPeer_getSelectionStart(JNIEnv * env,jobject self)815 Java_sun_awt_windows_WTextComponentPeer_getSelectionStart(JNIEnv *env,
816 jobject self)
817 {
818 TRY;
819
820 return static_cast<jint>(reinterpret_cast<INT_PTR>(AwtToolkit::GetInstance().SyncCall(
821 (void *(*)(void *))AwtTextComponent::_GetSelectionStart,
822 env->NewGlobalRef(self))));
823 // global ref is deleted in _GetSelectionStart()
824
825 CATCH_BAD_ALLOC_RET(0);
826 }
827
828 /*
829 * Class: sun_awt_windows_WTextComponentPeer
830 * Method: getSelectionEnd
831 * Signature: ()I
832 */
833 JNIEXPORT jint JNICALL
Java_sun_awt_windows_WTextComponentPeer_getSelectionEnd(JNIEnv * env,jobject self)834 Java_sun_awt_windows_WTextComponentPeer_getSelectionEnd(JNIEnv *env,
835 jobject self)
836 {
837 TRY;
838
839 return static_cast<jint>(reinterpret_cast<INT_PTR>(AwtToolkit::GetInstance().SyncCall(
840 (void *(*)(void *))AwtTextComponent::_GetSelectionEnd,
841 env->NewGlobalRef(self))));
842 // global ref is deleted in _GetSelectionEnd()
843
844 CATCH_BAD_ALLOC_RET(0);
845 }
846
847 /*
848 * Class: sun_awt_windows_WTextComponentPeer
849 * Method: select
850 * Signature: (II)V
851 */
852 JNIEXPORT void JNICALL
Java_sun_awt_windows_WTextComponentPeer_select(JNIEnv * env,jobject self,jint start,jint end)853 Java_sun_awt_windows_WTextComponentPeer_select(JNIEnv *env, jobject self,
854 jint start, jint end)
855 {
856 TRY;
857
858 SelectStruct *ss = new SelectStruct;
859 ss->textcomponent = env->NewGlobalRef(self);
860 ss->start = start;
861 ss->end = end;
862
863 AwtToolkit::GetInstance().SyncCall(AwtTextComponent::_Select, ss);
864 // global ref and ss are deleted in _Select
865
866 CATCH_BAD_ALLOC;
867 }
868
869 /*
870 * Class: sun_awt_windows_WTextComponentPeer
871 * Method: enableEditing
872 * Signature: (Z)V
873 */
874 JNIEXPORT void JNICALL
Java_sun_awt_windows_WTextComponentPeer_enableEditing(JNIEnv * env,jobject self,jboolean on)875 Java_sun_awt_windows_WTextComponentPeer_enableEditing(JNIEnv *env,
876 jobject self,
877 jboolean on)
878 {
879 TRY;
880
881 EnableEditingStruct *ees = new EnableEditingStruct;
882 ees->textcomponent = env->NewGlobalRef(self);
883 ees->on = on;
884
885 AwtToolkit::GetInstance().SyncCall(AwtTextComponent::_EnableEditing, ees);
886 // global ref and ees are deleted in _EnableEditing()
887
888 CATCH_BAD_ALLOC;
889 }
890
891 /*
892 * Class: sun_awt_windows_WTextComponentPeer
893 * Method: initIDs
894 * Signature: ()V
895 */
896 JNIEXPORT void JNICALL
Java_sun_awt_windows_WTextComponentPeer_initIDs(JNIEnv * env,jclass cls)897 Java_sun_awt_windows_WTextComponentPeer_initIDs(JNIEnv *env, jclass cls)
898 {
899 TRY;
900
901 jclass textComponentClassID = env->FindClass("java/awt/TextComponent");
902 CHECK_NULL(textComponentClassID);
903
904 AwtTextComponent::canAccessClipboardMID =
905 env->GetMethodID(textComponentClassID, "canAccessClipboard", "()Z");
906 env->DeleteLocalRef(textComponentClassID);
907
908 DASSERT(AwtTextComponent::canAccessClipboardMID != NULL);
909
910 CATCH_BAD_ALLOC;
911 }
912
913
914 AwtTextComponent::OleCallback AwtTextComponent::sm_oleCallback;
915
916 /************************************************************************
917 * Inner class OleCallback definition.
918 */
919
OleCallback()920 AwtTextComponent::OleCallback::OleCallback() {
921 m_refs = 0;
922 AddRef();
923 }
924
925 STDMETHODIMP
QueryInterface(REFIID riid,LPVOID * ppvObj)926 AwtTextComponent::OleCallback::QueryInterface(REFIID riid, LPVOID * ppvObj) {
927 if (::IsEqualIID(riid, IID_IUnknown) ||::IsEqualIID(riid, IID_IRichEditOleCallback) ) {
928 *ppvObj = static_cast<IRichEditOleCallback*>(this);
929 AddRef();
930 return S_OK;
931 }
932 *ppvObj = NULL;
933 return E_NOINTERFACE;
934 }
935
936
STDMETHODIMP_(ULONG)937 STDMETHODIMP_(ULONG)
938 AwtTextComponent::OleCallback::AddRef() {
939 return ++m_refs;
940 }
941
STDMETHODIMP_(ULONG)942 STDMETHODIMP_(ULONG)
943 AwtTextComponent::OleCallback::Release() {
944 return (ULONG)--m_refs;
945 }
946
947 STDMETHODIMP
GetNewStorage(LPSTORAGE FAR * ppstg)948 AwtTextComponent::OleCallback::GetNewStorage(LPSTORAGE FAR * ppstg) {
949 return E_NOTIMPL;
950 }
951
952 STDMETHODIMP
GetInPlaceContext(LPOLEINPLACEFRAME FAR * ppipframe,LPOLEINPLACEUIWINDOW FAR * ppipuiDoc,LPOLEINPLACEFRAMEINFO pipfinfo)953 AwtTextComponent::OleCallback::GetInPlaceContext(LPOLEINPLACEFRAME FAR * ppipframe,
954 LPOLEINPLACEUIWINDOW FAR* ppipuiDoc,
955 LPOLEINPLACEFRAMEINFO pipfinfo)
956 {
957 return E_NOTIMPL;
958 }
959
960 STDMETHODIMP
ShowContainerUI(BOOL fShow)961 AwtTextComponent::OleCallback::ShowContainerUI(BOOL fShow) {
962 return E_NOTIMPL;
963 }
964
965 STDMETHODIMP
QueryInsertObject(LPCLSID pclsid,LPSTORAGE pstg,LONG cp)966 AwtTextComponent::OleCallback::QueryInsertObject(LPCLSID pclsid,
967 LPSTORAGE pstg,
968 LONG cp) {
969 return S_OK;
970 }
971
972 STDMETHODIMP
DeleteObject(LPOLEOBJECT poleobj)973 AwtTextComponent::OleCallback::DeleteObject(LPOLEOBJECT poleobj) {
974 return S_OK;
975 }
976
977 STDMETHODIMP
QueryAcceptData(LPDATAOBJECT pdataobj,CLIPFORMAT * pcfFormat,DWORD reco,BOOL fReally,HGLOBAL hMetaPict)978 AwtTextComponent::OleCallback::QueryAcceptData(LPDATAOBJECT pdataobj,
979 CLIPFORMAT *pcfFormat,
980 DWORD reco,
981 BOOL fReally,
982 HGLOBAL hMetaPict) {
983 if (reco == RECO_PASTE) {
984 // If CF_TEXT format is available edit controls will select it,
985 // otherwise if it is CF_UNICODETEXT is available it will be
986 // selected, otherwise if CF_OEMTEXT is available it will be selected.
987 if (::IsClipboardFormatAvailable(CF_TEXT)) {
988 *pcfFormat = CF_TEXT;
989 } else if (::IsClipboardFormatAvailable(CF_UNICODETEXT)) {
990 *pcfFormat = CF_UNICODETEXT;
991 } else if (::IsClipboardFormatAvailable(CF_OEMTEXT)) {
992 *pcfFormat = CF_OEMTEXT;
993 } else {
994 // Don't allow rich edit to paste clipboard data
995 // in other formats.
996 *pcfFormat = CF_TEXT;
997 }
998 }
999
1000 return S_OK;
1001 }
1002
1003 STDMETHODIMP
ContextSensitiveHelp(BOOL fEnterMode)1004 AwtTextComponent::OleCallback::ContextSensitiveHelp(BOOL fEnterMode) {
1005 return S_OK;
1006 }
1007
1008 STDMETHODIMP
GetClipboardData(CHARRANGE * pchrg,DWORD reco,LPDATAOBJECT * ppdataobj)1009 AwtTextComponent::OleCallback::GetClipboardData(CHARRANGE *pchrg,
1010 DWORD reco,
1011 LPDATAOBJECT *ppdataobj) {
1012 return E_NOTIMPL;
1013 }
1014
1015 STDMETHODIMP
GetDragDropEffect(BOOL fDrag,DWORD grfKeyState,LPDWORD pdwEffect)1016 AwtTextComponent::OleCallback::GetDragDropEffect(BOOL fDrag,
1017 DWORD grfKeyState,
1018 LPDWORD pdwEffect) {
1019
1020 return E_NOTIMPL;
1021 }
1022
1023
1024 STDMETHODIMP
GetContextMenu(WORD seltype,LPOLEOBJECT lpoleobj,CHARRANGE FAR * lpchrg,HMENU FAR * lphmenu)1025 AwtTextComponent::OleCallback::GetContextMenu(WORD seltype,
1026 LPOLEOBJECT lpoleobj,
1027 CHARRANGE FAR * lpchrg,
1028 HMENU FAR * lphmenu) {
1029 return E_NOTIMPL;
1030 }
1031
1032
1033 /*
1034 * This routine is a window procedure for the subclass of the standard edit control
1035 * used to generate context menu. RichEdit controls don't have built-in context menu.
1036 * To implement this functionality we have to create an invisible edit control and
1037 * forward WM_CONTEXTMENU messages from a RichEdit control to this helper edit control.
1038 * While the edit control context menu is active we intercept the message generated in
1039 * response to particular item selection and forward it back to the RichEdit control.
1040 * (See AwtTextArea::WmContextMenu for more details).
1041 */
1042
1043 WNDPROC AwtTextComponent::sm_pDefWindowProc = NULL;
1044
1045 LRESULT
EditProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)1046 AwtTextComponent::EditProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
1047
1048 static BOOL bContextMenuActive = FALSE;
1049
1050 LRESULT retValue = 0;
1051 MsgRouting mr = mrDoDefault;
1052
1053 DASSERT(::IsWindow(::GetParent(hWnd)));
1054
1055 switch (message) {
1056 case WM_UNDO:
1057 case WM_CUT:
1058 case WM_COPY:
1059 case WM_PASTE:
1060 case WM_CLEAR:
1061 case EM_SETSEL:
1062 if (bContextMenuActive) {
1063 ::SendMessage(::GetParent(hWnd), message, wParam, lParam);
1064 mr = mrConsume;
1065 }
1066 break;
1067 case WM_CONTEXTMENU:
1068 bContextMenuActive = TRUE;
1069 break;
1070 }
1071
1072 if (mr == mrDoDefault) {
1073 DASSERT(sm_pDefWindowProc != NULL);
1074 retValue = ::CallWindowProc(sm_pDefWindowProc,
1075 hWnd, message, wParam, lParam);
1076 }
1077
1078 if (message == WM_CONTEXTMENU) {
1079 bContextMenuActive = FALSE;
1080 }
1081
1082 return retValue;
1083 }
1084
1085 MsgRouting
WmContextMenu(HWND hCtrl,UINT xPos,UINT yPos)1086 AwtTextComponent::WmContextMenu(HWND hCtrl, UINT xPos, UINT yPos) {
1087 /* Use the system provided edit control class to generate context menu. */
1088 if (m_hEditCtrl == NULL) {
1089 DWORD dwStyle = WS_CHILD;
1090 DWORD dwExStyle = 0;
1091 m_hEditCtrl = ::CreateWindowEx(dwExStyle,
1092 L"EDIT",
1093 L"TEXT",
1094 dwStyle,
1095 0, 0, 0, 0,
1096 GetHWnd(),
1097 reinterpret_cast<HMENU>(
1098 static_cast<INT_PTR>(
1099 CreateControlID())),
1100 AwtToolkit::GetInstance().GetModuleHandle(),
1101 NULL);
1102 DASSERT(m_hEditCtrl != NULL);
1103 if (sm_pDefWindowProc == NULL) {
1104 sm_pDefWindowProc = (WNDPROC)::GetWindowLongPtr(m_hEditCtrl,
1105 GWLP_WNDPROC);
1106 }
1107 ::SetLastError(0);
1108 INT_PTR ret = ::SetWindowLongPtr(m_hEditCtrl, GWLP_WNDPROC,
1109 (INT_PTR)AwtTextArea::EditProc);
1110 DASSERT(ret != 0 || ::GetLastError() == 0);
1111 }
1112
1113 /*
1114 * Tricks on the edit control to ensure that its context menu has
1115 * the correct set of enabled items according to the RichEdit state.
1116 */
1117 ::SetWindowText(m_hEditCtrl, TEXT("TEXT"));
1118
1119 if (m_bCanUndo == TRUE && SendMessage(EM_CANUNDO)) {
1120 /* Enable 'Undo' item. */
1121 ::SendMessage(m_hEditCtrl, WM_CHAR, 'A', 0);
1122 }
1123
1124 {
1125 /*
1126 * Initial selection for the edit control - (0,1).
1127 * This enables 'Cut', 'Copy' and 'Delete' and 'Select All'.
1128 */
1129 INT nStart = 0;
1130 INT nEnd = 1;
1131 if (SendMessage(EM_SELECTIONTYPE) == SEL_EMPTY) {
1132 /*
1133 * RichEdit selection is empty - clear selection of the edit control.
1134 * This disables 'Cut', 'Copy' and 'Delete'.
1135 */
1136 nStart = -1;
1137 nEnd = 0;
1138 } else {
1139
1140 CHARRANGE cr;
1141 EditGetSel(cr);
1142 /* Check if all the text is selected. */
1143 if (cr.cpMin == 0) {
1144
1145 int len = ::GetWindowTextLength(GetHWnd());
1146 if (cr.cpMin == 0 && cr.cpMax >= len) {
1147 /*
1148 * All the text is selected in RichEdit - select all the
1149 * text in the edit control. This disables 'Select All'.
1150 */
1151 nStart = 0;
1152 nEnd = -1;
1153 }
1154 }
1155 }
1156 ::SendMessage(m_hEditCtrl, EM_SETSEL, (WPARAM)nStart, (LPARAM)nEnd);
1157 }
1158
1159 /* Disable 'Paste' item if the RichEdit control is read-only. */
1160 ::SendMessage(m_hEditCtrl, EM_SETREADONLY,
1161 GetStyle() & ES_READONLY ? TRUE : FALSE, 0);
1162
1163 POINT p;
1164 p.x = xPos;
1165 p.y = yPos;
1166
1167 /*
1168 * If the context menu is requested with SHIFT+F10 or VK_APPS key,
1169 * we position its top left corner to the center of the RichEdit
1170 * client rect.
1171 */
1172 if (p.x == -1 && p.y == -1) {
1173 RECT r;
1174 VERIFY(::GetClientRect(GetHWnd(), &r));
1175 p.x = (r.left + r.right) / 2;
1176 p.y = (r.top + r.bottom) / 2;
1177 VERIFY(::ClientToScreen(GetHWnd(), &p));
1178 }
1179
1180 // The context menu steals focus from the proxy.
1181 // So, set the focus-restore flag up.
1182 SetRestoreFocus(TRUE);
1183 ::SendMessage(m_hEditCtrl, WM_CONTEXTMENU, (WPARAM)m_hEditCtrl, MAKELPARAM(p.x, p.y));
1184 SetRestoreFocus(FALSE);
1185
1186 return mrConsume;
1187 }
1188
1189 //
1190 // Accessibility support
1191 //
1192
1193 // [[[FIXME]]] need to switch to rich edit field; look for EN_SELCHANGE event instead
1194 /*
1195 * Handle WmKeyDown to catch keystrokes which may move the caret,
1196 * and fire events as appropriate when that happens, if they are wanted
1197 *
1198 * Note: mouse clicks come through WmKeyDown as well (do they??!?!)
1199 *
1200 MsgRouting AwtTextComponent::WmKeyDown(UINT wkey, UINT repCnt,
1201 UINT flags, BOOL system) {
1202
1203 printf("AwtTextComponent::WmKeyDown called\r\n");
1204
1205
1206 // NOTE: WmKeyDown won't be processed 'till well after we return
1207 // so we need to modify the values based on the keystroke
1208 //
1209 static long oldStart = -1;
1210 static long oldEnd = -1;
1211
1212 // most keystrokes can move the caret
1213 // so we'll simply check to see if the caret has moved!
1214 if (javaEventsMask & (jlong) java_awt_TextComponent_textSelectionMask) {
1215 long start;
1216 long end;
1217 SendMessage(EM_GETSEL, (WPARAM)&start, (LPARAM)&end);
1218 if (start != oldStart || end != oldEnd) {
1219
1220 printf(" -> calling TextComponent.selectionValuesChanged()\r\n");
1221 printf(" -> old = (%d, %d); new = (%d, %d)\r\n",
1222 oldStart, oldEnd, start, end);
1223
1224 DoCallback("selectionValuesChanged", "(II)V", start, end); // let Java-side track details...
1225 oldStart = start;
1226 oldEnd = end;
1227 }
1228 }
1229
1230 return AwtComponent::WmKeyDown(wkey, repCnt, flags, system);
1231 }
1232 */
1233 } /* extern "C" */
1234