/** Save state to the PreferencesExt. */
  public void saveState(PreferencesExt store) {
    if (store == null) return;

    int ncols = table.getColumnCount();
    int[] size = new int[ncols];
    int[] modelIndex = new int[ncols];

    TableColumnModel tcm = table.getColumnModel();
    for (int i = 0; i < ncols; i++) {
      TableColumn tc = tcm.getColumn(i);
      size[i] = tc.getWidth();
      modelIndex[i] = tc.getModelIndex();
    }
    store.putBeanObject("ColumnWidths", size);
    store.putBeanObject("ColumnOrder", modelIndex);

    store.putInt("SortOnCol", model.getSortCol());
    store.putBoolean("SortReverse", model.getReverse());
    store.putBoolean("isThreadsOn", model.isThreadsOn());

    if (debug) {
      System.out.println(" store widths = ");
      for (int i = 0; i < size.length; i++) System.out.print(" " + size[i]);
      System.out.println();
    }
  }
  /**
   * Constructor.
   *
   * @param m TreeTableModelSorted m
   */
  public JTreeTableSorted(TreeTableModelSorted m, boolean allowSortColChange) {

    this.model = m;
    this.useThreads = model.useThreads();
    this.treeSort = model.isTreeSort();

    // create the ui
    table = new JTreeTable(model);
    setLayout(new BorderLayout());
    scrollPane = new JScrollPane(table);
    add(scrollPane, BorderLayout.CENTER);

    // table.setSelectionMode( ListSelectionModel.SINGLE_SELECTION);
    table.setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS);
    // table.setFont( table.getFont().deriveFont( Font.BOLD));

    // now set the header renderers
    TableColumnModel tcm = table.getColumnModel();
    int ncolwt = useThreads ? table.getColumnCount() - 1 : table.getColumnCount();
    for (int i = 0; i < ncolwt; i++) {
      TableColumn tc = tcm.getColumn(i);
      tc.setHeaderRenderer(new SortedHeaderRenderer(model.getColumnName(i), i));
    }
    if (useThreads) {
      threadCol = ncolwt;
      threadHeaderRenderer = new ThreadHeaderRenderer(threadCol);
      tcm.getColumn(threadCol).setHeaderRenderer(threadHeaderRenderer);
    }

    // popupMenu
    popupMenu = new ucar.nc2.ui.widget.PopupMenu(table.getTableHeader(), "Visible");
    int ncols = model.getColumnCount();
    acts = new PopupAction[ncols];
    for (int i = 0; i < ncols; i++) {
      acts[i] = new PopupAction(model.getColumnName(i));
      popupMenu.addActionCheckBox(model.getColumnName(i), acts[i], true);
    }

    // listen for list selection
    table
        .getSelectionModel()
        .addListSelectionListener(
            new ListSelectionListener() {
              public void valueChanged(ListSelectionEvent e) {
                if (!e.getValueIsAdjusting() && lm.hasListeners() && (listSelectionEvent == null)) {
                  listSelectionEvent = e;
                  if (debugEvent) System.out.println(" JTreeTableSorted message selected = " + e);
                  SwingUtilities.invokeLater(
                      new Runnable() { // gotta do this after the dust settles

                        public void run() {
                          lm.sendEvent(listSelectionEvent);
                          listSelectionEvent = null; // dont like this
                        }
                      }); // new Runnable
                }
              }
            }); // new ListSelectionListener

    // listen for mouse clicks on the column header
    allowSortColChangeMouseListener =
        new MyMouseAdapter() {
          public void click(MouseEvent e) {
            TableColumnModel tcm2 = table.getColumnModel();
            int colIdx = tcm2.getColumnIndexAtX(e.getX());
            int colNo = table.convertColumnIndexToModel(colIdx);

            // keep track of selection
            selectedRow = getSelectedRow();
            if (debug) System.out.println("----selectedRow = " + selectedRow);

            if (colNo == threadCol) { // toggle threads
              threadHeaderRenderer.setOn(!threadHeaderRenderer.isOn);
              model.setThreadsOn(threadHeaderRenderer.isOn);
              model.sort();
            } else {
              boolean reverse = model.sort(colNo);
              setSortCol(colNo, reverse);
            }

            table.fireDataChanged();
            invokeSetPath();
          }
        };
    allowSortColChange(allowSortColChange);

    // event manager for ListSelection
    lm =
        new ListenerManager(
            "javax.swing.event.ListSelectionListener",
            "javax.swing.event.ListSelectionEvent",
            "valueChanged");

    // default sort
    setSortCol(model.getSortCol(), model.getReverse());
  }