public void expandColumn(short columnNumber) {
    int idx = findColumnIdx(columnNumber, 0);
    if (idx == -1) return;

    // If it is already exapanded do nothing.
    if (!isColumnGroupCollapsed(idx)) return;

    // Find the start of the group.
    int startIdx = findStartOfColumnOutlineGroup(idx);
    ColumnInfoRecord columnInfo = getColInfo(startIdx);

    // Find the end of the group.
    int endIdx = findEndOfColumnOutlineGroup(idx);
    ColumnInfoRecord endColumnInfo = getColInfo(endIdx);

    // expand:
    // colapsed bit must be unset
    // hidden bit gets unset _if_ surrounding groups are expanded you can determine
    //   this by looking at the hidden bit of the enclosing group.  You will have
    //   to look at the start and the end of the current group to determine which
    //   is the enclosing group
    // hidden bit only is altered for this outline level.  ie.  don't uncollapse contained groups
    if (!isColumnGroupHiddenByParent(idx)) {
      for (int i = startIdx; i <= endIdx; i++) {
        if (columnInfo.getOutlineLevel() == getColInfo(i).getOutlineLevel())
          getColInfo(i).setHidden(false);
      }
    }

    // Write collapse field
    setColumn((short) (columnInfo.getLastColumn() + 1), null, null, null, null, Boolean.FALSE);
  }
 public ColumnInfoRecord writeHidden(ColumnInfoRecord columnInfo, int idx, boolean hidden) {
   int level = columnInfo.getOutlineLevel();
   while (idx < records.size()) {
     columnInfo.setHidden(hidden);
     if (idx + 1 < records.size()) {
       ColumnInfoRecord nextColumnInfo = (ColumnInfoRecord) records.get(idx + 1);
       if (columnInfo.getLastColumn() + 1 == nextColumnInfo.getFirstColumn()) {
         if (nextColumnInfo.getOutlineLevel() < level) break;
         columnInfo = nextColumnInfo;
       } else {
         break;
       }
     }
     idx++;
   }
   return columnInfo;
 }
  public int findEndOfColumnOutlineGroup(int idx) {
    // Find the end of the group.
    ColumnInfoRecord columnInfo = (ColumnInfoRecord) records.get(idx);
    int level = columnInfo.getOutlineLevel();
    while (idx < records.size() - 1) {
      ColumnInfoRecord nextColumnInfo = (ColumnInfoRecord) records.get(idx + 1);
      if (columnInfo.getLastColumn() + 1 == nextColumnInfo.getFirstColumn()) {
        if (nextColumnInfo.getOutlineLevel() < level) {
          break;
        }
        idx++;
        columnInfo = nextColumnInfo;
      } else {
        break;
      }
    }

    return idx;
  }
  public int findStartOfColumnOutlineGroup(int idx) {
    // Find the start of the group.
    ColumnInfoRecord columnInfo = (ColumnInfoRecord) records.get(idx);
    int level = columnInfo.getOutlineLevel();
    while (idx != 0) {
      ColumnInfoRecord prevColumnInfo = (ColumnInfoRecord) records.get(idx - 1);
      if (columnInfo.getFirstColumn() - 1 == prevColumnInfo.getLastColumn()) {
        if (prevColumnInfo.getOutlineLevel() < level) {
          break;
        }
        idx--;
        columnInfo = prevColumnInfo;
      } else {
        break;
      }
    }

    return idx;
  }
  public void setColumn(
      short column, Short xfIndex, Short width, Integer level, Boolean hidden, Boolean collapsed) {
    ColumnInfoRecord ci = null;
    int k = 0;

    for (k = 0; k < records.size(); k++) {
      ci = (ColumnInfoRecord) records.get(k);
      if ((ci.getFirstColumn() <= column) && (column <= ci.getLastColumn())) {
        break;
      }
      ci = null;
    }

    if (ci != null) {
      boolean styleChanged = xfIndex != null && ci.getXFIndex() != xfIndex.shortValue();
      boolean widthChanged = width != null && ci.getColumnWidth() != width.shortValue();
      boolean levelChanged = level != null && ci.getOutlineLevel() != level.intValue();
      boolean hiddenChanged = hidden != null && ci.getHidden() != hidden.booleanValue();
      boolean collapsedChanged = collapsed != null && ci.getCollapsed() != collapsed.booleanValue();
      boolean columnChanged =
          styleChanged || widthChanged || levelChanged || hiddenChanged || collapsedChanged;
      if (!columnChanged) {
        // do nothing...nothing changed.
      } else if ((ci.getFirstColumn() == column)
          && (ci.getLastColumn() == column)) { // if its only for this cell then
        setColumnInfoFields(ci, xfIndex, width, level, hidden, collapsed);
      } else if ((ci.getFirstColumn() == column) || (ci.getLastColumn() == column)) {
        // okay so the width is different but the first or last column == the column we'return
        // setting
        // we'll just divide the info and create a new one
        if (ci.getFirstColumn() == column) {
          ci.setFirstColumn((short) (column + 1));
        } else {
          ci.setLastColumn((short) (column - 1));
        }
        ColumnInfoRecord nci = (ColumnInfoRecord) createColInfo();

        nci.setFirstColumn(column);
        nci.setLastColumn(column);
        nci.setOptions(ci.getOptions());
        nci.setXFIndex(ci.getXFIndex());
        setColumnInfoFields(nci, xfIndex, width, level, hidden, collapsed);

        insertColumn(k, nci);
      } else {
        // split to 3 records
        short lastcolumn = ci.getLastColumn();
        ci.setLastColumn((short) (column - 1));

        ColumnInfoRecord nci = (ColumnInfoRecord) createColInfo();
        nci.setFirstColumn(column);
        nci.setLastColumn(column);
        nci.setOptions(ci.getOptions());
        nci.setXFIndex(ci.getXFIndex());
        setColumnInfoFields(nci, xfIndex, width, level, hidden, collapsed);
        insertColumn(++k, nci);

        nci = (ColumnInfoRecord) createColInfo();
        nci.setFirstColumn((short) (column + 1));
        nci.setLastColumn(lastcolumn);
        nci.setOptions(ci.getOptions());
        nci.setXFIndex(ci.getXFIndex());
        nci.setColumnWidth(ci.getColumnWidth());
        insertColumn(++k, nci);
      }
    } else {

      // okay so there ISN'T a column info record that cover's this column so lets create one!
      ColumnInfoRecord nci = (ColumnInfoRecord) createColInfo();

      nci.setFirstColumn(column);
      nci.setLastColumn(column);
      setColumnInfoFields(nci, xfIndex, width, level, hidden, collapsed);
      insertColumn(k, nci);
    }
  }