Milán Major

netscape-revival

1 branch
Code

sun-java/awt.bad/win/awt_listbox.cpp

#include "awt_listbox.h"
#include "awt_toolkit.h"
#include "awt_defs.h"

#ifdef INTLUNICODE
#include "awt_wcompstr.h"
#include "awt_i18n.h"
#endif
// All java header files are extern "C"
extern "C" {
#include "java_awt_List.h"

#include "sun_awt_windows_WComponentPeer.h"
#include "sun_awt_windows_WListPeer.h"
};


AwtListbox::AwtListbox(HWListPeer *peer) : AwtWindow((JHandle *)peer)
{
    DEFINE_AWT_SENTINAL("LST");
    m_dwMultipleSelection = 0; // no multiple selection by default
}

// -----------------------------------------------------------------------
//
// Return the window class of an AwtListbox window.
//
// -----------------------------------------------------------------------
const char * AwtListbox::WindowClass()
{
    return "LISTBOX";
}


// -----------------------------------------------------------------------
//
// Return the window style used to create an AwtListbox window
//
// -----------------------------------------------------------------------
DWORD AwtListbox::WindowStyle()
{
    return WS_CHILD | WS_VSCROLL | WS_BORDER | WS_CLIPSIBLINGS
#ifdef INTLUNICODE
			| LBS_OWNERDRAWFIXED
#endif // INTLUNICODE
            | LBS_NOINTEGRALHEIGHT | LBS_NOTIFY 
            | m_dwMultipleSelection;
}


DWORD AwtListbox::WindowExStyle()
{
#ifdef _WIN32
    return WS_EX_CLIENTEDGE;
#else
    return 0;
#endif
}


// -----------------------------------------------------------------------
//
// Set or reset the list box flag to allow multiple selection
// If the list box has been created already we must create a new
// list, copy all the value into the new list and show it.
//
// -----------------------------------------------------------------------
void AwtListbox::SetMultipleSelections(HWListPeer* peer, long lMS)
{

    Lock();

    if ((m_dwMultipleSelection && !lMS) ||
                (!m_dwMultipleSelection && lMS)) {
        
        m_dwMultipleSelection = (lMS) ? LBS_MULTIPLESEL : 0;
    
        if (::IsWindow(m_hWnd)) {
            long lItems;
            HWND oldWnd = m_hWnd;

            SubclassWindow(FALSE);

            // create a new list box
            CreateWidget( GetParent(m_hWnd));

            // copy all the elements
            lItems = ::SendMessage(oldWnd, LB_GETCOUNT, 0, 0L);
            if (lItems != LB_ERR && lItems > 0) {
                long bSelectionDone = 0;

                for (long i = 0; i < lItems; i++) {
#ifdef INTLUNICODE
                    // get string at index
                    LRESULT ret =  ::SendMessage(oldWnd,
                                    LB_GETITEMDATA,
                                    (WPARAM)i,
                                    (LPARAM)0);
					VERIFY(ret != LB_ERR);
					if(ret != LB_ERR)
					{
						// We need to clone it

						WinCompStr	*pNew = new WinCompStr(* (WinCompStr*)ret);

						// insert string at index
						::SendMessage(m_hWnd,
										LB_INSERTSTRING,
										(WPARAM)i,
										(LPARAM)pNew);
					}
#else	// INTLUNICODE
                    char buffer[128]; //for now, this should be changed to a malloc

                    // get string at index
                    ::SendMessage(oldWnd,
                                    LB_GETTEXT,
                                    (WPARAM)i,
                                    (LPARAM)buffer);

                    // insert string at index
                    ::SendMessage(m_hWnd,
                                    LB_INSERTSTRING,
                                    (WPARAM)i,
                                    (LPARAM)buffer);
#endif	// INTLUNICODE
                    // keep selection. 
                    // From single to multiple is the selected item, if any.
                    // From multiple to single is the first selected item encountered
                    if (!bSelectionDone) {
                        bSelectionDone = ::SendMessage(oldWnd,
                                                        LB_GETSEL,
                                                        (WPARAM)i,
                                                        0);
                        if (bSelectionDone)
                            if (m_dwMultipleSelection)
                                ::SendMessage(m_hWnd, 
                                                LB_SETSEL,
                                                (WPARAM)bSelectionDone,
                                                (LPARAM)i);
                            else
                                ::SendMessage(m_hWnd, 
                                                LB_SETCURSEL,
                                                (WPARAM)i,
                                                0);
                    }
                }
            } 
            if (m_pFont)
                ::SendMessage(m_hWnd, WM_SETFONT, (WPARAM)(m_pFont->GetFont()), 0); 
			
			::UpdateWindow(m_hWnd);
            ::ShowWindow(m_hWnd, SW_SHOW);

            Destroy(oldWnd);
            
        } // if window exists

    } // if multiselection changed
	
    Unlock();
}


