View Javadoc
1   /*
2    * ObjectLab, http://www.objectlab.co.uk/open is supporting JTreeMap.
3    *
4    * Based in London, we are world leaders in the design and development
5    * of bespoke applications for the securities financing markets.
6    *
7    * <a href="http://www.objectlab.co.uk/open">Click here to learn more</a>
8    *           ___  _     _           _   _          _
9    *          / _ \| |__ (_) ___  ___| |_| |    __ _| |__
10   *         | | | | '_ \| |/ _ \/ __| __| |   / _` | '_ \
11   *         | |_| | |_) | |  __/ (__| |_| |__| (_| | |_) |
12   *          \___/|_.__// |\___|\___|\__|_____\__,_|_.__/
13   *                   |__/
14   *
15   *                     www.ObjectLab.co.uk
16   *
17   * $Id$
18   *
19   * Copyright 2006 the original author or authors.
20   *
21   * Licensed under the Apache License, Version 2.0 (the "License"); you may not
22   * use this file except in compliance with the License. You may obtain a copy of
23   * the License at
24   *
25   * http://www.apache.org/licenses/LICENSE-2.0
26   *
27   * Unless required by applicable law or agreed to in writing, software
28   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
29   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
30   * License for the specific language governing permissions and limitations under
31   * the License.
32   */
33  package net.sf.jtreemap.swing;
34  
35  import java.io.Serializable;
36  import java.util.ArrayList;
37  import java.util.Iterator;
38  import java.util.List;
39  
40  /**
41   * Abtract class with the method which split the elements of a JTreeMap.
42   * <p>
43   * The split is done by dichotomy. We split the elements in 2 groups with a
44   * defined strategy (for example : take care of the weight of the elements)
45   * <p>
46   *
47   * @author Laurent Dutheil
48   */
49  
50  public abstract class SplitStrategy implements Serializable {
51      /**
52       *
53       */
54      private static final long serialVersionUID = 1L;
55  
56      /**
57       * calculate the positions for all the elements of the root.
58       *
59       * @param root
60       *            the root to calculate
61       */
62      public void calculatePositions(final TreeMapNode root) {
63          if (root == null) {
64              return;
65          }
66  
67          final List<TreeMapNode> v = root.getChildren();
68          if (v != null && !v.isEmpty()) {
69              calculatePositionsRec(root.getX(), root.getY(), root.getWidth(), root.getHeight(), this.sumWeight(v), v);
70          }
71      }
72  
73      /**
74       * split the elements of a JTreeMap.
75       *
76       * @param v
77       *            List with the elements to split (arg IN)
78       * @param v1
79       *            first List of the split (arg OUT)
80       * @param v2
81       *            second List of the split (arg OUT)
82       */
83      public abstract void splitElements(List<TreeMapNode> v, List<TreeMapNode> v1, List<TreeMapNode> v2);
84  
85      /**
86       * Sum the weight of elements. <BR>
87       * You can override this method if you want to apply a coef on the weights
88       * or to cancel the effect of weight on the strategy.
89       *
90       * @param v
91       *            List with the elements to sum
92       * @return the sum of the weight of elements
93       */
94      public double sumWeight(final List<TreeMapNode> v) {
95          double d = 0.0;
96          if (v != null) {
97              final int size = v.size();
98  
99              for (int i = 0; i < size; i++) {
100                 d += v.get(i).getWeight();
101             }
102         }
103         return d;
104     }
105 
106     protected void calculatePositionsRec(final int x0, final int y0, final int w0, final int h0, final double weight0, final List<TreeMapNode> v) {
107 
108         if (v.isEmpty()) {
109             return;
110         }
111         // 1. don't calculate if the area is too small,
112         if (w0 * h0 < 20) {
113             return;
114         }
115 
116         // 2. don't calculate if the candidates are too many to display
117         if (w0 * h0 < v.size()) {
118             return;
119         }
120 
121         // if the List contains only one element
122         if (v.size() == 1) {
123             calculatePositionRecForSingleElement(x0, y0, w0, h0, weight0, v);
124         } else {
125             // if there is more than one element
126             // we split the List according to the selected strategy
127             final List<TreeMapNode> v1 = new ArrayList<>();
128             final List<TreeMapNode> v2 = new ArrayList<>();
129             double weight1;
130             double weight2; // poids des 2 vecteurs
131             this.splitElements(v, v1, v2);
132             weight1 = this.sumWeight(v1);
133             weight2 = this.sumWeight(v2);
134 
135             int w1;
136             int w2;
137             int h1;
138             int h2;
139             int x2;
140             int y2;
141             // if width is greater than height, we split the width
142             if (w0 > h0) {
143                 w1 = (int) (w0 * weight1 / weight0);
144                 w2 = w0 - w1;
145                 h1 = h0;
146                 h2 = h0;
147                 x2 = x0 + w1;
148                 y2 = y0;
149             } else {
150                 // else we split the height
151                 w1 = w0;
152                 w2 = w0;
153                 h1 = (int) (h0 * weight1 / weight0);
154                 h2 = h0 - h1;
155                 x2 = x0;
156                 y2 = y0 + h1;
157             }
158             // calculation for the new two Lists
159             calculatePositionsRec(x0, y0, w1, h1, weight1, v1);
160             calculatePositionsRec(x2, y2, w2, h2, weight2, v2);
161         }
162     }
163 
164     private void calculatePositionRecForSingleElement(final int x0, final int y0, final int w0, final int h0, final double weight0,
165             final List<TreeMapNode> v) {
166         final TreeMapNode f = v.get(0);
167         if (f.isLeaf()) {
168             // if this is a leaf, we display with the border
169             int w = w0 - TreeMapNode.getBorder();
170             if (w < 0) {
171                 w = 0;
172             }
173             int h = h0 - TreeMapNode.getBorder();
174             if (h < 0) {
175                 h = 0;
176             }
177             f.setDimension(x0 + TreeMapNode.getBorder(), y0 + TreeMapNode.getBorder(), w, h);
178         } else {
179             // if this is not a leaf, calculation for the children
180             f.setDimension(x0, y0, w0, h0);
181 
182             int bSub;
183             if (TreeMapNode.getBorder() > 1) {
184                 bSub = 2;
185             } else if (TreeMapNode.getBorder() == 1) {
186                 bSub = 1;
187             } else {
188                 bSub = 0;
189             }
190 
191             int w = w0 - bSub;
192             if (w < 0) {
193                 w = 0;
194             }
195             int h = h0 - bSub;
196             if (h < 0) {
197                 h = 0;
198             }
199 
200             TreeMapNode.setBorder(TreeMapNode.getBorder() - bSub);
201             calculatePositionsRec(x0 + bSub, y0 + bSub, w, h, weight0, f.getChildren());
202             TreeMapNode.setBorder(TreeMapNode.getBorder() + bSub);
203         }
204     }
205 
206     /**
207      * Sort the elements by descending weight.
208      *
209      * @param v
210      *            List with the elements to be sorted
211      */
212     protected void sortList(final List<TreeMapNode> v) {
213         TreeMapNode tmn;
214         // we use the bubble sort
215         for (int i = 0; i < v.size(); i++) {
216             for (int j = v.size() - 1; j > i; j--) {
217                 if (v.get(j).getWeight() > v.get(j - 1).getWeight()) {
218                     tmn = v.get(j);
219                     v.set(j, v.get(j - 1));
220                     v.set(j - 1, tmn);
221                 }
222             }
223         }
224 
225     }
226 
227     protected void workOutWeight(final List<TreeMapNode> v1, final List<TreeMapNode> v2, final List<TreeMapNode> vClone, final double sumWeight) {
228         double memWeight = 0.0;
229         double elemWeight;
230         for (final Iterator<TreeMapNode> i = vClone.iterator(); i.hasNext();) {
231             TreeMapNode tmn = i.next();
232             elemWeight = tmn.getWeight();
233             // if adding the current element pass the middle of total weight
234             if (memWeight + elemWeight >= sumWeight / 2) {
235                 // we look at the finest split (the nearest of the middle of
236                 // weight)
237                 if (sumWeight / 2 - memWeight > memWeight + elemWeight - sumWeight / 2) {
238                     // if it is after the add, we add the element to the first
239                     // List
240                     memWeight += elemWeight;
241                     v1.add(tmn);
242                 } else if (v1.isEmpty()) { // we must have at least 1 element in the first List
243                     v1.add(tmn);
244                 } else {
245                     // if it is before the add, we add the element to the
246                     // second List
247                     v2.add(tmn);
248                 }
249                 // then we fill the second List qith the rest of elements
250                 while (i.hasNext()) {
251                     tmn = i.next();
252                     v2.add(tmn);
253                 }
254             } else {
255                 // we add in the first List while we don't reach the middle of
256                 // weight
257                 memWeight += elemWeight;
258                 v1.add(tmn);
259             }
260         }
261     }
262 }
263 /*
264  *                 ObjectLab is supporing JTreeMap
265  *
266  * Based in London, we are world leaders in the design and development
267  * of bespoke applications for the securities financing markets.
268  *
269  * <a href="http://www.objectlab.co.uk/open">Click here to learn more about us</a>
270  *           ___  _     _           _   _          _
271  *          / _ \| |__ (_) ___  ___| |_| |    __ _| |__
272  *         | | | | '_ \| |/ _ \/ __| __| |   / _` | '_ \
273  *         | |_| | |_) | |  __/ (__| |_| |__| (_| | |_) |
274  *          \___/|_.__// |\___|\___|\__|_____\__,_|_.__/
275  *                   |__/
276  *
277  *                     www.ObjectLab.co.uk
278  */