1 /* Copyrights and Licenses
2 *
3 * This product includes Hypersonic SQL.
4 * Originally developed by Thomas Mueller and the Hypersonic SQL Group.
5 *
6 * Copyright (c) 1995-2000 by the Hypersonic SQL Group. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without modification, are permitted
8 * provided that the following conditions are met:
9 * - Redistributions of source code must retain the above copyright notice, this list of conditions
10 * and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright notice, this list of
12 * conditions and the following disclaimer in the documentation and/or other materials
13 * provided with the distribution.
14 * - All advertising materials mentioning features or use of this software must display the
15 * following acknowledgment: "This product includes Hypersonic SQL."
16 * - Products derived from this software may not be called "Hypersonic SQL" nor may
17 * "Hypersonic SQL" appear in their names without prior written permission of the
18 * Hypersonic SQL Group.
19 * - Redistributions of any form whatsoever must retain the following acknowledgment: "This
20 * product includes Hypersonic SQL."
21 * This software is provided "as is" and any expressed or implied warranties, including, but
22 * not limited to, the implied warranties of merchantability and fitness for a particular purpose are
23 * disclaimed. In no event shall the Hypersonic SQL Group or its contributors be liable for any
24 * direct, indirect, incidental, special, exemplary, or consequential damages (including, but
25 * not limited to, procurement of substitute goods or services; loss of use, data, or profits;
26 * or business interruption). However caused any on any theory of liability, whether in contract,
27 * strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this
28 * software, even if advised of the possibility of such damage.
29 * This software consists of voluntary contributions made by many individuals on behalf of the
30 * Hypersonic SQL Group.
31 *
32 *
33 * For work added by the HSQL Development Group:
34 *
35 * Copyright (c) 2001-2002, The HSQL Development Group
36 * All rights reserved.
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions are met:
40 *
41 * Redistributions of source code must retain the above copyright notice, this
42 * list of conditions and the following disclaimer, including earlier
43 * license statements (above) and comply with all above license conditions.
44 *
45 * Redistributions in binary form must reproduce the above copyright notice,
46 * this list of conditions and the following disclaimer in the documentation
47 * and/or other materials provided with the distribution, including earlier
48 * license statements (above) and comply with all above license conditions.
49 *
50 * Neither the name of the HSQL Development Group nor the names of its
51 * contributors may be used to endorse or promote products derived from this
52 * software without specific prior written permission.
53 *
54 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
55 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57 * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
58 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
59 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
60 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
61 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
62 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
63 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
64 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
65 */
66
67
68 package org.hsqldb.util;
69
70 import java.awt;
71 import java.util.Vector;
72
73 /**
74 *
75 * @version 1.7.0
76 */
77 class Tree extends Panel {
78
79 // static
80 private static Font fFont;
81 private static FontMetrics fMetrics;
82 private static int iRowHeight;
83 private static int iIndentWidth;
84 private int iMaxTextLength;
85
86 // drawing
87 private Dimension dMinimum;
88 private Graphics gImage;
89 private Image iImage;
90
91 // height / width
92 private int iWidth, iHeight;
93 private int iFirstRow;
94 private int iTreeWidth, iTreeHeight;
95 private int iX, iY;
96
97 // data
98 private Vector vData;
99 private int iRowCount;
100
101 // scrolling
102 private Scrollbar sbHoriz, sbVert;
103 private int iSbWidth, iSbHeight;
104
105 static {
106 fFont = new Font("Dialog", Font.PLAIN, 12);
107 fMetrics = Toolkit.getDefaultToolkit().getFontMetrics(fFont);
108 iRowHeight = getMaxHeight(fMetrics);
109 iIndentWidth = 12;
110 }
111
112 /**
113 * Constructor declaration
114 *
115 */
116 Tree() {
117
118 super();
119
120 vData = new Vector();
121
122 setLayout(null);
123
124 sbHoriz = new Scrollbar(Scrollbar.HORIZONTAL);
125
126 add(sbHoriz);
127
128 sbVert = new Scrollbar(Scrollbar.VERTICAL);
129
130 add(sbVert);
131 }
132
133 /**
134 * Method declaration
135 *
136 *
137 * @param d
138 */
139 public void setMinimumSize(Dimension d) {
140 dMinimum = d;
141 }
142
143 /**
144 * Method declaration
145 *
146 *
147 * @param x
148 * @param y
149 * @param w
150 * @param h
151 */
152
153 // fredt@users 20011210 - patch 450412 by elise@users
154 // with additional replacement of deprecated methods
155 public void setBounds(int x, int y, int w, int h) {
156
157 super.setBounds(x, y, w, h);
158
159 iSbHeight = sbHoriz.getPreferredSize().height;
160 iSbWidth = sbVert.getPreferredSize().width;
161 iHeight = h - iSbHeight;
162 iWidth = w - iSbWidth;
163
164 sbHoriz.setBounds(0, iHeight, iWidth, iSbHeight);
165 sbVert.setBounds(iWidth, 0, iSbWidth, iHeight);
166 adjustScroll();
167
168 iImage = null;
169
170 repaint();
171 }
172
173 /**
174 * Method declaration
175 *
176 */
177 public void removeAll() {
178
179 vData = new Vector();
180 iRowCount = 0;
181
182 adjustScroll();
183
184 iMaxTextLength = 10;
185
186 repaint();
187 }
188
189 /**
190 * Method declaration
191 *
192 *
193 * @param key
194 * @param value
195 * @param state
196 * @param color
197 */
198 public void addRow(String key, String value, String state, int color) {
199
200 String row[] = new String[4];
201
202 if (value == null) {
203 value = "";
204 }
205
206 row[0] = key;
207 row[1] = value;
208 row[2] = state; // null / "-" / "+"
209 row[3] = String.valueOf(color);
210
211 vData.addElement(row);
212
213 int len = fMetrics.stringWidth(value);
214
215 if (len > iMaxTextLength) {
216 iMaxTextLength = len;
217 }
218
219 iRowCount++;
220 }
221
222 /**
223 * Method declaration
224 *
225 *
226 * @param key
227 * @param value
228 */
229 public void addRow(String key, String value) {
230 addRow(key, value, null, 0);
231 }
232
233 /**
234 * Method declaration
235 *
236 */
237 public void update() {
238 adjustScroll();
239 repaint();
240 }
241
242 /**
243 * Method declaration
244 *
245 */
246 void adjustScroll() {
247
248 iTreeHeight = iRowHeight * (iRowCount + 1);
249
250 // correct would be iMaxTextLength + iMaxIndent*iIndentWidth
251 iTreeWidth = iMaxTextLength * 2;
252
253 sbHoriz.setValues(iX, iWidth, 0, iTreeWidth);
254
255 int v = iY / iRowHeight,
256 h = iHeight / iRowHeight;
257
258 sbVert.setValues(v, h, 0, iRowCount + 1);
259
260 iX = sbHoriz.getValue();
261 iY = iRowHeight * sbVert.getValue();
262 }
263
264 /**
265 * Method declaration
266 *
267 *
268 * @param e
269 *
270 * @return
271 */
272
273 // fredt@users 20020130 - comment by fredt
274 // to remove this deprecated method we need to rewrite the Tree class as a
275 // ScrollPane component
276 public boolean handleEvent(Event e) {
277
278 switch (e.id) {
279
280 case Event.SCROLL_LINE_UP :
281 case Event.SCROLL_LINE_DOWN :
282 case Event.SCROLL_PAGE_UP :
283 case Event.SCROLL_PAGE_DOWN :
284 case Event.SCROLL_ABSOLUTE :
285 iX = sbHoriz.getValue();
286 iY = iRowHeight * sbVert.getValue();
287
288 repaint();
289
290 return true;
291 }
292
293 return super.handleEvent(e);
294 }
295
296 /**
297 * Method declaration
298 *
299 *
300 * @param g
301 */
302 public void paint(Graphics g) {
303
304 if (g == null || iWidth <= 0 || iHeight <= 0) {
305 return;
306 }
307
308 g.setColor(SystemColor.control);
309 g.fillRect(iWidth, iHeight, iSbWidth, iSbHeight);
310
311 if (iImage == null) {
312 iImage = createImage(iWidth, iHeight);
313 gImage = iImage.getGraphics();
314
315 gImage.setFont(fFont);
316 }
317
318 gImage.setColor(Color.white);
319 gImage.fillRect(0, 0, iWidth, iHeight);
320
321 int lasty[] = new int[100];
322 String root[] = new String[100];
323
324 root[0] = "";
325
326 int currentindent = 0;
327 int y = iRowHeight;
328
329 y -= iY;
330
331 boolean closed = false;
332
333 for (int i = 0; i < iRowCount; i++) {
334 String s[] = (String[]) vData.elementAt(i);
335 String key = s[0];
336 String data = s[1];
337 String folder = s[2];
338 int ci = currentindent;
339
340 for (; ci > 0; ci--) {
341 if (key.startsWith(root[ci])) {
342 break;
343 }
344 }
345
346 if (root[ci].length() < key.length()) {
347 ci++;
348 }
349
350 if (closed && ci > currentindent) {
351 continue;
352 }
353
354 closed = folder != null && folder.equals("+");
355 root[ci] = key;
356
357 int x = iIndentWidth * ci - iX;
358
359 gImage.setColor(Color.lightGray);
360 gImage.drawLine(x, y, x + iIndentWidth, y);
361 gImage.drawLine(x, y, x, lasty[ci]);
362
363 lasty[ci + 1] = y;
364
365 int py = y + iRowHeight / 3;
366 int px = x + iIndentWidth * 2;
367
368 if (folder != null) {
369 lasty[ci + 1] += 4;
370
371 int rgb = Integer.parseInt(s[3]);
372
373 gImage.setColor(rgb == 0 ? Color.white
374 : new Color(rgb));
375 gImage.fillRect(x + iIndentWidth - 3, y - 3, 7, 7);
376 gImage.setColor(Color.black);
377 gImage.drawRect(x + iIndentWidth - 4, y - 4, 8, 8);
378 gImage.drawLine(x + iIndentWidth - 2, y,
379 x + iIndentWidth + 2, y);
380
381 if (folder.equals("+")) {
382 gImage.drawLine(x + iIndentWidth, y - 2,
383 x + iIndentWidth, y + 2);
384 }
385 } else {
386 px -= iIndentWidth;
387 }
388
389 gImage.setColor(Color.black);
390 gImage.drawString(data, px, py);
391
392 currentindent = ci;
393 y += iRowHeight;
394 }
395
396 g.drawImage(iImage, 0, 0, this);
397 }
398
399 /**
400 * Method declaration
401 *
402 *
403 * @param g
404 */
405 public void update(Graphics g) {
406 paint(g);
407 }
408
409 /**
410 * Method declaration
411 *
412 *
413 * @return
414 */
415 public Dimension preferredSize() {
416 return dMinimum;
417 }
418
419 /**
420 * Method declaration
421 *
422 *
423 * @return
424 */
425 public Dimension getPreferredSize() {
426 return dMinimum;
427 }
428
429 /**
430 * Method declaration
431 *
432 *
433 * @return
434 */
435 public Dimension getMinimumSize() {
436 return dMinimum;
437 }
438
439 /**
440 * Method declaration
441 *
442 *
443 * @return
444 */
445 public Dimension minimumSize() {
446 return dMinimum;
447 }
448
449 /**
450 * Method declaration
451 *
452 *
453 * @param e
454 * @param x
455 * @param y
456 *
457 * @return
458 */
459 public boolean mouseDown(Event e, int x, int y) {
460
461 if (iRowHeight == 0 || x > iWidth || y > iHeight) {
462 return true;
463 }
464
465 y += iRowHeight / 2;
466
467 String root[] = new String[100];
468
469 root[0] = "";
470
471 int currentindent = 0;
472 int cy = iRowHeight;
473 boolean closed = false;
474 int i = 0;
475
476 y += iY;
477
478 for (; i < iRowCount; i++) {
479 String s[] = (String[]) vData.elementAt(i);
480 String key = s[0];
481 String folder = s[2];
482 int ci = currentindent;
483
484 for (; ci > 0; ci--) {
485 if (key.startsWith(root[ci])) {
486 break;
487 }
488 }
489
490 if (root[ci].length() < key.length()) {
491 ci++;
492 }
493
494 if (closed && ci > currentindent) {
495 continue;
496 }
497
498 if (cy <= y && cy + iRowHeight > y) {
499 break;
500 }
501
502 root[ci] = key;
503 closed = folder != null && folder.equals("+");
504 currentindent = ci;
505 cy += iRowHeight;
506 }
507
508 if (i >= 0 && i < iRowCount) {
509 String s[] = (String[]) vData.elementAt(i);
510 String folder = s[2];
511
512 if (folder != null && folder.equals("+")) {
513 folder = "-";
514 } else if (folder != null && folder.equals("-")) {
515 folder = "+";
516 }
517
518 s[2] = folder;
519
520 vData.setElementAt(s, i);
521 repaint();
522 }
523
524 return true;
525 }
526
527 /**
528 * Method declaration
529 *
530 *
531 * @param f
532 *
533 * @return
534 */
535 private static int getMaxHeight(FontMetrics f) {
536 return f.getHeight() + 2;
537 }
538 }