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

fr.vergne.translation.editor.ListModel Maven / Gradle / Ivy

There is a newer version: 2.0
Show newest version
package fr.vergne.translation.editor;

import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;

import fr.vergne.collection.filter.Filter;
import fr.vergne.collection.util.NaturalComparator;
import fr.vergne.collection.util.NaturalComparator.Translator;
import fr.vergne.translation.editor.content.MapTreeNode;
import fr.vergne.translation.util.CollectionManager;
import fr.vergne.translation.util.MapInformer;
import fr.vergne.translation.util.MapInformer.MapSummaryListener;
import fr.vergne.translation.util.MapInformer.NoDataException;
import fr.vergne.translation.util.MapNamer;

@SuppressWarnings("serial")
public class ListModel extends DefaultTreeModel {

	private final DefaultMutableTreeNode root;
	private final MapInformer informer;
	private final Map> nodeMap;
	private final CollectionManager listManager = new CollectionManager();
	private final Collection listeners = new HashSet();
	private final Filter noFilter;
	private final Filter incompleteFilter;
	private final Map, Comparator> comparators = new HashMap<>();
	private MapNamer orderNamer;

	public ListModel(final MapInformer informer,
			final Collection> namers) {
		super(new DefaultMutableTreeNode("maps"));
		root = (DefaultMutableTreeNode) getRoot();
		this.informer = informer;

		noFilter = new Filter() {

			@Override
			public Boolean isSupported(MapID file) {
				return true;
			}
		};
		incompleteFilter = new Filter() {

			@Override
			public Boolean isSupported(MapID file) {
				try {
					return informer.getEntriesRemaining(file) > 0;
				} catch (NoDataException e) {
					return true;
				}
			}
		};

		for (final MapNamer mapNamer : namers) {
			NaturalComparator comparator = new NaturalComparator(
					new Translator() {

						@Override
						public String toString(MapID file) {
							return mapNamer.getNameFor(file);
						}
					}) {
				@Override
				public int compare(MapID id1, MapID id2) {
					int comparison = super.compare(id1, id2);
					if (comparison != 0) {
						return comparison;
					} else if (id1.equals(id2)) {
						return 0;
					}
					/*
					 * The last case enforces that two different IDs are not
					 * confused due to their identical names. Although none of
					 * the comparisons computed are 100% safe, having everyone
					 * of them leading to a null comparison is improbable, so it
					 * should be OK most of the time.
					 */
					else {
						comparison = id1.hashCode() - id2.hashCode();
						if (comparison == 0) {
							comparison = id1.toString().compareTo(
									id2.toString());
						}
						return comparison;
					}
				}
			};
			comparators.put(mapNamer, comparator);
			listManager.addCollection(noFilter, comparator);
			listManager.addCollection(incompleteFilter, comparator);
		}
		this.orderNamer = namers.iterator().next();

		nodeMap = new HashMap>();

		informer.addMapSummaryListener(new MapSummaryListener() {

			@Override
			public void mapSummarized(MapID mapId) {
				Object node = nodeMap.get(mapId);

				Collection ids = listManager.getCollection(
						getCurrentFilter(), getCurrentComparator());
				boolean oldContains = ids.contains(mapId);
				int index = -1;
				if (oldContains) {
					index = getIndexOfChild(root, node);
				} else {
					// not in the list
				}

				listManager.recheckElement(mapId);

				boolean newContains = ids.contains(mapId);
				if (index == -1 && newContains) {
					index = getIndexOfChild(root, node);
				} else {
					// not in the list nor necessary
				}

				Object[] rootPath = new Object[] { root };
				if (oldContains && newContains) {
					int[] childIndices = new int[] { index };
					Object[] children = new Object[] { node };
					fireTreeNodesChanged(root, rootPath, childIndices, children);
				} else if (oldContains && !newContains) {
					int[] childIndices = new int[] { index };
					Object[] children = new Object[] { node };
					fireTreeNodesRemoved(root, rootPath, childIndices, children);
				} else if (!oldContains && newContains) {
					int[] childIndices = new int[] { index };
					Object[] children = new Object[] { node };
					fireTreeNodesInserted(root, rootPath, childIndices,
							children);
				} else if (!oldContains && !newContains) {
					// no displayed update
				} else {
					throw new RuntimeException("This case should not happen.");
				}
			}
		});
	}

	public void setMaps(Collection maps) {
		listManager.clear();
		for (MapID id : maps) {
			listManager.addElement(id);
			nodeMap.put(id, new MapTreeNode(root, id));
		}
		fireTreeStructureChanged(root, new Object[] { root }, null, null);
		fireMapsChanged();
	}

	public void removeID(MapID id) {
		listManager.removeElement(id);
		nodeMap.remove(id);
		fireTreeStructureChanged(root, new Object[] { root }, null, null);
		fireMapsChanged();
	}

	public static interface MapsChangedListener {
		public void mapsChanged();
	}

	public void addMapsChangedListener(MapsChangedListener listener) {
		listeners.add(listener);
	}

	public void removeMapsChangedListener(MapsChangedListener listener) {
		listeners.remove(listener);
	}

	private void fireMapsChanged() {
		for (MapsChangedListener listener : listeners) {
			listener.mapsChanged();
		}
	}

	public Collection getCurrentMapIDs() {
		return listManager.getCollection(getCurrentFilter(),
				getCurrentComparator());
	}

	private Comparator getCurrentComparator() {
		return comparators.get(getOrderNamer());
	}

	private Filter getCurrentFilter() {
		return isClearedDisplayed ? noFilter : incompleteFilter;
	}

	public Collection getAllMapsIDs() {
		return listManager.getAllElements();
	}

	private boolean isClearedDisplayed;

	public void setClearedDisplayed(boolean isClearedDisplayed) {
		if (isClearedDisplayed != this.isClearedDisplayed) {
			this.isClearedDisplayed = isClearedDisplayed;
			fireTreeStructureChanged(root, new Object[] { root }, null, null);
		} else {
			// keep as is
		}
	}

	public boolean isClearedDisplayed() {
		return isClearedDisplayed;
	}

	@Override
	public Object getChild(Object parent, int index) {
		if (parent == root) {
			return nodeMap.get(getFileAt(index));
		} else {
			return super.getChild(parent, index);
		}
	}

	@Override
	public int getChildCount(Object parent) {
		if (parent == root) {
			return getCurrentMapIDs().size();
		} else {
			return super.getChildCount(parent);
		}
	}

	@Override
	public int getIndexOfChild(Object parent, Object child) {
		if (parent == root) {
			@SuppressWarnings("unchecked")
			MapTreeNode node = (MapTreeNode) child;
			MapID id = node.getMapID();
			return getIDIndex(id);
		} else {
			return super.getIndexOfChild(parent, child);
		}
	}

	@Override
	public boolean isLeaf(Object node) {
		if (node == getRoot()) {
			return false;
		} else {
			return true;
		}
	}

	private MapID getFileAt(int index) {
		List ids = new LinkedList<>(getCurrentMapIDs());
		return ids.get(index);
	}

	private int getIDIndex(MapID id) {
		return new LinkedList<>(getCurrentMapIDs()).indexOf(id);
	}

	public MapNamer getOrderNamer() {
		return orderNamer;
	}

	public void setOrderNamer(MapNamer orderNamer) {
		if (!this.orderNamer.equals(orderNamer)) {
			this.orderNamer = orderNamer;
			fireTreeStructureChanged(root, new Object[] { root }, null, null);
		} else {
			// keep as is
		}
	}

	public MapInformer getMapInformer() {
		return informer;
	}

	public void requestUpdate() {
		fireTreeStructureChanged(root, new Object[] { root }, null, null);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy