/*
This file is part of RouteConverter.
RouteConverter is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
RouteConverter is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with RouteConverter; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Copyright (C) 2007 Christian Pesch. All Rights Reserved.
*/
package slash.navigation.converter.gui.models;
import slash.navigation.common.NavigationPosition;
import slash.navigation.converter.gui.renderer.PositionsTableCellEditor;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.TableColumnModelEvent;
import javax.swing.table.DefaultTableColumnModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.prefs.Preferences;
import static java.text.DateFormat.MEDIUM;
import static java.text.DateFormat.SHORT;
import static java.text.DateFormat.getDateInstance;
import static java.text.DateFormat.getDateTimeInstance;
import static java.text.DateFormat.getTimeInstance;
import static java.util.Calendar.DAY_OF_MONTH;
import static java.util.Calendar.HOUR_OF_DAY;
import static java.util.Calendar.MINUTE;
import static java.util.Calendar.MONTH;
import static java.util.Calendar.SECOND;
import static java.util.Calendar.YEAR;
import static java.util.Locale.US;
import static slash.navigation.converter.gui.models.PositionTableColumn.VISIBLE_PROPERTY_NAME;
/**
* Helps to make table columns useable.
*
* @author Christian Pesch
*/
public abstract class AbstractTableColumnModel extends DefaultTableColumnModel {
private static final Preferences preferences = Preferences.userNodeForPackage(AbstractTableColumnModel.class);
private static final String VISIBLE_INFIX = "-visible-";
private static final String ORDER_INFIX = "-order-";
private final String preferencesPrefix;
private final List<PositionTableColumn> predefinedColumns = new ArrayList<>();
public AbstractTableColumnModel(String preferencesPrefix) {
this.preferencesPrefix = preferencesPrefix;
}
public List<PositionTableColumn> getPreparedColumns() {
return predefinedColumns;
}
protected void predefineColumn(int modelIndex, String name, Integer maxWidth, boolean visibilityDefault,
TableCellRenderer cellRenderer, TableCellRenderer headerRenderer) {
predefineColumn(modelIndex, name, maxWidth, visibilityDefault, cellRenderer, null, headerRenderer, null);
}
protected void predefineColumn(int modelIndex, String name, Integer maxWidth, boolean visibilityDefault,
PositionsTableCellEditor cellEditor, TableCellRenderer headerRenderer) {
predefineColumn(modelIndex, name, maxWidth, visibilityDefault, cellEditor, headerRenderer, null);
}
protected void predefineColumn(int modelIndex, String name, Integer maxWidth, boolean visibilityDefault,
PositionsTableCellEditor cellEditor, TableCellRenderer headerRenderer,
Comparator<NavigationPosition> comparator) {
predefineColumn(modelIndex, name, maxWidth, visibilityDefault, cellEditor, cellEditor, headerRenderer, comparator);
}
protected void predefineColumn(int modelIndex, String name, Integer maxWidth, boolean visibilityDefault,
TableCellRenderer cellRenderer, TableCellEditor cellEditor, TableCellRenderer headerRenderer,
Comparator<NavigationPosition> comparator) {
boolean visible = preferences.getBoolean(createVisibleKey(name), visibilityDefault);
PositionTableColumn column = new PositionTableColumn(modelIndex, name, visible, cellRenderer, cellEditor, comparator);
column.setHeaderRenderer(headerRenderer);
if (maxWidth != null) {
column.setMaxWidth(maxWidth * 2);
column.setPreferredWidth(maxWidth);
}
predefinedColumns.add(column);
}
private String createVisibleKey(String columnName) {
return preferencesPrefix + VISIBLE_INFIX + columnName;
}
private String createOrderKey(String columnName) {
return preferencesPrefix + ORDER_INFIX + columnName;
}
protected static Calendar createExampleCalendar() {
Calendar calendar = Calendar.getInstance(US);
calendar.set(YEAR, 2030);
calendar.set(MONTH, 11);
calendar.set(DAY_OF_MONTH, 22);
calendar.set(HOUR_OF_DAY, 22);
calendar.set(MINUTE, 33);
calendar.set(SECOND, 44);
return calendar;
}
protected static String getExampleDateTimeFromCurrentLocale() {
Calendar calendar = createExampleCalendar();
return getDateTimeInstance(SHORT, MEDIUM).format(new Date(calendar.getTimeInMillis()));
}
protected static String getExampleDateFromCurrentLocale() {
Calendar calendar = createExampleCalendar();
return getDateInstance(SHORT).format(new Date(calendar.getTimeInMillis()));
}
protected static String getExampleTimeFromCurrentLocale() {
Calendar calendar = createExampleCalendar();
return getTimeInstance(MEDIUM).format(new Date(calendar.getTimeInMillis()));
}
private void addColumn(int columnIndex, TableColumn aColumn) {
if (aColumn == null) {
throw new IllegalArgumentException("Object is null");
}
tableColumns.add(columnIndex, aColumn);
aColumn.addPropertyChangeListener(this);
recalcWidthCache();
// post columnAdded event notification
fireColumnAdded(new TableColumnModelEvent(this, columnIndex, columnIndex));
}
private int indexOf(PositionTableColumn predefinedColumn) {
int index = predefinedColumns.indexOf(predefinedColumn);
int result = 0;
for (int i = 0; i < index; i++) {
if (predefinedColumns.get(i).isVisible())
result++;
}
return result;
}
public void moveColumn(int columnIndex, int newIndex) {
super.moveColumn(columnIndex, newIndex);
if (columnIndex == newIndex)
return;
for (int i = 0; i < getColumnCount(); i++) {
PositionTableColumn column = (PositionTableColumn) getColumn(i);
preferences.putInt(createOrderKey(column.getName()), i);
}
}
protected void initializeColumns() {
VisibleListener visibleListener = new VisibleListener();
PositionTableColumn[] columns = new PositionTableColumn[predefinedColumns.size()];
for (int i = 0; i < predefinedColumns.size(); i++) {
PositionTableColumn column = predefinedColumns.get(i);
int index = preferences.getInt(createOrderKey(column.getName()), i);
if(columns[index] == null)
columns[index] = column;
else if (columns[i] == null)
columns[i] = column;
else if(column.isVisible())
column.toggleVisibility();
column.addPropertyChangeListener(visibleListener);
}
for (PositionTableColumn column : columns) {
if (column != null && column.isVisible())
addColumn(column);
}
}
public int getVisibleColumnCount() {
int count = 0;
for (PositionTableColumn predefinedColumn : getPreparedColumns()) {
if (predefinedColumn.isVisible())
count++;
}
return count;
}
private void visibilityChanged(PositionTableColumn column) {
if (column.isVisible())
addColumn(indexOf(column), column);
else
removeColumn(column);
preferences.putBoolean(createVisibleKey(column.getName()), column.isVisible());
fireVisibilityChanged(column);
}
private class VisibleListener implements PropertyChangeListener {
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals(VISIBLE_PROPERTY_NAME))
visibilityChanged((PositionTableColumn) evt.getSource());
}
}
protected void fireVisibilityChanged(PositionTableColumn column) {
ChangeEvent changeEvent = null;
Object[] listeners = listenerList.getListenerList();
for (int i = listeners.length - 2; i >= 0; i -= 2) {
if (listeners[i] == ChangeListener.class) {
if (changeEvent == null) {
changeEvent = new ChangeEvent(column);
}
((ChangeListener) listeners[i + 1]).stateChanged(changeEvent);
}
}
}
public void addChangeListener(ChangeListener l) {
listenerList.add(ChangeListener.class, l);
}
public void removeChangeListener(ChangeListener l) {
listenerList.remove(ChangeListener.class, l);
}
}