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