/******************************************************************************* * Copyright (c) MOBAC developers * * This program 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. * * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. ******************************************************************************/ package mobac.program.model; import java.awt.Toolkit; import java.util.HashSet; import java.util.LinkedList; import java.util.Set; import javax.swing.JOptionPane; import javax.swing.event.TreeModelEvent; import javax.swing.event.TreeModelListener; import javax.swing.tree.TreeModel; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; import mobac.exceptions.InvalidNameException; import mobac.program.interfaces.AtlasInterface; import mobac.program.interfaces.AtlasObject; import mobac.program.interfaces.LayerInterface; import mobac.program.interfaces.MapInterface; import org.apache.log4j.Logger; public class AtlasTreeModel implements TreeModel { private static Logger log = Logger.getLogger(AtlasTreeModel.class); protected AtlasInterface atlasInterface; protected Set<TreeModelListener> listeners = new HashSet<TreeModelListener>(); public AtlasTreeModel() { super(); atlasInterface = Atlas.newInstance(); } public void addTreeModelListener(TreeModelListener l) { listeners.add(l); } public void removeTreeModelListener(TreeModelListener l) { listeners.remove(l); } public void notifyStructureChanged() { notifyStructureChanged((TreeNode) atlasInterface); } public void notifyStructureChanged(TreeNode root) { notifyStructureChanged(new TreeModelEvent(this, new Object[] { root })); } /** * IMPORTANT: This method have to be called BEFORE deleting the element in * the data model!!! Otherwise the child index can not be retrieved anymore * which is important. * * @param node */ public void notifyNodeDelete(TreeNode node) { TreeNode parent = node.getParent(); Object[] children = new Object[] { node }; int childrenIdx = parent.getIndex(node); if (childrenIdx == -1) { // A problem detected - use fall back solution notifyStructureChanged(); return; } TreePath path = getNodePath(parent); TreeModelEvent event = new TreeModelEvent(this, path, new int[] { childrenIdx }, children); for (TreeModelListener l : listeners) l.treeNodesRemoved(event); } protected void notifyStructureChanged(TreeModelEvent event) { for (TreeModelListener l : listeners) l.treeStructureChanged(event); } public void notifyNodeInsert(TreeNode insertedNode) { TreeNode parent = insertedNode.getParent(); TreePath path = getNodePath(parent); TreeNode[] childs = new TreeNode[] { insertedNode }; int childId = parent.getIndex(insertedNode); assert (childId <= 0); TreeModelEvent event = new TreeModelEvent(this, path, new int[] { childId }, childs); for (TreeModelListener l : listeners) l.treeNodesInserted(event); } public TreePath getNodePath(TreeNode node) { LinkedList<TreeNode> path = new LinkedList<TreeNode>(); TreeNode n = node; while (n != null) { path.addFirst(n); n = n.getParent(); } return new TreePath(path.toArray()); } public Object getChild(Object parent, int index) { return ((TreeNode) parent).getChildAt(index); } public int getChildCount(Object parent) { return ((TreeNode) parent).getChildCount(); } public int getIndexOfChild(Object parent, Object child) { return ((TreeNode) parent).getIndex((TreeNode) child); } public Object getRoot() { return atlasInterface; } public boolean isLeaf(Object node) { return ((TreeNode) node).isLeaf(); } public void valueForPathChanged(TreePath path, Object newValue) { Object o = path.getLastPathComponent(); boolean success = false; try { AtlasObject sel = (AtlasObject) o; String newName = (String) newValue; if (newName.length() == 0) return; sel.setName(newName); success = true; } catch (ClassCastException e) { log.error("", e); } catch (InvalidNameException e) { log.error(e.getLocalizedMessage()); JOptionPane.showMessageDialog(null, e.getLocalizedMessage(), "Renaming failed", JOptionPane.ERROR_MESSAGE); } finally { if (!success) { Toolkit.getDefaultToolkit().beep(); } } } public void mergeLayers(LayerInterface source, LayerInterface target) throws InvalidNameException { boolean sourceFound = false; boolean targetFound = false; for (LayerInterface l : atlasInterface) { if (l.equals(source)) sourceFound = true; if (l.equals(target)) targetFound = true; } if (!targetFound) return; // Check for duplicate names HashSet<String> names = new HashSet<String>(); for (MapInterface map : source) names.add(map.getName()); for (MapInterface map : target) names.add(map.getName()); if (names.size() < (source.getMapCount() + target.getMapCount())) throw new InvalidNameException("Map naming conflict:\n" + "The layers to be merged contain map(s) of the same name."); if (sourceFound) atlasInterface.deleteLayer(source); for (MapInterface map : source) { target.addMap(map); } notifyNodeDelete((TreeNode) source); notifyStructureChanged((TreeNode) target); } public void moveMap(MapInterface map, LayerInterface targetLayer) { notifyNodeDelete((TreeNode) map); map.delete(); targetLayer.addMap(map); notifyNodeInsert((TreeNode) map); } public AtlasInterface getAtlas() { return atlasInterface; } public void setAtlas(Atlas atlas) { this.atlasInterface = atlas; notifyStructureChanged(); } public void save(Profile profile) throws Exception { profile.save(atlasInterface); } public void load(Profile profile) throws Exception { atlasInterface = profile.load(); notifyStructureChanged(); } }