All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.brunothg.swing2.model.table.DefaultObjectTableModel Maven / Gradle / Ivy

package com.github.brunothg.swing2.model.table;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Vector;

import javax.swing.table.AbstractTableModel;

import com.github.brunothg.swing2.utils.ClassUtils;

public class DefaultObjectTableModel extends AbstractTableModel {

	private static final long serialVersionUID = 1L;

	private Vector rows = new Vector();
	private Class type;

	private ObjectColumn[] columns;

	public DefaultObjectTableModel(Class type) {

		this.type = type;

		initialize();
	}

	@SuppressWarnings("unchecked")
	private void initialize() {

		List> columns = new LinkedList>();

		// Search fields
		Field[] fields = type.getDeclaredFields();
		for (Field field : fields) {
			for (Annotation annotation : field.getDeclaredAnnotations()) {
				if (annotation instanceof Column) {
					Column _column = (Column) annotation;
					ObjectColumn column = new FieldColumn(_column, type,
							field);
					columns.add(column);
					if (_column.index() >= 0) {
						column.setIndex(_column.index());
					}
				}
			}
		}

		// Search methods
		Method[] methods = type.getDeclaredMethods();
		for (Method method : methods) {
			for (Annotation annotation : method.getDeclaredAnnotations()) {
				if (annotation instanceof Column) {
					Column _column = (Column) annotation;
					ObjectColumn column = new MethodColumn(_column, type,
							method);
					columns.add(column);
					if (_column.index() >= 0) {
						column.setIndex(_column.index());
					}
				}
			}
		}

		Collections.sort(columns);
		this.columns = columns.toArray(new ObjectColumn[columns.size()]);
	}

	protected ObjectColumn getColumn(int columnIndex) {

		return columns[columnIndex];
	}

	/**
	 * Returns the value given by the {@link Column} Annotation.
	 * 
	 * @see Column#value()
	 */
	public String getColumnName(int columnIndex) {

		return getColumn(columnIndex).getName();
	}

	/**
	 * Override the columnName grabbed from the {@link Column} annotation
	 * 
	 * @param columnIndex
	 *            The column to change
	 * @param columnName
	 *            The new column name
	 */
	public void setColumnName(int columnIndex, String columnName) {

		getColumn(columnIndex).setName(columnName);
	}

	@Override
	public int getRowCount() {

		return rows.size();
	}

	@Override
	public int getColumnCount() {

		return columns.length;
	}

	/**
	 * Returns the value given by the {@link Column} Annotation.
	 * 
	 * @see Column#editable()
	 */
	public boolean isCellEditable(int rowIndex, int columnIndex) {

		return getColumn(columnIndex).isEditable();
	}

	/**
	 * Returns the type of the annotated field or the return type of the
	 * annotated method.
	 */
	public Class getColumnClass(int columnIndex) {

		return getColumn(columnIndex).getType();
	}