// -----------------------------------------------------------------------
//
// Add an item at the specified index
// No lock is needed because SendMessage is synchronized
//
// -----------------------------------------------------------------------
void AwtListbox::AddItem(Hjava_lang_String *item, long index)
{
    ASSERT( ::IsWindow(m_hWnd) );
#ifdef INTLUNICODE

	// We free the WinCompStr in the OnDeleteItem()
	WinCompStr *pNewItem = new WinCompStr(item);

	if(pNewItem)
        ::SendMessage(m_hWnd, LB_INSERTSTRING, (WPARAM)index, (LPARAM)(LPSTR)pNewItem);

#else	// INTLUNICODE
    int32_t len;
    char *buffer = NULL;


    len = javaStringLength(item);
    buffer = (char *)malloc(len+1);
    if (buffer) {
        javaString2CString(item, buffer, len+1);

        ::SendMessage(m_hWnd, LB_INSERTSTRING, (WPARAM)index, (LPARAM)(LPSTR)buffer);

        free(buffer);
    }
#endif	// INTLUNICODE
}


// -----------------------------------------------------------------------
//
// Delete a consecutive set of items (as specified by start/end)
// Lock because of the for(;;)
//
// -----------------------------------------------------------------------
void AwtListbox::DeleteItems(long start, long end)
{
    ASSERT( ::IsWindow(m_hWnd) );

    Lock();

    for (long i = end; i >= start; i--) 
        ::SendMessage(m_hWnd, LB_DELETESTRING, (WPARAM)i, 0L);

    Unlock();
}


// -----------------------------------------------------------------------
//
// Select or deselect the item at index according to bSelection
//
//! do we really need to lock?
//
// -----------------------------------------------------------------------
void AwtListbox::SetSelection(long index, BOOL bSelection)
{
    ASSERT( ::IsWindow(m_hWnd) );

    Lock();

    // use m_dwMultipleSelection to figure if multiple selection is setted
    if (m_dwMultipleSelection) {

        ::SendMessage(m_hWnd, LB_SETSEL, (WPARAM) bSelection, (LPARAM) index);
    }
    else {
        // single line list box, if deselect is called reset any selection
        // in case of deselection don't check if index is selected just
        // nuke whatever selection was there
        if (!bSelection)
            index = -1;

        ::SendMessage(m_hWnd, LB_SETCURSEL, (WPARAM) index, 0L);
    }

    Unlock();
}


// -----------------------------------------------------------------------
//
// Scroll a specified item into view
//
// -----------------------------------------------------------------------
void AwtListbox::MakeVisible(long index)
{
    ASSERT( ::IsWindow(m_hWnd) );

    ::SendMessage(m_hWnd, LB_SETTOPINDEX, (WPARAM) index, 0L);
}


// -----------------------------------------------------------------------
//
// Return whether the specified item is selected or not
//
// -----------------------------------------------------------------------
long AwtListbox::IsSelected(long index)
{
    ASSERT( ::IsWindow(m_hWnd) );

    return ::SendMessage(m_hWnd, LB_GETSEL, (WPARAM)index, 0L);
}


// -----------------------------------------------------------------------
//
// catch onSize so we don't let any events to flow
// Apparently notifing java about a combo or list box size change
// enter in an infinite loop (try to change the size back and forth!!??)
//
// -----------------------------------------------------------------------
BOOL AwtListbox::OnSize( UINT sizeCode, UINT newWidth, UINT newHeight )
{
    return FALSE;
}


