package ilarkesto.ui.swing;
import ilarkesto.core.logging.Log;
import ilarkesto.persistence.TransactionService;
import ilarkesto.swing.Swing;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import javax.swing.ComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
public abstract class AComponent {
private static final Log LOG = Log.get(AComponent.class);
protected abstract void initializeControls();
protected abstract JComponent createComponent();
protected abstract void updateControls();
private JComponent component;
private boolean initialized;
// --- dependencies ---
protected SwingUi ui;
protected TransactionService transactionService;
public final void setUi(SwingUi ui) {
this.ui = ui;
}
public final void setTransactionService(TransactionService transactionService) {
this.transactionService = transactionService;
}
public final void initialize() {
if (initialized) throw new RuntimeException(getName() + " already initialized");
initialized = true;
initializeControls();
}
// --- ---
public final JComponent getJavaComponent() {
if (!initialized) initialize();
if (component == null) {
Swing.invokeInEventDispatchThread(new Runnable() {
@Override
public void run() {
updateControls();
component = createComponent();
}
});
}
return component;
}
public final void resetComponent() {
component = null;
}
protected String getStringKeyPrefix() {
return getName();
}
protected String getName() {
return getClass().getSimpleName();
}
@Override
public String toString() {
return getName();
}
// --- helper ---
public final void updateControlsInEventDispatchThreadLater() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
updateControls();
}
});
}
protected final JButton createButton(String name) {
JButton c = new JButton();
c.setText(string(name + ".label"));
c.setToolTipText(string(name + ".hint"));
return c;
}
protected final JButton createButton(String name, String icon) {
JButton button = createButton(name);
button.setIcon(Swing.getIcon16(icon));
return button;
}
protected final String string(String key, Object... parameters) {
return ui.getLocalizer().string(getStringKeyPrefix() + "." + key, parameters);
}
protected abstract class ListModel<I> extends AbstractTableModel implements ListSelectionListener {
protected abstract void onItemsSelected(List<I> items);
protected abstract String getName();
private List<I> items = Collections.emptyList();
private JTable table;
private List<Column<I>> columns;
private boolean settingItems;
public ListModel() {}
public void addColumn(Column<I> column) {
if (columns == null) columns = new ArrayList<Column<I>>();
columns.add(column);
column.setListModel(this);
fireTableStructureChanged();
updateColumns();
}
private void updateColumns() {
TableColumnModel tcm = table.getColumnModel();
int count = tcm.getColumnCount();
for (int i = 0; i < count; i++) {
columns.get(i).update(tcm.getColumn(i));
}
}
public Object getValueAt(int columnIndex, I item) {
if (columns == null) return item.toString();
return columns.get(columnIndex).getValue(item);
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
I item = items.get(rowIndex);
return getValueAt(columnIndex, item);
}
public void setTable(JTable table) {
this.table = table;
}
public void setItems(Collection<I> items) {
List<I> selectedItems = getSelectedItems();
this.items = new ArrayList(items);
settingItems = true;
fireTableDataChanged();
settingItems = false;
setSelectedItems(selectedItems);
}
@Override
public int getRowCount() {
return items.size();
}
@Override
public int getColumnCount() {
if (columns == null) return 1;
return columns.size();
}
@Override
public String getColumnName(int column) {
if (columns == null) return null;
return columns.get(column).getLabel();
}
@Override
public void valueChanged(ListSelectionEvent e) {
if (e.getValueIsAdjusting()) return;
if (settingItems) return;
onItemsSelected(getSelectedItems());
}
public void setSelectedItems(List<I> selectedItems) {
selectedItems.retainAll(items);
ListSelectionModel selectionModel = table.getSelectionModel();
selectionModel.clearSelection();
for (int index : getIndexes(selectedItems)) {
selectionModel.addSelectionInterval(index, index);
}
}
public List<I> getSelectedItems() {
return getItems(table.getSelectedRows());
}
public I getSelectedItem() {
int index = table.getSelectedRow();
return index < 0 ? null : items.get(index);
}
private int[] getIndexes(Collection<I> items) {
int[] ret = new int[items.size()];
int i = 0;
for (I item : items) {
ret[i] = this.items.indexOf(item);
i++;
}
return ret;
}
private List<I> getItems(int[] indexes) {
List<I> ret = new ArrayList<I>(indexes.length);
for (int index : indexes) {
ret.add(items.get(index));
}
return ret;
}
}
protected abstract class Column<I> {
private ListModel<I> listModel;
public abstract String getName();
public abstract Object getValue(I item);
public String getLabel() {
return string(listModel.getName() + "." + getName());
}
public void setListModel(ListModel<I> listModel) {
this.listModel = listModel;
}
public void update(TableColumn tc) {}
}
protected abstract class DropdownModel<I> implements ComboBoxModel, ActionListener {
protected abstract void onItemSelected(I item);
private List<ListDataListener> listeners = new ArrayList<ListDataListener>(1);
private List<I> items = Collections.emptyList();
private I selectedItem;
private JComboBox dropdown;
public DropdownModel() {}
public void setDropdown(JComboBox dropdown) {
this.dropdown = dropdown;
}
public void setItems(Collection<I> items) {
this.items = new ArrayList(items);
ListDataEvent event = new ListDataEvent(AComponent.this, ListDataEvent.CONTENTS_CHANGED, 0,
items.size() - 1);
if (selectedItem != null) {
if (!items.contains(selectedItem)) setSelectedItem(null);
}
for (ListDataListener listener : listeners) {
listener.contentsChanged(event);
}
if (selectedItem == null && !this.items.isEmpty()) setSelectedItem(this.items.get(0));
}
public void setSelectedItem(Object anItem) {
if (this.selectedItem == anItem) return;
this.selectedItem = (I) anItem;
onItemSelected(selectedItem);
}
@Override
public void addListDataListener(ListDataListener l) {
listeners.add(l);
}
@Override
public Object getElementAt(int index) {
return items.get(index);
}
@Override
public int getSize() {
return items.size();
}
@Override
public void removeListDataListener(ListDataListener l) {
listeners.remove(l);
}
public I getSelectedItem() {
return selectedItem;
}
@Override
public void actionPerformed(ActionEvent e) {
setSelectedItem(dropdown.getSelectedItem());
}
}
}