	@Override
	public Object getValueAt(int rowIndex, int columnIndex) {

		try {

			return getColumn(columnIndex).getValue(rows.get(rowIndex));
		} catch (IllegalArgumentException | InvocationTargetException
				| IllegalAccessException e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * Sets the annotated field value
	 * 
	 * @see #getValueAt(int, int)
	 * @throws RuntimeException
	 *             if there are problems with the access through reflection
	 */
	public void setValueAt(Object aValue, int rowIndex, int columnIndex) {

		try {
			getColumn(columnIndex).setValue(rows.get(rowIndex), aValue);
		} catch (IllegalArgumentException | InvocationTargetException
				| IllegalAccessException e) {

			throw new RuntimeException(e);
		}

		fireTableCellUpdated(rowIndex, columnIndex);
	}

	/**
	 * Add a new row to the table model
	 * 
	 * @param object
	 *            The object, that represents the new row
	 */
	public void addRow(T object) {

		addRow(-1, object);
	}

	/**
	 * Add a new row at specific position to the table model. The element at
	 * this position (and the ones behind) will be shift to the right.
	 * 
	 * @param rowIndex
	 *            The index for the new row.
	 * @param object
	 *            The object, that represents the new row
	 */
	public void addRow(int rowIndex, T object) {

		if (object == null) {

			throw new NullPointerException("No null values allowed");
		}

		if (rowIndex < 0) {
			rowIndex = rows.size();
			rows.add(object);
		} else {
			rows.add(rowIndex, object);
		}

		fireTableRowsInserted(rowIndex, rowIndex);
	}

	/**
	 * Get the row object at a specific position.
	 * 
	 * @param rowIndex
	 *            The index of the row
	 * @return The object for the row
	 */
	public T getRow(int rowIndex) {

		return rows.get(rowIndex);
	}

	/**
	 * Search for the object (using equals method) and then delete it. Return
	 * null if it could not be found. Otherwise the row object is returned.
	 * 
	 * @param object
	 *            The object, that should be deleted
	 * @return Null or the row object
	 */
	public T removeRow(T object) {

		for (int i = 0; i < rows.size(); i++) {

			if (rows.get(i).equals(object)) {

				return removeRow(i);
			}
		}

		return null;
	}

	/**
	 * Removes a row by its index.
	 * 
	 * @param rowIndex
	 *            The index of the row
	 * @return The row object that was deleted
	 */
	public T removeRow(int rowIndex) {

		T removed = rows.remove(rowIndex);

		fireTableRowsDeleted(rowIndex, rowIndex);
		return removed;
	}

	protected static abstract class ObjectColumn implements
			Comparable> {

		private Class self;

		private int index;
		private String name;
		private Class type;
		private boolean editable;

		private Method setter;

		public ObjectColumn(Column column, Class self) {

			this.setSelf(self);
			this.name = column.value();
			this.editable = column.editable();
		}

		protected static Method findSetter(String name, Class type,
				Class self) {

			if (name == null || name.trim().isEmpty()) {
				return null;
			}

			Method[] methods = self.getDeclaredMethods();
			for (Method method : methods) {

				if (!method.getName().equals(name)) {
					continue;
				}

				Class[] parameters = method.getParameterTypes();
				if (parameters.length != 1) {
					continue;
				}

				if (ClassUtils.isAssignable(parameters[0], type)) {

					return method;
				}
			}

			return null;
		}

		public String getName() {
			return name;
		}

		public void setName(String name) {
			this.name = name;
		}

		public Class getType() {
			return type;
		}

		public void setType(Class type) {
			this.type = type;
		}

		public boolean isEditable() {
			return editable;
		}

		public void setEditable(boolean editable) {
			this.editable = editable;
		}

		public Class getSelf() {
			return self;
		}

		public void setSelf(Class self) {
			this.self = self;
		}

		public Method getSetter() {
			return setter;
		}

		public void setSetter(Method setter) {
			this.setter = setter;
		}

		public int getIndex() {
			return index;
		}

		public void setIndex(int index) {
			this.index = index;
		}

		@Override
		public int compareTo(ObjectColumn comp) {

			return new Integer(getIndex()).compareTo(new Integer(comp
					.getIndex()));
		}

		public abstract Object getValue(V row) throws IllegalArgumentException,
				IllegalAccessException, InvocationTargetException;

		public abstract void setValue(V row, Object value)
				throws IllegalArgumentException, IllegalAccessException,
				InvocationTargetException;

	}

	protected static class FieldColumn extends ObjectColumn {

		private Field f;

		public FieldColumn(Column column, Class self, Field f) {
			super(column, self);
			this.f = f;
			setType(f.getType());
			setSetter(ObjectColumn.findSetter(column.setter(), getType(),
					getSelf()));
		}

		@Override
		public Object getValue(V row) throws IllegalArgumentException,
				IllegalAccessException {

			try {
				f.setAccessible(true);
			} catch (SecurityException e) {
			}
			return f.get(row);
		}

		@Override
		public void setValue(V row, Object value)
				throws IllegalArgumentException, IllegalAccessException,
				InvocationTargetException {

			if (getSetter() != null) {

				try {
					getSetter().setAccessible(true);
				} catch (SecurityException e) {
				}

				getSetter().invoke(row, value);

			} else {

				try {
					f.setAccessible(true);
				} catch (SecurityException e) {
				}

				f.set(row, value);
			}
		}
	}

	protected static class MethodColumn extends ObjectColumn {

		private Method m;

		public MethodColumn(Column column, Class self, Method m) {
			super(column, self);
			this.m = m;
			setType(m.getReturnType());
			setSetter(ObjectColumn.findSetter(column.setter(), getType(),
					getSelf()));
		}

		@Override
		public boolean isEditable() {

			if (getSetter() == null) {

				return false;
			}

			return super.isEditable();
		}

		@Override
		public Object getValue(V row) throws IllegalAccessException,
				IllegalArgumentException, InvocationTargetException {

			try {
				m.setAccessible(true);
			} catch (SecurityException e) {
			}
			return m.invoke(row);
		}

		@Override
		public void setValue(V row, Object value)
				throws IllegalAccessException, IllegalArgumentException,
				InvocationTargetException {

			if (getSetter() != null) {

				try {
					getSetter().setAccessible(true);
				} catch (SecurityException e) {
				}

				getSetter().invoke(row, value);

			} else {

				throw new IllegalAccessException(
						"No setter is set for this column");
			}
		}

	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy