home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / mfc / database / daotable / addixdlg.cpp < prev    next >
C/C++ Source or Header  |  1998-03-26  |  20KB  |  634 lines

  1. // AddIxDlg.cpp : implementation file for dialog that lets user add
  2. // indexes to tabledefs
  3. //
  4. // This is a part of the Microsoft Foundation Classes C++ library.
  5. // Copyright (C) 1992-1998 Microsoft Corporation
  6. // All rights reserved.
  7. //
  8. // This source code is only intended as a supplement to the
  9. // Microsoft Foundation Classes Reference and related
  10. // electronic documentation provided with the library.
  11. // See these sources for detailed information regarding the
  12. // Microsoft Foundation Classes product.
  13.  
  14. #include "stdafx.h"
  15. #include "DAOTable.h"
  16. #include "listctrl.h"
  17. #include "AddIxDlg.h"
  18. #include "tabledef.h"
  19. #include "index.h"
  20. #include "field.h"
  21.  
  22. #ifdef _DEBUG
  23. #define new DEBUG_NEW
  24. #undef THIS_FILE
  25. static char THIS_FILE[] = __FILE__;
  26. #endif
  27.  
  28. /////////////////////////////////////////////////////////////////////////////
  29. // CAddIndexDlg dialog
  30.  
  31. // default constructor
  32. CAddIndexDlg::CAddIndexDlg(CWnd* pParent /*=NULL*/)
  33.     : CDialog(CAddIndexDlg::IDD, pParent)
  34. {
  35.     // call centralized initialization function
  36.     initializer();
  37. }
  38.  
  39. // constructor that will generally be used to create
  40. // the dialog--parameters are needed to do any useful
  41. // database operations
  42. //
  43. // IN: pDatabase--pointer to the open database object
  44. // IN: strTableName--name of the tabledef to which to add indexes
  45. // IN: pParent--pointer to parent of this dialog
  46. CAddIndexDlg::CAddIndexDlg(CDaoDatabase *pDatabase,
  47.                            CString strTableName,
  48.                            CWnd* pParent)
  49.     : CDialog(CAddIndexDlg::IDD, pParent)
  50.  
  51. {
  52.     // call centralized initialization function
  53.     initializer();
  54.  
  55.     // initiliaze and set members to incoming parameters
  56.     m_pTableDef = NULL;
  57.     m_pDatabase = pDatabase;
  58.     m_strTableName = strTableName;
  59. }
  60.  
  61. // centralized initialization function
  62. void CAddIndexDlg::initializer()
  63. {
  64.     // initialize the index info struct
  65.     indexInitializer();
  66.  
  67.     // by default, DDV functions are called in the DoDataExchange
  68.     m_bCheckDDV = TRUE;
  69.  
  70.     // collection index starts at zero
  71.     m_nIndexIndex = 0;
  72. }
  73.  
  74. // initialize the index info struct members and equivalent
  75. // class members
  76. void CAddIndexDlg::indexInitializer()
  77. {
  78.     //{{AFX_DATA_INIT(CAddIndexDlg)
  79.     //}}AFX_DATA_INIT
  80.  
  81.     // index info struct
  82.     m_II.m_strName = _T("");
  83.     m_II.m_bPrimary = FALSE;
  84.     m_II.m_bIgnoreNulls = FALSE;
  85.     m_II.m_bRequired = FALSE;
  86.     m_II.m_bUnique = FALSE;
  87.  
  88.     // clear out the list of fields in case it is not empty--
  89.     // this is an array of index field info structs that are
  90.     // the fields that make up the index
  91.     if (m_II.m_pFieldInfos != NULL)
  92.     {
  93.         delete [] m_II.m_pFieldInfos;
  94.         m_II.m_pFieldInfos = NULL;
  95.         m_II.m_nFields = 0;
  96.     }
  97. }
  98.  
  99.  
  100. void CAddIndexDlg::DoDataExchange(CDataExchange* pDX)
  101. {
  102.     CDialog::DoDataExchange(pDX);
  103.     //{{AFX_DATA_MAP(CAddIndexDlg)
  104.     DDX_Control(pDX, IDC_UNIQUE, m_UniqueControl);
  105.     DDX_Control(pDX, IDC_REQUIRED, m_RequiredControl);
  106.     DDX_Control(pDX, IDC_IGNORE_NULLS, m_IgnoreNullControl);
  107.     DDX_Control(pDX, IDC_PRIMARY, m_PrimaryControl);
  108.     DDX_Text(pDX, IDC_TABLE_NAME, m_strTableName);
  109.     //}}AFX_DATA_MAP
  110.  
  111.     // these have to be moved outside of the wizard block
  112.     // since they directly map to members of the index info
  113.     // struct
  114.     DDX_Check(pDX, IDC_PRIMARY, m_II.m_bPrimary);
  115.     DDX_Check(pDX, IDC_IGNORE_NULLS, m_II.m_bIgnoreNulls);
  116.     DDX_Check(pDX, IDC_REQUIRED, m_II.m_bRequired);
  117.     DDX_Check(pDX, IDC_UNIQUE, m_II.m_bUnique);
  118.  
  119.     DDX_Text(pDX, IDC_INDEX_NAME, m_II.m_strName);
  120.  
  121.     // moved outside of wizard block since DDV is used
  122.     DDX_Control(pDX, IDC_FIELD_LIST, m_FieldListListControl);
  123.     // conditionally check validity of input
  124.     if (m_bCheckDDV)
  125.     {
  126.         // user must select at least one field for the index
  127.         DDV_NoSel(pDX, &m_FieldListListControl);
  128.     }
  129. }
  130.  
  131.  
  132. // check if a field selection was made--at least one field must be
  133. // selected.  Selected fields contain a non-null string in their
  134. // first sub-item (i.e. "ascending" or "descending")
  135. void CAddIndexDlg::DDV_NoSel(CDataExchange* pDX, CListCtrl *theControl)
  136. {
  137.     // only process if transferring to member from control.  If
  138.     // no selection has been made, this constitutes an error condition
  139.     if (pDX->m_bSaveAndValidate)
  140.     {
  141.         // check if any items selected--initialize a counter
  142.         int count = 0;
  143.  
  144.         // for as many items in the list view, keep checking until one is
  145.         // found that has been selected
  146.         for (int i = 0; (count == 0) && (i < theControl->GetItemCount()); i++)
  147.         {
  148.             // the contents of the subitem determines selection state
  149.             if (theControl->GetItemText(i, 1) != _T(""))
  150.             {
  151.                 // up the count by one to end the loop
  152.                 count += 1;
  153.             }
  154.         }
  155.  
  156.         // if no selection, then error!
  157.         if (count == 0)
  158.         {
  159.             AfxMessageBox(_T("You must select a field."), MB_ICONEXCLAMATION);
  160.             pDX->m_hWndLastControl = theControl->m_hWnd;
  161.             pDX->Fail();
  162.         }
  163.     }
  164. }
  165.  
  166. BEGIN_MESSAGE_MAP(CAddIndexDlg, CDialog)
  167.     //{{AFX_MSG_MAP(CAddIndexDlg)
  168.     ON_BN_CLICKED(IDOK, OnDone)
  169.     ON_WM_CLOSE()
  170.     ON_BN_CLICKED(IDC_ADD_INDEX, OnAddIndex)
  171.     ON_BN_CLICKED(IDC_DELETE_INDEX, OnDeleteIndex)
  172.     ON_BN_CLICKED(IDC_NEXT_INDEX, OnNextIndex)
  173.     ON_BN_CLICKED(IDC_PREVIOUS_INDEX, OnPreviousIndex)
  174.     //}}AFX_MSG_MAP
  175. END_MESSAGE_MAP()
  176.  
  177. /////////////////////////////////////////////////////////////////////////////
  178. // CAddIndexDlg message handlers
  179.  
  180. BOOL CAddIndexDlg::OnInitDialog()
  181. {
  182.     CDialog::OnInitDialog();
  183.  
  184.     // do some initialization for the list control
  185.     //
  186.     // set style so that list view will show its selections even when the
  187.     // control loses focus
  188.     LONG style = ::GetWindowLong(m_FieldListListControl.m_hWnd,GWL_STYLE);
  189.     ::SetWindowLong(m_FieldListListControl.m_hWnd, GWL_STYLE,style | LVS_SHOWSELALWAYS);
  190.  
  191.     // get size of control to help set the column widths
  192.     CRect controlRect;
  193.     m_FieldListListControl.GetClientRect(controlRect);
  194.     //
  195.     // get width of control, width of potential scrollbar, width needed for sub-item
  196.     // string
  197.     int controlWidth = controlRect.Width();
  198.     int scrollThumbWidth = ::GetSystemMetrics(SM_CXHTHUMB);
  199.     int strWidth = m_FieldListListControl.GetStringWidth(_T("descending"));
  200.     // factor the border width into the string width
  201.     strWidth += 12 * ::GetSystemMetrics(SM_CXBORDER);
  202.     //
  203.     // set up columns--1st leaves room for second and scroll bar
  204.     m_FieldListListControl.InsertColumn(1, _T("Field"), LVCFMT_LEFT,
  205.                             controlWidth - scrollThumbWidth - strWidth, 1);
  206.     m_FieldListListControl.InsertColumn(2, _T("Sort"), LVCFMT_LEFT, strWidth + scrollThumbWidth, 2);
  207.  
  208.     // open the tabledef if possible
  209.     if(openTableDef(m_pDatabase, &m_pTableDef, m_strTableName))
  210.     {
  211.         // now populate the list of fields list control with fields
  212.         populateFieldList();
  213.  
  214.         // get the information for the first index in the collection of indexes
  215.         // last parameter specifies no error reporting--run silently since
  216.         // there may be no indexes yet
  217.         if(getIndexInfo(m_pTableDef, &m_II, m_nIndexIndex, FALSE))
  218.         {
  219.             // most properties are readonly once an index is in a collection
  220.             disableControlsForExisting(TRUE);
  221.  
  222.             // list control should reflect the fields in the index
  223.             setFieldListSelections();
  224.  
  225.             UpdateData(FALSE);
  226.         }
  227.     }
  228.  
  229.     // set focus to index name control unless there is some problem (unlikely)
  230.     CEdit *pEdit = (CEdit *)GetDlgItem(IDC_INDEX_NAME);
  231.     if (pEdit != NULL)
  232.     {
  233.         pEdit->SetFocus();
  234.         return FALSE;
  235.     }
  236.     else
  237.         return TRUE;  // return TRUE unless you set the focus to a control
  238. }
  239.  
  240. // user selected to move to the next index in the collection
  241. void CAddIndexDlg::OnNextIndex()
  242. {
  243.     // get values from control -- no validity checking
  244.     m_bCheckDDV = FALSE;    // turn validity checking off
  245.     UpdateData(TRUE);
  246.     m_bCheckDDV = TRUE;     // turn checking back on--don't forget this!
  247.  
  248.     // action depends on if this is an existing index or not
  249.     // if this is a new index (based on name) see if user wants to save it
  250.     // or not--if not, then try to move to next index
  251.     if ((m_II.m_strName != _T("")) && (!IsExistentIndex(m_pTableDef, m_II.m_strName)))
  252.         if (IDYES != AfxMessageBox(_T("Current index will be ignored unless added.  Continue anyway?"),
  253.                                 MB_YESNO))
  254.             return;
  255.  
  256.     // can only move next if there is a item at the current index in the
  257.     // collection--else you keep indexing into unused parts of the index.
  258.     // So, check for existence of current indexed item and only increment
  259.     // the index if there is an item (no error reporting)
  260.     if (getIndexInfo(m_pTableDef, &m_II, m_nIndexIndex, FALSE))
  261.         // move to next field index
  262.         m_nIndexIndex += 1;
  263.  
  264.     // get the information for the next index if possible--
  265.     // last parameter indicates no failure reporting
  266.     if (getIndexInfo(m_pTableDef, &m_II, m_nIndexIndex, FALSE))
  267.     {
  268.         // list control should be cleared and then set to new values for this index
  269.         setFieldListSelections(FALSE);
  270.  
  271.         // most properties are readonly once a field is in a collection
  272.         disableControlsForExisting(TRUE);
  273.     }
  274.     else
  275.     {
  276.         // initialize field property values for new field
  277.         indexInitializer();
  278.  
  279.         // list box should be cleared
  280.         setFieldListSelections(TRUE);
  281.  
  282.         // new field have read/write properties
  283.         disableControlsForExisting(FALSE);
  284.     }
  285.  
  286.     UpdateData(FALSE);
  287.  
  288.     // set focus to name of field edit box
  289.     CEdit *pEdit = (CEdit *)GetDlgItem(IDC_INDEX_NAME);
  290.     pEdit->SetFocus();
  291. }
  292.  
  293. // user selected to more to the previous index in the collection
  294. void CAddIndexDlg::OnPreviousIndex()
  295. {
  296.     // can't go previous if at 0th index
  297.     if (m_nIndexIndex >= 1)
  298.     {
  299.         // by default, we will move previous
  300.         int retCode = IDYES;
  301.  
  302.         // if user has entered an index name, then warn them they will lose
  303.         // it if it is not explicitly added--we don't want to do an auto-add
  304.         // since user may have entered name without meaning to add another index
  305.         //
  306.         // see if there is a index name specified
  307.         CString name;
  308.         CEdit *pEdit = (CEdit *)GetDlgItem(IDC_INDEX_NAME);
  309.         pEdit->GetWindowText(name);
  310.         // if there is a name, then warn the user
  311.         if (name.GetLength() != 0)
  312.         {
  313.             // only an issue if this is not an existing index
  314.             if (!IsExistentIndex(m_pTableDef, name))
  315.                 retCode = AfxMessageBox(_T("Current index will be ignored unless added.  Continue anyway?"),
  316.                                     MB_YESNO);
  317.         }
  318.  
  319.         // either there never was a field name specified or the user has
  320.         // chosen not to add the field
  321.         if (retCode == IDYES)
  322.         {
  323.             // move previous
  324.             m_nIndexIndex -= 1;
  325.  
  326.             // check for this item by index, no error reporting
  327.             // if found, display info, if not treat as new index
  328.             if (getIndexInfo(m_pTableDef, &m_II, m_nIndexIndex, FALSE))
  329.             {
  330.                 // list ctrl should be cleared and then set to new values for this index
  331.                 setFieldListSelections(FALSE);
  332.  
  333.                 // most properties are readonly once a field is in a collection
  334.                 disableControlsForExisting(TRUE);
  335.             }
  336.             else
  337.             {
  338.                 // initialize field property values for new field
  339.                 indexInitializer();
  340.  
  341.                 // list box should be cleared
  342.                 setFieldListSelections(TRUE);
  343.  
  344.                 // new field have read/write properties
  345.                 disableControlsForExisting(FALSE);
  346.             }
  347.  
  348.             // update the dialog controls with new values
  349.             UpdateData(FALSE);
  350.         }
  351.     }
  352.  
  353.     // set focus to name of field edit box
  354.     CEdit *pEdit = (CEdit *)GetDlgItem(IDC_INDEX_NAME);
  355.     pEdit->SetFocus();
  356. }
  357.  
  358. // user selected the "done" button--no more indexes to add/view.  The only
  359. // risk is losing an index that is under construction--check for that
  360. void CAddIndexDlg::OnDone()
  361. {
  362.     // set default to "ready to exit dialog"
  363.     int retCode = IDYES;
  364.  
  365.     // if user has entered an index name, then warn them they will lose
  366.     // it if it is not explicitly added--we don't want to do an auto-add
  367.     // since user may have entered name without meaning to add another index
  368.     //
  369.     // see if there is a index name specified
  370.     CString name;
  371.     CEdit *pEdit = (CEdit *)GetDlgItem(IDC_INDEX_NAME);
  372.     pEdit->GetWindowText(name);
  373.     // if there is a name, then warn the user
  374.     if (name.GetLength() != 0)
  375.     {
  376.         // only an issue if this is not an existing index
  377.         if (!IsExistentIndex(m_pTableDef, name))
  378.             retCode = AfxMessageBox(_T("Current index will be ignored unless added.  Continue anyway?"),
  379.                                 MB_YESNO);
  380.     }
  381.  
  382.     // either there never was a index name specified or the user has
  383.     // chosen not to add the index
  384.     if (retCode == IDYES)
  385.     {
  386.         // done with tabledef object
  387.         delete m_pTableDef;
  388.  
  389.         // end the dialog
  390.         CDialog::EndDialog(0);
  391.     }
  392. }
  393.  
  394. // user selected to exit the dialog--don't do any
  395. // checking for loss of newly specified indexes
  396. void CAddIndexDlg::OnClose()
  397. {
  398.     // close the tabledef if it is open
  399.     if (m_pTableDef->IsOpen())
  400.         m_pTableDef->Close();
  401.  
  402.     // clean up
  403.     delete m_pTableDef;
  404.  
  405.     CDialog::OnClose();
  406. }
  407.  
  408. // user wants to add the specified index to the collection
  409. void CAddIndexDlg::OnAddIndex()
  410. {
  411.     // get values from control -- don't continue if failure
  412.     if (!UpdateData(TRUE))
  413.         return;
  414.  
  415.     // don't do anything if this is an existing index (except
  416.     // say so)
  417.     if (!IsExistentIndex(m_pTableDef, m_II.m_strName))
  418.     {
  419.         // must create the fields that are in the index
  420.         createFieldArray(&(m_II.m_pFieldInfos), &(m_II.m_nFields));
  421.  
  422.         // try to create the index with error checking--may fail if a
  423.         // duplicate named index already exists. Note: creating an index
  424.         // also appends it to the tabledef's index collection
  425.         if (!createNewIndex(m_pTableDef, &m_II))
  426.             return;
  427.  
  428.         // clean out all properties
  429.         indexInitializer();
  430.  
  431.         // list constrol should be cleared
  432.         setFieldListSelections(TRUE);
  433.  
  434.         // performs visible clearing of controls that are initialized
  435.         UpdateData(FALSE);
  436.  
  437.         // move to next field index
  438.         m_nIndexIndex += 1;
  439.     }
  440.     else
  441.     {
  442.         AfxMessageBox(_T("Can't add index--it already exists in the TableDef."));
  443.     }
  444.  
  445.     // set focus to name of index edit box
  446.     CEdit *pEdit = (CEdit *)GetDlgItem(IDC_INDEX_NAME);
  447.     pEdit->SetFocus();
  448. }
  449.  
  450. // user selected to delete the current index--prompt for acceptance
  451. void CAddIndexDlg::OnDeleteIndex()
  452. {
  453.     // get values from control -- don't continue if failure
  454.     if (!UpdateData(TRUE))
  455.         return;
  456.  
  457.     // can only delete existing indexes
  458.     if (IsExistentIndex(m_pTableDef, m_II.m_strName))
  459.     {
  460.         // is user sure?
  461.         if (IDYES == AfxMessageBox(_T("Delete current index?"), MB_YESNO))
  462.         {
  463.             // only react if field is deleted!
  464.             if (deleteIndex(m_pTableDef, m_II.m_strName))
  465.             {
  466.                 // index into collection is unchanged, so
  467.                 // get the information for this index if there is one
  468.                 // (no error reporting)
  469.                 if (getIndexInfo(m_pTableDef, &m_II, m_nIndexIndex, FALSE))
  470.                 {
  471.                     // list control should be cleared and then set to reflect new index
  472.                     setFieldListSelections(FALSE);
  473.  
  474.                     // disable user selections
  475.                     disableControlsForExisting(TRUE);
  476.                 }
  477.                 else
  478.                 {
  479.                     // there is no index in collection following the
  480.                     // deletion at this collection index, so
  481.                     // set the index info to initial state
  482.                     indexInitializer();
  483.  
  484.                     // list control should be cleared
  485.                     setFieldListSelections(TRUE);
  486.  
  487.                     // enable user selections
  488.                     disableControlsForExisting(FALSE);
  489.                 }
  490.  
  491.                 // update the dialog controls to erase deleted field
  492.                 UpdateData(FALSE);
  493.             }
  494.         }
  495.     }
  496.  
  497.     // set focus to name of field edit box
  498.     CEdit *pEdit = (CEdit *)GetDlgItem(IDC_INDEX_NAME);
  499.     pEdit->SetFocus();
  500. }
  501.  
  502.  
  503. // since most index properties become read-only once the index
  504. // is added to a collection, manage the controls on the dialog
  505. // appropriate to whether this is an existing index or not
  506. void CAddIndexDlg::disableControlsForExisting(BOOL bDisable/* = TRUE*/)
  507. {
  508.     m_UniqueControl.EnableWindow(!bDisable);
  509.     m_RequiredControl.EnableWindow(!bDisable);
  510.     m_IgnoreNullControl.EnableWindow(!bDisable);
  511.     m_PrimaryControl.EnableWindow(!bDisable);
  512.  
  513.     // set the name edit to read-only
  514.     CEdit *pEdit = (CEdit *)GetDlgItem(IDC_INDEX_NAME);
  515.     pEdit->SetReadOnly(bDisable);
  516. }
  517.  
  518. // populate the list control with the fields in the field collection of
  519. // the current tabledef
  520. void CAddIndexDlg::populateFieldList()
  521. {
  522.     // struct for getting field information
  523.     CDaoFieldInfo fieldInfo;
  524.     // loop controls and index into the field collection
  525.     BOOL bContinue = TRUE;
  526.     int itemIndex = 0;
  527.  
  528.     // until we run out of items in the field collection, keep adding items
  529.     for (int i = 0; bContinue; i++)
  530.     {
  531.         // try to get info on the ith field -- no error reporting as specified by last
  532.         // parameter being FALSE
  533.         if (getFieldInfo(m_pTableDef, &fieldInfo, i, FALSE))
  534.         {
  535.             // if this is an indexable field type, then display it
  536.             if ((fieldInfo.m_nType != dbLongBinary) &&
  537.                 (fieldInfo.m_nType != dbMemo))
  538.             {
  539.                 // insert the name into the list view item, clear the subitem text
  540.                 m_FieldListListControl.InsertItem(itemIndex, fieldInfo.m_strName);
  541.                 m_FieldListListControl.SetItemText(itemIndex, 1, _T(""));
  542.  
  543.                 // move to next index into the collection
  544.                 itemIndex += 1;
  545.             }
  546.         }
  547.         else    // once we fail to get info on an item in the collection, stop the loop
  548.             bContinue = FALSE;
  549.     }
  550. }
  551.  
  552. // for every item selected in the list control, create an index field info
  553. // struct with the pertinent info and add it to the list of such
  554. // structures
  555. void CAddIndexDlg::createFieldArray(CDaoIndexFieldInfo **ppFields, short *pnFields)
  556. {
  557.     // get maximum count of items in the list control
  558.     int limit = m_FieldListListControl.GetItemCount();
  559.  
  560.     // if array isn't initialized, delete it, then allocate a new one
  561.     if ((*ppFields) != NULL)
  562.         delete [] (*ppFields);
  563.  
  564.     // allocate at maximum size although we probably won't use all
  565.     // just for simplicity's sake!
  566.     (*ppFields) = new CDaoIndexFieldInfo[limit];
  567.  
  568.     // keep track of how many items selected and loop through all items
  569.     (*pnFields) = 0;
  570.     for (int i = 0; i < limit; i++)
  571.     {
  572.         // if selected, get the name of the field (selection indicated by
  573.         // non-empty subitem string)
  574.         if (m_FieldListListControl.GetItemText(i, 1) != _T(""))
  575.         {
  576.             // put the name into the array
  577.             (*ppFields)[(*pnFields)].m_strName = m_FieldListListControl.GetItemText(i, 0);
  578.  
  579.             // put the sort order into the array as a boolean
  580.             (*ppFields)[(*pnFields)].m_bDescending =
  581.                         (m_FieldListListControl.GetItemText(i, 1) == _T("descending"));
  582.  
  583.             // up the count by one
  584.             (*pnFields) += 1;
  585.         }
  586.     }
  587. }
  588.  
  589. // make the list control reflect which fields make up the current index
  590. //
  591. // IN: bJustClear-by default, clear AND make selection in the list control, but
  592. //     you can specify to just clear the control of all selections
  593. //
  594. void CAddIndexDlg::setFieldListSelections(BOOL bJustClear /* = FALSE*/)
  595. {
  596.     // get maximum number of items in list
  597.     int numStrings = m_FieldListListControl.GetItemCount();
  598.     int selection;
  599.  
  600.     // reset any current selections
  601.     for (int i = 0; i < numStrings; i++)
  602.     {
  603.         m_FieldListListControl.SetItemState(i, 0, LVIS_SELECTED);
  604.         m_FieldListListControl.SetItemText(i, 1, _T(""));
  605.     }
  606.  
  607.     // this function can be called to simply clear the list control
  608.     // of selections or you can reflect the current index selections too
  609.     if (!bJustClear)
  610.     {
  611.         // select the appropriate items--set up the finder struct
  612.         LV_FINDINFO lvfi;
  613.         lvfi.flags = LVFI_STRING;   // searching for strings
  614.         CString strSort;            // used to create string to indicate sort direction
  615.  
  616.         // for all items in the index info struct, find and set the items
  617.         for (int i = 0; i < m_II.m_nFields; i++)
  618.         {
  619.             // find the item in the already populated list control--start from the top
  620.             lvfi.psz = m_II.m_pFieldInfos[i].m_strName;
  621.             selection = m_FieldListListControl.FindItem(&lvfi, -1);
  622.  
  623.             // select the item
  624.             m_FieldListListControl.SetItemState(selection, LVIS_SELECTED, LVIS_SELECTED);
  625.  
  626.             // set the sort order subitem text appropriately
  627.             strSort = m_II.m_pFieldInfos[i].m_bDescending ? _T("descending") : _T("ascending");
  628.             m_FieldListListControl.SetItemText(selection, 1, strSort);
  629.         }
  630.  
  631.         UpdateData(FALSE);
  632.     }
  633. }
  634.