Listing 3 LBWE member functions
// ListBoxWithExtras.cpp : implementation file
//
//This is the "meat and potatoes file. The functionality of the
//enhanced listbox is right here.
#include "stdafx.h"
#include "ListBoxWithExtras.h"
#include <new.h>
#include <fstream.h>
namespace std {
#include <vector.h>
#include <algo.h> //for sort() template
}
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
////////////////////////////////////////////////////////////////
// ListBoxWithExtras implementation
//Construction and Destruction
ListBoxWithExtras::ListBoxWithExtras()
: lbweInitialized(FALSE)
{}
ListBoxWithExtras::~ListBoxWithExtras() {}
//App Wizard sets this next stuff up. This will trap the keydown
//and double click list box selection messages so we get a crack
//at them. If you construct your list box with the 'Notify'
//option unchecked (that's NOT the default), you won't get
//ListBoxWithExtras::EditEntry() functionality when an string is
//double clicked.
BEGIN_MESSAGE_MAP(ListBoxWithExtras, CListBox)
//{{AFX_MSG_MAP(ListBoxWithExtras)
ON_CONTROL_REFLECT(LBN_DBLCLK, OnDblclk)
ON_WM_KEYDOWN()
ON_WM_PARENTNOTIFY()
ON_WM_CHAR()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
////////////////////////////////////////////////////////////////
void ListBoxWithExtras::AppendEntry()
//Adds a string to the box. An empty string is shoved into the
//last slot and then we edit that blank box.
{
SetCurSel(InsertString(GetCount(), ""));
CrankUpTheEdit(GetCount() - 1, INSERT_STRING);
}
void ListBoxWithExtras::InsertEntry()
//Inserts an entry before the highlighted entry. If no entry
//is highlighted, the user gets a chance to add an entry to the
//end of the list.
{
int position = GetCurSel();
//If there are no highlighted entries, or no entries at all,
//InsertEntry() becomes an AppendEntry()
if (position == LB_ERR)
AppendEntry();
else
{
SetCurSel(InsertString (position, ""));
CrankUpTheEdit(position, INSERT_STRING);
}
}
void ListBoxWithExtras::EditEntry()
//Double clicking a listbox entry allows edit or it can be called
//from a program to operate on a highlighted selection
{
int position = GetCurSel();
if (position == LB_ERR)
MessageBeep(MB_OK);
else
CrankUpTheEdit(position, EDIT_STRING);
}
void ListBoxWithExtras::DeleteEntry()
//Deletes the highlighted entry
{
int position = GetCurSel();
if (position == LB_ERR) //entry highlighted?
MessageBeep(MB_OK);
else
{
ListBoxState undoBuff;
//save the to be deleted string
GetText(position, undoBuff.valueLBS);
SetCurSel(std::min(DeleteString(position) - 1, position));
lbweBuffer.erase(lbweBuffer.begin() + position);
//finish saving the previous state for Undo()
undoBuff.positionLBS = position;
undoBuff.actionLBS = DELETE_STRING;
undoStack.push(undoBuff);
}
}
void ListBoxWithExtras::Undo()
//Undo() "turns back the clock" and undoes the last
//change to the listbox
{
if (undoStack.empty()) //anything to undo?
MessageBeep(MB_OK);
else
{
ListBoxState undo = undoStack.top();
undoStack.pop(); //STL stack pop() returns no value
//Now we have all the info need to restore the previous state
switch (undo.actionLBS)
{
case DELETE_STRING:
SetCurSel(InsertString (undo.positionLBS, undo.valueLBS));
lbweBuffer.insert(
lbweBuffer.begin() + undo.positionLBS,
undo.valueLBS);
break;
case INSERT_STRING:
SetCurSel(std::min(DeleteString(undo.positionLBS) - 1,
undo.positionLBS));
lbweBuffer.erase(
lbweBuffer.begin() + undo.positionLBS);
break;
case EDIT_STRING:
DeleteString(undo.positionLBS);
lbweBuffer.erase(
lbweBuffer.begin() + undo.positionLBS);
//When putting an entry into the box, the box style
//must be taken into account. If it's a sorted box,
//CListBox::AddString() does a fine job.
int position;
if (IsSortedBox())
position = AddString(undo.valueLBS);
else
position = InsertString(undo.positionLBS,
undo.valueLBS);
SetCurSel(position);
lbweBuffer.insert(
lbweBuffer.begin() + position, undo.valueLBS);
break;
default:
abort(); //we shouldn't ever get here
}
}
}
void ListBoxWithExtras::ResetUndo()
{
CString temp;
while (undoStack.size())
undoStack.pop();
lbweBuffer.erase(lbweBuffer.begin(), lbweBuffer.end());
for (int i = 0; i < GetCount(); i++)
{
GetText(i, temp);
lbweBuffer.push_back(temp);
}
}
// ...
// not shown: SortList and CrankUpTheEdit
// available electronically --mb
// ...
/////////////////////////////////////////////////////////////////
// ListBoxWithExtras message handlers
void ListBoxWithExtras::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
//Trap key presses in order to integrate <Delete> and <Insert>
//into the control. We're also changing <End> to mean
//AppendEntry()
{
switch (nChar)
{
case VK_END: //<End>
AppendEntry();
return;
case VK_DELETE: //<Delete>
DeleteEntry();
return;
case VK_INSERT: //<Insert>
InsertEntry();
return;
}
//Just pass along keys you don't care about.
CListBox::OnKeyDown(nChar, nRepCnt, nFlags);
}
void ListBoxWithExtras::OnDblclk()
//Double clicking a listbox entry gets us here
{
ASSERT(LB_ERR != GetCurSel());
EditEntry();
}
// ...
// not shown: OnParentNotify
// available electronically -- mb
// ...
void ListBoxWithExtras::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
//Here's the handler needed for calling member functions from
//"regular keys". <Ctrl>-Y will delete an entry and <Ctrl>-U will
//invoke ListBoxWithExtras::Undo()
{
const UINT CtrlY = 25; //delete command
const UINT CtrlU = 21; //undo command
switch (nChar)
{
case CtrlU:
Undo();
return;
case CtrlY:
DeleteEntry();
return;
}
//all other chars handles by base class
CListBox::OnChar(nChar, nRepCnt, nFlags);
}
LRESULT ListBoxWithExtras::DefWindowProc(UINT message,
WPARAM wParam,
LPARAM lParam)
{
if (!lbweInitialized)
{
CString temp;
lbweInitialized = TRUE;
std::vector<CString>::iterator i;
for (i = lbweBuffer.begin(); i != lbweBuffer.end(); i++)
AddString(*i);
lbweBuffer.erase(lbweBuffer.begin(), lbweBuffer.end());
for (int j = 0; j < GetCount(); j++)
{
GetText(j, temp);
lbweBuffer.push_back(temp);
}
SetCurSel(0);
}
return CListBox::DefWindowProc(message, wParam, lParam);
}
//End of File