1
2
3
4
5
6
7
8
9
10
11
12
13 package org.abstracthorizon.aequo.gui;
14
15 import java.awt.LayoutManager;
16
17 import javax.swing.JTable;
18 import javax.swing.table.TableColumn;
19 import javax.swing.table.TableColumnModel;
20 import javax.swing.table.TableModel;
21
22
23
24
25
26
27 public class ResizingTable extends JTable {
28
29 public ResizingTable(TableModel tableModel) {
30 super(tableModel);
31 }
32
33 public void createDefaultColumnsFromModel() {
34 TableModel m = getModel();
35 if (m != null) {
36
37 TableColumnModel cm = getColumnModel();
38 while (cm.getColumnCount() > 0) {
39 cm.removeColumn(cm.getColumn(0));
40 }
41
42
43 for (int i = 0; i < m.getColumnCount(); i++) {
44 TableColumn newColumn = new TableColumn(i) {
45
46 protected int preferredWidth;
47
48 public void setPreferredWidth(int width) {
49 preferredWidth = width;
50 }
51
52 public int getPreferredWidth() {
53 return preferredWidth;
54 }
55 };
56 addColumn(newColumn);
57 }
58 }
59 }
60
61 public void doLayout() {
62 TableColumn resizingColumn = getResizingColumn();
63 TableColumnModel columnModel = getColumnModel();
64
65 int width = getWidth();
66 int columns = getColumnCount();
67 int[] widths = new int[columns];
68 int[] minWidths = new int[columns];
69 int[] maxWidths = new int[columns];
70
71 int notDefined = 0;
72 int tWidth = 0;
73 if (resizingColumn != null) {
74 for (int i = 0; i < columns; i++) {
75 TableColumn col = columnModel.getColumn(i);
76 if (resizingColumn == col) {
77 widths[i] = col.getWidth();
78 } else {
79 if (col.getPreferredWidth() >= 0) {
80 widths[i] = col.getWidth();
81 } else {
82 widths[i] = -1;
83 notDefined = notDefined + 1;
84 }
85 }
86 minWidths[i] = col.getMinWidth();
87 maxWidths[i] = col.getMaxWidth();
88 tWidth = tWidth + widths[i];
89 if (minWidths[i] < 0) {
90 minWidths[i] = 15;
91 }
92 }
93 } else {
94 for (int i = 0; i < columns; i++) {
95 TableColumn col = columnModel.getColumn(i);
96 widths[i] = col.getPreferredWidth();
97 minWidths[i] = col.getMinWidth();
98 maxWidths[i] = col.getMaxWidth();
99 if (widths[i] > 0) {
100 tWidth = tWidth + widths[i];
101 } else {
102 notDefined = notDefined + 1;
103 }
104 if (minWidths[i] < 0) {
105 minWidths[i] = 15;
106 }
107 }
108 }
109 if (notDefined > 0) {
110 if (tWidth < width) {
111 int nWidth = 0;
112 for (int i = 0; i < columns; i++) {
113 if (widths[i] < 0) {
114 int calc = (width - tWidth) / notDefined;
115 if (calc < minWidths[i]) {
116 calc = minWidths[i];
117 }
118 widths[i] = calc;
119 nWidth = nWidth + calc;
120 notDefined = notDefined - 1;
121 } else {
122 nWidth = nWidth + widths[i];
123 }
124 }
125 tWidth = nWidth;
126 } else {
127 tWidth = 0;
128 for (int i = 0; i < columns; i++) {
129 if (widths[i] < 0) {
130 widths[i] = minWidths[i];
131 }
132 tWidth = tWidth + widths[i];
133 }
134 }
135 }
136 if (tWidth < width) {
137
138 int add = width - tWidth;
139 int i = 0;
140 while ((i < columns) && (add > 0)) {
141 int calc = add / (columns - i);
142 if (calc == 0) {
143 calc = 1;
144 }
145 if (maxWidths[i] >= widths[i] + calc) {
146 widths[i] = widths[i] + calc;
147 add = add - calc;
148 }
149 i++;
150 }
151 } else if (tWidth > width) {
152
153 int del = tWidth - width;
154 int i = 0;
155 while ((i < columns) && (del > 0)) {
156 int calc = del / (columns - i);
157 if (calc == 0) {
158 calc = 1;
159 }
160 if (minWidths[i] <= widths[i] - calc) {
161 widths[i] = widths[i] - calc;
162 del = del - calc;
163 }
164 i++;
165 }
166 }
167 for (int i = 0; i < columns; i++) {
168 columnModel.getColumn(i).setWidth(widths[i]);
169 }
170 }
171
172
173
174
175
176 public void doLayout2() {
177 TableColumn resizingColumn = getResizingColumn();
178 if (resizingColumn == null) {
179 setWidthsFromPreferredWidths(false);
180 } else {
181
182
183
184
185
186
187 int columnIndex = viewIndexForColumn(resizingColumn);
188 int delta = getWidth() - getColumnModel().getTotalColumnWidth();
189 accommodateDelta(columnIndex, delta);
190 delta = getWidth() - getColumnModel().getTotalColumnWidth();
191
192
193
194
195
196
197
198
199
200
201
202 if (delta != 0) {
203 resizingColumn.setWidth(resizingColumn.getWidth() + delta);
204 }
205
206
207
208
209
210
211
212 setWidthsFromPreferredWidths(true);
213 }
214
215 LayoutManager layoutMgr = getLayout();
216 if (layoutMgr != null) {
217 layoutMgr.layoutContainer(this);
218 }
219 }
220
221
222
223
224
225
226
227
228
229 private TableColumn getResizingColumn() {
230 return (tableHeader == null) ? null : tableHeader.getResizingColumn();
231 }
232
233 private void setWidthsFromPreferredWidths(final boolean inverse) {
234 int totalWidth = getWidth();
235 int totalPreferred = getPreferredSize().width;
236 int target = !inverse ? totalWidth : totalPreferred;
237
238 final TableColumnModel cm = columnModel;
239 Resizable3 r = new Resizable3() {
240 public int getElementCount() {
241 return cm.getColumnCount();
242 }
243
244 public int getLowerBoundAt(int i) {
245 return cm.getColumn(i).getMinWidth();
246 }
247
248 public int getUpperBoundAt(int i) {
249 return cm.getColumn(i).getMaxWidth();
250 }
251
252 public int getMidPointAt(int i) {
253 if (!inverse) {
254 return cm.getColumn(i).getPreferredWidth();
255 } else {
256 return cm.getColumn(i).getWidth();
257 }
258 }
259
260 public void setSizeAt(int s, int i) {
261 if (!inverse) {
262 cm.getColumn(i).setWidth(s);
263 } else {
264 cm.getColumn(i).setPreferredWidth(s);
265 }
266 }
267 };
268
269 adjustSizes(target, r, inverse);
270 }
271
272 private int viewIndexForColumn(TableColumn aColumn) {
273 TableColumnModel cm = getColumnModel();
274 for (int column = 0; column < cm.getColumnCount(); column++) {
275 if (cm.getColumn(column) == aColumn) {
276 return column;
277 }
278 }
279 return -1;
280 }
281
282 private void accommodateDelta(int resizingColumnIndex, int delta) {
283 int columnCount = getColumnCount();
284 int from = resizingColumnIndex;
285 int to = columnCount;
286
287
288 switch (autoResizeMode) {
289 case AUTO_RESIZE_NEXT_COLUMN:
290 from = from + 1;
291 to = Math.min(from + 1, columnCount);
292 break;
293 case AUTO_RESIZE_SUBSEQUENT_COLUMNS:
294 from = from + 1;
295 to = columnCount;
296 break;
297 case AUTO_RESIZE_LAST_COLUMN:
298 from = columnCount - 1;
299 to = from + 1;
300 break;
301 case AUTO_RESIZE_ALL_COLUMNS:
302 from = 0;
303 to = columnCount;
304 break;
305 default:
306 return;
307 }
308
309 final int start = from;
310 final int end = to;
311 final TableColumnModel cm = columnModel;
312 Resizable3 r = new Resizable3() {
313 public int getElementCount() {
314 return end - start;
315 }
316
317 public int getLowerBoundAt(int i) {
318 return cm.getColumn(i + start).getMinWidth();
319 }
320
321 public int getUpperBoundAt(int i) {
322 return cm.getColumn(i + start).getMaxWidth();
323 }
324
325 public int getMidPointAt(int i) {
326 return cm.getColumn(i + start).getWidth();
327 }
328
329 public void setSizeAt(int s, int i) {
330 cm.getColumn(i + start).setWidth(s);
331 }
332 };
333
334 int totalWidth = 0;
335 for (int i = from; i < to; i++) {
336 TableColumn aColumn = columnModel.getColumn(i);
337 int input = aColumn.getWidth();
338 totalWidth = totalWidth + input;
339 }
340
341 adjustSizes(totalWidth + delta, r, false);
342
343 return;
344 }
345
346 private void adjustSizes(long target, final Resizable3 r, boolean inverse) {
347 int N = r.getElementCount();
348 long totalPreferred = 0;
349 for (int i = 0; i < N; i++) {
350 totalPreferred += r.getMidPointAt(i);
351 }
352 Resizable2 s;
353 if ((target < totalPreferred) == !inverse) {
354 s = new Resizable2() {
355 public int getElementCount() {
356 return r.getElementCount();
357 }
358
359 public int getLowerBoundAt(int i) {
360 return r.getLowerBoundAt(i);
361 }
362
363 public int getUpperBoundAt(int i) {
364 return r.getMidPointAt(i);
365 }
366
367 public void setSizeAt(int newSize, int i) {
368 r.setSizeAt(newSize, i);
369 }
370
371 };
372 } else {
373 s = new Resizable2() {
374 public int getElementCount() {
375 return r.getElementCount();
376 }
377
378 public int getLowerBoundAt(int i) {
379 return r.getMidPointAt(i);
380 }
381
382 public int getUpperBoundAt(int i) {
383 return r.getUpperBoundAt(i);
384 }
385
386 public void setSizeAt(int newSize, int i) {
387 r.setSizeAt(newSize, i);
388 }
389
390 };
391 }
392 adjustSizes(target, s, !inverse);
393 }
394
395 private void adjustSizes(long target, Resizable2 r, boolean limitToRange) {
396 long totalLowerBound = 0;
397 long totalUpperBound = 0;
398 for (int i = 0; i < r.getElementCount(); i++) {
399 totalLowerBound += r.getLowerBoundAt(i);
400 totalUpperBound += r.getUpperBoundAt(i);
401 }
402
403 if (limitToRange) {
404 target = Math.min(Math.max(totalLowerBound, target),
405 totalUpperBound);
406 }
407
408 for (int i = 0; i < r.getElementCount(); i++) {
409 int lowerBound = r.getLowerBoundAt(i);
410 int upperBound = r.getUpperBoundAt(i);
411
412
413
414 int newSize;
415 if (totalLowerBound == totalUpperBound) {
416 newSize = lowerBound;
417 } else {
418 double f = (double) (target - totalLowerBound)
419 / (totalUpperBound - totalLowerBound);
420 newSize = (int) Math.round(lowerBound + f
421 * (upperBound - lowerBound));
422
423
424
425
426 }
427 r.setSizeAt(newSize, i);
428 target -= newSize;
429 totalLowerBound -= lowerBound;
430 totalUpperBound -= upperBound;
431 }
432 }
433
434 private interface Resizable2 {
435 public int getElementCount();
436
437 public int getLowerBoundAt(int i);
438
439 public int getUpperBoundAt(int i);
440
441 public void setSizeAt(int newSize, int i);
442 }
443
444 private interface Resizable3 extends Resizable2 {
445 public int getMidPointAt(int i);
446 }
447
448 }