1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * ident "%Z%%M% %I% %E% SMI" 24 * 25 * Copyright (c) 2001 by Sun Microsystems, Inc. 26 * All rights reserved. 27 */ 28 29 /* 30 * Copyright (C) 1996 Active Software, Inc. 31 * All rights reserved. 32 * 33 * @(#) Util.java 1.43 - last change made 07/16/97 34 */ 35 36 package sunsoft.jws.visual.rt.base; 37 38 import java.awt.*; 39 import java.util.*; 40 import java.io.*; 41 42 import java.awt.image.RGBImageFilter; 43 import java.awt.image.FilteredImageSource; 44 import java.net.URL; 45 import java.net.MalformedURLException; 46 import java.applet.Applet; 47 48 /** 49 * Utilities needed by run-time. 50 * 51 * @version 1.32, 03/09/97 52 */ 53 public class Util { 54 // Relief constants 55 public static final int RELIEF_FLAT = 0; 56 public static final int RELIEF_RAISED = 1; 57 public static final int RELIEF_SUNKEN = 2; 58 public static final int RELIEF_RIDGE = 3; 59 public static final int RELIEF_GROOVE = 4; 60 public static final int WIN95_RAISED = 6; 61 public static final int WIN95_SUNKEN = 7; 62 public static final int WIN95_FIELD_BORDER = 8; 63 public static final int WIN95_WINDOW_BORDER = 9; 64 public static final int BLACK_BORDER = 10; 65 66 // Character constants 67 public static final char BACKSLASH = /* NOI18N */ '\\'; 68 public static final char COLON = /* NOI18N */ ':'; 69 public static final char NEWLINE = /* NOI18N */ '\n'; 70 public static final char RETURN = /* NOI18N */ '\r'; 71 public static final char SLASH = /* NOI18N */ '/'; 72 public static final char SPACE = /* NOI18N */ ' '; 73 74 75 // codebase the user specified in the project - used at design time 76 private String codebaseStr = null; 77 78 // default class loader 79 private CustomClassLoader classLoader; 80 81 // Darkness constants 82 private static final double BFACTOR = 0.82; 83 private static final double DFACTOR = 0.7; 84 85 // Buffer size for reading files 86 private static final int BUFSIZE = 2048; 87 Util()88 public Util() { 89 classLoader = new VBClassLoader(); 90 } 91 92 /** 93 * Returns a brighter version of this color. 94 * 95 * This version is adjusted to compensate for border cases: 96 * If the base is white, the brighter color sometimes gets lost 97 * against the background, so the border of the panel (or whatever) 98 * is not seen. (Sun Bug # 4035733) 99 * The solution is to check if the "brighter" color 100 * is too bright, and if 101 * so, set it to a light grey. 102 * 103 */ 104 brighter(Color c)105 public Color brighter(Color c) { 106 int r = c.getRed(); 107 int g = c.getGreen(); 108 int b = c.getBlue(); 109 110 r = Math.min((int)(r * (1/BFACTOR)), 255); 111 g = Math.min((int)(g * (1/BFACTOR)), 255); 112 b = Math.min((int)(b * (1/BFACTOR)), 255); 113 114 if (r > 250 && g > 250 && b > 250) { 115 // note: we use the JDK darker, which simply makes 116 // the color darker, 117 // rather than this.darker, which will turn 118 // values of 255 into 119 // 128. 120 return new Color(225, 225, 225); 121 } 122 /* JSTYLED */ 123 return new Color(r, g, b); 124 } 125 126 /** 127 * Returns a darker version of this color. 128 */ darker(Color c)129 public Color darker(Color c) { 130 int r = c.getRed(); 131 int g = c.getGreen(); 132 int b = c.getBlue(); 133 134 if (r == 255) 135 r = 128; 136 else 137 r = Math.max((int)(r * DFACTOR), 0); 138 139 if (g == 255) 140 g = 128; 141 else 142 g = Math.max((int)(g * DFACTOR), 0); 143 144 if (b == 255) 145 b = 128; 146 else 147 b = Math.max((int)(b * DFACTOR), 0); 148 149 return new Color(r, g, b); 150 } 151 152 /** 153 * Draw a 3D rectable with the given relief and border width. 154 */ draw3DRect(Graphics g, int x, int y, int w, int h, int relief, int bd)155 public void draw3DRect(Graphics g, int x, int y, int w, int h, 156 int relief, int bd) { 157 int bd2 = (bd+1)/2; 158 for (int i = 0; i < bd; i++) 159 draw3DRect(g, x+i, y+i, w-2*i, h-2*i, relief, 160 (i < bd2)); 161 } 162 163 /** 164 * Draw a 3D rectable with the given relief and outer boolean. 165 */ draw3DRect(Graphics g, int x, int y, int w, int h, int relief, boolean isOuter)166 private void draw3DRect(Graphics g, int x, int y, int w, int h, 167 int relief, boolean isOuter) { 168 Color color = g.getColor(); 169 170 g.setColor(getEdgeColor(color, relief, true, isOuter)); 171 g.drawLine(x, y, x+w, y); 172 g.drawLine(x, y, x, y+h); 173 174 g.setColor(getEdgeColor(color, relief, false, isOuter)); 175 g.drawLine(x, y+h, x+w, y+h); 176 g.drawLine(x+w, y, x+w, y+h); 177 178 g.setColor(color); 179 } 180 181 182 /** 183 * Returns an adjusted color for the given 184 * edge and the given relief. 185 */ getEdgeColor(Color base, int relief, boolean isTopEdge, boolean isOuter)186 private Color getEdgeColor(Color base, int relief, 187 boolean isTopEdge, boolean isOuter) { 188 189 Color color = null; 190 191 switch (relief) { 192 case RELIEF_RAISED: 193 if (isTopEdge) 194 color = brighter(base); 195 else 196 color = darker(base); 197 break; 198 199 case RELIEF_SUNKEN: 200 if (isTopEdge) 201 color = darker(base); 202 else 203 color = brighter(base); 204 break; 205 206 case RELIEF_RIDGE: 207 if (isTopEdge) { 208 if (isOuter) 209 color = brighter(base); 210 else 211 color = darker(base); 212 } else { 213 if (isOuter) 214 color = darker(base); 215 else 216 color = brighter(base); 217 } 218 break; 219 220 case RELIEF_GROOVE: 221 if (isTopEdge) { 222 if (isOuter) 223 color = darker(base); 224 else 225 color = brighter(base); 226 } else { 227 if (isOuter) 228 color = brighter(base); 229 else 230 color = darker(base); 231 } 232 break; 233 234 case WIN95_RAISED: 235 if (isTopEdge) { 236 if (isOuter) 237 color = Color.white; 238 else 239 color = brighter(base); 240 } else { 241 if (isOuter) 242 color = Color.black; 243 else 244 color = darker(base); 245 } 246 break; 247 248 case WIN95_SUNKEN: 249 if (isTopEdge) { 250 if (isOuter) 251 color = Color.black; 252 else 253 color = darker(base); 254 } else { 255 if (isOuter) 256 color = Color.white; 257 else 258 color = brighter(base); 259 260 } 261 break; 262 263 case WIN95_FIELD_BORDER: 264 if (isTopEdge) { 265 if (isOuter) 266 color = darker(base); 267 else 268 color = Color.black; 269 } else { 270 if (isOuter) 271 color = Color.white; 272 else 273 color = brighter(base); 274 // was: base; // brighter(base); 275 } 276 break; 277 278 case WIN95_WINDOW_BORDER: 279 if (isTopEdge) { 280 if (isOuter) 281 color = brighter(base); 282 else 283 color = Color.white; 284 } else { 285 if (isOuter) 286 color = Color.black; 287 else 288 color = darker(base); 289 } 290 break; 291 292 case BLACK_BORDER: 293 color = Color.black; 294 break; 295 296 case RELIEF_FLAT: 297 default: 298 color = base; 299 break; 300 } 301 302 return color; 303 } 304 305 /** 306 * Get an image given a url. If we are on Windows 95, then we 307 * need to use a filter to get around the transparency bugs. 308 */ getWorkaroundImage(URL url, Component comp)309 public Image getWorkaroundImage(URL url, Component comp) { 310 Image image = comp.getToolkit().getImage(url); 311 return getWorkaroundImage(image, comp); 312 } 313 314 /** 315 * Get an image given another. If we are on Windows 95, then we 316 * need to use a filter to get around the transparency bugs. 317 * Otherwise, just return the image directly. 318 */ getWorkaroundImage(Image image, Component comp)319 public Image getWorkaroundImage(Image image, Component comp) { 320 if (image == null) 321 return null; 322 323 if (Global.isWindows95() && Global.javaVersion() == 1.0) { 324 RGBImageFilter filter = new TransFilter(comp); 325 image = comp.createImage( 326 new FilteredImageSource(image.getSource(), 327 filter)); 328 } 329 330 return image; 331 } 332 333 /** 334 * When the user specifies/changes the codebase attribute 335 * in the project, 336 * this method is called to update the value of "codebase" here. 337 * When we calculate an URL relative to codebase(such as the 338 * ImageLabel "image" attribute at design time, we use this 339 * codebase value. 340 */ setUserCodebase(String newCodebase)341 public boolean setUserCodebase(String newCodebase) { 342 codebaseStr = newCodebase; 343 return true; 344 } 345 getClassLoader()346 public CustomClassLoader getClassLoader() { 347 return (classLoader); 348 } 349 setClassLoader(CustomClassLoader newLoader)350 public void setClassLoader(CustomClassLoader newLoader) { 351 classLoader = newLoader; 352 } 353 354 /** 355 * Returns a URL based on a relative path to a file or directory. 356 * If we are running under a browser, then a URL is created based 357 * off of the code base. Otherwise, a file URL will be created 358 * by searching the CLASSPATH for the file. 359 */ pathToURL(String path, Applet applet)360 public URL pathToURL(String path, Applet applet) { 361 // general info: determine delimiter and urlPrefix 362 String delimiter, urlPrefix; 363 if (Global.isWindows()) { 364 delimiter = /* NOI18N */";"; 365 urlPrefix = /* NOI18N */"file:/"; 366 } else { 367 delimiter = /* NOI18N */":"; 368 urlPrefix = /* NOI18N */"file:"; 369 } 370 371 // First see if the path is a full URL path 372 // Note that the user must specify "file:" for files 373 try { 374 URL url = new URL(path); 375 // System.out.println( 376 // " detected full URL - URL=" + url); 377 return url; 378 } 379 catch (MalformedURLException ex) { 380 } 381 382 // Are we running as an applet? If running as the Visual Java 383 // applet in JWS can't use applet.getCodeBase because it is the 384 // codebase of Visual Java, not the users applet, so fall 385 // through 386 // and use the CLASSPATH 387 // Note: There's probably a better way to check if we're the 388 // Visual Java applet than checking for classname starting 389 // with "sun.jws" 390 if ((applet != null) && 391 !(applet.getClass().getName().startsWith(/* NOI18N */ 392 "sun.jws"))) { 393 String s = applet.getCodeBase().toExternalForm(); 394 if (s.charAt(s.length()-1) != SLASH) 395 path = /* NOI18N */"/" + path; 396 397 URL url; 398 try { 399 url = new URL(applet.getCodeBase(), path); 400 } 401 catch (MalformedURLException ex) { 402 url = null; 403 } 404 // System.out.println(" based on codebase=" 405 // + s + " URL=" + url); 406 return url; 407 } 408 409 // Search the CLASSPATH for the file 410 String classpath; 411 try { 412 classpath = System.getProperty( 413 /* NOI18N */"java.class.path"); 414 } 415 catch (SecurityException ex) { 416 throw new Error(Global.fmtMsg( 417 "sunsoft.jws.visual.rt.base.Util.NeedAppletparam", 418 Global.newline())); 419 } 420 421 classpath = DesignerAccess.getCWD() + delimiter + classpath; 422 423 StringTokenizer st = new StringTokenizer(classpath, delimiter); 424 boolean keepGoing = true; 425 while (st.hasMoreTokens() && keepGoing) { 426 String p = st.nextToken(); 427 428 if (p == /* NOI18N */"") 429 p = /* NOI18N */"."; 430 431 p = makeAbsolute(p); 432 433 char c = p.charAt(p.length()-1); 434 if (c != SLASH && c != BACKSLASH) 435 p = p + separator; 436 437 p = p + path; 438 439 if (Global.isWindows()) { 440 // Java allows the use of SLASH in the classpath, 441 // so we need 442 // convert SLASH to BACKSLASH. 443 char buf[] = p.toCharArray(); 444 for (int i = 0; i < buf.length; i++) { 445 if (buf[i] == SLASH) 446 buf[i] = BACKSLASH; 447 } 448 p = new String(buf); 449 } 450 451 File f = new File(p); 452 if (f.exists()) { 453 try { 454 URL url = new URL(urlPrefix + p); 455 // System.out.println(" based on 456 // classpath; found in " + p 457 // + "; URL=" + url + 458 // " classpath=" + classpath); 459 return url; 460 } 461 catch (MalformedURLException ex) { 462 // System.out.println(" based on 463 // classpath=" + classpath 464 // + 465 // " URL=null"); 466 keepGoing = false; 467 } 468 } 469 } 470 471 // Search relative to project's codebase attrib 472 // (meant for design time only) 473 if (codebaseStr != null) { 474 URL url; 475 String tmpPath; 476 if (!codebaseStr.endsWith(/* NOI18N */"/") && 477 !codebaseStr.endsWith(File.separator)) { 478 tmpPath = codebaseStr + /* NOI18N */"/" + path; 479 } else { 480 tmpPath = codebaseStr + path; 481 } 482 File f = new File(tmpPath); 483 if (f.exists()) { 484 tmpPath = urlPrefix + tmpPath; 485 } 486 try { 487 url = new URL(tmpPath); 488 // System.out.println(" based on proj 489 // codebase=" + codebase + " URL=" + url); 490 return url; 491 } 492 catch (MalformedURLException e) { 493 url = null; 494 } 495 } 496 497 // System.out.println(" all attempts 498 // failed - returning null"); 499 return null; 500 } 501 502 private static String separator; 503 private static String cwd; 504 makeAbsolute(String path)505 private String makeAbsolute(String path) { 506 if (separator == null) { 507 separator = System.getProperty(/* NOI18N */ 508 "file.separator"); 509 } 510 511 if (cwd == null) { 512 cwd = System.getProperty(/* NOI18N */"user.dir"); 513 if (cwd.charAt(cwd.length()-1) != separator.charAt(0)) 514 cwd = cwd + separator; 515 } 516 517 if (Global.isWindows()) { 518 if (path.length() < 3 || 519 (path.charAt(1) != COLON || 520 (path.charAt(2) != SLASH && path.charAt(2) 521 != BACKSLASH))) { 522 path = cwd + path; 523 } 524 } else { 525 if (path.charAt(0) != SLASH) 526 path = cwd + path; 527 } 528 529 return path; 530 } 531 532 /** 533 * Compares two objects and returns if they are equal. 534 * Will work with 535 * null objects 536 */ 537 isEqual(Object o1, Object o2)538 public boolean isEqual(Object o1, Object o2) { 539 if (o1 == null) { 540 return (o2 == null); 541 } else { 542 return (o1.equals(o2)); 543 } 544 } 545 546 /** 547 * Quicksort for strings. Could not get James Gosling's 548 * example working 549 * properly, or the "fixed" example, so wrote my own using 550 * algorithms 551 * book. 552 */ 553 qsort(String[] list)554 public void qsort(String[] list) { 555 quicksort(list, 0, list.length-1); 556 } 557 quicksort(String[] list, int p, int r)558 private void quicksort(String[] list, int p, int r) { 559 if (p < r) { 560 int q = partition(list, p, r); 561 if (q == r) { 562 q--; 563 } 564 quicksort(list, p, q); 565 quicksort(list, q+1, r); 566 } 567 } 568 partition(String[] list, int p, int r)569 private int partition(String[] list, int p, int r) { 570 String pivot = list[p]; 571 int lo = p; 572 int hi = r; 573 574 while (true) { 575 while (list[hi].compareTo(pivot) >= 0 && 576 lo < hi) { 577 hi--; 578 } 579 while (list[lo].compareTo(pivot) < 0 && 580 lo < hi) { 581 lo++; 582 } 583 if (lo < hi) { 584 String T = list[lo]; 585 list[lo] = list[hi]; 586 list[hi] = T; 587 } else return hi; 588 } 589 } 590 591 /** 592 * Quicksort for objects. The is a parameter for a 593 * QSortCompare object that is used to do the sorting. 594 */ 595 qsort(Object[] list, QSortCompare comp)596 public void qsort(Object[] list, QSortCompare comp) { 597 if (list != null) 598 quicksort(list, 0, list.length-1, comp); 599 } 600 quicksort(Object[] list, int p, int r, QSortCompare comp)601 private void quicksort(Object[] list, int p, int r, 602 QSortCompare comp) { 603 if (p < r) { 604 int q = partition(list, p, r, comp); 605 if (q == r) { 606 q--; 607 } 608 quicksort(list, p, q, comp); 609 quicksort(list, q+1, r, comp); 610 } 611 } 612 partition(Object[] list, int p, int r, QSortCompare comp)613 private int partition(Object[] list, int p, int r, 614 QSortCompare comp) { 615 Object pivot = list[p]; 616 int lo = p; 617 int hi = r; 618 619 while (true) { 620 while (comp.qsortCompare(list[hi], pivot) >= 0 && 621 lo < hi) { 622 hi--; 623 } 624 while (comp.qsortCompare(list[lo], pivot) < 0 && 625 lo < hi) { 626 lo++; 627 } 628 if (lo < hi) { 629 Object T = list[lo]; 630 list[lo] = list[hi]; 631 list[hi] = T; 632 } else return hi; 633 } 634 } 635 636 /** 637 * A workaround routine for the Windows95 pack bug in 1.0.2 638 * 639 * @param c The component to pack 640 */ pack(Window c)641 static public void pack(Window c) { 642 c.pack(); 643 if (Global.isWindows95() || Global.isWindowsNT()) { 644 Thread.yield(); 645 c.pack(); 646 } 647 } 648 } 649 650 651 /** 652 * A Work-around filter. 653 * 654 * Transparent gifs don't display properly on Windows 95. 655 * The work-around 656 * is to replace transparent pixels with the background color of the 657 * component they're being displayed in before drawing them. 658 */ 659 class TransFilter extends RGBImageFilter { 660 private Color bg; 661 private Component comp; 662 TransFilter(Component comp)663 TransFilter(Component comp) { 664 if (comp == null) 665 throw new Error(Global.fmtMsg( 666 "sunsoft.jws.visual.rt.base.Util.NullComp", 667 "TransWorkAroundFilter")); 668 669 this.comp = comp; 670 canFilterIndexColorModel = false; 671 } 672 filterRGB(int x, int y, int rgb)673 public int filterRGB(int x, int y, int rgb) { 674 if (bg == null) 675 bg = comp.getBackground(); 676 677 if ((rgb & 0xff000000) == 0) 678 return (bg.getRGB()); 679 else 680 return (rgb); 681 } 682 683 } 684