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.SubPopulation;
36  import p3j.pppm.parameters.ParameterAssignment;
37  import p3j.pppm.parameters.ParameterInstance;
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<>();
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<>(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().isGenerationDependent()
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     for (SubPopulation subPopulation : pTreeRoot.getEntity()
193         .getSubPopulationModel().getSubPopulations()) {
194       List<ParameterInstance> popInst = ProjectionModel
195           .filterParamInstancesBySubPopulation(instances, subPopulation);
196       if (popInst.isEmpty())
197         continue;
198       SubPopulationNode popNode = new SubPopulationNode(subPopulation);
199       root.add(popNode);
200       addInstancesSubTree(popNode, set, popInst);
201     }
202   }
203 
204   /**
205    * Adds sub tree for {@link ParameterInstance} entities.
206    * 
207    * @param root
208    *          the root of the sub tree
209    * @param set
210    *          the set containing the assumptions for the instances
211    * @param instances
212    *          the instances that will be nodes
213    */
214   protected void addInstancesSubTree(SubPopulationNode root, Set set,
215       List<ParameterInstance> instances) {
216     for (ParameterInstance instance : instances) {
217       ParameterInstanceNode instNode = new ParameterInstanceNode(instance);
218       root.add(instNode);
219       addAssumptionsSubTree(instNode, set, instance);
220     }
221   }
222 
223   /**
224    * Adds sub tree for {@link ParameterAssignment} entities.
225    * 
226    * @param root
227    *          the root node for this sub tree
228    * @param set
229    *          the set in which the assignments are defined
230    * @param instance
231    *          the instance to which the assignments belong
232    */
233   protected void addAssumptionsSubTree(ParameterInstanceNode root, Set set,
234       ParameterInstance instance) {
235     List<ParameterAssignment> assignments = new ArrayList<ParameterAssignment>(
236         set.getParameterAssignments(instance).getAssignments());
237 
238     // Sort assignments alphabetically
239     Collections.sort(assignments, new Comparator<ParameterAssignment>() {
240       @Override
241       public int compare(ParameterAssignment o1, ParameterAssignment o2) {
242         return o1.getName().compareTo(o2.getName());
243       }
244     });
245 
246     for (ParameterAssignment assignment : assignments) {
247       root.add(new ParameterAssignmentNode(assignment));
248     }
249 
250   }
251 
252   @Override
253   public void refreshNode(ProjectionTreeNode<?> node) {
254     getTreeModel().nodeChanged(node);
255   }
256 
257   @Override
258   public void refreshNodeSubStructure(ProjectionTreeNode<?> node) {
259     getTreeModel().nodeStructureChanged(node);
260 
261   }
262 
263   @Override
264   public void nodeAdded(ParameterInstanceNode node, int index) {
265     getTreeModel().nodesWereInserted(node, new int[] { index });
266   }
267 
268   @Override
269   public void selectNode(ProjectionTreeNode<?> node) {
270     selectProjectionTreePath(new TreePath(getTreeModel().getPathToRoot(node)));
271   }
272 
273   @Override
274   public void recursiveRefresh(ProjectionTreeNode<?> node) {
275     node.refreshRecursively(getTreeModel());
276     getTree().repaint();
277   }
278 
279   @Override
280   public void removeNode(ProjectionTreeNode<?> node) {
281     TreePath path = new TreePath(getTreeModel().getPathToRoot(node.getParent()));
282     getTreeModel().removeNodeFromParent(node);
283     selectProjectionTreePath(path);
284   }
285 
286   /**
287    * Selects node at the end of the given path in the projection tree.
288    * 
289    * @param path
290    *          the path to be selected
291    */
292   void selectProjectionTreePath(TreePath path) {
293     getTree().setSelectionPath(path);
294     getTree().scrollPathToVisible(path);
295   }
296 
297   @Override
298   public void removeNodes(ProjectionTreeNode<?> node,
299       Collection<? extends Object> repRemovObjects) {
300     if (repRemovObjects.contains(node.getEntity())) {
301       getTreeModel().removeNodeFromParent(node);
302     } else {
303       for (ProjectionTreeNode<?> child : node.getChilds()) {
304         removeNodes(child, repRemovObjects);
305       }
306     }
307   }
308 
309   @Override
310   public void cleanTree() {
311     cleanTree((ProjectionTreeNode<?>) getTreeModel().getRoot());
312   }
313 
314   /**
315    * Recursively cleans up the tree.
316    * 
317    * @param node
318    *          the current node
319    */
320   protected void cleanTree(ProjectionTreeNode<?> node) {
321     for (ProjectionTreeNode<?> child : node.getChilds()) {
322       cleanTree(child);
323     }
324     if (node.getChildCount() == 0
325         && (node instanceof SubPopulationNode || node instanceof GenerationNode)) {
326       getTreeModel().removeNodeFromParent(node);
327     }
328   }
329 
330   @Override
331   public SetNode createNewSetStructure(SetTypeNode stNode, Set set) {
332     return addSetSubTree(stNode, set, stNode.getEntity());
333   }
334 
335   @Override
336   public void totalRefresh() {
337 
338     // Remove children from root
339     for (ProjectionTreeNode<?> child : pTreeRoot.getChilds()) {
340       getTreeModel().removeNodeFromParent(child);
341     }
342 
343     // Add new children
344     addSetTypeSubTree(pTreeRoot, getProjectionModel().getDefaultSetType());
345     for (SetType type : getProjectionModel().getUserDefinedTypes()) {
346       addSetTypeSubTree(pTreeRoot, type);
347     }
348 
349     getTreeModel().nodeStructureChanged(pTreeRoot);
350     getTree().repaint();
351   }
352 }