// -----------------------------------------------------------------------
//
// raise java events from here!
// 
// -----------------------------------------------------------------------
BOOL AwtListbox::OnCommand(UINT notifyCode, UINT id)
{

    switch (notifyCode) {
        case LBN_DBLCLK:
            if (m_pJavaPeer) {
                int64 time = PR_NowMS(); // time in milliseconds

                // Call sun.awt.windows.WChoicePeer::handleAction(...)
                AwtToolkit::RaiseJavaEvent(m_pJavaPeer, 
                                            AwtEventDescription::ListAction,
                                            time, 
                                            NULL,
                                            ::SendMessage(m_hWnd, LB_GETCURSEL, 0, 0L));
            }
            
            break;

        case LBN_SELCHANGE:
            if (m_pJavaPeer) {
                long index = ::SendMessage(m_hWnd, LB_GETCURSEL, 0,0L);
                int64 time = PR_NowMS(); // time in milliseconds

                // Call sun.awt.windows.WListPeer::handleListChanged(...)
                AwtToolkit::RaiseJavaEvent(m_pJavaPeer, 
                                            AwtEventDescription::ListChanged,
                                            time, 
                                            NULL,
                                            index,
                                            ::SendMessage(m_hWnd, LB_GETSEL, (WPARAM)index, 0L));
            }
            
            break;

    }

    return FALSE; // let the def proc to process the message anyway
}


BOOL AwtListbox::OnPaint( HDC hdc, int x, int y, int w, int h )
{                                                                
    return AwtComponent::OnPaint(hdc, x, y, w, h);
}
    

BOOL AwtListbox::OnEraseBackground( HDC hdc )
{
    return FALSE;
}



//-------------------------------------------------------------------------
//
// Capture the mouse (if it's not the left button) so that mouse events 
// get re-direct to the proper component. 
// This allow MouseDrag to work correctly and MouseUp to be sent to the 
// component which received the mouse down.
// Left down is a special case because windows needs to handle that.
//
//-------------------------------------------------------------------------
void AwtListbox::CaptureMouse(AwtButtonType button, UINT metakeys)
{
    // capture the mouse if it was not captured already.
    // This may happen because of a previous call to CaptureMouse
    // or because the left mouse was clicked and windows captured
    // the mouse for us.
    // Here we use m_nCaptured with a different semantic.
    // It's setted to 1 if SetCapture gets called, otherwise is 0
    if (button == AwtLeftButton)
        m_nCaptured = 0;
    else if (!(metakeys & MK_LBUTTON) && !m_nCaptured) {
        ::SetCapture(m_hWnd);
        m_nCaptured = 1;
    }
}


//-------------------------------------------------------------------------
//
// Release the mouse if it was captured previously. We might not have 
// captured the mouse at all if the left button is the first to be pressed
// and the last released
//
//-------------------------------------------------------------------------
BOOL AwtListbox::ReleaseMouse(AwtButtonType button, UINT metakeys, int x, int y)
{
    // if at least the left button is pressed don't bother...
    if (!(metakeys & MK_LBUTTON)) {

        // check if no button is pressed and if we called SetCapture release it
        if (!(metakeys & MK_RBUTTON) && !(metakeys & MK_MBUTTON)) {
            if (m_nCaptured) {
                ::ReleaseCapture();
                m_nCaptured = 0;
            }
        }

        // the left button has just been released...
        else if (button == AwtLeftButton) {
            // ...see if there is any other button pressed...
            if ((metakeys & MK_RBUTTON) || (metakeys & MK_MBUTTON)) {
                    // Windows is giving up the mouse capture, it's time to take it. 
                    // Let the defproc do MouseUp first so it will release the mouse 
                    // before we capture otherwise WM_LBUTTONUP will release our capture
                    ::CallWindowProc(m_PrevWndProc, 
                                        m_hWnd, 
                                        WM_LBUTTONUP, 
                                        (WPARAM)metakeys, 
                                        MAKELPARAM(x, y));
                    ::SetCapture(m_hWnd);
                    m_nCaptured = 1;
                    return TRUE;
            }
        }

    }

    return FALSE;
}

