| 1 17 package thinlet; 18 19 import java.awt.*; 20 import java.awt.datatransfer.*; 21 import java.awt.image.*; 22 import java.awt.event.*; 23 import java.lang.reflect.*; 24 import java.io.*; 25 import java.net.*; 26 import java.util.*; 27 28 31 public class Thinlet extends Container 32 implements Runnable , Serializable { 33 34 private transient Font font; 35 private transient Color c_bg; 36 private transient Color c_text; 37 private transient Color c_textbg; 38 private transient Color c_border; 39 private transient Color c_disable; 40 private transient Color c_hover; 41 private transient Color c_press; 42 private transient Color c_focus; 43 private transient Color c_select; 44 private transient Color c_ctrl = null; 45 private transient int block; 46 private transient Image hgradient, vgradient; 47 48 private transient Thread timer; 49 private transient long watchdelay; 50 private transient long watch; 51 private transient String clipboard; 52 private transient ResourceBundle resourcebundle; 54 private static ResourceBundle langResource = null; private static ResourceBundle langResourceDefault = null; private transient boolean allI18n = false; 58 private transient String findprefix = ""; 60 private transient long findtime; 61 62 private Object content = createImpl("desktop"); 63 private transient Object mouseinside; 64 private transient Object insidepart; 65 private transient Object mousepressed; 66 private transient Object pressedpart; 67 private transient int referencex, referencey; 68 private transient int mousex, mousey; 69 private transient Object focusowner; 70 private transient boolean focusinside; 71 private transient Object popupowner; 72 private transient Object tooltipowner; 73 75 private static final int DRAG_ENTERED = AWTEvent.RESERVED_ID_MAX + 1; 76 private static final int DRAG_EXITED = AWTEvent.RESERVED_ID_MAX + 2; 77 78 private static long WHEEL_MASK = 0; 79 private static int MOUSE_WHEEL = 0; 80 private static Method wheelrotation = null; 81 private static int evm = 0; 82 static { 83 try { 84 WHEEL_MASK = AWTEvent.class.getField("MOUSE_WHEEL_EVENT_MASK").getLong(null); 85 MOUSE_WHEEL = MouseEvent.class.getField("MOUSE_WHEEL").getInt(null); 86 } catch (Exception exc) { } 87 } 88 { 89 setFont(new Font("SansSerif", Font.PLAIN, 12)); 90 setColors(0xe6e6e6, 0x000000, 0xffffff, 92 0x909090, 0xb0b0b0, 0xededed, 0xb9b9b9, 0x89899a, 0xc5c5dd); 93 94 if (MOUSE_WHEEL != 0) { 96 try { 97 getClass().getMethod("setFocusTraversalKeysEnabled", new Class [] { Boolean.TYPE }). 98 invoke(this, new Object [] { Boolean.FALSE }); 99 } catch (Exception exc) { } 100 } 101 enableEvents(AWTEvent.COMPONENT_EVENT_MASK | 103 AWTEvent.FOCUS_EVENT_MASK | AWTEvent.KEY_EVENT_MASK | 104 AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK | WHEEL_MASK); 105 try { 108 if ((System.getProperty("java.vendor").indexOf("Insignia") != -1) && 109 System.getProperty("os.name").indexOf("Windows CE") == -1) { evm = -1; } 110 } catch (Exception exc) { } 111 } 112 113 136 public void setColors(int background, int text, int textbackground, 137 int border, int disable, int hover, int press, 138 int focus, int select) { 139 c_bg = new Color(background); c_text = new Color(text); 140 c_textbg = new Color(textbackground); c_border = new Color(border); 141 c_disable = new Color(disable); c_hover = new Color(hover); 142 c_press = new Color(press); c_focus = new Color(focus); 143 c_select = new Color(select); 144 hgradient = vgradient = null; 145 repaint(); 146 } 147 148 150 157 public void setFont(Font font) { 158 block = getFontMetrics(font).getHeight(); 159 super.setFont(font); 160 this.font = font; 161 hgradient = vgradient = null; 162 if (content != null) validate(content); 163 } 164 165 168 private void doLayout(Object component) { 169 String classname = getClass(component); 170 if ("combobox" == classname) { 171 if (getBoolean(component, "editable", true)) { 172 Image icon = getIcon(component, "icon", null); 173 layoutField(component, block, false, 174 (icon != null) ? icon.getWidth(this) : 0); 175 } else { 177 int selected = getInteger(component, "selected", -1); 178 if (selected != -1) { Object choice = getItem(component, selected); 180 set(component, "text", get(choice, "text")); 181 set(component, "icon", get(choice, "icon")); 182 } 183 } 184 } 185 else if (("textfield" == classname) || ("passwordfield" == classname)) { 186 layoutField(component, 0, ("passwordfield" == classname), 0); 187 } 188 else if ("textarea" == classname) { 189 String text = getString(component, "text", ""); 190 int start = getInteger(component, "start", 0); 191 if (start > text.length()) { setInteger(component, "start", start = text.length(), 0); } 192 int end = getInteger(component, "end", 0); 193 if (end > text.length()) { setInteger(component, "end", end = text.length(), 0); } 194 195 boolean wrap = getBoolean(component, "wrap", false); 196 char[] chars = null; 197 if (wrap) { 198 Rectangle bounds = getRectangle(component, "bounds"); 199 chars = getChars(component, text, true, bounds.width - 4, bounds.height); 200 if (chars == null) { chars = getChars(component, text, true, bounds.width - block - 4, 0); 202 } 203 } 204 else { 205 chars = getChars(component, text, false, 0, 0); 206 } 207 208 Font currentfont = (Font) get(component, "font"); 209 FontMetrics fm = getFontMetrics((currentfont != null) ? currentfont : font); 210 int width = 0, height = 0; 211 int caretx = 0; int carety = 0; 212 for (int i = 0, j = 0; j <= chars.length; j++) { 213 if ((j == chars.length) || (chars[j] == '\n')) { 214 width = Math.max(width, fm.charsWidth(chars, i, j - i)); 215 if ((end >= i) && (end <= j)) { 216 caretx = fm.charsWidth(chars, i, end - i); 217 carety = height; 218 } 219 height += fm.getHeight(); 220 i = j + 1; 221 } 222 } 223 layoutScroll(component, width + 2, height - fm.getLeading() + 2, 0, 0, 0, 0, 224 getBoolean(component, "border", true), 0); 225 scrollToVisible(component, caretx, carety, 2, fm.getAscent() + fm.getDescent() + 2); } 227 else if ("tabbedpane" == classname) { 228 Rectangle bounds = getRectangle(component, "bounds"); 230 String placement = getString(component, "placement", "top"); 231 boolean horizontal = ((placement == "top") || (placement == "bottom")); 232 boolean stacked = (placement == "stacked"); 233 234 int tabd = 0; Rectangle first = null; int tabsize = 0; for (Object tab = get(component, ":comp"); tab != null; tab = get(tab, ":next")) { 238 if ((tabd == 0) && ((first = getRectangle(tab, "bounds")) != null)) { 239 tabd = horizontal ? first.x : first.y; } 241 Dimension d = getSize(tab, stacked ? 8 : horizontal ? 12 : 9, 242 stacked ? 3 : horizontal ? 5 : 8); 243 setRectangle(tab, "bounds", horizontal ? tabd : 0, horizontal ? 0 : tabd, 244 stacked ? bounds.width : d.width, d.height); 245 if (stacked) { 246 tabd += d.height; 247 } else { 248 tabd += (horizontal ? d.width : d.height) - 3; 249 tabsize = Math.max(tabsize, horizontal ? d.height : d.width); 250 } 251 } 252 253 int cx = (placement == "left") ? (tabsize + 1) : 2; 255 int cy = (placement == "top") ? (tabsize + 1) : 2; 256 int cwidth = bounds.width - ((horizontal || stacked) ? 4 : (tabsize + 3)); 257 int cheight = bounds.height - (stacked ? (tabd + 3) : 258 (horizontal ? (tabsize + 3) : 4)); 259 for (Object tab = get(component, ":comp"); tab != null; tab = get(tab, ":next")) { 260 Rectangle r = getRectangle(tab, "bounds"); 261 if (!stacked) { 262 if (horizontal) { 263 if (placement == "bottom") { r.y = bounds.height - tabsize; } 264 r.height = tabsize; 265 } 266 else { 267 if (placement == "right") { r.x = bounds.width - tabsize; } 268 r.width = tabsize; 269 } 270 } 271 272 Object comp = get(tab, ":comp"); if ((comp != null) && getBoolean(comp, "visible", true)) { 274 setRectangle(comp, "bounds", 275 cx - r.x, stacked ? (r.height + 1) : (cy - r.y), cwidth, cheight); 276 doLayout(comp); 277 } 278 } 279 checkOffset(component); 280 } 281 else if (("panel" == classname) || (classname == "dialog")) { 282 int gap = getInteger(component, "gap", 0); 283 int[][] grid = getGrid(component); 284 int top = 0; int left = 0; 285 int contentwidth = 0; int contentheight = 0; 286 if (grid != null) { top = getInteger(component, "top", 0); 288 left = getInteger(component, "left", 0); 289 int bottom = getInteger(component, "bottom", 0); 290 int right = getInteger(component, "right", 0); 291 contentwidth = left + getSum(grid[0], 0, grid[0].length, gap, false) + right; 293 contentheight = top + getSum(grid[1], 0, grid[1].length, gap, false) + bottom; 294 } 295 296 int titleheight = getSize(component, 0, 0).height; setInteger(component, ":titleheight", titleheight, 0); 298 boolean scrollable = getBoolean(component, "scrollable", false); 299 boolean border = ("panel" == classname) && getBoolean(component, "border", false); 300 int iborder = (border ? 1 : 0); 301 if (scrollable) { if ("panel" == classname) { 303 int head = titleheight / 2; 304 int headgap = (titleheight > 0) ? (titleheight - head - iborder) : 0; 305 scrollable = layoutScroll(component, contentwidth, contentheight, 306 head, 0, 0, 0, border, headgap); 307 } 308 else { scrollable = layoutScroll(component, contentwidth, contentheight, 310 3 + titleheight, 3, 3, 3, true, 0); 311 } 312 } 313 if (!scrollable) { set(component, ":view", null); set(component, ":port", null); 315 } 316 317 if (grid != null) { 318 int areax = 0; int areay = 0; int areawidth = 0; int areaheight = 0; 319 if (scrollable) { 320 Rectangle view = getRectangle(component, ":view"); 322 areawidth = view.width; areaheight = view.height; 323 } 324 else { Rectangle bounds = getRectangle(component, "bounds"); 327 areawidth = bounds.width; areaheight = bounds.height; 328 if ("panel" == classname) { 329 areax = iborder; areay = Math.max(iborder, titleheight); 330 areawidth -= 2 * iborder; areaheight -= areay + iborder; 331 } 332 else { areax = 4; areay = 4 + titleheight; 334 areawidth -= 8; areaheight -= areay + 4; 335 } 336 } 337 338 for (int i = 0; i < 2; i++) { int d = ((i == 0) ? (areawidth - contentwidth) : (areaheight - contentheight)); 341 if (d != 0) { int w = getSum(grid[2 + i], 0, grid[2 + i].length, 0, false); 343 if (w > 0) { 344 for (int j = 0; j < grid[i].length; j++) { 345 if (grid[2 + i][j] != 0) { 346 grid[i][j] += d * grid[2 + i][j] / w; 347 } 348 } 349 } 350 } 351 } 352 353 Object comp = get(component, ":comp"); 354 for (int i = 0; comp != null; comp = get(comp, ":next")) { 355 if (!getBoolean(comp, "visible", true)) { continue; } 356 int ix = areax + left + getSum(grid[0], 0, grid[4][i], gap, true); 357 int iy = areay + top + getSum(grid[1], 0, grid[5][i], gap, true); 358 int iwidth = getSum(grid[0], grid[4][i], grid[6][i], gap, false); 359 int iheight = getSum(grid[1], grid[5][i], grid[7][i], gap, false); 360 String halign = getString(comp, "halign", "fill"); 361 String valign = getString(comp, "valign", "fill"); 362 if ((halign != "fill") || (valign != "fill")) { 363 Dimension d = getPreferredSize(comp); 364 if (halign != "fill") { 365 int dw = Math.max(0, iwidth - d.width); 366 if (halign == "center") { ix += dw / 2; } 367 else if (halign == "right") { ix += dw; } 368 iwidth -= dw; 369 } 370 if (valign != "fill") { 371 int dh = Math.max(0, iheight - d.height); 372 if (valign == "center") { iy += dh / 2; } 373 else if (valign == "bottom") { iy += dh; } 374 iheight -= dh; 375 } 376 } 377 setRectangle(comp, "bounds", ix, iy, iwidth, iheight); 378 doLayout(comp); 379 i++; 380 } 381 } 382 } 383 else if ("desktop" == classname) { 384 Rectangle bounds = getRectangle(component, "bounds"); 385 for (Object comp = get(component, ":comp"); 386 comp != null; comp = get(comp, ":next")) { 387 String iclass = getClass(comp); 388 if (iclass == "dialog") { 389 Dimension d = getPreferredSize(comp); 390 if (get(comp, "bounds") == null) 391 setRectangle(comp, "bounds", 392 Math.max(0, (bounds.width - d.width) / 2), 393 Math.max(0, (bounds.height - d.height) / 2), 394 Math.min(d.width, bounds.width), Math.min(d.height, bounds.height)); 395 } else if ((iclass != ":combolist") && (iclass != ":popup")) { 396 setRectangle(comp, "bounds", 0, 0, bounds.width, bounds.height); 397 } 398 doLayout(comp); 399 } 400 } 401 else if ("spinbox" == classname) { 402 layoutField(component, block, false, 0); 403 } 404 else if ("splitpane" == classname) { 405 Rectangle bounds = getRectangle(component, "bounds"); 406 boolean horizontal = ("vertical" != get(component, "orientation")); 407 int divider = getInteger(component, "divider", -1); 408 int maxdiv = Math.max(0, (horizontal ? bounds.width : bounds.height) - 5); 409 410 Object comp1 = get(component, ":comp"); 411 boolean visible1 = (comp1 != null) && getBoolean(comp1, "visible", true); 412 if (divider == -1) { 413 int d1 = 0; 414 if (visible1) { 415 Dimension d = getPreferredSize(comp1); 416 d1 = horizontal ? d.width : d.height; 417 } 418 divider = Math.min(d1, maxdiv); 419 setInteger(component, "divider", divider, -1); 420 } 421 else if (divider > maxdiv) { 422 setInteger(component, "divider", divider = maxdiv, -1); 423 } 424 425 if (visible1) { 426 setRectangle(comp1, "bounds", 0, 0, horizontal ? divider : bounds.width, 427 horizontal ? bounds.height : divider); 428 doLayout(comp1); 429 } 430 Object comp2 = (comp1 != null) ? get(comp1, ":next") : null; 431 if ((comp2 != null) && getBoolean(comp2, "visible", true)) { 432 setRectangle(comp2, "bounds", horizontal ? (divider + 5) : 0, 433 horizontal ? 0 : (divider + 5), 434 horizontal ? (bounds.width - 5 - divider) : bounds.width, 435 horizontal ? bounds.height : (bounds.height - 5 - divider)); 436 doLayout(comp2); 437 } 438 } 439 else if (("list" == classname) || 440 ("table" == classname) || ("tree" == classname)) { 441 int line = getBoolean(component, "line", true) ? 1 : 0; 442 int width = 0; 443 int columnheight = 0; 444 if ("table" == classname) { 445 Object header = get(component, "header"); 446 int[] columnwidths = null; 447 if (header != null) { 448 columnwidths = new int[getCount(header)]; 449 Object column = get(header, ":comp"); 450 for (int i = 0; i < columnwidths.length; i++) { 451 if (i != 0) { column = get(column, ":next"); } 452 columnwidths[i] = getInteger(column, "width", 80); 453 width += columnwidths[i]; 454 Dimension d = getSize(column, 2, 2); 455 columnheight = Math.max(columnheight, d.height); 456 } 457 } 458 set(component, ":widths", columnwidths); 459 } 460 int y = 0; 461 int level = 0; 462 for (Object item = get(component, ":comp"); item != null;) { 463 int x = 0; 464 int iwidth = 0; int iheight = 0; 465 if ("table" == classname) { 466 iwidth = width; 467 for (Object cell = get(item, ":comp"); cell != null; cell = get(cell, ":next")) { 468 Dimension d = getSize(cell, 2, 2); 469 iheight = Math.max(iheight, d.height); 470 } 471 } 472 else { 473 if ("tree" == classname) { 474 x = (level + 1) * block; 475 } 476 Dimension d = getSize(item, 6, 2); 477 iwidth = d.width; iheight = d.height; 478 width = Math.max(width, x + d.width); 479 } 480 setRectangle(item, "bounds", x, y, iwidth, iheight); 481 y += iheight + line; 482 if ("tree" == classname) { 483 Object next = get(item, ":comp"); 484 if ((next != null) && getBoolean(item, "expanded", true)) { 485 level++; 486 } else { 487 while (((next = get(item, ":next")) == null) && (level > 0)) { 488 item = getParent(item); 489 level--; 490 } 491 } 492 item = next; 493 } else { 494 item = get(item, ":next"); 495 } 496 } 497 layoutScroll(component, width, y - line, columnheight, 0, 0, 0, true, 0); 498 } 499 else if ("menubar" == classname) { 500 Rectangle bounds = getRectangle(component, "bounds"); 501 int x = 0; 502 for (Object menu = get(component, ":comp"); 503 menu != null; menu = get(menu, ":next")) { 504 Dimension d = getSize(menu, 8, 4); 505 setRectangle(menu, "bounds", x, 0, d.width, bounds.height); 506 x += d.width; 507 } 508 } 509 else if ("bean" == classname) { 510 Rectangle r = getRectangle(component, "bounds"); 511 ((Component) get(component, "bean")).setBounds(r); 512 } 513 } 514 515 519 private void checkOffset(Object component) { 520 String placement = getString(component, "placement", "top"); 521 int selected = getInteger(component, "selected", 0); int i = 0; 522 if (placement == "stacked") { 523 int dy = 0; 524 for (Object tab = get(component, ":comp"); tab != null; tab = get(tab, ":next")) { 525 Rectangle r = getRectangle(tab, "bounds"); 526 r.y = dy; 527 dy += r.height; 528 if (i == selected) { dy += getRectangle(get(tab, ":comp"), "bounds").height + 2; } 529 i++; 530 } 531 if (mouseinside == component) { checkLocation(); 533 } 534 return; 535 } 536 boolean horizontal = ((placement == "top") || (placement == "bottom")); 537 Rectangle bounds = getRectangle(component, "bounds"); 538 int panesize = horizontal ? bounds.width : bounds.height; 539 int first = 0; int last = 0; int d = 0; 540 for (Object tab = get(component, ":comp"); tab != null; tab = get(tab, ":next")) { 541 Rectangle r = getRectangle(tab, "bounds"); 542 if (i == 0) { first = (horizontal ? r.x : r.y); } 543 last = (horizontal ? (r.x + r.width) : (r.y + r.height)); 544 if (i == selected) { 545 int ifrom = (horizontal ? r.x : r.y) - 6; 546 int ito = (horizontal ? (r.x + r.width) : (r.y + r.height)) + 6; 547 if (ifrom < 0) { d = -ifrom; } 548 else if (ito > panesize) { d = panesize - ito; } 549 } 550 i++; 551 } 552 d = Math.min(-first, Math.max(d, panesize - last)); 553 if (d != 0) { 554 for (Object tab = get(component, ":comp"); tab != null; tab = get(tab, ":next")) { 555 Rectangle r = getRectangle(tab, "bounds"); 556 if (horizontal) { r.x += d; } else { r.y += d; } 557 Object comp = get(tab, ":comp"); if ( (comp != null) && getBoolean(comp, "visible", true)) { 559 Rectangle rc = getRectangle(comp, "bounds"); 560 if (horizontal) { rc.x -= d; } else { rc.y -= d; } 561 } 562 } 563 if (mouseinside == component) { checkLocation(); 565 } 566 } 567 } 568 569 572 private char[] getChars(Object component, 573 String text, boolean wrap, int width, int height) { 574 char[] chars = (char[]) get(component, ":text"); 575 if ((chars == null) || (chars.length != text.length())) { 576 chars = text.toCharArray(); 577 set(component, ":text", chars); 578 } 579 else text.getChars(0, chars.length, chars, 0); 580 581 if (wrap) { 582 Font currentfont = (Font) get(component, "font"); 583 FontMetrics fm = getFontMetrics((currentfont != null) ? currentfont : font); 584 int lines = (height - 4 + fm.getLeading()) / fm.getHeight(); 585 boolean prevletter = false; int n = chars.length; int linecount = 0; 586 for (int i = 0, j = -1, k = 0; k <= n; k++) { if (((k == n) || (chars[k] == '\n') || (chars[k] == ' ')) && 588 (j > i) && (fm.charsWidth(chars, i, k - i) > width)) { 589 chars[j] = '\n'; 590 k--; } 592 else if ((k == n) || (chars[k] == '\n')) { j = k; prevletter = false; 594 } 595 else { 596 if ((chars[k] == ' ') && (prevletter || (j > i))) { j = k; } prevletter = (chars[k] != ' '); 598 continue; 599 } 600 linecount++; 601 if ((lines != 0) && (linecount == lines)) { return null; } 602 i = j + 1; 603 } 604 } 605 return chars; 606 } 607 608 611 635 636 |