1 |
|
package se.datadosen.component; |
2 |
|
|
3 |
|
import java.awt.*; |
4 |
|
import java.util.*; |
5 |
|
|
6 |
|
|
7 |
|
|
8 |
|
|
9 |
|
|
10 |
|
|
11 |
|
|
12 |
|
|
13 |
|
|
14 |
|
|
15 |
|
|
16 |
|
|
17 |
|
|
18 |
|
|
19 |
|
|
20 |
|
|
21 |
|
|
22 |
|
|
23 |
|
|
24 |
|
|
25 |
|
|
26 |
|
|
27 |
|
|
28 |
|
|
29 |
|
|
30 |
|
|
31 |
|
|
32 |
|
|
33 |
|
|
34 |
|
|
35 |
|
|
36 |
|
public class RiverLayout |
37 |
|
extends FlowLayout |
38 |
|
implements LayoutManager, java.io.Serializable { |
39 |
|
|
40 |
|
public static final String LINE_BREAK = "br"; |
41 |
|
public static final String PARAGRAPH_BREAK = "p"; |
42 |
|
public static final String TAB_STOP = "tab"; |
43 |
|
public static final String HFILL = "hfill"; |
44 |
|
public static final String VFILL = "vfill"; |
45 |
|
public static final String LEFT = "left"; |
46 |
|
public static final String RIGHT = "right"; |
47 |
|
public static final String CENTER = "center"; |
48 |
|
public static final String VTOP = "vtop"; |
49 |
|
public static final String VCENTER = "vcenter"; |
50 |
|
|
51 |
0 |
Map constraints = new HashMap(); |
52 |
0 |
String valign = VCENTER; |
53 |
|
int hgap; |
54 |
|
int vgap; |
55 |
|
Insets extraInsets; |
56 |
0 |
Insets totalInsets = new Insets(0, 0, 0, 0); |
57 |
|
|
58 |
|
|
59 |
|
public RiverLayout() { |
60 |
0 |
this(10, 5); |
61 |
0 |
} |
62 |
|
|
63 |
0 |
public RiverLayout(int hgap, class="keyword">int vgap) { |
64 |
0 |
this.hgap = hgap; |
65 |
0 |
this.vgap = vgap; |
66 |
0 |
setExtraInsets(new Insets(0, hgap, hgap, hgap)); |
67 |
0 |
} |
68 |
|
|
69 |
|
|
70 |
|
|
71 |
|
|
72 |
|
public int getHgap() { |
73 |
0 |
return hgap; |
74 |
|
} |
75 |
|
|
76 |
|
|
77 |
|
|
78 |
|
|
79 |
|
public void setHgap(int hgap) { |
80 |
0 |
this.hgap = hgap; |
81 |
0 |
} |
82 |
|
|
83 |
|
|
84 |
|
|
85 |
|
|
86 |
|
public int getVgap() { |
87 |
0 |
return vgap; |
88 |
|
} |
89 |
|
|
90 |
|
public Insets getExtraInsets() { |
91 |
0 |
return extraInsets; |
92 |
|
} |
93 |
|
|
94 |
|
public void setExtraInsets(Insets newExtraInsets) { |
95 |
0 |
extraInsets = newExtraInsets; |
96 |
0 |
} |
97 |
|
|
98 |
|
protected Insets getInsets(Container target) { |
99 |
0 |
Insets insets = target.getInsets(); |
100 |
0 |
totalInsets.top = insets.top + extraInsets.top; |
101 |
0 |
totalInsets.left = insets.left + extraInsets.left; |
102 |
0 |
totalInsets.bottom = insets.bottom + extraInsets.bottom; |
103 |
0 |
totalInsets.right = insets.right + extraInsets.right; |
104 |
0 |
return totalInsets; |
105 |
|
} |
106 |
|
|
107 |
|
|
108 |
|
|
109 |
|
|
110 |
|
public void setVgap(int vgap) { |
111 |
0 |
this.vgap = vgap; |
112 |
0 |
} |
113 |
|
|
114 |
|
|
115 |
|
|
116 |
|
|
117 |
|
|
118 |
|
|
119 |
|
public void addLayoutComponent(String name, Component comp) { |
120 |
0 |
constraints.put(comp, name); |
121 |
0 |
} |
122 |
|
|
123 |
|
|
124 |
|
|
125 |
|
|
126 |
|
|
127 |
|
|
128 |
|
|
129 |
|
public void removeLayoutComponent(Component comp) { |
130 |
0 |
constraints.remove(comp); |
131 |
0 |
} |
132 |
|
|
133 |
|
boolean isFirstInRow(Component comp) { |
134 |
0 |
String cons = (String) constraints.get(comp); |
135 |
0 |
return cons != null && (cons.indexOf(RiverLayout.LINE_BREAK) != -1 || |
136 |
|
cons.indexOf(RiverLayout.PARAGRAPH_BREAK) != -1); |
137 |
|
} |
138 |
|
|
139 |
|
boolean hasHfill(Component comp) { |
140 |
0 |
return hasConstraint(comp, RiverLayout.HFILL); |
141 |
|
} |
142 |
|
|
143 |
|
boolean hasVfill(Component comp) { |
144 |
0 |
return hasConstraint(comp, RiverLayout.VFILL); |
145 |
|
} |
146 |
|
|
147 |
|
boolean hasConstraint(Component comp, String test) { |
148 |
0 |
String cons = (String) constraints.get(comp); |
149 |
0 |
if (cons == null) return false; |
150 |
0 |
StringTokenizer tokens = new StringTokenizer(cons); |
151 |
0 |
while (tokens.hasMoreTokens()) |
152 |
0 |
if (tokens.nextToken().equals(test)) return true; |
153 |
0 |
return false; |
154 |
|
} |
155 |
|
|
156 |
|
|
157 |
|
|
158 |
|
|
159 |
|
protected Ruler calcTabs(Container target) { |
160 |
0 |
Ruler ruler = new Ruler(); |
161 |
0 |
int nmembers = target.getComponentCount(); |
162 |
|
|
163 |
0 |
int x = 0; |
164 |
0 |
int tabIndex = 0; |
165 |
0 |
for (int i = 0; i < nmembers; i++) { |
166 |
0 |
Component m = target.getComponent(i); |
167 |
|
|
168 |
0 |
if (isFirstInRow(m) || i == 0) { |
169 |
0 |
x = 0; |
170 |
0 |
tabIndex = 0; |
171 |
0 |
} |
172 |
0 |
else x+= hgap; |
173 |
0 |
if (hasConstraint(m, TAB_STOP)) { |
174 |
0 |
ruler.setTab(tabIndex, x); |
175 |
0 |
x = ruler.getTab(tabIndex++); |
176 |
|
} |
177 |
0 |
Dimension d = m.getPreferredSize(); |
178 |
0 |
x += d.width; |
179 |
|
} |
180 |
|
|
181 |
0 |
return ruler; |
182 |
|
} |
183 |
|
|
184 |
|
|
185 |
|
|
186 |
|
|
187 |
|
|
188 |
|
|
189 |
|
|
190 |
|
|
191 |
|
|
192 |
|
|
193 |
|
|
194 |
|
public Dimension preferredLayoutSize(Container target) { |
195 |
0 |
synchronized (target.getTreeLock()) { |
196 |
0 |
Dimension dim = new Dimension(0, 0); |
197 |
0 |
Dimension rowDim = new Dimension(0, 0); |
198 |
0 |
int nmembers = target.getComponentCount(); |
199 |
0 |
boolean firstVisibleComponent = true; |
200 |
0 |
int tabIndex = 0; |
201 |
0 |
Ruler ruler = calcTabs(target); |
202 |
|
|
203 |
0 |
for (int i = 0; i < nmembers; i++) { |
204 |
0 |
Component m = target.getComponent(i); |
205 |
|
|
206 |
0 |
if (isFirstInRow(m)) { |
207 |
0 |
tabIndex = 0; |
208 |
0 |
dim.width = Math.max(dim.width, rowDim.width); |
209 |
0 |
dim.height += rowDim.height + vgap; |
210 |
0 |
if (hasConstraint(m, PARAGRAPH_BREAK)) dim.height += 2*vgap; |
211 |
0 |
rowDim = new Dimension(0, 0); |
212 |
|
} |
213 |
0 |
if (hasConstraint(m, TAB_STOP)) rowDim.width = ruler.getTab(tabIndex++); |
214 |
0 |
Dimension d = m.getPreferredSize(); |
215 |
0 |
rowDim.height = Math.max(rowDim.height, d.height); |
216 |
0 |
if (firstVisibleComponent) { |
217 |
0 |
firstVisibleComponent = false; |
218 |
0 |
} |
219 |
|
else { |
220 |
0 |
rowDim.width += hgap; |
221 |
|
} |
222 |
0 |
rowDim.width += d.width; |
223 |
|
|
224 |
|
} |
225 |
0 |
dim.width = Math.max(dim.width, rowDim.width); |
226 |
0 |
dim.height += rowDim.height; |
227 |
|
|
228 |
0 |
Insets insets = getInsets(target); |
229 |
0 |
dim.width += insets.left + insets.right; |
230 |
0 |
dim.height += insets.top + insets.bottom; |
231 |
0 |
return dim; |
232 |
0 |
} |
233 |
|
} |
234 |
|
|
235 |
|
|
236 |
|
|
237 |
|
|
238 |
|
|
239 |
|
|
240 |
|
|
241 |
|
|
242 |
|
|
243 |
|
|
244 |
|
|
245 |
|
public Dimension minimumLayoutSize(Container target) { |
246 |
0 |
synchronized (target.getTreeLock()) { |
247 |
0 |
Dimension dim = new Dimension(0, 0); |
248 |
0 |
Dimension rowDim = new Dimension(0, 0); |
249 |
0 |
int nmembers = target.getComponentCount(); |
250 |
0 |
boolean firstVisibleComponent = true; |
251 |
0 |
int tabIndex = 0; |
252 |
0 |
Ruler ruler = calcTabs(target); |
253 |
|
|
254 |
0 |
for (int i = 0; i < nmembers; i++) { |
255 |
0 |
Component m = target.getComponent(i); |
256 |
|
|
257 |
0 |
if (isFirstInRow(m)) { |
258 |
0 |
tabIndex = 0; |
259 |
0 |
dim.width = Math.max(dim.width, rowDim.width); |
260 |
0 |
dim.height += rowDim.height + vgap; |
261 |
0 |
if (hasConstraint(m, PARAGRAPH_BREAK)) dim.height += 2*vgap; |
262 |
0 |
rowDim = new Dimension(0, 0); |
263 |
|
} |
264 |
0 |
if (hasConstraint(m, TAB_STOP)) rowDim.width = ruler.getTab(tabIndex++); |
265 |
0 |
Dimension d = m.getMinimumSize(); |
266 |
0 |
rowDim.height = Math.max(rowDim.height, d.height); |
267 |
0 |
if (firstVisibleComponent) { |
268 |
0 |
firstVisibleComponent = false; |
269 |
0 |
} |
270 |
|
else { |
271 |
0 |
rowDim.width += hgap; |
272 |
|
} |
273 |
0 |
rowDim.width += d.width; |
274 |
|
|
275 |
|
} |
276 |
0 |
dim.width = Math.max(dim.width, rowDim.width); |
277 |
0 |
dim.height += rowDim.height; |
278 |
|
|
279 |
0 |
Insets insets = getInsets(target); |
280 |
0 |
dim.width += insets.left + insets.right; |
281 |
0 |
dim.height += insets.top + insets.bottom; |
282 |
0 |
return dim; |
283 |
0 |
} |
284 |
|
} |
285 |
|
|
286 |
|
|
287 |
|
|
288 |
|
|
289 |
|
|
290 |
|
|
291 |
|
|
292 |
|
|
293 |
|
|
294 |
|
|
295 |
|
|
296 |
|
protected void moveComponents(Container target, int x, class="keyword">int y, class="keyword">int width, |
297 |
|
int height, |
298 |
|
int rowStart, class="keyword">int rowEnd, boolean ltr, Ruler ruler) { |
299 |
0 |
synchronized (target.getTreeLock()) { |
300 |
0 |
switch (getAlignment()) { |
301 |
|
case FlowLayout.LEFT: |
302 |
0 |
x += ltr ? 0 : width; |
303 |
0 |
break; |
304 |
|
case FlowLayout.CENTER: |
305 |
0 |
x += width / 2; |
306 |
0 |
break; |
307 |
|
case FlowLayout.RIGHT: |
308 |
0 |
x += ltr ? width : 0; |
309 |
0 |
break; |
310 |
|
case LEADING: |
311 |
0 |
break; |
312 |
|
case TRAILING: |
313 |
0 |
x += width; |
314 |
|
break; |
315 |
|
} |
316 |
0 |
int tabIndex = 0; |
317 |
0 |
for (int i = rowStart; i < rowEnd; i++) { |
318 |
0 |
Component m = target.getComponent(i); |
319 |
|
|
320 |
0 |
if (hasConstraint(m, TAB_STOP)) x = getInsets(target).left + ruler.getTab(tabIndex++); |
321 |
0 |
int dy = (valign == VTOP) ? 0 : (height - m.getHeight()) / 2; |
322 |
0 |
if (ltr) { |
323 |
0 |
m.setLocation(x, y + dy); |
324 |
0 |
} |
325 |
|
else { |
326 |
0 |
m.setLocation(target.getWidth() - x - m.getWidth(), |
327 |
|
y + dy); |
328 |
|
} |
329 |
0 |
x += m.getWidth() + hgap; |
330 |
|
|
331 |
|
} |
332 |
0 |
} |
333 |
0 |
} |
334 |
|
|
335 |
|
|
336 |
|
protected void relMove(Container target, int dx, class="keyword">int dy, class="keyword">int rowStart, |
337 |
|
int rowEnd) { |
338 |
0 |
synchronized (target.getTreeLock()) { |
339 |
0 |
for (int i = rowStart; i < rowEnd; i++) { |
340 |
0 |
Component m = target.getComponent(i); |
341 |
|
|
342 |
0 |
m.setLocation(m.getX() + dx, m.getY() + dy); |
343 |
|
|
344 |
|
} |
345 |
|
|
346 |
0 |
} |
347 |
0 |
} |
348 |
|
|
349 |
|
protected void adjustAlignment(Component m) { |
350 |
0 |
if (hasConstraint(m, RiverLayout.LEFT)) setAlignment(FlowLayout.LEFT); |
351 |
0 |
else if (hasConstraint(m, RiverLayout.RIGHT)) setAlignment(FlowLayout.RIGHT); |
352 |
0 |
else if (hasConstraint(m, RiverLayout.CENTER)) setAlignment(FlowLayout.CENTER); |
353 |
0 |
if (hasConstraint(m, RiverLayout.VTOP)) valign = VTOP; |
354 |
0 |
else if (hasConstraint(m, RiverLayout.VCENTER)) valign = VCENTER; |
355 |
|
|
356 |
0 |
} |
357 |
|
|
358 |
|
|
359 |
|
|
360 |
|
|
361 |
|
|
362 |
|
|
363 |
|
|
364 |
|
|
365 |
|
|
366 |
|
public void layoutContainer(Container target) { |
367 |
0 |
setAlignment(FlowLayout.LEFT); |
368 |
0 |
synchronized (target.getTreeLock()) { |
369 |
0 |
Insets insets = getInsets(target); |
370 |
0 |
int maxwidth = target.getWidth() - |
371 |
|
(insets.left + insets.right); |
372 |
0 |
int maxheight = target.getHeight() - |
373 |
|
(insets.top + insets.bottom); |
374 |
|
|
375 |
0 |
int nmembers = target.getComponentCount(); |
376 |
0 |
int x = 0, y = insets.top + vgap; |
377 |
0 |
int rowh = 0, start = 0, moveDownStart = 0; |
378 |
|
|
379 |
0 |
boolean ltr = target.getComponentOrientation().isLeftToRight(); |
380 |
0 |
Component toHfill = null; |
381 |
0 |
Component toVfill = null; |
382 |
0 |
Ruler ruler = calcTabs(target); |
383 |
0 |
int tabIndex = 0; |
384 |
|
|
385 |
0 |
for (int i = 0; i < nmembers; i++) { |
386 |
0 |
Component m = target.getComponent(i); |
387 |
|
|
388 |
0 |
Dimension d = m.getPreferredSize(); |
389 |
0 |
m.setSize(d.width, d.height); |
390 |
|
|
391 |
0 |
if (isFirstInRow(m)) tabIndex = 0; |
392 |
0 |
if (hasConstraint(m, TAB_STOP)) x = ruler.getTab(tabIndex++); |
393 |
0 |
if (!isFirstInRow(m)) { |
394 |
0 |
if (i > 0 && !hasConstraint(m, TAB_STOP)) { |
395 |
0 |
x += hgap; |
396 |
|
} |
397 |
0 |
x += d.width; |
398 |
0 |
rowh = Math.max(rowh, d.height); |
399 |
0 |
} |
400 |
|
else { |
401 |
0 |
if (toVfill != null && moveDownStart == 0) { |
402 |
0 |
moveDownStart = i; |
403 |
|
} |
404 |
0 |
if (toHfill != null) { |
405 |
0 |
toHfill.setSize(toHfill.getWidth() + maxwidth - x, |
406 |
|
toHfill.getHeight()); |
407 |
0 |
x = maxwidth; |
408 |
|
} |
409 |
0 |
moveComponents(target, insets.left, y, |
410 |
|
maxwidth - x, |
411 |
|
rowh, start, i, ltr, ruler); |
412 |
0 |
x = d.width; |
413 |
0 |
y += vgap + rowh; |
414 |
0 |
if (hasConstraint(m, PARAGRAPH_BREAK)) y += 2*vgap; |
415 |
0 |
rowh = d.height; |
416 |
0 |
start = i; |
417 |
0 |
toHfill = null; |
418 |
|
} |
419 |
|
|
420 |
0 |
if (hasHfill(m)) { |
421 |
0 |
toHfill = m; |
422 |
|
} |
423 |
0 |
if (hasVfill(m)) { |
424 |
0 |
toVfill = m; |
425 |
|
} |
426 |
0 |
adjustAlignment(m); |
427 |
|
} |
428 |
|
|
429 |
0 |
if (toVfill != null && moveDownStart == 0) { |
430 |
0 |
moveDownStart = nmembers; |
431 |
|
} |
432 |
0 |
if (toHfill != null) { |
433 |
0 |
toHfill.setSize(toHfill.getWidth() + maxwidth - x, |
434 |
|
toHfill.getHeight()); |
435 |
0 |
x = maxwidth; |
436 |
|
} |
437 |
0 |
moveComponents(target, insets.left, y, maxwidth - x, rowh, |
438 |
|
start, nmembers, ltr, ruler); |
439 |
0 |
int yslack = maxheight - (y+rowh); |
440 |
0 |
if (yslack > 0 && toVfill != null) { |
441 |
0 |
toVfill.setSize(toVfill.getWidth(), yslack + toVfill.getHeight()); |
442 |
0 |
relMove(target, 0, yslack, moveDownStart, nmembers); |
443 |
|
} |
444 |
0 |
} |
445 |
0 |
} |
446 |
|
|
447 |
|
} |
448 |
|
|
449 |
|
class Ruler { |
450 |
|
private Vector tabs = new Vector(); |
451 |
|
|
452 |
|
public void setTab(int num, class="keyword">int xpos) { |
453 |
|
if (num >= tabs.size()) tabs.add(num, new Integer(xpos)); |
454 |
|
else { |
455 |
|
|
456 |
|
int delta = xpos - getTab(num); |
457 |
|
if (delta > 0) { |
458 |
|
for (int i = num; i < tabs.size(); i++) { |
459 |
|
tabs.set(i, new Integer(getTab(i) + delta)); |
460 |
|
} |
461 |
|
} |
462 |
|
} |
463 |
|
} |
464 |
|
|
465 |
|
public int getTab(class="keyword">int num) { |
466 |
|
return ((Integer)tabs.get(num)).intValue(); |
467 |
|
} |
468 |
|
|
469 |
|
public String toString() { |
470 |
|
StringBuffer ret = new StringBuffer(getClass().getName() + " {"); |
471 |
|
for (int i=0; i<tabs.size(); i++) { |
472 |
|
ret.append(tabs.get(i)); |
473 |
|
if (i < tabs.size()-1) ret.append(','); |
474 |
|
} |
475 |
|
ret.append('}'); |
476 |
|
return ret.toString(); |
477 |
|
} |
478 |
|
|
479 |
|
public static void main(String[] args) { |
480 |
|
Ruler r = new Ruler(); |
481 |
|
r.setTab(0,10); |
482 |
|
r.setTab(1,20); |
483 |
|
r.setTab(2,30); |
484 |
|
System.out.println(r); |
485 |
|
r.setTab(1,25); |
486 |
|
System.out.println(r); |
487 |
|
System.out.println(r.getTab(0)); |
488 |
|
} |
489 |
|
} |