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_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 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 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 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 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. */ 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 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 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 351 BOOL AwtTextComponent::IsFocusingMouseMessage(MSG *pMsg) 352 { 353 return pMsg->message == WM_LBUTTONDOWN || pMsg->message == WM_LBUTTONDBLCLK; 354 } 355 356 MsgRouting 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 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 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 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 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 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 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 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 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 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 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 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 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 */ 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 */ 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 */ 742 void AwtTextComponent::SetBackgroundColor(COLORREF c) { 743 AwtComponent::SetBackgroundColor(c); 744 SendMessage(EM_SETBKGNDCOLOR, (WPARAM)FALSE, (LPARAM)GetBackgroundColor()); 745 } 746 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 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 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 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 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 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 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 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 920 AwtTextComponent::OleCallback::OleCallback() { 921 m_refs = 0; 922 AddRef(); 923 } 924 925 STDMETHODIMP 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 937 STDMETHODIMP_(ULONG) 938 AwtTextComponent::OleCallback::AddRef() { 939 return ++m_refs; 940 } 941 942 STDMETHODIMP_(ULONG) 943 AwtTextComponent::OleCallback::Release() { 944 return (ULONG)--m_refs; 945 } 946 947 STDMETHODIMP 948 AwtTextComponent::OleCallback::GetNewStorage(LPSTORAGE FAR * ppstg) { 949 return E_NOTIMPL; 950 } 951 952 STDMETHODIMP 953 AwtTextComponent::OleCallback::GetInPlaceContext(LPOLEINPLACEFRAME FAR * ppipframe, 954 LPOLEINPLACEUIWINDOW FAR* ppipuiDoc, 955 LPOLEINPLACEFRAMEINFO pipfinfo) 956 { 957 return E_NOTIMPL; 958 } 959 960 STDMETHODIMP 961 AwtTextComponent::OleCallback::ShowContainerUI(BOOL fShow) { 962 return E_NOTIMPL; 963 } 964 965 STDMETHODIMP 966 AwtTextComponent::OleCallback::QueryInsertObject(LPCLSID pclsid, 967 LPSTORAGE pstg, 968 LONG cp) { 969 return S_OK; 970 } 971 972 STDMETHODIMP 973 AwtTextComponent::OleCallback::DeleteObject(LPOLEOBJECT poleobj) { 974 return S_OK; 975 } 976 977 STDMETHODIMP 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 1004 AwtTextComponent::OleCallback::ContextSensitiveHelp(BOOL fEnterMode) { 1005 return S_OK; 1006 } 1007 1008 STDMETHODIMP 1009 AwtTextComponent::OleCallback::GetClipboardData(CHARRANGE *pchrg, 1010 DWORD reco, 1011 LPDATAOBJECT *ppdataobj) { 1012 return E_NOTIMPL; 1013 } 1014 1015 STDMETHODIMP 1016 AwtTextComponent::OleCallback::GetDragDropEffect(BOOL fDrag, 1017 DWORD grfKeyState, 1018 LPDWORD pdwEffect) { 1019 1020 return E_NOTIMPL; 1021 } 1022 1023 1024 STDMETHODIMP 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 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 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" */