private void buildPreferencesSoundPanel()
  {
    logger.logDebug("ENTERED SoundsController::buildPreferencesSoundPanel ");
    preferencesSoundPanel = new PreferencesSoundPanel();

    // build jtable and table model
    logger.logDebug("   buildPreferencesSoundPanel::getting sounds table");
    soundsTable = preferencesSoundPanel.getSoundsTable();

    // play the sound any time a cell is selected.
    // don't do this for the first row or first column.
    logger.logDebug("   buildPreferencesSoundPanel::adding ListSelectionListener to SoundsTable");
    soundsTable.getSelectionModel().addListSelectionListener(new ListSelectionListener()
    {
      public void valueChanged(ListSelectionEvent event)
      {
        if (!event.getValueIsAdjusting())
        {
          int row = soundsTable.getSelectedRow();
          int col = soundsTable.getSelectedColumn();
          int editingRow = soundsTable.getEditingRow();
          
          if (col == SoundsTableModel.FILE_DESCRIPTION_COLUMN_NUM) return;

          // need to use editingRow, at least on mac os x; otherwise, 'row' can
          // often be -1.
          // TODO i may need to check the values or row and editingRow here, but for
          //      now i'm just going with editingRow
          if (editingRow != 0)
          {
            // TODO when i click a checkbox, the row is no longer being selected
            playSound(editingRow);
          }
        }
      }
    });

    logger.logDebug("   buildPreferencesSoundPanel::updateSoundsTableModelFromFilesInDirectory");
    // make sure we have up-to-the-moment data
    updateSoundsTableModelFromFilesInDirectory();

    // TODO may want to do this differently; refresh the table model
    // instead of constantly whacking it
    logger.logDebug("   buildPreferencesSoundPanel::soundsTable.setModel(soundsTableModel)");
    if (soundsTable == null)
    {
      logger.logDebug("   ***** soundsTable IS NULL");
    }
    soundsTable.setModel(soundsTableModel);
    
    logger.logDebug("   buildPreferencesSoundPanel::calling tellTableModelWhichSoundsToSelect ...");
    tellTableModelWhichSoundsShouldBeSelected();

    // misc table things
    logger.logDebug("   buildPreferencesSoundPanel::soundsTable, getting header, setting size and selection model ...");
    soundsTable.getTableHeader().setReorderingAllowed(false);
    soundsTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

    // did this work b/c the jtable size and viewport size need to be correct so the user
    // can see all their files, whether they have 20, or 500
    setSoundsTableSize();

    // use this to implement table tow striping; i had problems with quaqua table row striping
    // and checkboxes (booleans)
    soundsTable.setDefaultRenderer(Object.class, new StripedRowTableCellRenderer());
    soundsTable.setDefaultRenderer(Boolean.class, new StripedRowTableCellRenderer());
    
    // for use with quaqua
    //soundsTable.putClientProperty("Quaqua.Table.style", "striped");
    
    logger.logDebug("   buildPreferencesSoundPanel::looping through sounds table columns to set widths ...");
    for (int i = 0; i < soundsTableModel.getColumnCount(); i++)
    {
      logger.logDebug("  i = " + i);
      TableColumn column = soundsTable.getColumnModel().getColumn(i);
      if (i == 0)
        column.setPreferredWidth(180);
      else if (i == SoundsTableModel.SHOW_CURTAIN_COLUMN_NUM)
        column.setPreferredWidth(100);
      else if (i == SoundsTableModel.QUIT_CURTAIN_COLUMN_NUM)
        column.setPreferredWidth(100);
      else if (i == SoundsTableModel.REFILL_CURTAIN_COLUMN_NUM)
        column.setPreferredWidth(100);
    }
  }