/**
   * Backs up the settings from the old model.
   *
   * @param model the old model (the model stored within the SortedModel)
   * @return the backed up settings
   */
  protected Hashtable<String, Object> backupModelSettings(TableModel model) {
    Hashtable<String, Object> result;

    result = new Hashtable<String, Object>();

    result.put(KEY_SORTCOL, m_Model.getSortColumn());
    result.put(KEY_SORTORDER, m_Model.isAscending());

    if (model instanceof SearchableTableModel) {
      if (((SearchableTableModel) model).getSeachString() != null)
        result.put(KEY_SEARCHSTRING, ((SearchableTableModel) model).getSeachString());
      result.put(KEY_SEARCHREGEXP, ((SearchableTableModel) model).isRegExpSearch());
    }

    return result;
  }
  /**
   * Restores the settings previously backed up.
   *
   * @param model the new model (the model stored within the SortedModel)
   * @param settings the old settings, null if no settings were available
   */
  protected void restoreModelSettings(TableModel model, Hashtable<String, Object> settings) {
    int sortCol;
    boolean asc;
    String search;
    boolean regexp;

    // default values
    sortCol = 0;
    asc = true;
    search = null;
    regexp = false;

    // get stored values
    if (settings != null) {
      sortCol = (Integer) settings.get(KEY_SORTCOL);
      asc = (Boolean) settings.get(KEY_SORTORDER);

      if (model instanceof SearchableTableModel) {
        search = (String) settings.get(KEY_SEARCHSTRING);
        regexp = (Boolean) settings.get(KEY_SEARCHREGEXP);
      }
    }

    // restore sorting
    if (getSortNewTableModel()) m_Model.sort(sortCol, asc);

    // restore search
    if (model instanceof SearchableTableModel)
      ((SearchableTableModel) model).search(search, regexp);

    // set optimal column widths
    if (getUseOptimalColumnWidths()) setOptimalColumnWidth();
  }
  /**
   * Sets the model to display - only {@link #getTableModelClass()}.
   *
   * @param model the model to display
   */
  @Override
  public synchronized void setModel(TableModel model) {
    Hashtable<String, Object> settings;

    if (!(getTableModelClass().isInstance(model))) model = createDefaultDataModel();

    // backup current setup
    if (m_Model != null) {
      settings = backupModelSettings(m_Model);
      getTableHeader().removeMouseListener(m_Model.getHeaderMouseListener());
    } else {
      settings = null;
    }

    m_Model = new SortableAndSearchableWrapperTableModel(model);
    super.setModel(m_Model);
    m_Model.addMouseListenerToHeader(this);

    // restore setup
    restoreModelSettings(m_Model, settings);
  }
  /** Initializes some GUI-related things. */
  @Override
  protected void initGUI() {
    super.initGUI();

    m_SortNewTableModel = initialSortNewTableModel();
    m_Model.addMouseListenerToHeader(this);
    if (getSortNewTableModel()) sort(0);

    m_UseOptimalColumnWidths = initialUseOptimalColumnWidths();
    if (getUseOptimalColumnWidths()) {
      setAutoResizeMode(AUTO_RESIZE_OFF);
      setOptimalColumnWidth();
    }
  }
  /**
   * Performs a search for the given string. Limits the display of rows to ones containing the
   * search string.
   *
   * @param searchString the string to search for
   * @param regexp whether to perform regular expression matching or just plain string comparison
   */
  public synchronized void search(String searchString, boolean regexp) {
    int[] selected;
    int i;
    int index;

    // determine actual selected rows
    selected = getSelectedRows();
    for (i = 0; i < selected.length; i++) selected[i] = getActualRow(selected[i]);

    m_Model.search(searchString, regexp);

    // re-select rows that are still in current search
    clearSelection();
    for (i = 0; i < selected.length; i++) {
      index = getDisplayRow(selected[i]);
      if (index != -1) getSelectionModel().addSelectionInterval(index, index);
    }
  }
 /**
  * Returns the actual row count in the model.
  *
  * @return the row count in the underlying data
  */
 public synchronized int getActualRowCount() {
   return m_Model.getActualRowCount();
 }
 /**
  * sorts the table over the given column, either ascending or descending.
  *
  * @param columnIndex the column to sort over
  * @param ascending ascending if true, otherwise descending
  */
 public synchronized void sort(int columnIndex, boolean ascending) {
   if (m_Model != null) m_Model.sort(columnIndex, ascending);
 }
 /**
  * sorts the table over the given column (ascending).
  *
  * @param columnIndex the column to sort over
  */
 public synchronized void sort(int columnIndex) {
   if (m_Model != null) m_Model.sort(columnIndex);
 }
 /**
  * Returns whether sorting is ascending or not.
  *
  * @return true if ascending
  * @see #isSorted()
  * @see #getSortColumn()
  */
 public synchronized boolean isAscending() {
   return m_Model.isAscending();
 }
 /**
  * Returns the sort column.
  *
  * @return the sort column
  */
 public synchronized int getSortColumn() {
   return m_Model.getSortColumn();
 }
 /**
  * Returns the "visible" row derived from row in the actual table model.
  *
  * @param internalRow the row in the actual model
  * @return the row in the sorted model, -1 in case of an error
  */
 public synchronized int getDisplayRow(int internalRow) {
   return m_Model.getDisplayRow(internalRow);
 }
 /**
  * Returns the actual underlying row the given visible one represents. Useful for retrieving
  * "non-visual" data that is also stored in a TableModel.
  *
  * @param visibleRow the displayed row to retrieve the original row for
  * @return the original row
  */
 public synchronized int getActualRow(int visibleRow) {
   return m_Model.getActualRow(visibleRow);
 }
 /**
  * returns the underlying model, can be null.
  *
  * @return the current model
  */
 public synchronized TableModel getUnsortedModel() {
   if (m_Model != null) return m_Model.getUnsortedModel();
   else return null;
 }
 /**
  * Sets the base model to use.
  *
  * @param value the base model
  * @param restoreSorting whether to restore the sorting
  */
 public synchronized void setUnsortedModel(TableModel value, boolean restoreSorting) {
   m_Model.setUnsortedModel(value, restoreSorting);
 }
 /**
  * Sets the base model to use. Discards any sorting.
  *
  * @param value the base model
  */
 public synchronized void setUnsortedModel(TableModel value) {
   m_Model.setUnsortedModel(value);
 }
 /**
  * Returns the current search string.
  *
  * @return the search string, null if not filtered
  */
 public synchronized String getSeachString() {
   return m_Model.getSeachString();
 }
 /**
  * Returns whether the last search was a regular expression based one.
  *
  * @return true if last search was a reg exp one
  */
 public synchronized boolean isRegExpSearch() {
   return m_Model.isRegExpSearch();
 }
 /**
  * returns whether the table was sorted.
  *
  * @return true if the table was sorted
  */
 public synchronized boolean isSorted() {
   return m_Model.isSorted();
 }