1 7 package com.sun.java.swing.plaf.gtk; 8 9 import com.sun.java.swing.SwingUtilities2; 10 11 import javax.swing.plaf.synth.*; 12 13 import java.awt.*; 14 import java.awt.geom.*; 15 import java.awt.image.*; 16 import java.io.*; 17 import java.net.*; 18 import java.security.*; 19 import java.util.*; 20 21 import javax.swing.*; 22 import javax.swing.border.*; 23 24 import javax.xml.parsers.*; 25 import org.xml.sax.SAXException ; 26 import org.w3c.dom.*; 27 28 31 class Metacity implements SynthConstants { 32 35 38 static Metacity INSTANCE; 39 40 private static final String [] themeNames = { 41 getUserTheme(), 42 "blueprint", 43 "Bluecurve", 44 "Crux", 45 "SwingFallbackTheme" 46 }; 47 48 49 static { 50 for (String themeName : themeNames) { 51 if (themeName != null) { 52 try { 53 INSTANCE = new Metacity(themeName); 54 } catch (FileNotFoundException ex) { 55 } catch (IOException ex) { 56 logError(themeName, ex); 57 } catch (ParserConfigurationException ex) { 58 logError(themeName, ex); 59 } catch (SAXException ex) { 60 logError(themeName, ex); 61 } 62 } 63 if (INSTANCE != null) { 64 break; 65 } 66 } 67 if (INSTANCE == null) { 68 throw new Error ("Could not find any installed metacity theme, and fallback failed"); 69 } 70 } 71 72 private static boolean errorLogged = false; 73 private static DocumentBuilder documentBuilder; 74 private static Document xmlDoc; 75 private static String userHome; 76 77 private Node frame_style_set; 78 private Map<String , Object > frameGeometry; 79 private Map<String , Map<String , Object >> frameGeometries; 80 81 private LayoutManager titlePaneLayout = new TitlePaneLayout(); 82 83 private ColorizeImageFilter imageFilter = new ColorizeImageFilter(); 84 private URL themeDir = null; 85 private SynthContext context; 86 private String themeName; 87 88 private ArithmeticExpressionEvaluator aee = new ArithmeticExpressionEvaluator(); 89 private Map<String , Integer > variables; 90 91 private RoundRectClipShape roundedClipShape; 93 94 protected Metacity(String themeName) throws IOException, ParserConfigurationException, SAXException { 95 this.themeName = themeName; 96 themeDir = getThemeDir(themeName); 97 if (themeDir != null) { 98 URL themeURL = new URL(themeDir, "metacity-theme-1.xml"); 99 xmlDoc = getXMLDoc(themeURL); 100 if (xmlDoc == null) { 101 throw new IOException(themeURL.toString()); 102 } 103 } else { 104 throw new FileNotFoundException(themeName); 105 } 106 107 variables = new HashMap(); 109 NodeList nodes = xmlDoc.getElementsByTagName("constant"); 110 int n = nodes.getLength(); 111 for (int i = 0; i < n; i++) { 112 Node node = nodes.item(i); 113 String name = getStringAttr(node, "name"); 114 if (name != null) { 115 String value = getStringAttr(node, "value"); 116 if (value != null) { 117 try { 118 variables.put(name, Integer.parseInt(value)); 119 } catch (NumberFormatException ex) { 120 logError(themeName, ex); 121 } 123 } 124 } 125 } 126 127 frameGeometries = new HashMap(); 129 nodes = xmlDoc.getElementsByTagName("frame_geometry"); 130 n = nodes.getLength(); 131 for (int i = 0; i < n; i++) { 132 Node node = nodes.item(i); 133 String name = getStringAttr(node, "name"); 134 if (name != null) { 135 HashMap<String , Object > gm = new HashMap(); 136 frameGeometries.put(name, gm); 137 138 String parentGM = getStringAttr(node, "parent"); 139 if (parentGM != null) { 140 gm.putAll(frameGeometries.get(parentGM)); 141 } 142 143 gm.put("has_title", 144 Boolean.valueOf(getBooleanAttr(node, "has_title", true))); 145 gm.put("rounded_top_left", 146 Boolean.valueOf(getBooleanAttr(node, "rounded_top_left", false))); 147 gm.put("rounded_top_right", 148 Boolean.valueOf(getBooleanAttr(node, "rounded_top_right", false))); 149 gm.put("rounded_bottom_left", 150 Boolean.valueOf(getBooleanAttr(node, "rounded_bottom_left", false))); 151 gm.put("rounded_bottom_right", 152 Boolean.valueOf(getBooleanAttr(node, "rounded_bottom_right", false))); 153 154 NodeList childNodes = node.getChildNodes(); 155 int nc = childNodes.getLength(); 156 for (int j = 0; j < nc; j++) { 157 Node child = childNodes.item(j); 158 if (child.getNodeType() == Node.ELEMENT_NODE) { 159 name = child.getNodeName(); 160 Object value = null; 161 if ("distance".equals(name)) { 162 value = new Integer (getIntAttr(child, "value", 0)); 163 } else if ("border".equals(name)) { 164 value = new Insets(getIntAttr(child, "top", 0), 165 getIntAttr(child, "left", 0), 166 getIntAttr(child, "bottom", 0), 167 getIntAttr(child, "right", 0)); 168 } else if ("aspect_ratio".equals(name)) { 169 value = new Float (getFloatAttr(child, "value", 1.0F)); 170 } else { 171 logError(themeName, "Unknown Metacity frame geometry value type: "+name); 172 } 173 String childName = getStringAttr(child, "name"); 174 if (childName != null && value != null) { 175 gm.put(childName, value); 176 } 177 } 178 } 179 } 180 } 181 frameGeometry = frameGeometries.get("normal"); 182 } 183 184 185 public static LayoutManager getTitlePaneLayout() { 186 return INSTANCE.titlePaneLayout; 187 } 188 189 private Shape getRoundedClipShape(int x, int y, int w, int h, 190 int arcw, int arch, int corners) { 191 if (roundedClipShape == null) { 192 roundedClipShape = new RoundRectClipShape(); 193 } 194 roundedClipShape.setRoundedRect(x, y, w, h, arcw, arch, corners); 195 196 return roundedClipShape; 197 } 198 199 void paintButtonBackground(SynthContext context, Graphics g, int x, int y, int w, int h) { 200 this.context = context; 201 JButton button = (JButton)context.getComponent(); 202 String buttonName = button.getName(); 203 int buttonState = context.getComponentState(); 204 205 JComponent titlePane = (JComponent)button.getParent(); 206 Container titlePaneParent = titlePane.getParent(); 207 208 JInternalFrame jif; 209 if (titlePaneParent instanceof JInternalFrame) { 210 jif = (JInternalFrame)titlePaneParent; 211 } else if (titlePaneParent instanceof JInternalFrame.JDesktopIcon) { 212 jif = ((JInternalFrame.JDesktopIcon)titlePaneParent).getInternalFrame(); 213 } else { 214 return; 215 } 216 217 boolean active = jif.isSelected(); 218 button.setOpaque(false); 219 220 String state = "normal"; 221 if ((buttonState & PRESSED) != 0) { 222 state = "pressed"; 223 } else if ((buttonState & MOUSE_OVER) != 0) { 224 state = "prelight"; 225 } 226 227 String function = null; 228 String location = null; 229 boolean left_corner = false; 230 boolean right_corner = false; 231 232 233 if (buttonName == "InternalFrameTitlePane.menuButton") { 234 function = "menu"; 235 location = "left_left"; 236 left_corner = true; 237 } else if (buttonName == "InternalFrameTitlePane.iconifyButton") { 238 function = "minimize"; 239 int nButtons = ((jif.isIconifiable() ? 1 : 0) + 240 (jif.isMaximizable() ? 1 : 0) + 241 (jif.isClosable() ? 1 : 0)); 242 right_corner = (nButtons == 1); 243 switch (nButtons) { 244 case 1: location = "right_right"; break; 245 case 2: location = "right_middle"; break; 246 case 3: location = "right_left"; break; 247 } 248 } else if (buttonName == "InternalFrameTitlePane.maximizeButton") { 249 function = "maximize"; 250 right_corner = !jif.isClosable(); 251 location = jif.isClosable() ? "right_middle" : "right_right"; 252 } else if (buttonName == "InternalFrameTitlePane.closeButton") { 253 function = "close"; 254 right_corner = true; 255 location = "right_right"; 256 } 257 258 Node frame = getNode(frame_style_set, "frame", new String [] { 259 "focus", (active ? "yes" : "no"), 260 "state", (jif.isMaximum() ? "maximized" : "normal") 261 }); 262 263 if (function != null && frame != null) { 264 Node frame_style = getNode("frame_style", new String [] { 265 "name", getStringAttr(frame, "style") 266 }); 267 if (frame_style != null) { 268 setFrameGeometry(titlePane, 269 frameGeometries.get(getStringAttr(frame_style, "geometry"))); 270 271 272 Shape oldClip = g.getClip(); 273 if ((right_corner && getBoolean("rounded_top_right", false)) || 274 (left_corner && getBoolean("rounded_top_left", false))) { 275 276 Point buttonLoc = button.getLocation(); 277 if (right_corner) { 278 g.setClip(getRoundedClipShape(0, 0, w, h, 279 12, 12, RoundRectClipShape.TOP_RIGHT)); 280 } else { 281 g.setClip(getRoundedClipShape(0, 0, w, h, 282 11, 11, RoundRectClipShape.TOP_LEFT)); 283 } 284 } 285 drawButton(frame_style, location+"_background", state, g, w, h, jif); 286 drawButton(frame_style, function, state, g, w, h, jif); 287 g.setClip(oldClip); 288 } 289 } 290 } 291 292 protected void drawButton(Node frame_style, String function, String state, 293 Graphics g, int w, int h, JInternalFrame jif) { 294 Node buttonNode = getNode(frame_style, "button", 295 new String [] { "function", function, "state", state }); 296 if (buttonNode == null && !state.equals("normal")) { 297 buttonNode = getNode(frame_style, "button", 298 new String [] { "function", function, "state", "normal" }); 299 } 300 if (buttonNode != null) { 301 Node draw_ops; 302 String draw_ops_name = getStringAttr(buttonNode, "draw_ops"); 303 if (draw_ops_name != null) { 304 draw_ops = getNode("draw_ops", new String [] { "name", draw_ops_name }); 305 } else { 306 draw_ops = getNode(buttonNode, "draw_ops", null); 307 } 308 variables.put("width", w); 309 variables.put("height", h); 310 draw(draw_ops, g, jif); 311 } 312 } 313 314 void paintFrameBorder(SynthContext context, Graphics g, int x0, int y0, int width, int height) { 315 this.context = context; 316 JComponent comp = context.getComponent(); 317 JComponent titlePane = findChild(comp, "InternalFrame.northPane"); 318 319 if (titlePane == null) { 320 return; 321 } 322 323 JInternalFrame jif = null; 324 if (comp instanceof JInternalFrame) { 325 jif = (JInternalFrame)comp; 326 } else if (comp instanceof JInternalFrame.JDesktopIcon) { 327 jif = ((JInternalFrame.JDesktopIcon)comp).getInternalFrame(); 328 } else { 329 return; 330 } 331 332 boolean active = jif.isSelected(); 333 Font oldFont = g.getFont(); 334 g.setFont(titlePane.getFont()); 335 g.translate(x0, y0); 336 337 Rectangle titleRect = calculateTitleArea(jif); 338 JComponent menuButton = findChild(titlePane, "InternalFrameTitlePane.menuButton"); 339 340 Icon frameIcon = jif.getFrameIcon(); 341 variables.put("mini_icon_width", 342 (frameIcon != null) ? frameIcon.getIconWidth() : 0); 343 variables.put("mini_icon_height", 344 (frameIcon != null) ? frameIcon.getIconHeight() : 0); 345 variables.put("title_width", calculateTitleTextWidth(g, jif)); 346 FontMetrics fm = SwingUtilities2.getFontMetrics(jif, g); 347 variables.put("title_height", fm.getAscent() + fm.getDescent()); 348 349 variables.put("icon_width", 32); 351 variables.put("icon_height", 32); 352 353 354 if (frame_style_set == null) { 355 frame_style_set = getNode("frame_style_set", new String [] { "name", "normal" }); 356 } 357 358 if (frame_style_set != null) { 359 Node frame = getNode(frame_style_set, "frame", new String [] { 360 "focus", (active ? "yes" : "no"), 361 "state", (jif.isMaximum() ? "maximized" : "normal") 362 }); 363 364 if (frame != null) { 365 Node frame_style = getNode("frame_style", new String [] { 366 "name", getStringAttr(frame, "style") 367 }); 368 if (frame_style != null) { 369 Map gm = frameGeometries.get(getStringAttr(frame_style, "geometry")); 370 setFrameGeometry(titlePane, gm); 371 Shape oldClip = g.getClip(); 372 boolean roundTopLeft = getBoolean("rounded_top_left", false); 373 boolean roundTopRight = getBoolean("rounded_top_right", false); 374 boolean roundBottomLeft = getBoolean("rounded_bottom_left", false); 375 boolean roundBottomRight = getBoolean("rounded_bottom_right", false); 376 377 if (roundTopLeft || roundTopRight || roundBottomLeft || roundBottomRight) { 378 jif.setOpaque(false); 379 380 g.setClip(getRoundedClipShape(0, 0, width, height, 12, 12, 381 (roundTopLeft ? RoundRectClipShape.TOP_LEFT : 0) | 382 (roundTopRight ? RoundRectClipShape.TOP_RIGHT : 0) | 383 (roundBottomLeft ? RoundRectClipShape.BOTTOM_LEFT : 0) | 384 (roundBottomRight ? RoundRectClipShape.BOTTOM_RIGHT : 0))); 385 } 386 387 int titleHeight = titlePane.getHeight(); 388 389 boolean minimized = jif.isIcon(); 390 Insets insets = getBorderInsets(context, null); 391 392 int leftTitlebarEdge = getInt("left_titlebar_edge"); 393 int rightTitlebarEdge = getInt("right_titlebar_edge"); 394 int topTitlebarEdge = getInt("top_titlebar_edge"); 395 int bottomTitlebarEdge = getInt("bottom_titlebar_edge"); 396 397 if (!minimized) { 398 drawPiece(frame_style, g, "entire_background", 399 0, 0, width, height, jif); 400 } 401 drawPiece(frame_style, g, "titlebar", 402 0, 0, width, titleHeight, jif); 403 drawPiece(frame_style, g, "titlebar_middle", 404 leftTitlebarEdge, topTitlebarEdge, 405 width - leftTitlebarEdge - rightTitlebarEdge, 406 titleHeight - topTitlebarEdge - bottomTitlebarEdge, 407 jif); 408 drawPiece(frame_style, g, "left_titlebar_edge", 409 0, 0, leftTitlebarEdge, titleHeight, jif); 410 drawPiece(frame_style, g, "right_titlebar_edge", 411 width - rightTitlebarEdge, 0, 412 rightTitlebarEdge, titleHeight, jif); 413 drawPiece(frame_style, g, "top_titlebar_edge", 414 0, 0, width, topTitlebarEdge, jif); 415 drawPiece(frame_style, g, "bottom_titlebar_edge", 416 0, titleHeight - bottomTitlebarEdge, 417 width, bottomTitlebarEdge, jif); 418 drawPiece(frame_style, g, "title", 419 titleRect.x, titleRect.y, titleRect.width, titleRect.height, jif); 420 if (!minimized) { 421 drawPiece(frame_style, g, "left_edge", 422 0, titleHeight, insets.left, height-titleHeight, jif); 423 drawPiece(frame_style, g, "right_edge", 424 width-insets.right, titleHeight, insets.right, height-titleHeight, jif); 425 drawPiece(frame_style, g, "bottom_edge", 426 0, height - insets.bottom, width, insets.bottom, jif); 427 drawPiece(frame_style, g, "overlay", 428 0, 0, width, height, jif); 429 } 430 g.setClip(oldClip); 431 } 432 } 433 } 434 g.translate(-x0, -y0); 435 g.setFont(oldFont); 436 } 437 438 439 440 private static class Privileged implements PrivilegedAction { 441 private static int GET_THEME_DIR = 0; 442 private static int GET_USER_THEME = 1; 443 private static int GET_IMAGE = 2; 444 private int type; 445 private Object arg; 446 447 public Object doPrivileged(int type, Object arg) { 448 this.type = type; 449 this.arg = arg; 450 return AccessController.doPrivileged(this); 451 } 452 453 public Object run() { 454 if (type == GET_THEME_DIR) { 455 String sep = File.separator; 456 String [] dirs = new String [] { 457 userHome + sep + ".themes", 458 System.getProperty("swing.metacitythemedir"), 459 "/usr/share/themes", 460 "/usr/gnome/share/themes", "/opt/gnome2/share/themes" }; 463 464 URL themeDir = null; 465 for (int i = 0; i < dirs.length; i++) { 466 if (dirs[i] == null) { 468 continue; 469 } 470 File dir = 471 new File(dirs[i] + sep + arg + sep + "metacity-1"); 472 if (new File(dir, "metacity-theme-1.xml").canRead()) { 473 try { 474 themeDir = dir.toURL(); 475 } catch (MalformedURLException ex) { 476 themeDir = null; 477 } 478 break; 479 } 480 } 481 if (themeDir == null) { 482 String filename = "resources/metacity/" + arg + 483 "/metacity-1/metacity-theme-1.xml"; 484 URL url = getClass().getResource(filename); 485 if (url != null) { 486 String str = url.toString(); 487 try { 488 themeDir = new URL(str.substring(0, str.lastIndexOf('/'))+"/"); 489 } catch (MalformedURLException ex) { 490 themeDir = null; 491 } 492 } 493 } 494 return themeDir; 495 } else if (type == GET_USER_THEME) { 496 try { 497 userHome = System.getProperty("user.home"); 499 500 String theme = System.getProperty("swing.metacitythemename"); 501 if (theme != null) { 502 return theme; 503 } 504 URL url = new URL(new File(userHome).toURL(), 507 ".gconf/apps/metacity/general/%25gconf.xml"); 508 Reader reader = new InputStreamReader(url.openStream(), "ISO-8859-1"); 510 char[] buf = new char[1024]; 511 StringBuffer strBuf = new StringBuffer (); 512 int n; 513 while ((n = reader.read(buf)) >= 0) { 514 strBuf.append(buf, 0, n); 515 } 516 reader.close(); 517 String str = strBuf.toString(); 518 if (str != null) { 519 String strLowerCase = str.toLowerCase(); 520 int i = strLowerCase.indexOf("<entry name=\"theme\""); 521 if (i >= 0) { 522 i = strLowerCase.indexOf("<stringvalue>", i); 523 if (i > 0) { 524 i += "<stringvalue>".length(); 525 int i2 = str.indexOf("<", i); 526 return str.substring(i, i2); 527 } 528 } 529 } 530 } catch (MalformedURLException ex) { 531 } catch (IOException ex) { 533 } 535 return null; 536 } else if (type == GET_IMAGE) { 537 return new ImageIcon((URL)arg).getImage(); 538 } else { 539 return null; 540 } 541 } 542 } 543 544 private static URL getThemeDir(String themeName) { 545 return (URL)new Privileged().doPrivileged(Privileged.GET_THEME_DIR, themeName); 546 } 547 548 private static String getUserTheme() { 549 return (String )new Privileged().doPrivileged(Privileged.GET_USER_THEME, null); 550 } 551 552 protected void tileImage(Graphics g, Image image, int x0, int y0, int w, int h, float[] alphas) { 553 Graphics2D g2 = (Graphics2D)g; 554 Composite oldComp = g2.getComposite(); 555 556 int sw = image.getWidth(null); 557 int sh = image.getHeight(null); 558 int y = y0; 559 while (y < y0 + h) { 560 sh = Math.min(sh, y0 + h - y); 561 int x = x0; 562 while (x < x0 + w) { 563 float f = (alphas.length - 1.0F) * x / (x0 + w); 564 int i = (int)f; 565 f -= (int)f; 566 float alpha = (1-f) * alphas[i]; 567 if (i+1 < alphas.length) { 568 alpha += f * alphas[i+1]; 569 } 570 g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha)); 571 int swm = Math.min(sw, x0 + w - x); 572 g.drawImage(image, x, y, x+swm, y+sh, 0, 0, swm, sh, null); 573 x += swm; 574 } 575 y += sh; 576 } 577 g2.setComposite(oldComp); 578 } 579 580 private HashMap<String , Image> images = new HashMap(); 581 582 protected Image getImage(String key, Color c) { 583 Image image = images.get(key+"-"+c.getRGB()); 584 if (image == null) { 585 image = imageFilter.colorize(getImage(key), c); 586 if (image != null) { 587 images.put(key+"-"+c.getRGB(), image); 588 } 589 } 590 return image; 591 } 592 593 protected Image getImage(String key) { 594 Image image = images.get(key); 595 if (image == null) { 596 if (themeDir != null) { 597 try { 598 URL url = new URL(themeDir, key); 599 image = (Image)new Privileged().doPrivileged(Privileged.GET_IMAGE, url); 600 } catch (MalformedURLException ex) { 601 } 603 } 604 if (image != null) { 605 images.put(key, image); 606 } 607 } 608 return image; 609 } 610 611 private class ColorizeImageFilter extends RGBImageFilter { 612 double cr, cg, cb; 613 614 public ColorizeImageFilter() { 615 canFilterIndexColorModel = true; 616 } 617 618 public void setColor(Color color) { 619 cr = color.getRed() / 255.0; 620 cg = color.getGreen() / 255.0; 621 cb = color.getBlue() / 255.0; 622 } 623 624 public Image colorize(Image fromImage, Color c) { 625 setColor(c); 626 ImageProducer producer = new FilteredImageSource(fromImage.getSource(), this); 627 return new ImageIcon(context.getComponent().createImage(producer)).getImage(); 628 } 629 630 public int filterRGB(int x, int y, int rgb) { 631 double grayLevel = 2 * (rgb & 0xff) / 255.0; 633 double r, g, b; 634 635 if (grayLevel <= 1.0) { 636 r = cr * grayLevel; 637 g = cg * grayLevel; 638 b = cb * grayLevel; 639 } else { 640 grayLevel -= 1.0; 641 r = cr + (1.0 - cr) * grayLevel; 642 g = cg + (1.0 - cg) * grayLevel; 643 b = cb + (1.0 - cb) * grayLevel; 644 } 645 646 return ((rgb & 0xff000000) + 647 (((int)(r * 255)) << 16) + 648 (((int)(g * 255)) << 8) + 649 (int)(b * 255)); 650 } 651 } 652 653 protected static JComponent findChild(JComponent parent, String name) { 654 int n = parent.getComponentCount(); 655 for (int i = 0; i < n; i++) { 656 JComponent c = (JComponent)parent.getComponent(i); 657 if (name.equals(c.getName())) { 658 return c; 659 } 660 } 661 return null; 662 } 663 664 665 protected class TitlePaneLayout implements LayoutManager { 666 public void addLayoutComponent(String name, Component c) {} 667 public void removeLayoutComponent(Component c) {} 668 public Dimension preferredLayoutSize(Container c) { 669 return minimumLayoutSize(c); 670 } 671 672 public Dimension minimumLayoutSize(Container c) { 673 JComponent titlePane = (JComponent)c; 674 Container titlePaneParent = titlePane.getParent(); 675 JInternalFrame frame; 676 if (titlePaneParent instanceof JInternalFrame) { 677 frame = (JInternalFrame)titlePaneParent; 678 } else if (titlePaneParent instanceof JInternalFrame.JDesktopIcon) { 679 frame = ((JInternalFrame.JDesktopIcon)titlePaneParent).getInternalFrame(); 680 } else { 681 return null; 682 } 683 684 Dimension buttonDim = calculateButtonSize(titlePane); 685 Insets title_border = (Insets)getFrameGeometry().get("title_border"); 686 Insets button_border = (Insets)getFrameGeometry().get("button_border"); 687 688 int width = getInt("left_titlebar_edge") + buttonDim.width + getInt("right_titlebar_edge"); 690 if (title_border != null) { 691 width += title_border.left + title_border.right; 692 } 693 if (frame.isClosable()) { 694 width += buttonDim.width; 695 } 696 if (frame.isMaximizable()) { 697 width += buttonDim.width; 698 } 699 if (frame.isIconifiable()) { 700 width += buttonDim.width; 701 } 702 FontMetrics fm = frame.getFontMetrics(titlePane.getFont()); 703 String frameTitle = frame.getTitle(); 704 int title_w = frameTitle != null ? SwingUtilities2.stringWidth( 705 frame, fm, frameTitle) : 0; 706 int title_length = frameTitle != null ? frameTitle.length() : 0; 707 708 if (title_length > 3) { 710 int subtitle_w = SwingUtilities2.stringWidth( 711 frame, fm, frameTitle.substring(0, 3) + "..."); 712 width += (title_w < subtitle_w) ? title_w : subtitle_w; 713 } else { 714 width += title_w; 715 } 716 717 int titleHeight = fm.getHeight() + getInt("title_vertical_pad"); 719 if (title_border != null) { 720 titleHeight += title_border.top + title_border.bottom; 721 } 722 int buttonHeight = buttonDim.height; 723 if (button_border != null) { 724 buttonHeight += button_border.top + button_border.bottom; 725 } 726 int height = Math.max(buttonHeight, titleHeight); 727 728 return new Dimension(width, height); 729 } 730 731 public void layoutContainer(Container c) { 732 JComponent titlePane = (JComponent)c; 733 Container titlePaneParent = titlePane.getParent(); 734 JInternalFrame frame; 735 if (titlePaneParent instanceof JInternalFrame) { 736 frame = (JInternalFrame)titlePaneParent; 737 } else if (titlePaneParent instanceof JInternalFrame.JDesktopIcon) { 738 frame = ((JInternalFrame.JDesktopIcon)titlePaneParent).getInternalFrame(); 739 } else { 740 return; 741 } 742 Map gm = getFrameGeometry(); 743 744 int w = titlePane.getWidth(); 745 int h = titlePane.getHeight(); 746 747 JComponent menuButton = findChild(titlePane, "InternalFrameTitlePane.menuButton"); 748 JComponent minimizeButton = findChild(titlePane, "InternalFrameTitlePane.iconifyButton"); 749 JComponent maximizeButton = findChild(titlePane, "InternalFrameTitlePane.maximizeButton"); 750 JComponent closeButton = findChild(titlePane, "InternalFrameTitlePane.closeButton"); 751 752 int buttonGap = 0; 753 754 Insets button_border = (Insets)gm.get("button_border"); 755 Dimension buttonDim = calculateButtonSize(titlePane); 756 757 int x = getInt("left_titlebar_edge"); 758 int y = (button_border != null) ? button_border.top : 0; 759 760 menuButton.setBounds(x, y, buttonDim.width, buttonDim.height); 761 762 x = w - buttonDim.width - getInt("right_titlebar_edge"); 763 if (button_border != null) { 764 x -= button_border.right; 765 } 766 767 if (frame.isClosable()) { 768 closeButton.setBounds(x, y, buttonDim.width, buttonDim.height); 769 x -= (buttonDim.width + buttonGap); 770 } 771 772 if (frame.isMaximizable()) { 773 maximizeButton.setBounds(x, y, buttonDim.width, buttonDim.height); 774 x -= (buttonDim.width + buttonGap); 775 } 776 777 if (frame.isIconifiable()) { 778 minimizeButton.setBounds(x, y, buttonDim.width, buttonDim.height); 779 } 780 } 781 } 783 protected Map getFrameGeometry() { 784 return frameGeometry; 785 } 786 787 protected void setFrameGeometry(JComponent titlePane, Map gm) { 788 this.frameGeometry = gm; 789 if (getInt("top_height") == 0) { 790 gm.put("top_height", new Integer (titlePane.getHeight())); 791 } 792 } 793 794 protected int getInt(String key) { 795 Integer i = (Integer )frameGeometry.get(key); 796 if (i == null) { 797 i = variables.get(key); 798 } 799 return (i != null) ? i.intValue() : 0; 800 } 801 802 protected boolean getBoolean(String key, boolean fallback) { 803 Boolean b = (Boolean )frameGeometry.get(key); 804 return (b != null) ? b.booleanValue() : fallback; 805 } 806 807 808 protected void drawArc(Node node, Graphics g) { 809 NamedNodeMap attrs = node.getAttributes(); 810 Color color = parseColor(getStringAttr(attrs, "color")); 811 int x = aee.evaluate(getStringAttr(attrs, "x")); 812 int y = aee.evaluate(getStringAttr(attrs, "y")); 813 int w = aee.evaluate(getStringAttr(attrs, "width")); 814 int h = aee.evaluate(getStringAttr(attrs, "height")); 815 int start_angle = aee.evaluate(getStringAttr(attrs, "start_angle")); 816 int extent_angle = aee.evaluate(getStringAttr(attrs, "extent_angle")); 817 boolean filled = getBooleanAttr(node, "filled", false); 818 if (getInt("width") == -1) { 819 x -= w; 820 } 821 if (getInt("height") == -1) { 822 y -= h; 823 } 824 g.setColor(color); 825 if (filled) { 826 g.fillArc(x, y, w, h, start_angle, extent_angle); 827 } else { 828 g.drawArc(x, y, w, h, start_angle, extent_angle); 829 } 830 } 831 832 protected void drawLine(Node node, Graphics g) { 833 NamedNodeMap attrs = node.getAttributes(); 834 Color color = parseColor(getStringAttr(attrs, "color")); 835 int x1 = aee.evaluate(getStringAttr(attrs, "x1")); 836 int y1 = aee.evaluate(getStringAttr(attrs, "y1")); 837 int x2 = aee.evaluate(getStringAttr(attrs, "x2")); 838 int y2 = aee.evaluate(getStringAttr(attrs, "y2")); 839 int lineWidth = aee.evaluate(getStringAttr(attrs, "width"), 1); 840 g.setColor(color); 841 if (lineWidth != 1) { 842 Graphics2D g2d = (Graphics2D)g; 843 Stroke stroke = g2d.getStroke(); 844 g2d.setStroke(new BasicStroke((float)lineWidth)); 845 g2d.drawLine(x1, y1, x2, y2); 846 g2d.setStroke(stroke); 847 } else { 848 g.drawLine(x1, y1, x2, y2); 849 } 850 } 851 852 protected void drawRectangle(Node node, Graphics g) { 853 NamedNodeMap attrs = node.getAttributes(); 854 Color color = parseColor(getStringAttr(attrs, "color")); 855 boolean filled = getBooleanAttr(node, "filled", false); 856 int x = aee.evaluate(getStringAttr(attrs, "x")); 857 int y = aee.evaluate(getStringAttr(attrs, "y")); 858 int w = aee.evaluate(getStringAttr(attrs, "width")); 859 int h = aee.evaluate(getStringAttr(attrs, "height")); 860 g.setColor(color); 861 if (getInt("width") == -1) { 862 x -= w; 863 } 864 if (getInt("height") == -1) { 865 y -= h; 866 } 867 if (filled) { 868 g.fillRect(x, y, w, h); 869 } else { 870 g.drawRect(x, y, w, h); 871 } 872 } 873 874 protected void drawTile(Node node, Graphics g, JInternalFrame jif) { 875 NamedNodeMap attrs = node.getAttributes(); 876 int x0 = aee.evaluate(getStringAttr(attrs, "x")); 877 int y0 = aee.evaluate(getStringAttr(attrs, "y")); 878 int w = aee.evaluate(getStringAttr(attrs, "width")); 879 int h = aee.evaluate(getStringAttr(attrs, "height")); 880 int tw = aee.evaluate(getStringAttr(attrs, "tile_width")); 881 int th = aee.evaluate(getStringAttr(attrs, "tile_height")); 882 int width = getInt("width"); 883 int height = getInt("height"); 884 if (width == -1) { 885 x0 -= w; 886 } 887 if (height == -1) { 888 y0 -= h; 889 } 890 Shape oldClip = g.getClip(); 891 if (g instanceof Graphics2D) { 892 ((Graphics2D)g).clip(new Rectangle(x0, y0, w, h)); 893 } 894 variables.put("width", tw); 895 variables.put("height", th); 896 897 Node draw_ops = getNode("draw_ops", new String [] { "name", getStringAttr(node, "name") }); 898 899 int y = y0; 900 while (y < y0 + h) { 901 int x = x0; 902 while (x < x0 + w) { 903 g.translate(x, y); 904 draw(draw_ops, g, jif); 905 g.translate(-x, -y); 906 x += tw; 907 } 908 y += th; 909 } 910 911 variables.put("width", width); 912 variables.put("height", height); 913 g.setClip(oldClip); 914 } 915 916 protected void drawTint(Node node, Graphics g) { 917 NamedNodeMap attrs = node.getAttributes(); 918 Color color = parseColor(getStringAttr(attrs, "color")); 919 float alpha = Float.parseFloat(getStringAttr(attrs, "alpha")); 920 int x = aee.evaluate(getStringAttr(attrs, "x")); 921 int y = aee.evaluate(getStringAttr(attrs, "y")); 922 int w = aee.evaluate(getStringAttr(attrs, "width")); 923 int h = aee.evaluate(getStringAttr(attrs, "height")); 924 if (getInt("width") == -1) { 925 x -= w; 926 } 927 if (getInt("height") == -1) { 928 y -= h; 929 } 930 if (g instanceof Graphics2D) { 931 Graphics2D g2 = (Graphics2D)g; 932 Composite oldComp = g2.getComposite(); 933 AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha); 934 g2.setComposite(ac); 935 g2.setColor(color); 936 g2.fillRect(x, y, w, h); 937 g2.setComposite(oldComp); 938 } 939 } 940 941 protected void drawTitle(Node node, Graphics g, JInternalFrame jif) { 942 NamedNodeMap attrs = node.getAttributes(); 943 String colorStr = getStringAttr(attrs, "color"); 944 int i = colorStr.indexOf("gtk:fg["); 945 if (i > 0) { 946 colorStr = colorStr.substring(0, i) + "gtk:text[" + colorStr.substring(i+7); 947 } 948 Color color = parseColor(colorStr); 949 int x = aee.evaluate(getStringAttr(attrs, "x")); 950 int y = aee.evaluate(getStringAttr(attrs, "y")); 951 952 String title = jif.getTitle(); 953 if (title != null) { 954 FontMetrics fm = SwingUtilities2.getFontMetrics(jif, g); 955 if (jif.getComponentOrientation().isLeftToRight()) { 956 title = SwingUtilities2.clipStringIfNecessary(jif, fm, title, 957 calculateTitleTextWidth(g, jif)); 958 } 959 g.setColor(color); 960 SwingUtilities2.drawString(jif, g, title, x, y + fm.getAscent()); 961 } 962 } 963 964 protected Dimension calculateButtonSize(JComponent titlePane) { 965 int buttonHeight = getInt("button_height"); 966 if (buttonHeight == 0) { 967 buttonHeight = titlePane.getHeight(); 968 if (buttonHeight == 0) { 969 buttonHeight = 13; 970 } else { 971 Insets button_border = (Insets)frameGeometry.get("button_border"); 972 if (button_border != null) { 973 buttonHeight -= (button_border.top + button_border.bottom); 974 } 975 } 976 } 977 int buttonWidth = getInt("button_width"); 978 if (buttonWidth == 0) { 979 buttonWidth = buttonHeight; 980 Float aspect_ratio = (Float )frameGeometry.get("aspect_ratio"); 981 if (aspect_ratio != null) { 982 buttonWidth = (int)(buttonHeight / aspect_ratio.floatValue()); 983 } 984 } 985 return new Dimension(buttonWidth, buttonHeight); 986 } 987 988 protected Rectangle calculateTitleArea(JInternalFrame jif) { 989 JComponent titlePane = findChild(jif, "InternalFrame.northPane"); 990 Dimension buttonDim = calculateButtonSize(titlePane); 991 Insets title_border = (Insets)frameGeometry.get("title_border"); 992 Rectangle r = new Rectangle(); 993 994 r.x = getInt("left_titlebar_edge") + buttonDim.width; 995 r.y = 0; 996 r.height = titlePane.getHeight(); 997 if (title_border != null) { 998 r.x += title_border.left; 999 r.y += title_border.top; 1000 r.height -= (title_border.top + title_border.bottom); 1001 } 1002 1003 r.width = titlePane.getWidth() - r.x - getInt("right_titlebar_edge"); 1004 if (jif.isClosable()) { 1005 r.width -= buttonDim.width; 1006 } 1007 if (jif.isMaximizable()) { 1008 r.width -= buttonDim.width; 1009 } 1010 if (jif.isIconifiable()) { 1011 r.width -= buttonDim.width; 1012 } 1013 if (title_border != null) { 1014 r.width -= title_border.right; 1015 } 1016 return r; 1017 } 1018 1019 1020 protected int calculateTitleTextWidth(Graphics g, JInternalFrame jif) { 1021 String title = jif.getTitle(); 1022 if (title != null) { 1023 Rectangle r = calculateTitleArea(jif); 1024 return Math.min(SwingUtilities2.stringWidth(jif, 1025 SwingUtilities2.getFontMetrics(jif, g), title), r.width); 1026 } 1027 return 0; 1028 } 1029 1030 protected void setClip(Node node, Graphics g) { 1031 NamedNodeMap attrs = node.getAttributes(); 1032 int x = aee.evaluate(getStringAttr(attrs, "x")); 1033 int y = aee.evaluate(getStringAttr(attrs, "y")); 1034 int w = aee.evaluate(getStringAttr(attrs, "width")); 1035 int h = aee.evaluate(getStringAttr(attrs, "height")); 1036 if (getInt("width") == -1) { 1037 x -= w; 1038 } 1039 if (getInt("height") == -1) { 1040 y -= h; 1041 } 1042 if (g instanceof Graphics2D) { 1043 ((Graphics2D)g).clip(new Rectangle(x, y, w, h)); 1044 } 1045 } 1046 1047 protected void drawGTKArrow(Node node, Graphics g) { 1048 NamedNodeMap attrs = node.getAttributes(); 1049 String arrow = getStringAttr(attrs, "arrow"); 1050 String shadow = getStringAttr(attrs, "shadow"); 1051 String stateStr = getStringAttr(attrs, "state").toUpperCase(); 1052 int x = aee.evaluate(getStringAttr(attrs, "x")); 1053 int y = aee.evaluate(getStringAttr(attrs, "y")); 1054 int w = aee.evaluate(getStringAttr(attrs, "width")); 1055 int h = aee.evaluate(getStringAttr(attrs, "height")); 1056 1057 int state = -1; 1058 if ("NORMAL".equals(stateStr)) { 1059 state = ENABLED; 1060 } else if ("SELECTED".equals(stateStr)) { 1061 state = SELECTED; 1062 } else if ("INSENSITIVE".equals(stateStr)) { 1063 state = DISABLED; 1064 } else if ("PRELIGHT".equals(stateStr)) { 1065 state = MOUSE_OVER; 1066 } 1067 1068 int shadowType = -1; 1069 if ("in".equals(shadow)) { 1070 shadowType = GTKConstants.SHADOW_IN; 1071 } else if ("out".equals(shadow)) { 1072 shadowType = GTKConstants.SHADOW_OUT; 1073 } else if ("etched_in".equals(shadow)) { 1074 shadowType = GTKConstants.SHADOW_ETCHED_IN; 1075 } else if ("etched_out".equals(shadow)) { 1076 shadowType = GTKConstants.SHADOW_ETCHED_OUT; 1077 } else if ("none".equals(shadow)) { 1078 shadowType = GTKConstants.SHADOW_NONE; 1079 } 1080 int direction = -1; 1081 if ("up".equals(arrow)) { 1082 direction = GTKConstants.ARROW_UP; 1083 } else if ("down".equals(arrow)) { 1084 direction = GTKConstants.ARROW_DOWN; 1085 } else if ("left".equals(arrow)) { 1086 direction = GTKConstants.ARROW_LEFT; 1087 } else if ("right".equals(arrow)) { 1088 direction = GTKConstants.ARROW_RIGHT; 1089 } 1090 GTKEngine engine = ((GTKStyle)context.getStyle()).getEngine(context); 1091 engine.paintArrow(context, g, state, shadowType, 1092 direction, null, x, y, w, h); 1093 } 1094 1095 protected void drawGTKBox(Node node, Graphics g) { 1096 NamedNodeMap attrs = node.getAttributes(); 1097 String shadow = getStringAttr(attrs, "shadow"); 1098 String stateStr = getStringAttr(attrs, "state").toUpperCase(); 1099 int x = aee.evaluate(getStringAttr(attrs, "x")); 1100 int y = aee.evaluate(getStringAttr(attrs, "y")); 1101 int w = aee.evaluate(getStringAttr(attrs, "width")); 1102 int h = aee.evaluate(getStringAttr(attrs, "height")); 1103 1104 int state = -1; 1105 if ("NORMAL".equals(stateStr)) { 1106 state = ENABLED; 1107 } else if ("SELECTED".equals(stateStr)) { 1108 state = SELECTED; 1109 } else if ("INSENSITIVE".equals(stateStr)) { 1110 state = DISABLED; 1111 } else if ("PRELIGHT".equals(stateStr)) { 1112 state = MOUSE_OVER; 1113 } 1114 1115 int shadowType = -1; 1116 if ("in".equals(shadow)) { 1117 shadowType = GTKConstants.SHADOW_IN; 1118 } else if ("out".equals(shadow)) { 1119 shadowType = GTKConstants.SHADOW_OUT; 1120 } else if ("etched_in".equals(shadow)) { 1121 shadowType = GTKConstants.SHADOW_ETCHED_IN; 1122 } else if ("etched_out".equals(shadow)) { 1123 shadowType = GTKConstants.SHADOW_ETCHED_OUT; 1124 } else if ("none".equals(shadow)) { 1125 shadowType = GTKConstants.SHADOW_NONE; 1126 } 1127 GTKEngine.INSTANCE.paintBox(context, g, state, shadowType, 1128 null, x, y, w, h); 1129 } 1130 1131 protected void drawGTKVLine(Node node, Graphics g) { 1132 NamedNodeMap attrs = node.getAttributes(); 1133 String stateStr = getStringAttr(attrs, "state").toUpperCase(); 1134 1135 int x = aee.evaluate(getStringAttr(attrs, "x")); 1136 int y1 = aee.evaluate(getStringAttr(attrs, "y1")); 1137 int y2 = aee.evaluate(getStringAttr(attrs, "y2")); 1138 1139 int state = -1; 1140 if ("NORMAL".equals(stateStr)) { 1141 state = ENABLED; 1142 } else if ("SELECTED".equals(stateStr)) { 1143 state = SELECTED; 1144 } else if ("INSENSITIVE".equals(stateStr)) { 1145 state = DISABLED; 1146 } else if ("PRELIGHT".equals(stateStr)) { 1147 state = MOUSE_OVER; 1148 } 1149 1150 GTKEngine.INSTANCE.paintVline(context, g, state, null, x, y1, 1, y2-y1); 1151 } 1152 1153 protected void drawGradient(Node node, Graphics g) { 1154 NamedNodeMap attrs = node.getAttributes(); 1155 String type = getStringAttr(attrs, "type"); 1156 float alpha = getFloatAttr(node, "alpha", -1F); 1157 int x = aee.evaluate(getStringAttr(attrs, "x")); 1158 int y = aee.evaluate(getStringAttr(attrs, "y")); 1159 int w = aee.evaluate(getStringAttr(attrs, "width")); 1160 int h = aee.evaluate(getStringAttr(attrs, "height")); 1161 if (getInt("width") == -1) { 1162 x -= w; 1163 } 1164 if (getInt("height") == -1) { 1165 y -= h; 1166 } 1167 1168 Node[] colorNodes = getNodesByName(node, "color"); 1170 Color[] colors = new Color[colorNodes.length]; 1171 for (int i = 0; i < colorNodes.length; i++) { 1172 colors[i] = parseColor(getStringAttr(colorNodes[i], "value")); 1173 } 1174 1175 boolean horizontal = ("diagonal".equals(type) || "horizontal".equals(type)); 1176 boolean vertical = ("diagonal".equals(type) || "vertical".equals(type)); 1177 1178 if (g instanceof Graphics2D) { 1179 Graphics2D g2 = (Graphics2D)g; 1180 Composite oldComp = g2.getComposite(); 1181 if (alpha >= 0F) { 1182 g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha)); 1183 } 1184 int n = colors.length - 1; 1185 for (int i = 0; i < n; i++) { 1186 g2.setPaint(new GradientPaint(x + (horizontal ? (i*w/n) : 0), 1187 y + (vertical ? (i*h/n) : 0), 1188 colors[i], 1189 x + (horizontal ? ((i+1)*w/n) : 0), 1190 y + (vertical ? ((i+1)*h/n) : 0), 1191 colors[i+1])); 1192 g2.fillRect(x + (horizontal ? (i*w/n) : 0), 1193 y + (vertical ? (i*h/n) : 0), 1194 (horizontal ? (w/n) : w), 1195 (vertical ? (h/n) : h)); 1196 } 1197 g2.setComposite(oldComp); 1198 } 1199 } 1200 1201 protected void drawImage(Node node, Graphics g) { 1202 NamedNodeMap attrs = node.getAttributes(); 1203 String filename = getStringAttr(attrs, "filename"); 1204 String colorizeStr = getStringAttr(attrs, "colorize"); 1205 Color colorize = (colorizeStr != null) ? parseColor(colorizeStr) : null; 1206 String alpha = getStringAttr(attrs, "alpha"); 1207 Image object = (colorize != null) ? getImage(filename, colorize) : getImage(filename); 1208 variables.put("object_width", object.getWidth(null)); 1209 variables.put("object_height", object.getHeight(null)); 1210 String fill_type = getStringAttr(attrs, "fill_type"); 1211 int x = aee.evaluate(getStringAttr(attrs, "x")); 1212 int y = aee.evaluate(getStringAttr(attrs, "y")); 1213 int w = aee.evaluate(getStringAttr(attrs, "width")); 1214 int h = aee.evaluate(getStringAttr(attrs, "height")); 1215 if (getInt("width") == -1) { 1216 x -= w; 1217 } 1218 if (getInt("height") == -1) { 1219 y -= h; 1220 } 1221 1222 if (alpha != null) { 1223 if ("tile".equals(fill_type)) { 1224 StringTokenizer tokenizer = new StringTokenizer(alpha, ":"); 1225 float[] alphas = new float[tokenizer.countTokens()]; 1226 for (int i = 0; i < alphas.length; i++) { 1227 alphas[i] = Float.parseFloat(tokenizer.nextToken()); 1228 } 1229 tileImage(g, object, x, y, w, h, alphas); 1230 } else { 1231 float a = Float.parseFloat(alpha); 1232 if (g instanceof Graphics2D) { 1233 Graphics2D g2 = (Graphics2D)g; 1234 Composite oldComp = g2.getComposite(); 1235 g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, a)); 1236 g2.drawImage(object, x, y, w, h, null); 1237 g2.setComposite(oldComp); 1238 } 1239 } 1240 } else { 1241 g.drawImage(object, x, y, w, h, null); 1242 } 1243 } 1244 1245 protected void drawIcon(Node node, Graphics g, JInternalFrame jif) { 1246 Icon icon = jif.getFrameIcon(); 1247 if (icon == null) { 1248 return; 1249 } 1250 1251 NamedNodeMap attrs = node.getAttributes(); 1252 String alpha = getStringAttr(attrs, "alpha"); 1253 int x = aee.evaluate(getStringAttr(attrs, "x")); 1254 int y = aee.evaluate(getStringAttr(attrs, "y")); 1255 int w = aee.evaluate(getStringAttr(attrs, "width")); 1256 int h = aee.evaluate(getStringAttr(attrs, "height")); 1257 if (getInt("width") == -1) { 1258 x -= w; 1259 } 1260 if (getInt("height") == -1) { 1261 y -= h; 1262 } 1263 1264 if (alpha != null) { 1265 float a = Float.parseFloat(alpha); 1266 if (g instanceof Graphics2D) { 1267 Graphics2D g2 = (Graphics2D)g; 1268 Composite oldComp = g2.getComposite(); 1269 g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, a)); 1270 icon.paintIcon(jif, g, x, y); 1271 g2.setComposite(oldComp); 1272 } 1273 } else { 1274 icon.paintIcon(jif, g, x, y); 1275 } 1276 } 1277 1278 protected void drawInclude(Node node, Graphics g, JInternalFrame jif) { 1279 int oldWidth = getInt("width"); 1280 int oldHeight = getInt("height"); 1281 1282 NamedNodeMap attrs = node.getAttributes(); 1283 int x = aee.evaluate(getStringAttr(attrs, "x"), 0); 1284 int y = aee.evaluate(getStringAttr(attrs, "y"), 0); 1285 int w = aee.evaluate(getStringAttr(attrs, "width"), -1); 1286 int h = aee.evaluate(getStringAttr(attrs, "height"), -1); 1287 1288 if (w != -1) { 1289 variables.put("width", w); 1290 } 1291 if (h != -1) { 1292 variables.put("height", h); 1293 } 1294 1295 Node draw_ops = getNode("draw_ops", new String [] { 1296 "name", getStringAttr(node, "name") 1297 }); 1298 g.translate(x, y); 1299 draw(draw_ops, g, jif); 1300 g.translate(-x, -y); 1301 1302 if (w != -1) { 1303 variables.put("width", oldWidth); 1304 } 1305 if (h != -1) { 1306 variables.put("height", oldHeight); 1307 } 1308 } 1309 1310 protected void draw(Node draw_ops, Graphics g, JInternalFrame jif) { 1311 if (draw_ops != null) { 1312 NodeList nodes = draw_ops.getChildNodes(); 1313 if (nodes != null) { 1314 Shape oldClip = g.getClip(); 1315 for (int i = 0; i < nodes.getLength(); i++) { 1316 Node child = nodes.item(i); 1317 if (child.getNodeType() == Node.ELEMENT_NODE) { 1318 try { 1319 String name = child.getNodeName(); 1320 if ("include".equals(name)) { 1321 drawInclude(child, g, jif); 1322 } else if ("arc".equals(name)) { 1323 drawArc(child, g); 1324 } else if ("clip".equals(name)) { 1325 setClip(child, g); 1326 } else if ("gradient".equals(name)) { 1327 drawGradient(child, g); 1328 } else if ("gtk_arrow".equals(name)) { 1329 drawGTKArrow(child, g); 1330 } else if ("gtk_box".equals(name)) { 1331 drawGTKBox(child, g); 1332 } else if ("gtk_vline".equals(name)) { 1333 drawGTKVLine(child, g); 1334 } else if ("image".equals(name)) { 1335 drawImage(child, g); 1336 } else if ("icon".equals(name)) { 1337 drawIcon(child, g, jif); 1338 } else if ("line".equals(name)) { 1339 drawLine(child, g); 1340 } else if ("rectangle".equals(name)) { 1341 drawRectangle(child, g); 1342 } else if ("tint".equals(name)) { 1343 drawTint(child, g); 1344 } else if ("tile".equals(name)) { 1345 drawTile(child, g, jif); 1346 } else if ("title".equals(name)) { 1347 drawTitle(child, g, jif); 1348 } else { 1349 System.err.println("Unknown Metacity drawing op: "+child); 1350 } 1351 } catch (NumberFormatException ex) { 1352 logError(themeName, ex); 1353 } 1354 } 1355 } 1356 g.setClip(oldClip); 1357 } 1358 } 1359 } 1360 1361 protected void drawPiece(Node frame_style, Graphics g, String position, int x, int y, 1362 int width, int height, JInternalFrame jif) { 1363 Node piece = getNode(frame_style, "piece", new String [] { "position", position }); 1364 if (piece != null) { 1365 Node draw_ops; 1366 String draw_ops_name = getStringAttr(piece, "draw_ops"); 1367 if (draw_ops_name != null) { 1368 draw_ops = getNode("draw_ops", new String [] { "name", draw_ops_name }); 1369 } else { 1370 draw_ops = getNode(piece, "draw_ops", null); 1371 } 1372 variables.put("width", width); 1373 variables.put("height", height); 1374 g.translate(x, y); 1375 draw(draw_ops, g, jif); 1376 g.translate(-x, -y); 1377 } 1378 } 1379 1380 1381 Insets getBorderInsets(SynthContext context, Insets insets) { 1382 if (insets == null) { 1383 insets = new Insets(0, 0, 0, 0); 1384 } 1385 insets.top = ((Insets)frameGeometry.get("title_border")).top; 1386 insets.bottom = getInt("bottom_height"); 1387 insets.left = getInt("left_width"); 1388 insets.right = getInt("right_width"); 1389 return insets; 1390 } 1391 1392 1393 protected static void logError(String themeName, Exception ex) { 1394 logError(themeName, ex.toString()); 1395 } 1396 1397 protected static void logError(String themeName, String msg) { 1398 if (!errorLogged) { 1399 System.err.println("Exception in Metacity for theme \""+themeName+"\": "+msg); 1400 errorLogged = true; 1401 } 1402 } 1403 1404 1405 1407 1408 protected static Document getXMLDoc(final URL xmlFile) 1409 throws IOException, 1410 ParserConfigurationException, 1411 SAXException { 1412 if (documentBuilder == null) { 1413 documentBuilder = 1414 DocumentBuilderFactory.newInstance().newDocumentBuilder(); 1415 } 1416 InputStream inputStream = 1417 (InputStream)AccessController.doPrivileged(new PrivilegedAction() { 1418 public Object run() { 1419 try { 1420 return new BufferedInputStream(xmlFile.openStream()); 1421 } catch (IOException ex) { 1422 return null; 1423 } 1424 } 1425 }); 1426 1427 Document doc = null; 1428 if (inputStream != null) { 1429 doc = documentBuilder.parse(inputStream); 1430 } 1431 return doc; 1432 } 1433 1434 1435 protected Node[] getNodesByName(Node parent, String name) { 1436 NodeList nodes = parent.getChildNodes(); int n = nodes.getLength(); 1438 ArrayList<Node> list = new ArrayList(); 1439 for (int i=0; i < n; i++) { 1440 Node node = nodes.item(i); 1441 if (name.equals(node.getNodeName())) { 1442 list.add(node); 1443 } 1444 } 1445 return list.toArray(new Node[list.size()]); 1446 } 1447 1448 1449 1450 protected Node getNode(String tagName, String [] attrs) { 1451 NodeList nodes = xmlDoc.getElementsByTagName(tagName); 1452 return (nodes != null) ? getNode(nodes, tagName, attrs) : null; 1453 } 1454 1455 protected Node getNode(Node parent, String name, String [] attrs) { 1456 Node node = null; 1457 NodeList nodes = parent.getChildNodes(); 1458 if (nodes != null) { 1459 node = getNode(nodes, name, attrs); 1460 } 1461 if (node == null) { 1462 String inheritFrom = getStringAttr(parent, "parent"); 1463 if (inheritFrom != null) { 1464 Node inheritFromNode = getNode(parent.getParentNode(), 1465 parent.getNodeName(), 1466 new String [] { "name", inheritFrom }); 1467 if (inheritFromNode != null) { 1468 node = getNode(inheritFromNode, name, attrs); 1469 } 1470 } 1471 } 1472 return node; 1473 } 1474 1475 protected Node getNode(NodeList nodes, String name, String [] attrs) { 1476 int n = nodes.getLength(); 1477 for (int i=0; i < n; i++) { 1478 Node node = nodes.item(i); 1479 if (name.equals(node.getNodeName())) { 1480 if (attrs != null) { 1481 NamedNodeMap nodeAttrs = node.getAttributes(); 1482 if (nodeAttrs != null) { 1483 boolean matches = true; 1484 int nAttrs = attrs.length / 2; 1485 for (int a = 0; a < nAttrs; a++) { 1486 String aName = attrs[a * 2]; 1487 String aValue = attrs[a * 2 + 1]; 1488 Node attr = nodeAttrs.getNamedItem(aName); 1489 if (attr == null || !aValue.equals((String )attr.getNodeValue())) { 1490 matches = false; 1491 break; 1492 } 1493 } 1494 if (matches) { 1495 return node; 1496 } 1497 } 1498 } else { 1499 return node; 1500 } 1501 } 1502 } 1503 return null; 1504 } 1505 1506 protected String getStringAttr(Node node, String name) { 1507 String value = null; 1508 NamedNodeMap attrs = node.getAttributes(); 1509 if (attrs != null) { 1510 value = getStringAttr(attrs, name); 1511 if (value == null) { 1512 String inheritFrom = getStringAttr(attrs, "parent"); 1513 if (inheritFrom != null) { 1514 Node inheritFromNode = getNode(node.getParentNode(), 1515 node.getNodeName(), 1516 new String [] { "name", inheritFrom }); 1517 if (inheritFromNode != null) { 1518 value = getStringAttr(inheritFromNode, name); 1519 } 1520 } 1521 } 1522 } 1523 return value; 1524 } 1525 1526 protected String getStringAttr(NamedNodeMap attrs, String name) { 1527 Node item = attrs.getNamedItem(name); 1528 return (item != null) ? (String )item.getNodeValue() : null; 1529 } 1530 1531 protected boolean getBooleanAttr(Node node, String name, boolean fallback) { 1532 String str = getStringAttr(node, name); 1533 if (str != null) { 1534 return Boolean.valueOf(str).booleanValue(); 1535 } 1536 return fallback; 1537 } 1538 1539 protected int getIntAttr(Node node, String name, int fallback) { 1540 String str = getStringAttr(node, name); 1541 int value = fallback; 1542 if (str != null) { 1543 try { 1544 value = Integer.parseInt(str); 1545 } catch (NumberFormatException ex) { 1546 logError(themeName, ex); 1547 } 1548 } 1549 return value; 1550 } 1551 1552 protected float getFloatAttr(Node node, String name, float fallback) { 1553 String str = getStringAttr(node, name); 1554 float value = fallback; 1555 if (str != null) { 1556 try { 1557 value = Float.parseFloat(str); 1558 } catch (NumberFormatException ex) { 1559 logError(themeName, ex); 1560 } 1561 } 1562 return value; 1563 } 1564 1565 1566 1567 protected Color parseColor(String str) { 1568 StringTokenizer tokenizer = new StringTokenizer(str, "/"); 1569 int n = tokenizer.countTokens(); 1570 if (n > 1) { 1571 String function = tokenizer.nextToken(); 1572 if ("shade".equals(function)) { 1573 assert (n == 3); 1574 Color c = parseColor2(tokenizer.nextToken()); 1575 float alpha = Float.parseFloat(tokenizer.nextToken()); 1576 return GTKColorType.adjustColor(c, 1.0F, alpha, alpha); 1577 } else if ("blend".equals(function)) { 1578 assert (n == 4); 1579 Color bg = parseColor2(tokenizer.nextToken()); 1580 Color fg = parseColor2(tokenizer.nextToken()); 1581 float alpha = Float.parseFloat(tokenizer.nextToken()); 1582 return new Color((int)(bg.getRed() + ((fg.getRed() - bg.getRed()) * alpha)), 1583 (int)(bg.getRed() + ((fg.getRed() - bg.getRed()) * alpha)), 1584 (int)(bg.getRed() + ((fg.getRed() - bg.getRed()) * alpha))); 1585 } else { 1586 System.err.println("Unknown Metacity color function="+str); 1587 return null; 1588 } 1589 } else { 1590 return parseColor2(str); 1591 } 1592 } 1593 1594 protected Color parseColor2(String str) { 1595 Color c = null; 1596 if (str.startsWith("gtk:")) { 1597 int i1 = str.indexOf('['); 1598 if (i1 > 3) { 1599 String typeStr = str.substring(4, i1).toLowerCase(); 1600 int i2 = str.indexOf(']'); 1601 if (i2 > i1+1) { 1602 String stateStr = str.substring(i1+1, i2).toUpperCase(); 1603 int state = -1; 1604 if ("ACTIVE".equals(stateStr)) { 1605 state = PRESSED; 1606 } else if ("INSENSITIVE".equals(stateStr)) { 1607 state = DISABLED; 1608 } else if ("NORMAL".equals(stateStr)) { 1609 state = ENABLED; 1610 } else if ("PRELIGHT".equals(stateStr)) { 1611 state = MOUSE_OVER; 1612 } else if ("SELECTED".equals(stateStr)) { 1613 state = SELECTED; 1614 } 1615 ColorType type = null; 1616 if ("fg".equals(typeStr)) { 1617 type = GTKColorType.FOREGROUND; 1618 } else if ("bg".equals(typeStr)) { 1619 type = GTKColorType.BACKGROUND; 1620 } else if ("base".equals(typeStr)) { 1621 type = GTKColorType.TEXT_BACKGROUND; 1622 } else if ("text".equals(typeStr)) { 1623 type = GTKColorType.TEXT_FOREGROUND; 1624 } else if ("dark".equals(typeStr)) { 1625 type = GTKColorType.DARK; 1626 } else if ("light".equals(typeStr)) { 1627 type = GTKColorType.LIGHT; 1628 } 1629 if (state >= 0 && type != null) { 1630 c = ((GTKStyle)context.getStyle()).getGTKColor(context.getComponent(), 1631 context.getRegion(), 1632 state, type); 1633 } 1634 } 1635 } 1636 } 1637 if (c == null) { 1638 c = GTKParser.parseColorString(str); 1639 } 1640 return c; 1641 } 1642 1643 class ArithmeticExpressionEvaluator { 1644 private PeekableStringTokenizer tokenizer; 1645 1646 int evaluate(String expr) { 1647 tokenizer = new PeekableStringTokenizer(expr, " \t+-*/%()", true); 1648 return Math.round(expression()); 1649 } 1650 1651 int evaluate(String expr, int fallback) { 1652 return (expr != null) ? evaluate(expr) : fallback; 1653 } 1654 1655 public float expression() { 1656 float value = getTermValue(); 1657 boolean done = false; 1658 while (!done && tokenizer.hasMoreTokens()) { 1659 String next = tokenizer.peek(); 1660 if ("+".equals(next) || 1661 "-".equals(next) || 1662 "`max`".equals(next) || 1663 "`min`".equals(next)) { 1664 tokenizer.nextToken(); 1665 float value2 = getTermValue(); 1666 if ("+".equals(next)) { 1667 value += value2; 1668 } else if ("-".equals(next)) { 1669 value -= value2; 1670 } else if ("`max`".equals(next)) { 1671 value = Math.max(value, value2); 1672 } else if ("`min`".equals(next)) { 1673 value = Math.min(value, value2); 1674 } 1675 } else { 1676 done = true; 1677 } 1678 } 1679 return value; 1680 } 1681 1682 public float getTermValue() { 1683 float value = getFactorValue(); 1684 boolean done = false; 1685 while (!done && tokenizer.hasMoreTokens()) { 1686 String next = tokenizer.peek(); 1687 if ("*".equals(next) || "/".equals(next) || "%".equals(next)) { 1688 tokenizer.nextToken(); 1689 float value2 = getFactorValue(); 1690 if ("*".equals(next)) { 1691 value *= value2; 1692 } else if ("/".equals(next)) { 1693 value /= value2; 1694 } else { 1695 value %= value2; 1696 } 1697 } else { 1698 done = true; 1699 } 1700 } 1701 return value; 1702 } 1703 1704 public float getFactorValue() { 1705 float value; 1706 if ("(".equals(tokenizer.peek())) { 1707 tokenizer.nextToken(); 1708 value = expression(); 1709 tokenizer.nextToken(); } else { 1711 String token = tokenizer.nextToken(); 1712 if (Character.isDigit(token.charAt(0))) { 1713 value = Float.parseFloat(token); 1714 } else { 1715 Integer i = variables.get(token); 1716 if (i == null) { 1717 i = (Integer )getFrameGeometry().get(token); 1718 } 1719 if (i == null) { 1720 logError(themeName, "Variable \"" + token + "\" not defined"); 1721 return 0; 1722 } 1723 value = (i != null) ? i.intValue() : 0F; 1724 } 1725 } 1726 return value; 1727 } 1728 1729 1730 } 1731 1732 static class PeekableStringTokenizer extends StringTokenizer { 1733 String token = null; 1734 1735 public PeekableStringTokenizer(String str, String delim, 1736 boolean returnDelims) { 1737 super(str, delim, returnDelims); 1738 peek(); 1739 } 1740 1741 public String peek() { 1742 if (token == null) { 1743 token = nextToken(); 1744 } 1745 return token; 1746 } 1747 1748 public boolean hasMoreTokens() { 1749 return (token != null || super.hasMoreTokens()); 1750 } 1751 1752 public String nextToken() { 1753 if (token != null) { 1754 String t = token; 1755 token = null; 1756 if (hasMoreTokens()) { 1757 peek(); 1758 } 1759 return t; 1760 } else { 1761 String token = super.nextToken(); 1762 while ((token.equals(" ") || token.equals("\t")) 1763 && hasMoreTokens()) { 1764 token = super.nextToken(); 1765 } 1766 return token; 1767 } 1768 } 1769 } 1770 1771 1772 static class RoundRectClipShape extends RectangularShape { 1773 static final int TOP_LEFT = 1; 1774 static final int TOP_RIGHT = 2; 1775 static final int BOTTOM_LEFT = 4; 1776 static final int BOTTOM_RIGHT = 8; 1777 1778 int x; 1779 int y; 1780 int width; 1781 int height; 1782 int arcwidth; 1783 int archeight; 1784 int corners; 1785 1786 public RoundRectClipShape() { 1787 } 1788 1789 public RoundRectClipShape(int x, int y, int w, int h, 1790 int arcw, int arch, int corners) { 1791 setRoundedRect(x, y, w, h, arcw, arch, corners); 1792 } 1793 1794 public void setRoundedRect(int x, int y, int w, int h, 1795 int arcw, int arch, int corners) { 1796 this.corners = corners; 1797 this.x = x; 1798 this.y = y; 1799 this.width = w; 1800 this.height = h; 1801 this.arcwidth = arcw; 1802 this.archeight = arch; 1803 } 1804 1805 public double getX() { 1806 return (double)x; 1807 } 1808 1809 public double getY() { 1810 return (double)y; 1811 } 1812 1813 public double getWidth() { 1814 return (double)width; 1815 } 1816 1817 public double getHeight() { 1818 return (double)height; 1819 } 1820 1821 public double getArcWidth() { 1822 return (double)arcwidth; 1823 } 1824 1825 public double getArcHeight() { 1826 return (double)archeight; 1827 } 1828 1829 public boolean isEmpty() { 1830 return false; } 1832 1833 public Rectangle2D getBounds2D() { 1834 return null; } 1836 1837 public int getCornerFlags() { 1838 return corners; 1839 } 1840 1841 public void setFrame(double x, double y, double w, double h) { 1842 } 1844 1845 public boolean contains(double x, double y) { 1846 return false; } 1848 1849 private int classify(double coord, double left, double right, double arcsize) { 1850 return 0; } 1852 1853 public boolean intersects(double x, double y, double w, double h) { 1854 return false; } 1856 1857 public boolean contains(double x, double y, double w, double h) { 1858 return false; } 1860 1861 public PathIterator getPathIterator(AffineTransform at) { 1862 return new RoundishRectIterator(this, at); 1863 } 1864 1865 1866 static class RoundishRectIterator implements PathIterator { 1867 double x, y, w, h, aw, ah; 1868 AffineTransform affine; 1869 int index; 1870 1871 double ctrlpts[][]; 1872 int types[]; 1873 1874 private static final double angle = Math.PI / 4.0; 1875 private static final double a = 1.0 - Math.cos(angle); 1876 private static final double b = Math.tan(angle); 1877 private static final double c = Math.sqrt(1.0 + b * b) - 1 + a; 1878 private static final double cv = 4.0 / 3.0 * a * b / c; 1879 private static final double acv = (1.0 - cv) / 2.0; 1880 1881 private static final double CtrlPtTemplate[][] = { 1886 { 0.0, 0.0, 1.0, 0.0 }, 1887 { 0.0, 0.0, 1.0, -0.5 }, 1888 { 0.0, 0.0, 1.0, -acv, 1889 0.0, acv, 1.0, 0.0, 1890 0.0, 0.5, 1.0, 0.0 }, 1891 { 1.0, 0.0, 1.0, 0.0 }, 1892 { 1.0, -0.5, 1.0, 0.0 }, 1893 { 1.0, -acv, 1.0, 0.0, 1894 1.0, 0.0, 1.0, -acv, 1895 1.0, 0.0, 1.0, -0.5 }, 1896 { 1.0, 0.0, 0.0, 0.0 }, 1897 { 1.0, 0.0, 0.0, 0.5 }, 1898 { 1.0, 0.0, 0.0, acv, 1899 1.0, -acv, 0.0, 0.0, 1900 1.0, -0.5, 0.0, 0.0 }, 1901 { 0.0, 0.0, 0.0, 0.0 }, 1902 { 0.0, 0.5, 0.0, 0.0 }, 1903 { 0.0, acv, 0.0, 0.0, 1904 0.0, 0.0, 0.0, acv, 1905 0.0, 0.0, 0.0, 0.5 }, 1906 {}, 1907 }; 1908 private static final int CornerFlags[] = { 1909 RoundRectClipShape.BOTTOM_LEFT, 1910 RoundRectClipShape.BOTTOM_RIGHT, 1911 RoundRectClipShape.TOP_RIGHT, 1912 RoundRectClipShape.TOP_LEFT, 1913 }; 1914 1915 RoundishRectIterator(RoundRectClipShape rr, AffineTransform at) { 1916 this.x = rr.getX(); 1917 this.y = rr.getY(); 1918 this.w = rr.getWidth(); 1919 this.h = rr.getHeight(); 1920 this.aw = Math.min(w, Math.abs(rr.getArcWidth())); 1921 this.ah = Math.min(h, Math.abs(rr.getArcHeight())); 1922 this.affine = at; 1923 if (w < 0 || h < 0) { 1924 ctrlpts = new double[0][]; 1926 types = new int[0]; 1927 } else { 1928 int corners = rr.getCornerFlags(); 1929 int numedges = 5; for (int i = 1; i < 0x10; i <<= 1) { 1931 if ((corners & i) != 0) numedges++; 1933 } 1934 ctrlpts = new double[numedges][]; 1935 types = new int[numedges]; 1936 int j = 0; 1937 for (int i = 0; i < 4; i++) { 1938 types[j] = SEG_LINETO; 1939 if ((corners & CornerFlags[i]) == 0) { 1940 ctrlpts[j++] = CtrlPtTemplate[i*3+0]; 1941 } else { 1942 ctrlpts[j++] = CtrlPtTemplate[i*3+1]; 1943 types[j] = SEG_CUBICTO; 1944 ctrlpts[j++] = CtrlPtTemplate[i*3+2]; 1945 } 1946 } 1947 types[j] = SEG_CLOSE; 1948 ctrlpts[j++] = CtrlPtTemplate[12]; 1949 types[0] = SEG_MOVETO; 1950 } 1951 } 1952 1953 public int getWindingRule() { 1954 return WIND_NON_ZERO; 1955 } 1956 1957 public boolean isDone() { 1958 return index >= ctrlpts.length; 1959 } 1960 1961 public void next() { 1962 index++; 1963 } 1964 1965 public int currentSegment(float[] coords) { 1966 if (isDone()) { 1967 throw new NoSuchElementException("roundrect iterator out of bounds"); 1968 } 1969 double ctrls[] = ctrlpts[index]; 1970 int nc = 0; 1971 for (int i = 0; i < ctrls.length; i += 4) { 1972 coords[nc++] = (float) (x + ctrls[i + 0] * w + ctrls[i + 1] * aw); 1973 coords[nc++] = (float) (y + ctrls[i + 2] * h + ctrls[i + 3] * ah); 1974 } 1975 if (affine != null) { 1976 affine.transform(coords, 0, coords, 0, nc / 2); 1977 } 1978 return types[index]; 1979 } 1980 1981 public int currentSegment(double[] coords) { 1982 return 0; } 1984 } 1985 } 1986} 1987 1988 | Popular Tags |