25 26 #include "awt_Toolkit.h" 27 #include "awt_TextField.h" 28 #include "awt_TextComponent.h" 29 #include "awt_Canvas.h" 30 31 /* IMPORTANT! Read the README.JNI file for notes on JNI converted AWT code. 32 */ 33 34 /***********************************************************************/ 35 // struct for _SetEchoChar() method 36 struct SetEchoCharStruct { 37 jobject textfield; 38 jchar echoChar; 39 }; 40 /************************************************************************ 41 * AwtTextField methods 42 */ 43 44 AwtTextField::AwtTextField() 45 : m_initialRescrollFlag( true ) 46 { 47 } 48 49 /* Create a new AwtTextField object and window. */ 50 AwtTextField* AwtTextField::Create(jobject peer, jobject parent) 51 { 52 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 53 54 jobject target = NULL; 55 AwtTextField* c = NULL; 56 57 try { 58 PDATA pData; 59 AwtCanvas* awtParent; 60 JNI_CHECK_PEER_GOTO(parent, done); 61 awtParent = (AwtCanvas*)pData; 62 63 JNI_CHECK_NULL_GOTO(awtParent, "null awtParent", done); 64 65 target = env->GetObjectField(peer, AwtObject::targetID); 66 JNI_CHECK_NULL_GOTO(target, "null target", done); 67 68 c = new AwtTextField(); 69 70 { 71 DWORD style = WS_CHILD | WS_CLIPSIBLINGS | 72 ES_LEFT | ES_AUTOHSCROLL; 73 DWORD exStyle = WS_EX_CLIENTEDGE; 74 if (GetRTL()) { 75 exStyle |= WS_EX_RIGHT | WS_EX_LEFTSCROLLBAR; 76 if (GetRTLReadingOrder()) 77 exStyle |= WS_EX_RTLREADING; 78 } 79 80 jint x = env->GetIntField(target, AwtComponent::xID); 81 jint y = env->GetIntField(target, AwtComponent::yID); 82 jint width = env->GetIntField(target, AwtComponent::widthID); 83 jint height = env->GetIntField(target, AwtComponent::heightID); 84 85 c->CreateHWnd(env, L"", style, exStyle, 86 x, y, width, height, 87 awtParent->GetHWnd(), 88 reinterpret_cast<HMENU>(static_cast<INT_PTR>( 89 awtParent->CreateControlID())), 90 ::GetSysColor(COLOR_WINDOWTEXT), 91 ::GetSysColor(COLOR_WINDOW), 92 peer); 93 94 c->m_backgroundColorSet = TRUE; 95 /* suppress inheriting parent's color. */ 96 c->UpdateBackground(env, target); 97 c->SendMessage(EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, 98 MAKELPARAM(1, 1)); 99 /* 100 * Fix for BugTraq Id 4260109. 101 * Set the text limit to the maximum. 102 */ 103 c->SendMessage(EM_SETLIMITTEXT); 104 105 } 106 } catch (...) { 107 env->DeleteLocalRef(target); 108 throw; 109 } 110 111 done: 112 env->DeleteLocalRef(target); 113 114 return c; 115 } 116 117 void AwtTextField::EditSetSel(CHARRANGE &cr) { 118 SendMessage(EM_SETSEL, cr.cpMin, cr.cpMax); 119 } 120 121 LONG AwtTextField::EditGetCharFromPos(POINT& pt) { 122 return static_cast<LONG>(SendMessage(EM_CHARFROMPOS, 0, MAKELPARAM(pt.x, pt.y))); 123 } 124 125 LRESULT AwtTextField::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) 126 { 127 if (message == WM_UNDO || message == EM_UNDO || message == EM_CANUNDO) { 128 if (GetWindowLong(GetHWnd(), GWL_STYLE) & ES_READONLY) { 129 return FALSE; 130 } 131 } 132 return AwtTextComponent::WindowProc(message, wParam, lParam); 133 } 134 135 MsgRouting 136 AwtTextField::HandleEvent(MSG *msg, BOOL synthetic) 137 { 138 MsgRouting returnVal; 139 /* 140 * RichEdit 1.0 control starts internal message loop if the 141 * left mouse button is pressed while the cursor is not over 142 * the current selection or the current selection is empty. 145 * this behavior we process the relevant mouse messages 146 * by ourselves. 147 * By consuming WM_MOUSEMOVE messages we also don't give 148 * the RichEdit control a chance to recognize a drag gesture 149 * and initiate its own drag-n-drop operation. 150 * 151 * The workaround also allows us to implement synthetic focus mechanism. 152 */ 153 if (IsFocusingMouseMessage(msg)) { 154 155 LONG lCurPos = EditGetCharFromPos(msg->pt); 156 157 /* 158 * NOTE: Plain EDIT control always clears selection on mouse 159 * button press. We are clearing the current selection only if 160 * the mouse pointer is not over the selected region. 161 * In this case we sacrifice backward compatibility 162 * to allow dnd of the current selection. 163 */ 164 if (msg->message == WM_LBUTTONDBLCLK) { 165 SetStartSelectionPos(static_cast<LONG>(SendMessage( 166 EM_FINDWORDBREAK, WB_MOVEWORDLEFT, lCurPos))); 167 SetEndSelectionPos(static_cast<LONG>(SendMessage( 168 EM_FINDWORDBREAK, WB_MOVEWORDRIGHT, lCurPos))); 169 } else { 170 SetStartSelectionPos(lCurPos); 171 SetEndSelectionPos(lCurPos); 172 } 173 CHARRANGE cr; 174 cr.cpMin = GetStartSelectionPos(); 175 cr.cpMax = GetEndSelectionPos(); 176 EditSetSel(cr); 177 178 delete msg; 179 return mrConsume; 180 } else if (msg->message == WM_LBUTTONUP) { 181 182 /* 183 * If the left mouse button is pressed on the selected region 184 * we don't clear the current selection. We clear it on button 185 * release instead. This is to allow dnd of the current selection. 186 */ 187 if (GetStartSelectionPos() == -1 && GetEndSelectionPos() == -1) { 188 CHARRANGE cr; 288 289 SetEchoCharStruct *secs = (SetEchoCharStruct *)param; 290 jobject self = secs->textfield; 291 jchar echo = secs->echoChar; 292 293 AwtTextField *c = NULL; 294 295 PDATA pData; 296 JNI_CHECK_PEER_GOTO(self, ret); 297 c = (AwtTextField *)pData; 298 if (::IsWindow(c->GetHWnd())) 299 { 300 c->SendMessage(EM_SETPASSWORDCHAR, echo); 301 // Fix for 4307281: force redraw so that changes will take effect 302 VERIFY(::InvalidateRect(c->GetHWnd(), NULL, FALSE)); 303 } 304 ret: 305 env->DeleteGlobalRef(self); 306 307 delete secs; 308 } 309 310 void AwtTextField::Reshape(int x, int y, int w, int h) 311 { 312 AwtTextComponent::Reshape( x, y, w, h ); 313 314 // Another option would be to call this 315 // after WM_SIZE notification is handled 316 initialRescroll(); 317 } 318 319 320 // Windows' Edit control features: 321 // (i) if text selection is set while control's width or height is 0, 322 // text is scrolled oddly. 323 // (ii) if control's size is changed, text seems never be automatically 324 // rescrolled. 325 // 326 // This method is designed for the following scenario: AWT spawns Edit 327 // control with 0x0 dimensions, then sets text selection, then resizes the 328 // control (couple of times). This might cause text appear undesirably scrolled. 329 // So we reset/set selection again to rescroll text. (see also CR 6480547) 330 void AwtTextField::initialRescroll() 331 { 332 if( ! m_initialRescrollFlag ) { 333 return; 334 } 335 336 ::RECT r; 337 BOOL ok = ::GetClientRect( GetHWnd(), &r ); 338 if( ! ok || r.right==0 || r.bottom==0 ) { 339 return; 340 } 341 342 m_initialRescrollFlag = false; 343 344 DWORD start, end; 345 SendMessage( EM_GETSEL, (WPARAM)&start, (LPARAM)&end ); 346 SendMessage( EM_SETSEL, (WPARAM)0, (LPARAM)0 ); 347 SendMessage( EM_SETSEL, (WPARAM)start, (LPARAM)end ); 348 } 349 350 351 /************************************************************************ 352 * WTextFieldPeer native methods 353 */ 354 355 extern "C" { 356 357 /* 358 * Class: sun_awt_windows_WTextFieldPeer 359 * Method: create 360 * Signature: (Lsun/awt/windows/WComponentPeer;)V 361 */ 362 JNIEXPORT void JNICALL 363 Java_sun_awt_windows_WTextFieldPeer_create(JNIEnv *env, jobject self, 364 jobject parent) 365 { 366 TRY; 367 | 25 26 #include "awt_Toolkit.h" 27 #include "awt_TextField.h" 28 #include "awt_TextComponent.h" 29 #include "awt_Canvas.h" 30 31 /* IMPORTANT! Read the README.JNI file for notes on JNI converted AWT code. 32 */ 33 34 /***********************************************************************/ 35 // struct for _SetEchoChar() method 36 struct SetEchoCharStruct { 37 jobject textfield; 38 jchar echoChar; 39 }; 40 /************************************************************************ 41 * AwtTextField methods 42 */ 43 44 AwtTextField::AwtTextField() 45 { 46 } 47 48 /* Create a new AwtTextField object and window. */ 49 AwtTextField* AwtTextField::Create(jobject peer, jobject parent) 50 { 51 return (AwtTextField*) AwtTextComponent::Create(peer, parent, false); 52 } 53 54 void AwtTextField::EditSetSel(CHARRANGE &cr) { 55 SendMessage(EM_EXSETSEL, 0, reinterpret_cast<LPARAM>(&cr)); 56 57 // 6417581: force expected drawing 58 if (IS_WINVISTA && cr.cpMin == cr.cpMax) { 59 ::InvalidateRect(GetHWnd(), NULL, TRUE); 60 } 61 62 } 63 64 LRESULT AwtTextField::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) 65 { 66 if (message == WM_UNDO || message == EM_UNDO || message == EM_CANUNDO) { 67 if (GetWindowLong(GetHWnd(), GWL_STYLE) & ES_READONLY) { 68 return FALSE; 69 } 70 } 71 return AwtTextComponent::WindowProc(message, wParam, lParam); 72 } 73 74 MsgRouting 75 AwtTextField::HandleEvent(MSG *msg, BOOL synthetic) 76 { 77 MsgRouting returnVal; 78 /* 79 * RichEdit 1.0 control starts internal message loop if the 80 * left mouse button is pressed while the cursor is not over 81 * the current selection or the current selection is empty. 84 * this behavior we process the relevant mouse messages 85 * by ourselves. 86 * By consuming WM_MOUSEMOVE messages we also don't give 87 * the RichEdit control a chance to recognize a drag gesture 88 * and initiate its own drag-n-drop operation. 89 * 90 * The workaround also allows us to implement synthetic focus mechanism. 91 */ 92 if (IsFocusingMouseMessage(msg)) { 93 94 LONG lCurPos = EditGetCharFromPos(msg->pt); 95 96 /* 97 * NOTE: Plain EDIT control always clears selection on mouse 98 * button press. We are clearing the current selection only if 99 * the mouse pointer is not over the selected region. 100 * In this case we sacrifice backward compatibility 101 * to allow dnd of the current selection. 102 */ 103 if (msg->message == WM_LBUTTONDBLCLK) { 104 jchar echo = SendMessage(EM_GETPASSWORDCHAR); 105 106 if(echo == 0){ 107 SetStartSelectionPos(static_cast<LONG>(SendMessage( 108 EM_FINDWORDBREAK, WB_MOVEWORDLEFT, lCurPos))); 109 SetEndSelectionPos(static_cast<LONG>(SendMessage( 110 EM_FINDWORDBREAK, WB_MOVEWORDRIGHT, lCurPos))); 111 }else{ 112 SetStartSelectionPos(0); 113 SetEndSelectionPos(GetTextLength()); 114 } 115 116 } else { 117 SetStartSelectionPos(lCurPos); 118 SetEndSelectionPos(lCurPos); 119 } 120 CHARRANGE cr; 121 cr.cpMin = GetStartSelectionPos(); 122 cr.cpMax = GetEndSelectionPos(); 123 EditSetSel(cr); 124 125 delete msg; 126 return mrConsume; 127 } else if (msg->message == WM_LBUTTONUP) { 128 129 /* 130 * If the left mouse button is pressed on the selected region 131 * we don't clear the current selection. We clear it on button 132 * release instead. This is to allow dnd of the current selection. 133 */ 134 if (GetStartSelectionPos() == -1 && GetEndSelectionPos() == -1) { 135 CHARRANGE cr; 235 236 SetEchoCharStruct *secs = (SetEchoCharStruct *)param; 237 jobject self = secs->textfield; 238 jchar echo = secs->echoChar; 239 240 AwtTextField *c = NULL; 241 242 PDATA pData; 243 JNI_CHECK_PEER_GOTO(self, ret); 244 c = (AwtTextField *)pData; 245 if (::IsWindow(c->GetHWnd())) 246 { 247 c->SendMessage(EM_SETPASSWORDCHAR, echo); 248 // Fix for 4307281: force redraw so that changes will take effect 249 VERIFY(::InvalidateRect(c->GetHWnd(), NULL, FALSE)); 250 } 251 ret: 252 env->DeleteGlobalRef(self); 253 254 delete secs; 255 } 256 257 258 /************************************************************************ 259 * WTextFieldPeer native methods 260 */ 261 262 extern "C" { 263 264 /* 265 * Class: sun_awt_windows_WTextFieldPeer 266 * Method: create 267 * Signature: (Lsun/awt/windows/WComponentPeer;)V 268 */ 269 JNIEXPORT void JNICALL 270 Java_sun_awt_windows_WTextFieldPeer_create(JNIEnv *env, jobject self, 271 jobject parent) 272 { 273 TRY; 274 |