Files
ayanova7/archive/ayanova 1.9.4 CE final release db schema 171/sp/gzCombo.cpp

491 lines
12 KiB
C++

// gzCombo.cpp : implementation file
//
#include "stdafx.h"
#include "gzCombo.h"
#include <crtdbg.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CgzCombo
CgzCombo::CgzCombo()
{
m_bAutoComplete = TRUE;
plist = new CStringList[2];//2 column string list
//Color related code
m_clrText = RGB( 0, 0, 0 );
//get the background color so it will not
//look like an editable control and more like a
//chooser control
m_clrBkgnd = GetSysColor(COLOR_3DFACE);
m_brBkgnd.CreateSolidBrush( GetSysColor(COLOR_3DFACE) );
//font related code
::GetObject((HFONT)GetStockObject(DEFAULT_GUI_FONT),sizeof(m_lf),&m_lf);
m_lf.lfWeight = FW_SEMIBOLD ;//FW_MEDIUM,FW_SEMIBOLD,FW_BOLD,FW_BLACK
m_font.DeleteObject();
BOOL bCreated = m_font.CreateFontIndirect(&m_lf);
ASSERT(bCreated);
}
CgzCombo::~CgzCombo()
{
delete[] plist;
}
BEGIN_MESSAGE_MAP(CgzCombo, CComboBox)
//{{AFX_MSG_MAP(CgzCombo)
ON_CONTROL_REFLECT(CBN_EDITUPDATE, OnEditupdate)
ON_CONTROL_REFLECT(CBN_KILLFOCUS, OnKillfocus)
ON_CONTROL_REFLECT(CBN_SETFOCUS, OnSetfocus)
ON_WM_CTLCOLOR()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CgzCombo message handlers
//********************************************************************
//this function and the next are basically all the autoselect feature
void CgzCombo::OnEditupdate()
{
// if we are not to auto update the text, get outta here
if (!m_bAutoComplete)
return;
// Get the text in the edit box
CString str;
GetWindowText(str);
int nLength = str.GetLength();
// Currently selected range
DWORD dwCurSel = GetEditSel();
WORD dStart = LOWORD(dwCurSel);
WORD dEnd = HIWORD(dwCurSel);
// Search for, and select in, string in the combo box that is prefixed
// by the text in the edit box
if (SelectString(-1, str) == CB_ERR)
{
SetWindowText(str); // No text selected, so restore what was there before
if (dwCurSel != CB_ERR)
SetEditSel(dStart, dEnd); //restore cursor postion
}
else
// Set the text selection as the additional text that we have added
if (dEnd < nLength && dwCurSel != CB_ERR)
SetEditSel(dStart, dEnd);
else
SetEditSel(nLength, -1);
}
//*******************************************************************
BOOL CgzCombo::PreTranslateMessage(MSG* pMsg)
{
// Need to check for backspace/delete. These will modify the text in
// the edit box, causing the auto complete to just add back the text
// the user has just tried to delete.
if (pMsg->message == WM_KEYDOWN)
{
m_bAutoComplete = TRUE;
int nVirtKey = (int) pMsg->wParam;
if (nVirtKey == VK_DELETE || nVirtKey == VK_BACK)
{
m_bAutoComplete = FALSE;
}
//if it's the escape key then return the selection
//to it's previous value as in vb combo box
if (nVirtKey == VK_ESCAPE)
{
m_bAutoComplete = FALSE;
SetWindowText(m_InitialValue);
return 1;//nonzero so app does not get the esc key and exit
}
}
return CComboBox::PreTranslateMessage(pMsg);
}
//*********************** Add a row ******************
void CgzCombo::AddRow(CString text, CString ID)
{
SetFont(&m_font,FALSE);
//add the visible text part and use the return value
//to place the id number in the list of pointers
//since were using the ID number returned by the combo
//it's irrelevant whether the combo is in sort mode or not
int x=AddString(text);
if(x==0)
{
plist[0].AddHead(text);
plist[1].AddHead(ID);
}
else
if(x == (GetCount()-1))
{
plist[0].AddTail(text);
plist[1].AddTail(ID);
}
else
{
plist[0].InsertBefore(plist[0].FindIndex(x), text);
plist[1].InsertBefore(plist[1].FindIndex(x), ID);
}
}
//*****************************************************
//returns the id string of the currently selected item
//or blank on error, you might want to modify this
//for more robust error handling if you change the
//way the user typed text is validated from what it
//is here. See OnKillFocus.
CString CgzCombo::GetCurrentRowID()
{
int x=GetCurSel();
if(x!=CB_ERR)
return plist[1].GetAt(plist[1].FindIndex(x));
return "";
}
//*****************************************************
//return the text string of the currently selected item
CString CgzCombo::GetCurrentRowText()
{
int x=GetCurSel();
if(x!=CB_ERR)
return plist[0].GetAt(plist[0].FindIndex(x));
return "";
}
//******************************************************
//clear the combo box completely
//remove all strings
void CgzCombo::Clear()
{
ResetContent();
plist[0].RemoveAll();
plist[1].RemoveAll();
}
//******************************************************
//override kill focus to see if user has made a valid
//selection by typing in text, if so send a
//CBN_CLOSEUP message to the parent window to simulate
//the user having selected a string from the drop down
//list. This way you only have to handle CBN_CLOSEUP
//in the parent window to see if a user has made a change
//either via drop list or typing in an entry.
void CgzCombo::OnKillfocus()
{
//if the list box is empty then there
//can never be a valid selection so just return
//without this user is trapped in combo
//if there aren't any items in the list box
if( 0==GetCount() )
return;
//See what's been selected from the list box?
int cursel=GetCurSel();
//if cursel==CB_ERR then were here because
//the user has typed some text and then left the control
//and we want to process that
// Get the text in the edit box
CString CurrentText;
GetWindowText(CurrentText);
//otherwise, were here because the user selected something in
//the list box so we should exit because we don't need to process it
//however, we could also be here because the user tabbed to the control and
//used the down or up arrow keys to make a list box selection without
//dropping down the list box, so we also check to see if the text in the
//edit box is the same as it was when we first came here, if so then we just exit
//this is a workaround to a problem discovered by Chris Mancini
//thank you Chris.
if (cursel!=CB_ERR && CurrentText==m_InitialValue)
return;
//check to see if users entry in edit part of combo
//matches a string in listbox part of combo
int x=FindStringExact(-1, CurrentText);
if ( x == CB_ERR ) //yes, you saw it! I used x as a variable and I dont care who knows. I might even use y later on.
{
//this is how I handle an invalid entry:
//go back to the combo box and reset it to
//whatever it was before the user modified it
SetWindowText(m_InitialValue);//initialvalue set in OnSetFocus
SetFocus();
}
else//its a valid entry (in the list)
{
//synch the current listbox selection to the
//typed text. If you don't do this your combo doesn't know that you have a selection
SetCurSel(x);
int y=GetDlgCtrlID();
//"Simulate" a list box selection by sending CBN_CLOSEUP
//to the parent window.
::SendMessage(GetParent()->m_hWnd,WM_COMMAND,MAKEWPARAM(y,CBN_CLOSEUP),LPARAM(m_hWnd));
}
}
//*************************************
//Removes the current (selected) row
void CgzCombo::RemoveCurrentRow()
{
//you could easily add a function to
//remove a row based on an ID value or
//different combobox list value but I don't need that
//so it's not here
int x=GetCurSel();
DeleteString(x);
if(x==0)
{
plist[0].RemoveHead();
plist[1].RemoveHead();
}
else
if(x ==GetCount())
{
plist[0].RemoveTail();
plist[1].RemoveTail();
}
else
{
plist[0].RemoveAt(plist[0].FindIndex(x));
plist[1].RemoveAt(plist[1].FindIndex(x));
}
}
//***************************************
void CgzCombo::OnSetfocus()
{
// Get the original text before user makes changes
// so that it can be set back to it if necessary
GetWindowText(m_InitialValue);
}
//********************************
//Select a string in combo based on id value
bool CgzCombo::Select(CString ID)
{
//finds row that matches ID and selects it
//as the displayed item
//I could not find a simpler way to do this
//because stringlist objects dont appear to have
// a function that returns and index of a given
// item. They do return POSITION types but according
// to the docs that is not to be considered an index
// value in any way.
//this function does not generate an On_closeup message
//as the other selection functions do because I use it
//for displaying an initial record from a database
//and no change has been made to the actual record so I
//don't want to process it that way.
//assert on an empty ID string if in debug mode
_ASSERTE(!ID.IsEmpty());
//handle an empty ID string in release mode
if(ID.IsEmpty())
return false;
int x;
POSITION pos;
//if the list is empty, return
if(plist[1].IsEmpty()==TRUE) return false;
//set x to the number of items in the list
x=plist[1].GetCount();
//bail if there is nothing in the list
if(x==0) return false;
//iterate through the list comparing the id
//string at each y index location to the passed ID value
//upon a match we know that y is the index value in the
//combo box that matches the ID value passed to this function
//CHANGE: changed y<x+1 to y<x 042500 2pm
for(int y=0;y<x;y++)
{
//will assert if invalid id attempted
pos=plist[1].FindIndex(y);
_ASSERTE(pos!=NULL);
if(pos==NULL)
return false;
if(ID==plist[1].GetAt(pos))
{
SetCurSel(y);//found a match, set the combo to it
return true;
}
}
//default to top of list
//Added 05/26/00 3.34 pm
SetCurSel(0);
return false;
}
//********************************
//Select a string in combo based on LONG id value
bool CgzCombo::Select(long lID)
{
//Long version of CString version above for convenience
//because 90% of the time I'm passing a long
//record ID value
CString ID;
ID.Format("%d",lID);
//assert on an empty ID string if in debug mode
ASSERT(!ID.IsEmpty());
//handle an empty ID string in release mode
if(ID.IsEmpty())
return false;
int x;
POSITION pos;
//if the list is empty, return
if(plist[1].IsEmpty()==TRUE) return false;
//set x to the number of items in the list
x=plist[1].GetCount();
//bail if there is nothing in the list
if(x==0) return false;
//iterate through the list comparing the id
//string at each y index location to the passed ID value
//upon a match we know that y is the index value in the
//combo box that matches the ID value passed to this function
//CHANGE: changed y<x+1 to y<x 042500 2pm
for(int y=0;y<x;y++)
{
//will assert if invalid id attempted
pos=plist[1].FindIndex(y);
_ASSERTE(pos!=NULL);
if(pos==NULL)
return false;
if(ID==plist[1].GetAt(pos))
{
SetCurSel(y);//found a match, set the combo to it
return true;
}
}
//default to top of list
//Added 05/26/00 3.34 pm
SetCurSel(0);
return false;
}
HBRUSH CgzCombo::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
pDC->SetTextColor( m_clrText ); // text
pDC->SetBkColor( m_clrBkgnd ); // text bkgnd
return m_brBkgnd;
/*
if (nCtlColor == CTLCOLOR_EDIT)
{
pDC->SetTextColor( m_clrText ); // text
pDC->SetBkColor( m_clrBkgnd ); // text bkgnd
return m_brBkgnd;
}
else if (nCtlColor == CTLCOLOR_LISTBOX)
{
pDC->SetTextColor( m_clrText ); // text
pDC->SetBkColor( m_clrBkgnd ); // text bkgnd
return m_brBkgnd;
}
HBRUSH hbr = CComboBox::OnCtlColor(pDC, pWnd, nCtlColor);
return hbr;
*/
HBRUSH hbr = CComboBox::OnCtlColor(pDC, pWnd, nCtlColor);
return hbr;
}