//---------------------------------------------------------------------------- // ObjectWindows // (C) Copyright 1991, 1994 by Borland International, All Rights Reserved // // Implementation of class TListBox and TlistBoxData. //---------------------------------------------------------------------------- #pragma hdrignore SECTION #include #include #include #include #if !defined(SECTION) || SECTION == 1 #define MULTIPLESEL (LBS_MULTIPLESEL | LBS_EXTENDEDSEL) // // TListBoxData constructor // TListBoxData::TListBoxData() : Strings(10, 0, 10), ItemDatas(10, 0, 10), SelIndices(1, 0, 10) { } // // TListBoxData destructor // TListBoxData::~TListBoxData() { } // // adds "str" to "Strings" // // if "isSelected" is true, marks it as selected // void TListBoxData::AddString(const char* str, bool isSelected) { Strings.Add(str); if (isSelected) Select(Strings.GetItemsInContainer()-1); } // // adds str and associated item data to strings and datas // void TListBoxData::AddStringItem(const char* str, uint32 itemData, bool isSelected) { ItemDatas.Add(itemData); AddString(str, isSelected); } // // selects an item at a given index. // void TListBoxData::Select(int index) { if (index != LB_ERR) SelIndices.Add(index); } // // adds "str" to selection lists if it is in Strings // void TListBoxData::SelectString(const char far* str) { for (int i = 0; i < Strings.GetItemsInContainer(); i++) if (strcmp(Strings[i].c_str(), str) == 0) { Select(i); break; } } // // returns the length of the string at the passed selection index // excluding the terminating 0 // int TListBoxData::GetSelStringLength(int index) const { if (index >= 0 && index < GetSelCount()) return Strings[SelIndices[index]].length(); return -1; } // // copies the string at the passed selection index into buffer // // bufferSize includes the terminating 0 // void TListBoxData::GetSelString(char far* buffer, int bufferSize, int index) const { if (bufferSize > 0) { if (index < 0 || index >= GetSelCount()) *buffer = 0; else { strncpy(buffer, Strings[SelIndices[index]].c_str(), bufferSize-1); buffer[bufferSize - 1] = 0; } } } // // copies the string at the passed index in SelStrings into str // void TListBoxData::GetSelString(string& str, int index) const { if (index >= 0 && index < GetSelCount()) str = Strings[SelIndices[index]]; else str = ""; } //---------------------------------------------------------------------------- TStringArray::TStringArray(int upper, int lower, int delta) : Data(upper, lower, delta) { } int TStringArray::LowerBound() const { return Data.LowerBound(); } int TStringArray::UpperBound() const { return Data.UpperBound(); } unsigned TStringArray::ArraySize() const { return Data.ArraySize(); } int TStringArray::IsFull() const { return Data.IsFull(); } int TStringArray::IsEmpty() const { return Data.IsEmpty(); } unsigned TStringArray::GetItemsInContainer() const { return Data.GetItemsInContainer(); } int TStringArray::Add(const string& t) { return Data.Add(t); } int TStringArray::Detach(const string& t) { return Data.Detach(t); } int TStringArray::Detach(int loc) { return Data.Detach(loc); } int TStringArray::Destroy(const string& t) { return Detach(t); } int TStringArray::Destroy(int loc) { return Detach(loc); } int TStringArray::HasMember(const string& t) const { return Data.HasMember(t); } int TStringArray::Find(const string& t) const { return Data.Find(t); } string& TStringArray::operator [](int loc) { return Data[loc]; } string& TStringArray::operator [](int loc) const { return Data[loc]; } void TStringArray::ForEach(IterFunc iter, void* args) { Data.ForEach(iter, args); } string* TStringArray::FirstThat(CondFunc cond, void* args) const { return Data.FirstThat(cond, args); } string* TStringArray::LastThat(CondFunc cond, void* args) const { return Data.LastThat(cond, args); } void TStringArray::Flush() { Data.Flush(); } //---------------------------------------------------------------------------- TIntArray::TIntArray(int upper, int lower, int delta) : Data(upper, lower, delta) { } int TIntArray::LowerBound() const { return Data.LowerBound(); } int TIntArray::UpperBound() const { return Data.UpperBound(); } unsigned TIntArray::ArraySize() const { return Data.ArraySize(); } int TIntArray::IsFull() const { return Data.IsFull(); } int TIntArray::IsEmpty() const { return Data.IsEmpty(); } unsigned TIntArray::GetItemsInContainer() const { return Data.GetItemsInContainer(); } int TIntArray::Add(const TInt& t) { return Data.Add(t); } int TIntArray::Detach(const TInt& t) { return Data.Detach(t); } int TIntArray::Detach(int loc) { return Data.Detach(loc); } int TIntArray::Destroy(const TInt& t) { return Detach(t); } int TIntArray::Destroy(int loc) { return Detach(loc); } int TIntArray::HasMember(const TInt& t) const { return Data.HasMember(t); } int TIntArray::Find(const TInt& t) const { return Data.Find(t); } TInt& TIntArray::operator [](int loc) { return Data[loc]; } TInt& TIntArray::operator [](int loc) const { return Data[loc]; } void TIntArray::ForEach(IterFunc iter, void* args) { Data.ForEach(iter, args); } TInt* TIntArray::FirstThat(CondFunc cond, void* args) const { return Data.FirstThat(cond, args); } TInt* TIntArray::LastThat(CondFunc cond, void* args) const { return Data.LastThat(cond, args); } void TIntArray::Flush() { Data.Flush(); } //---------------------------------------------------------------------------- TDwordArray::TDwordArray(int upper, int lower, int delta) : Data(upper, lower, delta) { } int TDwordArray::LowerBound() const { return Data.LowerBound(); } int TDwordArray::UpperBound() const { return Data.UpperBound(); } unsigned TDwordArray::ArraySize() const { return Data.ArraySize(); } int TDwordArray::IsFull() const { return Data.IsFull(); } int TDwordArray::IsEmpty() const { return Data.IsEmpty(); } unsigned TDwordArray::GetItemsInContainer() const { return Data.GetItemsInContainer(); } int TDwordArray::Add(const uint32& t) { return Data.Add(t); } int TDwordArray::Detach(const uint32& t) { return Data.Detach(t); } int TDwordArray::Detach(int loc) { return Data.Detach(loc); } int TDwordArray::Destroy(const uint32& t) { return Detach(t); } int TDwordArray::Destroy(int loc) { return Detach(loc); } int TDwordArray::HasMember(const uint32& t) const { return Data.HasMember(t); } int TDwordArray::Find(const uint32& t) const { return Data.Find(t); } uint32& TDwordArray::operator [](int loc) { return Data[loc]; } uint32& TDwordArray::operator [](int loc) const { return Data[loc]; } void TDwordArray::ForEach(IterFunc iter, void* args) { Data.ForEach(iter, args); } uint32* TDwordArray::FirstThat(CondFunc cond, void* args) const { return Data.FirstThat(cond, args); } uint32* TDwordArray::LastThat(CondFunc cond, void* args) const { return Data.LastThat(cond, args); } void TDwordArray::Flush() { Data.Flush(); } //---------------------------------------------------------------------------- // // constructor for TListBox // // initializes its data fields using parameters passed and default values // // by default, an MS-Windows listbox associated with the TListBox will: // - be visible upon creation // - have a border and a vertical scrollbar // - maintain entries in alphabetical order // - notify its parent when a selection is made // TListBox::TListBox(TWindow* parent, int id, int x, int y, int w, int h, TModule* module) : TControl(parent, id, 0, x, y, w, h, module) { Attr.Style |= LBS_STANDARD; } TListBox::TListBox(TWindow* parent, int resourceId, TModule* module) : TControl(parent, resourceId, module) { } char far* TListBox::GetClassName() { return "LISTBOX"; } // // transfers state information for a TListBox // // transfers the items and selection of the list to or from a transfer // buffer if tdSetData or tdGetData, respectively, is passed as the // direction // // buffer should point to a TListBoxData which points to the data to be // transferred // // Transfer returns the size of TListBoxData // // to retrieve the size without transferring data, pass tdSizeData as the // direction // uint TListBox::Transfer(void* buffer, TTransferDirection direction) { long style = GetWindowLong(GWL_STYLE); TListBoxData* listBoxData = (TListBoxData*)buffer; if (direction == tdGetData) { // // first, clear out Strings array and fill with contents of list box // listBoxData->Clear(); // // pre-calculate max string length so that one big buffer can be used // int count = GetCount(); int maxStrLen = 0; for (int i = 0; i < count; i++) { int strLen = GetStringLen(i); if (strLen > maxStrLen) maxStrLen = strLen; } // // Get each string and item data in the listbox & add to listboxdata // char* tmpStr = new char[maxStrLen+1]; for (i = 0; i < GetCount(); i++) { GetString(tmpStr, i); listBoxData->AddStringItem(tmpStr, GetItemData(i), false); } delete tmpStr; // // update transfer data with new selected item(s) // listBoxData->ResetSelections(); if (!(style & MULTIPLESEL)) { // // single selection // listBoxData->Select(GetSelIndex()); } else { // // multiple selection // int selCount = GetSelCount(); if (selCount > 0) { int* selections = new int[selCount]; GetSelIndexes(selections, selCount); // Select each item by index // for (int selIndex = 0; selIndex < selCount; selIndex++) listBoxData->Select(selections[selIndex]); delete selections; } } } else if (direction == tdSetData) { ClearList(); // // add each string, item data and selections in listBoxData to list box // const int noSelection = -1; int selCount = listBoxData->GetSelCount(); // for multi selection int selIndex = noSelection; // for single selection for (int i = 0; i < listBoxData->GetStrings().GetItemsInContainer(); i++) { // index may be different from i when the listbox is sorted. // int index = AddString(listBoxData->GetStrings()[i].c_str()); SetItemData(index, listBoxData->GetItemDatas()[i]); if (style & MULTIPLESEL) { for (int j = 0; j < selCount; j++) if (listBoxData->GetSelIndices()[j] == i) { SetSel(index, true); break; } } else { if (listBoxData->GetSelIndices()[0] == i) selIndex = index; else // inserted something before item and the item to select has been // pushed further down in the list. // if (selIndex != noSelection && index <= selIndex) selIndex++; } } if (selIndex != noSelection && !(style & MULTIPLESEL)) SetSelIndex(selIndex); } return sizeof(TListBoxData); } // // returns the index of the first string in the associated listbox // which is the same as the passed string // // searches for a match beginning at the passed indexStart // // if a match is not found after the last string has been compared, // the search continues from the beginning of the list until a match // is found or until the list has been completely traversed // // searches from beginning of list when -1 is passed as the index // // returns the index of the selected string; a negative value is returned // if an error occurs // // for single or multiple-selection list boxes // int TListBox::FindExactString(const char far* findStr, int indexStart) const { bool found = false; int firstMatch = indexStart = FindString(findStr, indexStart); do { if (indexStart > -1) { char* tmpStr = new char[GetStringLen(indexStart) + 1]; GetString(tmpStr, indexStart); if (strcmp(tmpStr, findStr) == 0) found = true; else indexStart = FindString(findStr, indexStart); delete tmpStr; } } while (!found && indexStart != firstMatch); return found ? indexStart : -1; } // // for use with single-selection list boxes (and combo boxes) // // retrieves the text of the string which is selected in the associated // listbox // // returns the number of characters copied; -1 is returned if no string // is selected or this is a multiple-selection list box // // since the Windows function is not passed a size parameter, we have to // allocate a string to hold the largest string (gotten from a query), and // copy a part of it // int TListBox::GetSelString(char far* str, int maxChars) const { int index = GetSelIndex(); if (index > -1) { int length = GetStringLen(index); if (maxChars >= length) return GetString(str, index); else { char* tmpStr = new char[length + 1]; if (tmpStr) { GetString(tmpStr, index); strncpy(str, tmpStr, maxChars); delete tmpStr; return maxChars; } } } return -1; } // // returns the number of selected items in the list box. For // multiple-selection list boxes only // int TListBox::GetSelCount() const { if (!(GetWindowLong(GWL_STYLE) & MULTIPLESEL)) return GetSelIndex() < 0 ? 0 : 1; // // multiple-selection list box // return (int)CONST_CAST(TListBox*,this)->HandleMessage(LB_GETSELCOUNT); } // // retrieves the text of the strings which are selected in the // associated listbox // // returns the number of items put into Strings. -1 is returned if this is // not a multiple-selection list box // // since the Windows function is not passed a size parameter, we have to // allocate a string to hold the largest string (gotten from a query), and // copy a part of it // // only for use with multiple-selection list boxes // int TListBox::GetSelStrings(char far** strs, int maxCount, int maxChars) const { if (!(GetWindowLong(GWL_STYLE) & MULTIPLESEL)) return -1; int i = GetSelCount(); if (i < maxCount) maxCount = i; if (maxCount > 0) { int* selections = new int[maxCount]; GetSelIndexes(selections, maxCount); for (int selIndex = 0; selIndex < maxCount; selIndex++) { int tmpStrLen = GetStringLen(selections[selIndex]); if (maxChars >= tmpStrLen) GetString(strs[selIndex], selections[selIndex]); else { char* tmpStr = new char[tmpStrLen+1]; if (tmpStr) { GetString(tmpStr, selections[selIndex]); strncpy(strs[selIndex], tmpStr, maxChars); delete tmpStr; } } } delete selections; } return maxCount; } // // selects the first string in the associated listbox following the // passed index which begins with the passed string // // searches for a match beginning at the passed Index. if a match is not // found after the last string has been compared, the search continues // from the beginning of the list until a match is found or until the list // has been completely traversed // // searches from beginning of list when -1 is passed as the index // // returns the index of the selected string. a negative value is returned // if an error occurs // // only for single-selection list boxes // int TListBox::SetSelString(const char far* findStr, int indexStart) { if (!(GetWindowLong(GWL_STYLE) & MULTIPLESEL)) return (int)HandleMessage(LB_SELECTSTRING, indexStart, (LPARAM)findStr); return -1; } // // selects the strings in the associated list box which begin with // the passed prefixes // // for each string the search begins at the beginning of the list // and continues until a match is found or until the list has been // completely traversed // // if ShouldSet is true, the matched strings are selected and highlighted; // otherwise the highlight is removed from the matched strings and they // are no longer selected // // returns the number of strings successfully selected or deselected // // if NumSelections is less than zero, all strings are selected or deselected // and a negative value is returned on failure // // only for multiple-selection list boxes (-1 is returned if this is not // a multiple-selection list box) // int TListBox::SetSelStrings(const char far** strs, int numSelections, bool shouldSet) { if (!(GetWindowLong(GWL_STYLE) & MULTIPLESEL)) return -1; if (numSelections < 0) return SetSel(-1, shouldSet); int successes = 0; for (int i = 0; i < numSelections; i++) { int selIndex; if ((selIndex = FindString(strs[i], -1)) > -1) if (SetSel(selIndex, shouldSet) > -1) successes++; } return successes; } // // returns the index of the selected string in the associated listbox // // a negative value is returned if no string is selected or this // is a multiple-selection list box // // only for single-selection list boxes // int TListBox::GetSelIndex() const { if (!(GetWindowLong(GWL_STYLE) & MULTIPLESEL)) return (int)CONST_CAST(TListBox*,this)->HandleMessage(LB_GETCURSEL); return -1; } // // fills indexes with the indexes of up to maxCount selected strings // // returns number of items put in the array(-1 for single-selection // list boxes) // int TListBox::GetSelIndexes(int* indexes, int maxCount) const { if (!(GetWindowLong(GWL_STYLE) & MULTIPLESEL)) return -1; return (int)CONST_CAST(TListBox*,this)->HandleMessage(LB_GETSELITEMS, maxCount, (LPARAM)indexes); } // selects the string at passed index in the associated listbox and // forces the string into view // // clears selection when -1 is passed as the index. a negative value is // returned if an error occurs // // only for single-selection list boxes // int TListBox::SetSelIndex(int index) { if (!(GetWindowLong(GWL_STYLE) & MULTIPLESEL)) return (int)HandleMessage(LB_SETCURSEL, index); return -1; } // // selects/deselects the strings in the associated list box at the // passed indexes // // if ShouldSet is true, the indexed strings are selected and highlighted; // otherwise the highlight is removed and they are no longer selected // // returns the number of strings successfully selected or deselected(-1 // if not a multiple-selection list box) // // if NumSelections is less than zero, all strings are selected or deselected // and a negative value is returned on failure // // only for multiple-selection list boxes // int TListBox::SetSelIndexes(int* indexes, int numSelections, bool shouldSet) { int successes = 0; if (!(GetWindowLong(GWL_STYLE) & MULTIPLESEL)) return -1; // including if it's a combobox if (numSelections < 0) return (int)HandleMessage(LB_SETSEL, shouldSet, -1); else { for (int i = 0; i < numSelections; i++) if ((int)HandleMessage(LB_SETSEL, shouldSet, indexes[i]) > -1) successes++; } return successes; } #endif #if !defined(SECTION) || SECTION == 2 IMPLEMENT_STREAMABLE1(TListBox, TControl); // // reads an instance of TListBox from the supplied ipstream // void* TListBox::Streamer::Read(ipstream& is, uint32 /*version*/) const { ReadBaseObject((TControl*)GetObject(), is); return GetObject(); } // // writes the TListBox to the supplied opstream // void TListBox::Streamer::Write(opstream& os) const { WriteBaseObject((TControl*)GetObject(), os); } #endif