View Javadoc

1   /*
2    * Copyright 2006 - 2012 Christina Bohk and Roland Ewald
3    *  
4    * Licensed under the Apache License, Version 2.0 (the "License"); 
5    * you may not use this file except in compliance with the License. 
6    * You may obtain a copy of the License at 
7    *  
8    *  http://www.apache.org/licenses/LICENSE-2.0
9    *  
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
13   * See the License for the specific language governing permissions and 
14   * limitations under the License. 
15   */
16  package p3j.gui.panels.projections;
17  
18  import java.util.ArrayList;
19  import java.util.Collection;
20  import java.util.Collections;
21  import java.util.Comparator;
22  import java.util.HashMap;
23  import java.util.List;
24  import java.util.Map;
25  
26  import javax.swing.JPanel;
27  import javax.swing.JScrollPane;
28  import javax.swing.JTree;
29  import javax.swing.tree.DefaultMutableTreeNode;
30  import javax.swing.tree.DefaultTreeModel;
31  import javax.swing.tree.TreePath;
32  
33  import p3j.gui.panels.AbstractNavigationPanel;
34  import p3j.pppm.ProjectionModel;
35  import p3j.pppm.parameters.ParameterAssignment;
36  import p3j.pppm.parameters.ParameterInstance;
37  import p3j.pppm.parameters.Population;
38  import p3j.pppm.sets.Set;
39  import p3j.pppm.sets.SetType;
40  
41  /**
42   * Panel that displays a {@link JTree} in a {@link java.awt.ScrollPane} and
43   * initializes them properly.
44   * 
45   * Created: August 23, 2008
46   * 
47   * @author Christina Bohk
48   * @author Roland Ewald
49   * 
50   */
51  public class ProjectionTreePanel extends AbstractNavigationPanel implements
52      IProjectionTree {
53  
54  	/** Serialization ID. */
55  	private static final long serialVersionUID = 1648793294436076701L;
56  
57  	/** Root of the projection tree. */
58  	private ProjectionNode pTreeRoot;
59  
60  	/**
61  	 * The Constructor.
62  	 * 
63  	 * @param proj
64  	 *          the projection model
65  	 * @param content
66  	 *          the content pane (to display editing panels)
67  	 */
68  	public ProjectionTreePanel(ProjectionModel proj, JPanel content) {
69  		super(proj, content);
70  	}
71  
72  	/**
73  	 * Initializes projection tree.
74  	 */
75  	@Override
76  	protected void initTree() {
77  		pTreeRoot = new ProjectionNode(getProjectionModel());
78  		setTreeModel(new DefaultTreeModel(pTreeRoot));
79  		setTree(new JTree(getTreeModel()));
80  		getTree().setCellRenderer(new ProjectionTreeCellRenderer());
81  		setScrollPane(new JScrollPane(getTree()));
82  
83  		totalRefresh();
84  		getTree().addTreeSelectionListener(
85  		    new ProjectionTreeSelectionListener(getContentPanel(), this));
86  		getTree().setSelectionPath(new TreePath(pTreeRoot));
87  	}
88  
89  	/**
90  	 * Adds sub tree for {@link SetType}.
91  	 * 
92  	 * @param root
93  	 *          the root of this sub tree
94  	 * @param setType
95  	 *          the Settype to be represented
96  	 */
97  	protected void addSetTypeSubTree(DefaultMutableTreeNode root, SetType setType) {
98  		SetTypeNode stNode = new SetTypeNode(setType);
99  		root.add(stNode);
100 		for (p3j.pppm.sets.Set set : setType.getSets()) {
101 			addSetSubTree(stNode, set, setType);
102 		}
103 	}
104 
105 	/**
106 	 * Adds sub tree for {@link Set}.
107 	 * 
108 	 * @param root
109 	 *          the root of this sub tree
110 	 * @param set
111 	 *          the set to be represented
112 	 * @param setType
113 	 *          the Settype of this set
114 	 * @return the set node at the top of the subtree
115 	 */
116 	protected SetNode addSetSubTree(SetTypeNode root, Set set, SetType setType) {
117 		SetNode sNode = new SetNode(set);
118 		root.add(sNode);
119 
120 		Map<Integer, List<ParameterInstance>> generationMap = new HashMap<Integer, List<ParameterInstance>>();
121 
122 		for (ParameterInstance instance : setType.getDefinedParameters()) {
123 			int generation = retrieveGeneration(instance);
124 			List<ParameterInstance> genInstList = generationMap.get(generation);
125 			if (genInstList == null) {
126 				genInstList = new ArrayList<ParameterInstance>();
127 				generationMap.put(generation, genInstList);
128 			}
129 			genInstList.add(instance);
130 		}
131 
132 		List<Integer> genIndices = new ArrayList<Integer>(generationMap.keySet());
133 		Collections.sort(genIndices);
134 
135 		for (Integer genIndex : genIndices) {
136 			if (genIndex < 0) {
137 				addPopulationsSubTree(sNode, set, generationMap.get(genIndex));
138 			} else {
139 				addGenerationSubTree(sNode, generationMap.get(genIndex));
140 			}
141 		}
142 
143 		return sNode;
144 	}
145 
146 	/**
147 	 * Retrieves generation for given instance. Generation-0 instances of
148 	 * emigrants and immigrants are added to their base populations (i.e. -1 is
149 	 * returned).
150 	 * 
151 	 * @param instance
152 	 *          the instance of interest
153 	 * @return its generation
154 	 */
155 	private int retrieveGeneration(ParameterInstance instance) {
156 		int generation = instance.getGeneration();
157 		if (instance.getParameter().getPopulation() != Population.NATIVES
158 		    && instance.getGeneration() == 0) {
159 			generation = -1;
160 		}
161 		return generation;
162 	}
163 
164 	/**
165 	 * Adds sub-tree for a generation. A generation is the set of all instances
166 	 * that define parameters for a specific generation.
167 	 * 
168 	 * @param root
169 	 *          the root of this sub tree
170 	 * @param instances
171 	 *          the list of parameter instances of this generation
172 	 */
173 	protected void addGenerationSubTree(SetNode root,
174 	    List<ParameterInstance> instances) {
175 		GenerationNode gNode = new GenerationNode(instances);
176 		root.add(gNode);
177 		addPopulationsSubTree(gNode, root.getEntity(), instances);
178 	}
179 
180 	/**
181 	 * Adds sub tree for populations.
182 	 * 
183 	 * @param root
184 	 *          the root of this sub tree
185 	 * @param set
186 	 *          the set containing the assumptions for the instances
187 	 * @param instances
188 	 *          list of instances
189 	 */
190 	protected void addPopulationsSubTree(ProjectionTreeNode<?> root, Set set,
191 	    List<ParameterInstance> instances) {
192 
193 		Map<Population, List<ParameterInstance>> popMap = new HashMap<Population, List<ParameterInstance>>();
194 		for (ParameterInstance instance : instances) {
195 			List<ParameterInstance> popInsts = popMap.get(instance.getParameter()
196 			    .getPopulation());
197 			if (popInsts == null) {
198 				popInsts = new ArrayList<ParameterInstance>();
199 				popMap.put(instance.getParameter().getPopulation(), popInsts);
200 			}
201 			popInsts.add(instance);
202 		}
203 
204 		// Use always the same order of sub-populations
205 		List<Population> populations = new ArrayList<Population>(popMap.keySet());
206 		Collections.sort(populations, new Comparator<Population>() {
207 			@Override
208 			public int compare(Population o1, Population o2) {
209 				return o1.compareTo(o2);
210 			}
211 		});
212 
213 		for (Population population : populations) {
214 			List<ParameterInstance> popInst = popMap.get(population);
215 			PopulationNode popNode = new PopulationNode(population);
216 			root.add(popNode);
217 			addInstancesSubTree(popNode, set, popInst);
218 		}
219 	}
220 
221 	/**
222 	 * Adds sub tree for {@link ParameterInstance} entities.
223 	 * 
224 	 * @param root
225 	 *          the root of the sub tree
226 	 * @param set
227 	 *          the set containing the assumptions for the instances
228 	 * @param instances
229 	 *          the instances that will be nodes
230 	 */
231 	protected void addInstancesSubTree(PopulationNode root, Set set,
232 	    List<ParameterInstance> instances) {
233 		for (ParameterInstance instance : instances) {
234 			ParameterInstanceNode instNode = new ParameterInstanceNode(instance);
235 			root.add(instNode);
236 			addAssumptionsSubTree(instNode, set, instance);
237 		}
238 	}
239 
240 	/**
241 	 * Adds sub tree for {@link ParameterAssignment} entities.
242 	 * 
243 	 * @param root
244 	 *          the root node for this sub tree
245 	 * @param set
246 	 *          the set in which the assignments are defined
247 	 * @param instance
248 	 *          the instance to which the assignments belong
249 	 */
250 	protected void addAssumptionsSubTree(ParameterInstanceNode root, Set set,
251 	    ParameterInstance instance) {
252 		List<ParameterAssignment> assignments = new ArrayList<ParameterAssignment>(
253 		    set.getParameterAssignments(instance).getAssignments());
254 
255 		// Sort assignments alphabetically
256 		Collections.sort(assignments, new Comparator<ParameterAssignment>() {
257 			@Override
258 			public int compare(ParameterAssignment o1, ParameterAssignment o2) {
259 				return o1.getName().compareTo(o2.getName());
260 			}
261 		});
262 
263 		for (ParameterAssignment assignment : assignments) {
264 			root.add(new ParameterAssignmentNode(assignment));
265 		}
266 
267 	}
268 
269 	@Override
270 	public void refreshNode(ProjectionTreeNode<?> node) {
271 		getTreeModel().nodeChanged(node);
272 	}
273 
274 	@Override
275 	public void refreshNodeSubStructure(ProjectionTreeNode<?> node) {
276 		getTreeModel().nodeStructureChanged(node);
277 
278 	}
279 
280 	@Override
281 	public void nodeAdded(ParameterInstanceNode node, int index) {
282 		getTreeModel().nodesWereInserted(node, new int[] { index });
283 	}
284 
285 	@Override
286 	public void selectNode(ProjectionTreeNode<?> node) {
287 		selectProjectionTreePath(new TreePath(getTreeModel().getPathToRoot(node)));
288 	}
289 
290 	@Override
291 	public void recursiveRefresh(ProjectionTreeNode<?> node) {
292 		node.refreshRecursively(getTreeModel());
293 		getTree().repaint();
294 	}
295 
296 	@Override
297 	public void removeNode(ProjectionTreeNode<?> node) {
298 		TreePath path = new TreePath(getTreeModel().getPathToRoot(node.getParent()));
299 		getTreeModel().removeNodeFromParent(node);
300 		selectProjectionTreePath(path);
301 	}
302 
303 	/**
304 	 * Selects node at the end of the given path in the projection tree.
305 	 * 
306 	 * @param path
307 	 *          the path to be selected
308 	 */
309 	void selectProjectionTreePath(TreePath path) {
310 		getTree().setSelectionPath(path);
311 		getTree().scrollPathToVisible(path);
312 	}
313 
314 	@Override
315 	public void removeNodes(ProjectionTreeNode<?> node,
316 	    Collection<? extends Object> repRemovObjects) {
317 		if (repRemovObjects.contains(node.getEntity())) {
318 			getTreeModel().removeNodeFromParent(node);
319 		} else {
320 			for (ProjectionTreeNode<?> child : node.getChilds()) {
321 				removeNodes(child, repRemovObjects);
322 			}
323 		}
324 	}
325 
326 	@Override
327 	public void cleanTree() {
328 		cleanTree((ProjectionTreeNode<?>) getTreeModel().getRoot());
329 	}
330 
331 	/**
332 	 * Recursively cleans up the tree.
333 	 * 
334 	 * @param node
335 	 *          the current node
336 	 */
337 	protected void cleanTree(ProjectionTreeNode<?> node) {
338 		for (ProjectionTreeNode<?> child : node.getChilds()) {
339 			cleanTree(child);
340 		}
341 		if (node.getChildCount() == 0
342 		    && (node instanceof PopulationNode || node instanceof GenerationNode)) {
343 			getTreeModel().removeNodeFromParent(node);
344 		}
345 	}
346 
347 	@Override
348 	public SetNode createNewSetStructure(SetTypeNode stNode, Set set) {
349 		return addSetSubTree(stNode, set, stNode.getEntity());
350 	}
351 
352 	@Override
353 	public void totalRefresh() {
354 
355 		// Remove children from root
356 		for (ProjectionTreeNode<?> child : pTreeRoot.getChilds()) {
357 			getTreeModel().removeNodeFromParent(child);
358 		}
359 
360 		// Add new children
361 		addSetTypeSubTree(pTreeRoot, getProjectionModel().getDefaultSetType());
362 		for (SetType type : getProjectionModel().getUserDefinedTypes()) {
363 			addSetTypeSubTree(pTreeRoot, type);
364 		}
365 
366 		getTreeModel().nodeStructureChanged(pTreeRoot);
367 		getTree().repaint();
368 	}
369 }