#ifdef INTLUNICODE
BOOL AwtListbox::SetFont(AwtFont *font)
{
    BOOL bStatus;
    bStatus = AwtComponent::SetFont(font);
    if(font && bStatus)
    {
        HDC hDC;
        VERIFY( hDC = ::GetDC(m_hWnd));
        if(hDC)
        {
            TEXTMETRIC metrics;
            ::SelectObject(hDC, (HGDIOBJ) font->GetFont());
            VERIFY( ::GetTextMetrics(hDC, &metrics));
            VERIFY( ::ReleaseDC(m_hWnd, hDC));
            ::SendMessage(m_hWnd, LB_SETITEMHEIGHT, 0,
                  MAKELPARAM(metrics.tmHeight + metrics.tmExternalLeading 
				                              + metrics.tmInternalLeading, 0));
			::RedrawWindow(m_hWnd, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_FRAME);
		}
    }
    return bStatus;
}
#endif

//-------------------------------------------------------------------------
//
// Native method implementations for sun.awt.WListboxPeer
//
//-------------------------------------------------------------------------

extern "C" {

void
sun_awt_windows_WListPeer_create(HWListPeer *self, 
                                    HWComponentPeer *hParent)
{
    AwtListbox   *pNewListbox;

    CHECK_NULL(self,    "ListboxPeer is null.");
    CHECK_NULL(hParent, "ComponentPeer is null.");

    pNewListbox = new AwtListbox(self);
    CHECK_ALLOCATION(pNewListbox);

// What about locking the new object??
    pNewListbox->CreateWidget( pNewListbox->GetParentWindowHandle(hParent) );
}


#if 0
void
sun_awt_windows_WListPeer_createWidget(HWListPeer *self, 
                                        HWComponentPeer *hParent)
{
    CHECK_PEER(self);

    AwtListbox *obj = GET_OBJ_FROM_PEER(AwtListbox, self);

// What about locking the new object??
    obj->CreateWidget( obj->GetParentWindowHandle(hParent) );
}
#endif


void 
sun_awt_windows_WListPeer_setMultipleSelections(HWListPeer* self,
                                                /*boolean*/ long lSelection)
{
    CHECK_PEER(self);

    AwtListbox *obj = GET_OBJ_FROM_PEER(AwtListbox, self);

    obj->SetMultipleSelections(self, lSelection);
}

												
void 
sun_awt_windows_WListPeer_addItem( HWListPeer* self, 
                                   Hjava_lang_String *string,
                                   long lIndex)
{
    CHECK_PEER(self);
    CHECK_NULL(string, "null text");

    AwtListbox *obj = GET_OBJ_FROM_PEER(AwtListbox, self);

    obj->AddItem(string, lIndex);
}


void 
sun_awt_windows_WListPeer_delItems( HWListPeer* self,
                                    long start,
                                    long end)
{
    CHECK_PEER(self);

    AwtListbox *obj = GET_OBJ_FROM_PEER(AwtListbox, self);

    obj->DeleteItems(start, end);
}


void 
sun_awt_windows_WListPeer_select( HWListPeer* self,
                                  long index)
{
    CHECK_PEER(self);

    AwtListbox *obj = GET_OBJ_FROM_PEER(AwtListbox, self);

    obj->SetSelection(index, TRUE);
}


void 
sun_awt_windows_WListPeer_deselect( HWListPeer* self,
                                    long index)
{
    CHECK_PEER(self);

    AwtListbox *obj = GET_OBJ_FROM_PEER(AwtListbox, self);

    obj->SetSelection(index, FALSE);
}


void 
sun_awt_windows_WListPeer_makeVisible( HWListPeer* self,
                                       long index)
{
    CHECK_PEER(self);

    AwtListbox *obj = GET_OBJ_FROM_PEER(AwtListbox, self);

    obj->MakeVisible(index);
}


/*boolean*/ long 
sun_awt_windows_WListPeer_isSelected( HWListPeer* self,
                                      long index)
{
    CHECK_PEER_AND_RETURN(self, FALSE);

    AwtListbox *obj = GET_OBJ_FROM_PEER(AwtListbox, self);

    return obj->IsSelected(index);
}


};  // end of extern "C"