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 */