Java tutorial
/** * Copyright Vclav Brodec 2014. * * This file is part of Botn?ek. * * Botn?ek 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 3 of the License, or * (at your option) any later version. * * Botn?ek 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 Botn?ek. If not, see <http://www.gnu.org/licenses/>. */ package cz.cuni.mff.ms.brodecva.botnicek.ide.utils.swing.models; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.TreeMap; import javax.swing.table.AbstractTableModel; import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap.Builder; import com.google.common.collect.Lists; import cz.cuni.mff.ms.brodecva.botnicek.ide.utils.data.Presence; /** * <p> * Model se dvma sloupci, kter mohou mt libovoln typ (ne nutn stejn) - * nzev a hodnota. * </p> * <p> * V ppad, e typ nzvu neimplementuje rozhran {@link Comparable} a nen sm * v?i sob porovnateln, mus ddc tda dodat vlastn {@link Comparator} v * konstruktoru. * </p> * <p> * Model o?ekv uniktn nzvy a podporuje vskyt jednoho dku s przdnm * nzvem, kter je ovem ignorovn a slou do?asn pro vklad nov hodnoty. * </p> * * @author Vclav Brodec * @version 1.0 * @param <N> * typ nzvu * @param <V> * typ hodnoty */ public abstract class AbstractNameValueTableModel<N, V> extends AbstractTableModel implements NameValueTableModel<N, V> { /** * Kompartor, kter jako zklad vyuv porovnateln typ. * * @param <N> * porovnvan typ */ private static final class NaturalComparator<N> implements Comparator<N> { @Override public int compare(final N first, final N second) { @SuppressWarnings("unchecked") final Comparable<? super N> castFirst = (Comparable<? super N>) first; return castFirst.compareTo(second); } } /** * Dekortor kompartoru volitelnch hodnot, kter zaad chybjc hodnoty * na konec. * * @param <N> * porovnvan typ */ private static final class OptionalLastComparator<N> implements Comparator<Optional<N>> { private final Comparator<? super N> comparator; private OptionalLastComparator(final Comparator<? super N> keyComparator) { this.comparator = keyComparator; } /* * (non-Javadoc) * * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) */ @Override public int compare(final Optional<N> first, final Optional<N> second) { if (first.isPresent()) { if (second.isPresent()) { return this.comparator.compare(first.get(), second.get()); } else { return -1; } } else { if (second.isPresent()) { return 1; } else { return 0; } } } } private static final long serialVersionUID = 1L; private static final int COLUMNS_COUNT = 2; private static final int NAME_COLUMN_INDEX = 0; private static final int VALUE_COLUMN_INDEX = 1; private final Map<Optional<N>, V> namesToValues; private final List<String> columnNames; /** * Vytvo model. * * @param nameComparator * kompartor nzv * @param nameColumnName * nzev sloupce s nzvy * @param valueColumnName * nzev sloupce s hodnotami */ protected AbstractNameValueTableModel(final Comparator<? super N> nameComparator, final String nameColumnName, final String valueColumnName) { this(ImmutableMap.<N, V>of(), nameComparator, nameColumnName, valueColumnName); } /** * Vytvo model. * * @param namesToValues * zobrazen nzv na hodnoty * @param nameComparator * kompartor nzv * @param nameColumnName * nzev sloupce s nzvy * @param valueColumnName * nzev sloupce s hodnotami */ protected AbstractNameValueTableModel(final Map<? extends N, ? extends V> namesToValues, final Comparator<? super N> nameComparator, final String nameColumnName, final String valueColumnName) { Preconditions.checkNotNull(namesToValues); Preconditions.checkNotNull(nameComparator); Preconditions.checkNotNull(nameColumnName); Preconditions.checkNotNull(valueColumnName); final Map<N, V> namesToValuesCopy = ImmutableMap.copyOf(namesToValues); this.namesToValues = new TreeMap<Optional<N>, V>(new OptionalLastComparator<N>(nameComparator)); for (final Entry<N, V> entry : namesToValuesCopy.entrySet()) { this.namesToValues.put(Optional.of(entry.getKey()), entry.getValue()); } this.columnNames = ImmutableList.of(nameColumnName, valueColumnName); } /** * Vytvo model, kter srovnv nzvy podle pirozenho azen. * * @param namesToValues * zobrazen nzv na hodnoty * @param nameColumnName * nzev sloupce nzv * @param valueColumnName * nzev sloupce hodnot */ protected AbstractNameValueTableModel(final Map<? extends N, ? extends V> namesToValues, final String nameColumnName, final String valueColumnName) { this(namesToValues, new NaturalComparator<N>(), nameColumnName, valueColumnName); } /** * Vytvo model, kter srovnv nzvy podle pirozenho azen. * * @param nameColumnName * nzev sloupce nzv * @param valueColumnName * nzev sloupce hodnot */ protected AbstractNameValueTableModel(final String nameColumnName, final String valueColumnName) { this(new TreeMap<N, V>(), nameColumnName, valueColumnName); } /* * (non-Javadoc) * * @see * cz.cuni.mff.ms.brodecva.botnicek.ide.utils.swing.models.NameValueTableModel * #addRow() */ @Override public final void addRow() { this.namesToValues.put(Optional.<N>absent(), defaultValue()); fireTableDataChanged(); } /** * Vrt vchoz hodnotu. * * @return vchoz hodnota hodnota */ protected abstract V defaultValue(); /* * (non-Javadoc) * * @see javax.swing.table.TableModel#getColumnClass(int) */ @Override public Class<?> getColumnClass(final int column) { return String.class; } /* * (non-Javadoc) * * @see javax.swing.table.TableModel#getColumnCount() */ @Override public int getColumnCount() { return COLUMNS_COUNT; } /* * (non-Javadoc) * * @see javax.swing.table.TableModel#getColumnName(int) */ @Override public String getColumnName(final int column) { Preconditions.checkPositionIndex(column, this.columnNames.size()); return this.columnNames.get(column); } /* * (non-Javadoc) * * @see * cz.cuni.mff.ms.brodecva.botnicek.ide.utils.swing.models.NameValueTableModel * #getNamesToValues() */ @Override public final Map<N, V> getNamesToValues() { final Builder<N, V> resultBuilder = ImmutableMap.builder(); for (final Entry<Optional<N>, V> entry : this.namesToValues.entrySet()) { final Optional<N> possibleKey = entry.getKey(); if (!possibleKey.isPresent()) { continue; } resultBuilder.put(possibleKey.get(), entry.getValue()); } return resultBuilder.build(); } /* * (non-Javadoc) * * @see javax.swing.table.TableModel#getRowCount() */ @Override public int getRowCount() { return this.namesToValues.size(); } /* * (non-Javadoc) * * @see javax.swing.table.TableModel#getValueAt(int, int) */ @Override public Object getValueAt(final int rowIndex, final int columnIndex) { final List<Entry<Optional<N>, V>> rows = new ArrayList<>(this.namesToValues.entrySet()); final Entry<Optional<N>, V> row = rows.get(rowIndex); final Optional<N> rowKey = row.getKey(); final String keyValue = rowKey.isPresent() ? nameToString(rowKey.get()) : ""; final List<Object> columns = Lists.<Object>newArrayList(keyValue, valueToString(row.getValue())); return columns.get(columnIndex); } /* * (non-Javadoc) * * @see javax.swing.table.TableModel#isCellEditable(int, int) */ @Override public boolean isCellEditable(final int rowIndex, final int columnIndex) { return true; } /** * Konverze textu na nzev. * * @param nameString * text s nzvem * @return nzev */ protected abstract N nameOf(final String nameString); /** * Konverze nzvu na text. * * @param name * nzev * @return textov hodnota */ protected String nameToString(final N name) { Preconditions.checkNotNull(name); return name.toString(); } /* * (non-Javadoc) * * @see javax.swing.table.AbstractTableModel#setValueAt(java.lang.Object, * int, int) */ @Override public void setValueAt(final Object aValue, final int rowIndex, final int columnIndex) { if (Presence.isAbsent(aValue)) { return; } final String currentKeyString = (String) getValueAt(rowIndex, NAME_COLUMN_INDEX); final Optional<N> currentKey = currentKeyString.isEmpty() ? Optional.<N>absent() : Optional.of(nameOf(currentKeyString)); if (columnIndex == NAME_COLUMN_INDEX) { final String newKeyString = (String) aValue; if (newKeyString.isEmpty()) { this.namesToValues.remove(currentKey); fireTableDataChanged(); } else { final Optional<N> newKey; try { newKey = Optional.of(nameOf(newKeyString)); } catch (final IllegalArgumentException e) { return; } final V currentValue = valueOf((String) getValueAt(rowIndex, VALUE_COLUMN_INDEX)); this.namesToValues.remove(currentKey); this.namesToValues.put(newKey, currentValue); fireTableDataChanged(); } } else if (columnIndex == VALUE_COLUMN_INDEX) { final V newValue; try { newValue = valueOf((String) aValue); } catch (final IllegalArgumentException e) { return; } this.namesToValues.put(currentKey, newValue); fireTableDataChanged(); } } /* * (non-Javadoc) * * @see * cz.cuni.mff.ms.brodecva.botnicek.ide.utils.swing.models.NameValueTableModel * #update(java.util.Map) */ @Override public void update(final Map<N, V> namesToValues) { Preconditions.checkNotNull(namesToValues); final Map<N, V> namesToValuesCopy = ImmutableMap.copyOf(namesToValues); this.namesToValues.clear(); for (final Entry<N, V> entry : namesToValuesCopy.entrySet()) { this.namesToValues.put(Optional.of(entry.getKey()), entry.getValue()); } fireTableDataChanged(); } /** * Konverze textu na hodnotu. * * @param valueString * text s hodnotou * @return hodnota */ protected abstract V valueOf(final String valueString); /** * Konverze hodnoty na text. * * @param value * hodnota * @return textov hodnota */ protected String valueToString(final V value) { Preconditions.checkNotNull(value); return value.toString(); } }