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