home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1998 May / Pcwk5b98.iso / Borland / Cplus45 / BC45 / OWL1.PAK / LISTBOX.CPP < prev    next >
C/C++ Source or Header  |  1995-08-29  |  19KB  |  547 lines

  1. // ObjectWindows - (C) Copyright 1992 by Borland International
  2.  
  3. /* --------------------------------------------------------
  4.   LISTBOX.CPP
  5.   Defines type TListBox.  This defines the basic behavior
  6.   of all listbox controls.
  7.   -------------------------------------------------------- */
  8.  
  9. #include "listbox.h"
  10. #include <stdlib.h>
  11.  
  12. #define MULTIPLESEL (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)
  13.  
  14. /* Constructs Strings and SelStrings, and initializes SelCount
  15.    to zero. */
  16. TListBoxData::TListBoxData()
  17. {
  18.   SelCount = 0;
  19.   Strings = new Array(10, 0, 10);
  20.   SelStrings = new Array(10, 0, 10);
  21. }
  22.  
  23. /* Deletes Strings and SelStrings. */
  24. TListBoxData::~TListBoxData()
  25. {
  26.   if ( Strings )
  27.     delete Strings;
  28.   if ( SelStrings )
  29.     delete SelStrings ;
  30. }
  31.  
  32. /* Adds the specified string to Strings.  If IsSelected is
  33.    TRUE, also adds the string to SelStrings. */
  34. void TListBoxData::AddString(Pchar AString, BOOL IsSelected)
  35. {
  36.   Strings->add(*new String(AString));
  37.   if ( IsSelected )
  38.     SelStrings->addAt(*new String(AString), SelCount++);
  39. }
  40.  
  41. /* Adds the specified string to SelStrings. */
  42. void TListBoxData::SelectString(LPSTR AString)
  43. {
  44.   Pchar TmpString = new char[_fstrlen(AString) + 1];
  45.   _fstrcpy(TmpString, AString);
  46.   SelStrings->addAt(*new String(TmpString), SelCount++);
  47.   delete TmpString;
  48. }
  49.  
  50. /* Removes all strings from SelStrings and sets SelCount to 0. */
  51. void TListBoxData::ResetSelections()
  52. {
  53.     SelStrings->flush();
  54.     SelCount = 0;
  55. }
  56.  
  57. /* Returns the length of the string at the passed index in
  58.    SelStrings excluding the terminating null. */
  59. int TListBoxData::GetSelStringLength(int Index)
  60. {
  61.     if (Index >= 0 && Index < SelCount)
  62.         return strlen((PCchar)(RString)(*SelStrings)[Index]);
  63.     else
  64.         return -1;
  65. }
  66.  
  67. /* Copies the string at the passed index in SelStrings into
  68.    Buffer. BufferSize includes the terminating null. */
  69. void TListBoxData::GetSelString(LPSTR Buffer, int BufferSize, int Index)
  70. {
  71.   if (BufferSize > 0)
  72.   {
  73.       if (Index >= 0 && Index < SelCount)
  74.       {
  75.           _fstrncpy(Buffer, (PCchar)(RString)(*SelStrings)[Index],
  76.               BufferSize-1);
  77.           Buffer[BufferSize - 1] = '\0';
  78.       }
  79.       else
  80.           Buffer[0] = '\0';
  81.   }
  82. }
  83.  
  84. /* Constructor for an instance of TListBox.  Initializes its data fields
  85.   using parameters passed and default values.  By default, an MS-Windows
  86.   listbox associated with the TListBox will: be visible upon creation;
  87.   have a border and a vertical scrollbar; maintain entries in
  88.   alphabetical order; and notify its parent when a selection is made. */
  89. TListBox::TListBox(PTWindowsObject AParent, int AnId, int X, int Y,
  90.                    int W, int H, PTModule AModule)
  91.          : TControl(AParent, AnId, NULL, X, Y, W, H, AModule)
  92. {
  93.   Attr.Style |= LBS_STANDARD;
  94. }
  95.  
  96. static void DoAddForLB(RObject AString, Pvoid AListBox)
  97. {
  98.   if (AString!=NOOBJECT)
  99.     ((PTListBox)AListBox)->AddString((Pchar)(PCchar)(RString)AString);
  100. }
  101.  
  102. /* Transfers state information for a TListBox. The TransferFlag passed
  103.   specifies whether data is to be read from or written to the passed
  104.   buffer, or whether the data element size is simply to be returned.
  105.   The return value is the size (in bytes) of the transfer data. */
  106. WORD TListBox::Transfer(Pvoid DataPtr, WORD TransferFlag)
  107. {
  108.   int I, SelIndex;
  109.   long Style;
  110.   int *Selections;
  111.   int MaxStringLen = 0, TmpStringLen = 0;
  112.   Pchar TmpString;
  113.   PTListBoxData ListBoxData = *(PTListBoxData _FAR *)DataPtr;
  114.  
  115.   Style = GetWindowLong(HWindow, GWL_STYLE);
  116.   if ( TransferFlag == TF_GETDATA )
  117.   {
  118.     // first, clear out Strings array and fill with contents of list box
  119.     ListBoxData->Strings->flush();
  120.  
  121.     for (int i=0; i<GetCount(); i++) {
  122.        TmpString = new char[GetStringLen(i)+1];
  123.        GetString(TmpString, i);
  124.        ListBoxData->AddString(TmpString, FALSE);
  125.        delete TmpString;
  126.     }
  127.  
  128.     // then update transfer data with new selected item(s)
  129.     ListBoxData->ResetSelections();
  130.     if ( (Style & MULTIPLESEL) == 0 ) // single selection
  131.     {
  132.       // Get selected item
  133.       SelIndex = (int)SendMessage(HWindow, LB_GETCURSEL, 0, 0);
  134.       if ( SelIndex != LB_ERR )
  135.       {
  136.          // allocate string for selected item and copy string to transfer data
  137.           MaxStringLen = GetStringLen(SelIndex);
  138.           TmpString = new char[MaxStringLen + 1];
  139.           GetString(TmpString, SelIndex);
  140.           ListBoxData->SelectString(TmpString);
  141.           delete TmpString;
  142.       }
  143.     }
  144.     else // multiple selection
  145.     {
  146.       I = GetSelCount();
  147.       if ( I > 0 )
  148.       {
  149.         Selections = new int[I];
  150.         SendMessage(HWindow, LB_GETSELITEMS, I, (long)(Selections));
  151.         // loop through all selections to find longest string
  152.         for (int SelIndex = 0; SelIndex < I; SelIndex++)
  153.         {
  154.           TmpStringLen = GetStringLen(Selections[SelIndex]);
  155.           if ( TmpStringLen > MaxStringLen )
  156.             MaxStringLen = TmpStringLen;
  157.         }
  158.         // allocate temporary string large enough to hold longest selection
  159.         TmpString = new char[MaxStringLen+1];
  160.         for (SelIndex = 0; SelIndex < I; SelIndex++)
  161.         {
  162.           GetString(TmpString, Selections[SelIndex]);
  163.           ListBoxData->SelectString(TmpString);
  164.         }
  165.          delete TmpString;
  166.          delete Selections;
  167.       }
  168.     }
  169.   }
  170.   else if ( TransferFlag == TF_SETDATA )
  171.   {
  172.     ClearList();
  173.     // add each string in ListBoxData to list box
  174.     ListBoxData->Strings->forEach(DoAddForLB, this);
  175.  
  176.     // now update selected item(s) as per ListBoxData
  177.  
  178.     if ( (Style & MULTIPLESEL) == 0 )
  179.     {       // single selection list box
  180.       if ( ListBoxData->SelCount )
  181.       {
  182.         SelIndex = FindExactString((LPSTR)(PCchar)(RString)
  183.                      (*ListBoxData->SelStrings)[0], -1);
  184.         if ( SelIndex > -1 )
  185.           SetSelIndex(SelIndex);
  186.       }
  187.     }
  188.     else    // multiple selection list box
  189.     {
  190.       SendMessage(HWindow, LB_SETSEL, 0, -1); // Unselect all
  191.  
  192.       for (I = 0; I < ListBoxData->SelCount; ++I)
  193.       {
  194.         SelIndex = FindExactString((LPSTR)(PCchar)(RString)
  195.                      (*ListBoxData->SelStrings)[I], -1);
  196.         if ( SelIndex > -1 )
  197.           SendMessage(HWindow, LB_SETSEL, 1, SelIndex);
  198.       }
  199.     }
  200.   }
  201.   return sizeof(PTListBoxData);
  202. }
  203.  
  204. /* Adds a string to an associated listbox.  Returns index of the string
  205.   in the list (the first entry is at index 0).  A negative value is
  206.   returned if an error occurs. */
  207. int TListBox::AddString(LPSTR AString)
  208. {
  209.   return (int)(SendMessage(HWindow, GetMsgID(MN_ADDSTRING),
  210.                            0, (long)AString));
  211. }
  212.  
  213. /* Inserts a string in the associated listbox at the passed index,
  214.   returning the index of the string in the list.  A negative value is
  215.   returned if an error occurs. */
  216. int TListBox::InsertString(LPSTR AString, int Index)
  217. {
  218.   return (int)SendMessage(HWindow, GetMsgID(MN_INSERTSTRING),
  219.                           Index, (long)AString);
  220. }
  221.  
  222. /* Deletes the string at the passed index in the associated listbox.
  223.   Returns a count of the entries remaining in the list.  A negative
  224.   value is returned if an error occurs. */
  225. int TListBox::DeleteString(int Index)
  226. {
  227.   return (int)SendMessage(HWindow, GetMsgID(MN_DELETESTRING), Index, 0);
  228. }
  229.  
  230. /* Clears all the entries in the associated listbox. */
  231. void TListBox::ClearList()
  232. {
  233.   SendMessage(HWindow, GetMsgID(MN_RESETCONTENT), 0, 0);
  234. }
  235.  
  236. /* Returns the number of entries in the associated listbox. A negative
  237.   value is returned if an error occurs. */
  238. int TListBox::GetCount()
  239. {
  240.   return (int)SendMessage(HWindow, GetMsgID(MN_GETCOUNT), 0, 0);
  241. }
  242.  
  243. /* Returns the index of the first string in the associated listbox
  244.   which begins with the passed string.  Searches for a match beginning
  245.   at the passed SearchIndex. If a match is not found after the last
  246.   string has been compared, the search continues from the beginning of
  247.   the list until a match is found or until the list has been completely
  248.   traversed.  Searches from beginning of list when -1 is passed as the
  249.   index.  Returns the index of the selected string.  A negative value
  250.   is returned if an error occurs. For single or multiple-selection
  251.   list boxes. */
  252. int TListBox::FindString(LPSTR Prefix, int SearchIndex)
  253. {
  254.   return (int)SendMessage(HWindow, GetMsgID(MN_FINDSTRING),
  255.       SearchIndex, (long)Prefix);
  256. }
  257.  
  258. /* Returns the index of the first string in the associated listbox
  259.   which is the same as the passed string.  Searches for a match
  260.   beginning at the passed SearchIndex. If a match is not found after
  261.   the last string has been compared, the search continues from the
  262.   beginning of the list until a match is found or until the list has
  263.   been completely traversed.  Searches from beginning of list when -1
  264.   is passed as the index.  Returns the index of the selected string.
  265.   A negative value is returned if an error occurs. For single or
  266.   multiple-selection list boxes. */
  267. int TListBox::FindExactString(LPSTR AString, int SearchIndex)
  268. {
  269.   Pchar TmpString;
  270.   int FirstMatch;
  271.   BOOL Found = FALSE;
  272.  
  273.   FirstMatch = SearchIndex = (int)SendMessage(HWindow,
  274.      GetMsgID(MN_FINDSTRING), SearchIndex, (long)AString);
  275.   do
  276.   {
  277.     if ( SearchIndex > -1 )
  278.     {
  279.       TmpString = new char[GetStringLen(SearchIndex) + 1];
  280.       GetString(TmpString, SearchIndex);
  281.       if ( lstrcmp(TmpString, AString) == 0 )
  282.         Found = TRUE;
  283.       else
  284.         SearchIndex = (int)SendMessage(HWindow,
  285.            GetMsgID(MN_FINDSTRING), SearchIndex, (long)AString);
  286.       delete TmpString;
  287.     }
  288.   } while ( !Found && SearchIndex != FirstMatch );
  289.  
  290.   if ( !Found )
  291.     return -1;
  292.   else
  293.     return SearchIndex;
  294. }
  295.  
  296. /* Retrieves the contents of the string at the passed index of the
  297.   associated listbox, returning the length of the string (in bytes
  298.   excluding the terminating null) as the value of the call. A
  299.   negative value is returned if the passed index is not valid.
  300.   The buffer must be large enough for the string and the terminating
  301.   null. */
  302. int TListBox::GetString(LPSTR AString, int Index)
  303. {
  304.   return (int)SendMessage(HWindow, GetMsgID(MN_GETTEXT),
  305.                           Index, (long)AString);
  306. }
  307.  
  308. /* Returns the length of the string at the passed index in the
  309.    associated listbox excluding the terminating null. A negative
  310.    value is returned if an error occurs. */
  311. int TListBox::GetStringLen(int Index)
  312. {
  313.   return (int)SendMessage(HWindow, GetMsgID(MN_GETTEXTLEN), Index, 0);
  314. }
  315.  
  316. /* Returns the number of selected items in the list box. For single-
  317.    or multiple-selection list boxes (and combo boxes). */
  318. int TListBox::GetSelCount()
  319. {
  320.   if ( (GetWindowLong(HWindow, GWL_STYLE) & MULTIPLESEL) == 0)
  321.     //including if it's a combobox.
  322.     return GetSelIndex() < 0 ? 0 : 1;
  323.   else  // multiple-selection list box
  324.     return (int)SendMessage(HWindow, LB_GETSELCOUNT, 0, 0);
  325. }
  326.  
  327. /* For use with single-selection list boxes (and combo boxes).
  328.    Retrieves the text of the string which is selected in the
  329.    associated listbox.  Returns the number of characters copied.
  330.    -1 is returned if no string is selected or if this is a
  331.    multiple-selection list box.  Since the Windows function is not
  332.    passed a size parameter, we have to allocate a string to hold
  333.    the largest string (gotten from a query), and copy a part of it. */
  334. int TListBox::GetSelString(LPSTR AString, int MaxChars)
  335. {
  336.   int Index, Length;
  337.   Pchar TempString;
  338.  
  339.   if ( (GetWindowLong(HWindow, GWL_STYLE) & MULTIPLESEL) == 0)
  340.   //including if it's a combobox.
  341.   {
  342.     Index = GetSelIndex();
  343.     if ( Index > -1 )
  344.     {
  345.       Length = GetStringLen(Index);
  346.       if ( MaxChars >= Length )
  347.         return GetString(AString,Index);
  348.       else
  349.       {
  350.         TempString = new char[Length+1];
  351.         if ( TempString )
  352.         {
  353.           GetString(TempString, Index);
  354.           _fstrncpy(AString, TempString, MaxChars);
  355.           delete TempString;
  356.           return MaxChars;
  357.         }
  358.       }
  359.     }
  360.   }
  361.   return -1;
  362. }
  363.  
  364. /* Retrieves the text of the strings which are selected in the
  365.    associated listbox.  Returns the number of items put into Strings.  -1 is
  366.    returned if this is not a multiple-selection list box.  Since the Windows
  367.    function is not  passed a size parameter, we have to allocate a string
  368.    to hold the largest string (gotten from a query), and copy a part of it.
  369.    Only for use with multiple-selection list boxes. */
  370. int TListBox::GetSelStrings(LPSTR *Strings, int MaxCount, int MaxChars)
  371. {
  372.   int I, TmpStringLen, *Selections;
  373.   Pchar TmpString;
  374.  
  375.   if ( (GetWindowLong(HWindow, GWL_STYLE) & MULTIPLESEL) == 0)
  376.     //including if it's a combobox.
  377.     return -1;
  378.  
  379.   I = GetSelCount();
  380.   if ( I < MaxCount )
  381.     MaxCount = I;
  382.  
  383.   if ( MaxCount > 0 )
  384.   {
  385.     Selections = new int[MaxCount];
  386.     SendMessage(HWindow, LB_GETSELITEMS, MaxCount, (long)(Selections));
  387.     for (int SelIndex = 0; SelIndex < MaxCount; SelIndex++)
  388.     {
  389.       TmpStringLen = GetStringLen(Selections[SelIndex]);
  390.       if ( MaxChars >= TmpStringLen )
  391.         GetString(Strings[SelIndex], Selections[SelIndex]);
  392.       else
  393.       {
  394.         TmpString = new char [TmpStringLen+1];
  395.         if ( TmpString )
  396.         {
  397.           GetString(TmpString, Selections[SelIndex]);
  398.           _fstrncpy(Strings[SelIndex], TmpString, MaxChars);
  399.           delete TmpString;
  400.         }
  401.       }
  402.     }
  403.     delete Selections;
  404.   }
  405.   return MaxCount;
  406. }
  407.  
  408. /* Selects the first string in the associated listbox following the
  409.   passed index which begins with the passed string.  Searches for a
  410.   match beginning at the passed Index.  If a match is not found after
  411.   the last string has been compared, the search continues from the
  412.   beginning of the list until a match is found or until the list has
  413.   been completely traversed.  Searches from beginning of list when
  414.   -1 is passed as the index.  Returns the index of the selected
  415.   string.  A negative value is returned if an error occurs. Only for
  416.   single-selection list boxes (and combo boxes). */
  417. int TListBox::SetSelString(LPSTR Prefix, int SearchIndex)
  418. {
  419.   if ( (GetWindowLong(HWindow, GWL_STYLE) & MULTIPLESEL) == 0 )
  420.     //including if it's a combobox.
  421.     return (int)SendMessage(HWindow, GetMsgID(MN_SELECTSTRING),
  422.                             SearchIndex, (long)Prefix);
  423.   else
  424.     return -1;
  425. }
  426.  
  427. /* Selects the strings in the associated list box which begin with
  428.    the passed prefixes.  For each string the search begins at the
  429.    beginning of the list and continues until a match is found or
  430.    until the list has been completely traversed. If ShouldSet is
  431.    TRUE, the matched strings are selected and highlighted, if
  432.    ShouldSet is FALSE the highlight is removed from the matched
  433.    strings and they are no longer selected. Returns the number of
  434.    strings successfully selected or deselected. If NumSelections
  435.    is less than zero, all strings are selected or deselected, and a
  436.    negative value is returned on failure. Only for multiple-
  437.    selection list boxes.  (-1 is returned if this is not a
  438.    multiple-selectionlist box). */
  439. int TListBox::SetSelStrings(LPSTR *Prefixes, int NumSelections,
  440.                             BOOL ShouldSet)
  441. {
  442.   int SelIndex, Successes = 0;
  443.  
  444.   if ( (GetWindowLong(HWindow, GWL_STYLE) & MULTIPLESEL) == 0)
  445.     //including if it's a combobox.
  446.     return -1;
  447.  
  448.   if ( NumSelections > -1 )
  449.   {
  450.     for ( int I = 0; I < NumSelections; I++ )
  451.       if ((SelIndex = FindString(Prefixes[I], -1)) > -1 )
  452.         if ( (int)SendMessage(HWindow, LB_SETSEL, ShouldSet, SelIndex)
  453.              > -1 )
  454.           Successes++;
  455.   }
  456.   else
  457.     return (int)SendMessage(HWindow, LB_SETSEL, ShouldSet, -1);
  458.   return Successes;
  459. }
  460.  
  461. /* Returns the index of the selected string in the associated listbox.
  462.    A negative value is returned if no string is selected or this
  463.    is a multiple-selection list box. Only for single-selection
  464.    flist boxes (and combo boxes). */
  465. int TListBox::GetSelIndex()
  466. {
  467.   if ( (GetWindowLong(HWindow, GWL_STYLE) & MULTIPLESEL) == 0)
  468.     //including if it's a combobox.
  469.     return (int)SendMessage(HWindow, GetMsgID(MN_GETCURSEL), 0, 0);
  470.   else
  471.     return -1;
  472. }
  473.  
  474. /* Fills Indexes with the indexes of up to Count selected strings.
  475.    Returns number of items put in the array (-1 for single-selection
  476.    list boxes and combo boxes). */
  477. int TListBox::GetSelIndexes(Pint Indexes, int MaxCount)
  478. {
  479.   if ( (GetWindowLong(HWindow, GWL_STYLE) & MULTIPLESEL) == 0)
  480.     //including if it's a combobox.
  481.     return -1;
  482.   return (int)SendMessage(HWindow, LB_GETSELITEMS, MaxCount,
  483.                           (long)(Indexes));
  484. }
  485.  
  486. /* Selects the string at passed index in the associated listbox and
  487.    forces the string into view.  Clears selection when -1 is passed
  488.    as the index. A negative value is returned if an error occurs.
  489.    Only for single-selection list boxes (and combo boxes). */
  490. int TListBox::SetSelIndex(int Index)
  491. {
  492.   if ( (GetWindowLong(HWindow, GWL_STYLE) & MULTIPLESEL) == 0)
  493.     //including if it's a combobox.
  494.     return (int)SendMessage(HWindow, GetMsgID(MN_SETCURSEL), Index, 0);
  495.   else
  496.     return -1;
  497. }
  498.  
  499. /* Selects/deselects the strings in the associated list box at the
  500.    passed indexes. If ShouldSet is TRUE, the indexed strings are
  501.    selected and highlighted, if ShouldSet is FALSE the highlight is
  502.    removed and they are no longer selected. Returns the number of
  503.    strings successfully selected or deselected (-1 if not a
  504.    multiple-selection list box).  If NumSelections is less than zero,
  505.    all strings are selected or deselected, and a negative value is
  506.    returned on failure. Only for multiple-selection list boxes. */
  507. int TListBox::SetSelIndexes(Pint Indexes, int NumSelections,
  508.                             BOOL ShouldSet)
  509. {
  510.   int Successes = 0;
  511.  
  512.   if ( (GetWindowLong(HWindow, GWL_STYLE) & MULTIPLESEL) == 0)
  513.     //including if it's a combobox.
  514.     return -1;
  515.  
  516.   if ( NumSelections > -1 )
  517.   {
  518.     for ( int I = 0; I < NumSelections; I++ )
  519.       if ( (int)SendMessage(HWindow, LB_SETSEL, ShouldSet, Indexes[I])
  520.              > -1 )
  521.         Successes++;
  522.   }
  523.   else
  524.     return (int)SendMessage(HWindow, LB_SETSEL, ShouldSet, -1);
  525.   return Successes;
  526. }
  527.  
  528. /* Returns the appropriate MS-Windows message WORD identifier for
  529.    the function identified by the passed MsgName string. Allows
  530.    instances of TComboBox (which redefines GetMsgID) to inherit
  531.    many TListBox methods. */
  532. WORD TListBox::GetMsgID(WORD AMsg)
  533. {
  534.   WORD MsgXlat[] = { LB_ADDSTRING,    LB_INSERTSTRING, LB_DELETESTRING,
  535.                      LB_RESETCONTENT, LB_GETCOUNT,     LB_GETTEXT,
  536.                      LB_GETTEXTLEN,   LB_SELECTSTRING, LB_SETCURSEL,
  537.                      LB_GETCURSEL,    LB_FINDSTRING };
  538.   return MsgXlat[AMsg];
  539. }
  540.  
  541. PTStreamable TListBox::build()
  542. {
  543.   return new TListBox(streamableInit);
  544. }
  545.  
  546. TStreamableClass RegListBox("TListBox", TListBox::build, __DELTA(TListBox));
  547.