blob: 21f42bea3dd4fdb84983be24b920e8c0e32d5723 [file] [log] [blame]
/*
* Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include "awt.h"
#include "awt_Toolkit.h"
#include "awt_Checkbox.h"
#include "awt_Canvas.h"
#include "awt_Window.h"
/* IMPORTANT! Read the README.JNI file for notes on JNI converted AWT code.
*/
/***********************************************************************/
// Struct for _SetLabel() method
struct SetLabelStruct {
jobject checkbox;
jstring label;
};
// Struct for _SetState() method
struct SetStateStruct {
jobject checkbox;
jboolean state;
};
/************************************************************************
* AwtCheckbox fields
*/
/* java.awt.Checkbox field IDs */
jfieldID AwtCheckbox::labelID;
jfieldID AwtCheckbox::groupID;
jfieldID AwtCheckbox::stateID;
const int AwtCheckbox::CHECK_SIZE = 13;
/************************************************************************
* AwtCheckbox methods
*/
AwtCheckbox::AwtCheckbox() {
m_fLButtonDowned = FALSE;
}
LPCTSTR AwtCheckbox::GetClassName() {
return TEXT("BUTTON"); /* System provided checkbox class (a type of button) */
}
AwtCheckbox* AwtCheckbox::Create(jobject peer, jobject parent)
{
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
jstring label = NULL;
jobject target = NULL;
AwtCheckbox *checkbox = NULL;
try {
if (env->EnsureLocalCapacity(2) < 0) {
return NULL;
}
AwtComponent* awtParent;
JNI_CHECK_NULL_GOTO(parent, "null parent", done);
awtParent = (AwtComponent*)JNI_GET_PDATA(parent);
JNI_CHECK_NULL_GOTO(awtParent, "null awtParent", done);
target = env->GetObjectField(peer, AwtObject::targetID);
JNI_CHECK_NULL_GOTO(target, "null target", done);
checkbox = new AwtCheckbox();
{
DWORD style = WS_CHILD | WS_CLIPSIBLINGS | BS_OWNERDRAW;
LPCWSTR defaultLabelStr = L"";
LPCWSTR labelStr = defaultLabelStr;
DWORD exStyle = 0;
if (GetRTL()) {
exStyle |= WS_EX_RIGHT;
if (GetRTLReadingOrder())
exStyle |= WS_EX_RTLREADING;
}
label = (jstring)env->GetObjectField(target, AwtCheckbox::labelID);
if (label != NULL) {
labelStr = JNU_GetStringPlatformChars(env, label, 0);
}
if (labelStr != 0) {
jint x = env->GetIntField(target, AwtComponent::xID);
jint y = env->GetIntField(target, AwtComponent::yID);
jint width = env->GetIntField(target, AwtComponent::widthID);
jint height = env->GetIntField(target, AwtComponent::heightID);
checkbox->CreateHWnd(env, labelStr, style, exStyle,
x, y, width, height,
awtParent->GetHWnd(),
reinterpret_cast<HMENU>(static_cast<INT_PTR>(
awtParent->CreateControlID())),
::GetSysColor(COLOR_WINDOWTEXT),
::GetSysColor(COLOR_BTNFACE),
peer);
if (labelStr != defaultLabelStr) {
JNU_ReleaseStringPlatformChars(env, label, labelStr);
}
} else {
throw std::bad_alloc();
}
}
} catch (...) {
env->DeleteLocalRef(label);
env->DeleteLocalRef(target);
throw;
}
done:
env->DeleteLocalRef(label);
env->DeleteLocalRef(target);
return checkbox;
}
MsgRouting
AwtCheckbox::WmMouseUp(UINT flags, int x, int y, int button)
{
MsgRouting mrResult = AwtComponent::WmMouseUp(flags, x, y, button);
if (::IsWindow(AwtWindow::GetModalBlocker(AwtComponent::GetTopLevelParentForWindow(GetHWnd()))))
{
return mrConsume;
}
POINT p = {x, y};
RECT rect;
::GetClientRect(GetHWnd(), &rect);
if (::PtInRect(&rect, p) && button == LEFT_BUTTON && m_fLButtonDowned) {
WmNotify(BN_CLICKED);
}
m_fLButtonDowned = FALSE;
return mrResult;
}
MsgRouting
AwtCheckbox::WmMouseDown(UINT flags, int x, int y, int button)
{
m_fLButtonDowned = TRUE;
return AwtComponent::WmMouseDown(flags, x, y, button);
}
MsgRouting
AwtCheckbox::WmNotify(UINT notifyCode)
{
if (notifyCode == BN_CLICKED) {
BOOL fChecked = !GetState();
DoCallback("handleAction", "(Z)V", fChecked);
}
return mrDoDefault;
}
BOOL AwtCheckbox::GetState()
{
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
if (env->EnsureLocalCapacity(2) < 0) {
return NULL;
}
jobject target = GetTarget(env);
jboolean result = JNI_FALSE;
if (target != NULL) {
result = env->GetBooleanField(target, AwtCheckbox::stateID);
}
env->DeleteLocalRef(target);
return (BOOL)result;
}
int AwtCheckbox::GetCheckSize()
{
/* using height of small icon for check mark size */
return CHECK_SIZE;
}
MsgRouting
AwtCheckbox::OwnerDrawItem(UINT /*ctrlId*/, DRAWITEMSTRUCT& drawInfo)
{
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
if (env->EnsureLocalCapacity(4) < 0) {
return mrConsume;
}
jobject self = GetPeer(env);
jobject target = env->GetObjectField(self, AwtObject::targetID);
HDC hDC = drawInfo.hDC;
RECT rect = drawInfo.rcItem;
int checkSize;
UINT nState;
SIZE size;
jobject font = GET_FONT(target, self);
jstring str = (jstring)env->GetObjectField(target, AwtCheckbox::labelID);
size = AwtFont::getMFStringSize(hDC, font, str);
jobject group = env->GetObjectField(target, AwtCheckbox::groupID);
if (group != NULL)
nState = DFCS_BUTTONRADIO;
else
nState = DFCS_BUTTONCHECK;
if (GetState())
nState |= DFCS_CHECKED;
else
nState &= ~DFCS_CHECKED;
if (drawInfo.itemState & ODS_SELECTED)
nState |= DFCS_PUSHED;
if (drawInfo.itemAction & ODA_DRAWENTIRE) {
VERIFY(::FillRect (hDC, &rect, GetBackgroundBrush()));
}
/* draw check mark */
checkSize = GetCheckSize();
RECT boxRect;
boxRect.left = (GetRTL()) ? rect.right - checkSize : rect.left;
boxRect.top = (rect.bottom - rect.top - checkSize)/2;
boxRect.right = boxRect.left + checkSize;
boxRect.bottom = boxRect.top + checkSize;
::DrawFrameControl(hDC, &boxRect, DFC_BUTTON, nState);
/*
* draw string
*
* 4 is a heuristic number
*/
rect.left = rect.left + checkSize + checkSize/4;
if (drawInfo.itemAction & ODA_DRAWENTIRE) {
BOOL bEnabled = isEnabled();
int x = (GetRTL()) ? rect.right - (checkSize + checkSize / 4 + size.cx)
: rect.left;
int y = (rect.top + rect.bottom - size.cy) / 2;
if (bEnabled) {
AwtComponent::DrawWindowText(hDC, font, str, x, y);
} else {
AwtComponent::DrawGrayText(hDC, font, str, x, y);
}
}
/* Draw focus rect */
RECT focusRect;
const int margin = 2; /* 2 is a heuristic number */
focusRect.left = (GetRTL()) ? rect.right - checkSize - checkSize / 4 -
2 * margin - size.cx
: rect.left - margin;
focusRect.top = (rect.top+rect.bottom-size.cy)/2;
focusRect.right = (GetRTL()) ? rect.right - checkSize - checkSize / 4 +
margin
: focusRect.left + size.cx + 2 * margin;
focusRect.bottom = focusRect.top + size.cy;
/* draw focus rect */
if ((drawInfo.itemState & ODS_FOCUS) &&
((drawInfo.itemAction & ODA_FOCUS)||
(drawInfo.itemAction &ODA_DRAWENTIRE))) {
VERIFY(::DrawFocusRect(hDC, &focusRect));
}
/* erase focus rect */
else if (!(drawInfo.itemState & ODS_FOCUS) &&
(drawInfo.itemAction & ODA_FOCUS)) {
VERIFY(::DrawFocusRect(hDC, &focusRect));
}
/* Notify any subclasses */
rect = drawInfo.rcItem;
DoCallback("handlePaint", "(IIII)V", rect.left, rect.top,
rect.right-rect.left, rect.bottom-rect.top);
env->DeleteLocalRef(target);
env->DeleteLocalRef(font);
env->DeleteLocalRef(str);
env->DeleteLocalRef(group);
return mrConsume;
}
MsgRouting AwtCheckbox::WmPaint(HDC)
{
/* Suppress peer notification, because it's handled in WmDrawItem. */
return mrDoDefault;
}
BOOL AwtCheckbox::IsFocusingMouseMessage(MSG *pMsg) {
return pMsg->message == WM_LBUTTONDOWN || pMsg->message == WM_LBUTTONUP;
}
BOOL AwtCheckbox::IsFocusingKeyMessage(MSG *pMsg) {
return (pMsg->message == WM_KEYDOWN || pMsg->message == WM_KEYUP) &&
pMsg->wParam == VK_SPACE;
}
MsgRouting AwtCheckbox::HandleEvent(MSG *msg, BOOL synthetic)
{
if (IsFocusingMouseMessage(msg)) {
SendMessage(BM_SETSTATE, (WPARAM)(msg->message == WM_LBUTTONDOWN ? TRUE : FALSE));
delete msg;
return mrConsume;
}
if (IsFocusingKeyMessage(msg)) {
SendMessage(BM_SETSTATE, (WPARAM)(msg->message == WM_KEYDOWN ? TRUE : FALSE));
if (msg->message == WM_KEYDOWN) {
m_fLButtonDowned = TRUE;
} else if (m_fLButtonDowned == TRUE) {
WmNotify(BN_CLICKED);
m_fLButtonDowned = TRUE;
}
delete msg;
return mrConsume;
}
return AwtComponent::HandleEvent(msg, synthetic);
}
void AwtCheckbox::_SetLabel(void *param)
{
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
SetLabelStruct *sls = (SetLabelStruct *)param;
jobject checkbox = sls->checkbox;
jstring label = sls->label;
int badAlloc = 0;
AwtCheckbox *c = NULL;
PDATA pData;
JNI_CHECK_PEER_GOTO(checkbox, done);
c = (AwtCheckbox *)pData;
if (::IsWindow(c->GetHWnd()))
{
LPCTSTR labelStr = NULL;
// By convension null label means empty string
if (label == NULL)
{
labelStr = TEXT("");
}
else
{
labelStr = JNU_GetStringPlatformChars(env, label, JNI_FALSE);
}
if (labelStr == NULL)
{
badAlloc = 1;
}
else
{
c->SetText(labelStr);
c->VerifyState();
JNU_ReleaseStringPlatformChars(env, label, labelStr);
}
}
done:
env->DeleteGlobalRef(checkbox);
if (label != NULL)
{
env->DeleteGlobalRef(label);
}
delete sls;
if (badAlloc) {
throw std::bad_alloc();
}
}
void AwtCheckbox::_SetCheckboxGroup(void *param)
{
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
jobject *jos = (jobject *)param;
jobject checkbox = jos[0];
jobject group = jos[1];
AwtCheckbox *c = NULL;
PDATA pData;
JNI_CHECK_PEER_GOTO(checkbox, done);
c = (AwtCheckbox *)pData;
if (::IsWindow(c->GetHWnd()))
{
/*
#ifdef DEBUG
if (group != NULL) {
DASSERT(IsInstanceOf((HObject*)group, "java/awt/CheckboxGroup"));
}
#endif
*/
long style = c->GetStyle();
if (group == NULL) {
style = style & ~BS_AUTORADIOBUTTON;
style = style | BS_AUTOCHECKBOX;
} else {
style = style & ~BS_AUTOCHECKBOX;
style = style | BS_AUTORADIOBUTTON;
}
c->SetStyle(style);
c->SendMessage(BM_SETSTYLE, (WPARAM)BS_OWNERDRAW, (LPARAM)TRUE);
c->VerifyState();
}
done:
env->DeleteGlobalRef(checkbox);
if (group != NULL) {
env->DeleteGlobalRef(group);
}
delete[] jos;
}
void AwtCheckbox::_SetState(void *param)
{
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
SetStateStruct *sss = (SetStateStruct *)param;
jobject checkbox = sss->checkbox;
jboolean state = sss->state;
AwtCheckbox *c = NULL;
PDATA pData;
JNI_CHECK_PEER_GOTO(checkbox, done);
c = (AwtCheckbox *)pData;
if (::IsWindow(c->GetHWnd()))
{
/*
* when multifont and group checkbox receive setState native
* method, it must be redraw to display correct check mark
*/
jobject target = env->GetObjectField(checkbox, AwtObject::targetID);
jobject group = env->GetObjectField(target, AwtCheckbox::groupID);
HWND hWnd = c->GetHWnd();
if (group != NULL) {
RECT rect;
VERIFY(::GetWindowRect(hWnd, &rect));
VERIFY(::ScreenToClient(hWnd, (LPPOINT)&rect));
VERIFY(::ScreenToClient(hWnd, ((LPPOINT)&rect) + 1));
VERIFY(::InvalidateRect(hWnd, &rect,TRUE));
VERIFY(::UpdateWindow(hWnd));
} else {
c->SendMessage(BM_SETCHECK, (WPARAM)(state ? BST_CHECKED : BST_UNCHECKED));
VERIFY(::InvalidateRect(hWnd, NULL, FALSE));
}
c->VerifyState();
env->DeleteLocalRef(target);
env->DeleteLocalRef(group);
}
done:
env->DeleteGlobalRef(checkbox);
delete sss;
}
#ifdef DEBUG
void AwtCheckbox::VerifyState()
{
if (AwtToolkit::GetInstance().VerifyComponents() == FALSE) {
return;
}
if (m_callbacksEnabled == FALSE) {
/* Component is not fully setup yet. */
return;
}
AwtComponent::VerifyState();
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
if (env->EnsureLocalCapacity(2) < 0) {
return;
}
jobject target = GetTarget(env);
/* Check button style */
DWORD style = ::GetWindowLong(GetHWnd(), GWL_STYLE);
DASSERT(style & BS_OWNERDRAW);
/* Check label */
int len = ::GetWindowTextLength(GetHWnd());
LPTSTR peerStr;
try {
peerStr = new TCHAR[len+1];
} catch (std::bad_alloc&) {
env->DeleteLocalRef(target);
throw;
}
GetText(peerStr, len+1);
jstring label = (jstring)env->GetObjectField(target, AwtCheckbox::labelID);
DASSERT(_tcscmp(peerStr, JavaStringBuffer(env, label)) == 0);
delete [] peerStr;
env->DeleteLocalRef(target);
env->DeleteLocalRef(label);
}
#endif
/************************************************************************
* Checkbox native methods
*/
extern "C" {
/*
* Class: sun_awt_windows_WButtonPeer
* Method: initIDs
* Signature: ()V
*/
JNIEXPORT void JNICALL
Java_java_awt_Checkbox_initIDs(JNIEnv *env, jclass cls)
{
TRY;
AwtCheckbox::labelID =
env->GetFieldID(cls, "label", "Ljava/lang/String;");
AwtCheckbox::groupID =
env->GetFieldID(cls, "group", "Ljava/awt/CheckboxGroup;");
AwtCheckbox::stateID =
env->GetFieldID(cls, "state", "Z");
DASSERT(AwtCheckbox::labelID != NULL);
DASSERT(AwtCheckbox::groupID != NULL);
DASSERT(AwtCheckbox::stateID != NULL);
CATCH_BAD_ALLOC;
}
} /* extern "C" */
/************************************************************************
* WCheckboxPeer native methods
*/
extern "C" {
/*
* Class: sun_awt_windows_WCheckboxPeer
* Method: getCheckMarkSize
* Signature: ()I
*/
JNIEXPORT jint JNICALL
Java_sun_awt_windows_WCheckboxPeer_getCheckMarkSize(JNIEnv *env,
jclass cls)
{
return (jint)AwtCheckbox::GetCheckSize();
}
/*
* Class: sun_awt_windows_WCheckboxPeer
* Method: setState
* Signature: (Z)V
*/
JNIEXPORT void JNICALL
Java_sun_awt_windows_WCheckboxPeer_setState(JNIEnv *env, jobject self,
jboolean state)
{
TRY;
SetStateStruct *sss = new SetStateStruct;
sss->checkbox = env->NewGlobalRef(self);
sss->state = state;
AwtToolkit::GetInstance().SyncCall(AwtCheckbox::_SetState, sss);
// global refs and sss are deleted in _SetState()
CATCH_BAD_ALLOC;
}
/*
* Class: sun_awt_windows_WCheckboxPeer
* Method: setCheckboxGroup
* Signature: (Ljava/awt/CheckboxGroup;)V
*/
JNIEXPORT void JNICALL
Java_sun_awt_windows_WCheckboxPeer_setCheckboxGroup(JNIEnv *env, jobject self,
jobject group)
{
TRY;
jobject *jos = new jobject[2];
jos[0] = env->NewGlobalRef(self);
jos[1] = env->NewGlobalRef(group);
AwtToolkit::GetInstance().SyncCall(AwtCheckbox::_SetCheckboxGroup, jos);
// global refs and jos are deleted in _SetLabel()
CATCH_BAD_ALLOC;
}
/*
* Class: sun_awt_windows_WCheckboxPeer
* Method: setLabel
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL
Java_sun_awt_windows_WCheckboxPeer_setLabel(JNIEnv *env, jobject self,
jstring label)
{
TRY;
SetLabelStruct *sls = new SetLabelStruct;
sls->checkbox = env->NewGlobalRef(self);
sls->label = (label != NULL) ? (jstring)env->NewGlobalRef(label) : NULL;
AwtToolkit::GetInstance().SyncCall(AwtCheckbox::_SetLabel, sls);
// global refs and sls are deleted in _SetLabel()
CATCH_BAD_ALLOC;
}
/*
* Class: sun_awt_windows_WCheckboxPeer
* Method: create
* Signature: (Lsun/awt/windows/WComponentPeer;)V
*/
JNIEXPORT void JNICALL
Java_sun_awt_windows_WCheckboxPeer_create(JNIEnv *env, jobject self,
jobject parent)
{
TRY;
PDATA pData;
JNI_CHECK_PEER_RETURN(parent);
AwtToolkit::CreateComponent(self, parent,
(AwtToolkit::ComponentFactory)
AwtCheckbox::Create);
JNI_CHECK_PEER_CREATION_RETURN(self);
#ifdef DEBUG
((AwtComponent*)JNI_GET_PDATA(self))->VerifyState();
#endif
CATCH_BAD_ALLOC;
}
} /* extern "C" */