Search This Blog

Monday, June 9, 2008

Design Thoughts - Protected vs Private

1) if you didn't design it to be extended, i,e., you didn't design it to be abstract, then all class attribute should be private. Sometimes I would create a publicly accessible class and think to myself... "self, let's make the private members protected in case someone needs to extend upon this class in the future."... well, I have now come to realize that that is a bad design choice. It breaks encapsulation. I now think that if a class is intended to be extended then the class itself should be abstract and its members (that need to be available to subclasses) obviously be protected. A class should be designed to be extended, if it's not designed to be extended then its members should be private (when there is no obvious choice but to make them private, of course.) Just a thought...

Friday, June 6, 2008

SortableJTableModel

Here is a code example for a sortable JTableModel. In the future I intend to build upon it and design a simple framework.
This was re-factored from a work implementation because the code was coupled with a certain object that seems to be pervasive. Anyway's here is the result.

import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Vector;

import javax.swing.JTable;
import javax.swing.table.DefaultTableColumnModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;

public class SortableJTableModel extends DefaultTableModel implements SortableTableModel {
private static class Compare implements Comparator {
int sortKey;
int sortOrder;

Compare(int sortKey, int sortOrder) {
this.sortKey = sortKey;
this.sortOrder = sortOrder;
}

public int compare(Object o1, Object o2) {
Vector v1 = (Vector) o1;
Vector v2 = (Vector) o2;
Comparable s1 = (Comparable) v1.get(sortKey);
Comparable s2 = (Comparable) v2.get(sortKey);
int ans = s1.compareTo(s2);
if (sortOrder==DESCENDING) {
ans *= -1;
}
return (ans);
}

public boolean equals(Object obj) {
return (false);
}
}
// private class HeaderMouseAdapter extends MouseAdapter {
// public void mousePressed(MouseEvent e) {
// Point mousePoint = new Point(e.getX(), e.getY());
// selectedHeaderColumn = header.columnAtPoint(mousePoint);
// DefaultTableColumnModel cmodel = (DefaultTableColumnModel) table.getColumnModel();
// backupTableColumnAttr(cmodel);
//
// clickCount++;
// boolean reverseOrder = false;
// if(clickCount>0 && (clickCount % 2) == 0) {
// sort(new int[] {selectedHeaderColumn}, DESCENDING);
// }
// else {
// sort(new int[] {selectedHeaderColumn}, ASCENDING);
// }
// restoreTableColumnAttr(cmodel);
// }
//
// void backupTableColumnAttr(DefaultTableColumnModel cmodel) {
// for (int i = 0; i < cmodel.getColumnCount(); i++) {
// TableColumn column = cmodel.getColumn(i);
// minWidth[i] = column.getWidth();
// cellRenderer[i] = column.getCellRenderer();
// headerRenderer[i] = column.getHeaderRenderer();
// }
// }
//
// void restoreTableColumnAttr(DefaultTableColumnModel cmodel) {
// for (int i = 0; i < cmodel.getColumnCount(); i++) {
// TableColumn column = cmodel.getColumn(i);
// column.setMinWidth(minWidth[i]);
// column.setCellRenderer(cellRenderer[i]);
// column.setHeaderRenderer(headerRenderer[i]);
// }
// }
// }
private int currentSortColumn = -1;
private int currentSortDirection = NOT_SORTED;
private JTable table;
private JTableHeader header;
private Vector columnNames;
private int selectedHeaderColumn;
private int[] minWidth;
private TableCellRenderer[] cellRenderer;
private TableCellRenderer[] headerRenderer;
private int clickCount = 0;

public SortableJTableModel(JTable table, String[] columnNames, int rowCount) {
this(table, DefaultTableModel.convertToVector(columnNames), rowCount);
}
public SortableJTableModel(JTable table, Vector columnNames, int rowCount) {
super(columnNames, rowCount);
this.table = table;
this.columnNames = columnNames;
dataVector = ((DefaultTableModel) table.getModel()).getDataVector();
header = table.getTableHeader();
header.setReorderingAllowed(false);
//header.addMouseListener(new HeaderMouseAdapter());
minWidth = new int[columnNames.size()];
cellRenderer = new TableCellRenderer[columnNames.size()];
headerRenderer = new TableCellRenderer[columnNames.size()];
}



public void setCurrentSortColumn(int column, int direction) {
if (column < 0 || column >= getColumnCount()) {
throw new IllegalArgumentException("column " + column + " is outside column numbers");
}
if (direction != ASCENDING && direction != DESCENDING) {
throw new IllegalArgumentException("direction " + direction + " is not a valid sort direction");
}
currentSortColumn = column;
currentSortDirection = direction;
}

public int getCurrentSortDirection(int column) {
return (currentSortColumn != column) ? NOT_SORTED : currentSortDirection;
}

public int getCurrentSortColumn() {
return currentSortColumn;
}

public int getRowCount() {
return dataVector.size();
}

public String getColumnNameNoNewLine(int column) {
String hvalue = (String) columnNames.get(column);
return hvalue.replace('\n', ' ');
}
public void sort(int sortColumns[], int direction) {
DefaultTableColumnModel cmodel = (DefaultTableColumnModel) table.getColumnModel();
backupTableColumnAttr(cmodel);
Object[] array = dataVector.toArray();
Arrays.sort(array, new Compare(sortColumns[0], direction));
dataVector = DefaultTableModel.convertToVector(array);
setDataVector(dataVector, columnNames);
restoreTableColumnAttr(cmodel);
}
void backupTableColumnAttr(DefaultTableColumnModel cmodel) {
for (int i = 0; i < cmodel.getColumnCount(); i++) {
TableColumn column = cmodel.getColumn(i);
minWidth[i] = column.getWidth();
cellRenderer[i] = column.getCellRenderer();
headerRenderer[i] = column.getHeaderRenderer();
}
}

void restoreTableColumnAttr(DefaultTableColumnModel cmodel) {
for (int i = 0; i < cmodel.getColumnCount(); i++) {
TableColumn column = cmodel.getColumn(i);
column.setMinWidth(minWidth[i]);
column.setCellRenderer(cellRenderer[i]);
column.setHeaderRenderer(headerRenderer[i]);
}
}
// void sort(boolean reverseOrder) {
// Object[] array = dataVector.toArray();
// Arrays.sort(array, new Compare(selectedHeaderColumn, reverseOrder));
// dataVector = DefaultTableModel.convertToVector(array);
// setDataVector(dataVector, columnNames);
// }
}