KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > java > swing > plaf > gtk > Metacity


1 /*
2  * @(#)Metacity.java 1.23 04/08/31
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

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 JavaDoc;
26 import org.w3c.dom.*;
27
28 /**
29  * @version 1.23, 08/31/04
30  */

31 class Metacity implements SynthConstants {
32     // Tutorial:
33
// http://developer.gnome.org/doc/tutorials/metacity/metacity-themes.html
34

35     // Themes:
36
// http://art.gnome.org/theme_list.php?category=metacity
37

38     static Metacity INSTANCE;
39
40     private static final String JavaDoc[] themeNames = {
41     getUserTheme(),
42         "blueprint",
43     "Bluecurve",
44     "Crux",
45     "SwingFallbackTheme"
46     };
47
48
49     static {
50     for (String JavaDoc 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 JavaDoc ex) {
60             logError(themeName, ex);
61         }
62         }
63         if (INSTANCE != null) {
64         break;
65         }
66     }
67     if (INSTANCE == null) {
68         throw new Error JavaDoc("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 JavaDoc userHome;
76
77     private Node frame_style_set;
78     private Map<String JavaDoc, Object JavaDoc> frameGeometry;
79     private Map<String JavaDoc, Map<String JavaDoc, Object JavaDoc>> 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 JavaDoc themeName;
87
88     private ArithmeticExpressionEvaluator aee = new ArithmeticExpressionEvaluator();
89     private Map<String JavaDoc, Integer JavaDoc> variables;
90
91     // Reusable clip shape object
92
private RoundRectClipShape roundedClipShape;
93
94     protected Metacity(String JavaDoc themeName) throws IOException, ParserConfigurationException, SAXException JavaDoc {
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     // Initialize constants
108
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 JavaDoc name = getStringAttr(node, "name");
114         if (name != null) {
115         String JavaDoc value = getStringAttr(node, "value");
116         if (value != null) {
117             try {
118             variables.put(name, Integer.parseInt(value));
119             } catch (NumberFormatException JavaDoc ex) {
120             logError(themeName, ex);
121             // Ignore bad value
122
}
123         }
124         }
125     }
126
127     // Cache frame geometries
128
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 JavaDoc name = getStringAttr(node, "name");
134         if (name != null) {
135         HashMap<String JavaDoc, Object JavaDoc> gm = new HashMap();
136         frameGeometries.put(name, gm);
137
138         String JavaDoc 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 JavaDoc value = null;
161             if ("distance".equals(name)) {
162                 value = new Integer JavaDoc(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 JavaDoc(getFloatAttr(child, "value", 1.0F));
170             } else {
171                 logError(themeName, "Unknown Metacity frame geometry value type: "+name);
172             }
173             String JavaDoc 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 JavaDoc 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 JavaDoc state = "normal";
221     if ((buttonState & PRESSED) != 0) {
222         state = "pressed";
223     } else if ((buttonState & MOUSE_OVER) != 0) {
224         state = "prelight";
225     }
226
227     String JavaDoc function = null;
228     String JavaDoc 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 JavaDoc[] {
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 JavaDoc[] {
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 JavaDoc function, String JavaDoc state,
293                 Graphics g, int w, int h, JInternalFrame jif) {
294     Node buttonNode = getNode(frame_style, "button",
295                   new String JavaDoc[] { "function", function, "state", state });
296     if (buttonNode == null && !state.equals("normal")) {
297         buttonNode = getNode(frame_style, "button",
298                  new String JavaDoc[] { "function", function, "state", "normal" });
299     }
300     if (buttonNode != null) {
301         Node draw_ops;
302         String JavaDoc draw_ops_name = getStringAttr(buttonNode, "draw_ops");
303         if (draw_ops_name != null) {
304         draw_ops = getNode("draw_ops", new String JavaDoc[] { "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     // These don't seem to apply here, but the Galaxy theme uses them. Not sure why.
350
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 JavaDoc[] { "name", "normal" });
356     }
357
358     if (frame_style_set != null) {
359         Node frame = getNode(frame_style_set, "frame", new String JavaDoc[] {
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 JavaDoc[] {
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 JavaDoc arg;
446
447     public Object JavaDoc doPrivileged(int type, Object JavaDoc arg) {
448         this.type = type;
449         this.arg = arg;
450         return AccessController.doPrivileged(this);
451     }
452
453     public Object JavaDoc run() {
454         if (type == GET_THEME_DIR) {
455         String JavaDoc sep = File.separator;
456         String JavaDoc[] dirs = new String JavaDoc[] {
457             userHome + sep + ".themes",
458             System.getProperty("swing.metacitythemedir"),
459             "/usr/share/themes",
460             "/usr/gnome/share/themes", // Debian/Redhat/Solaris
461
"/opt/gnome2/share/themes" // SuSE
462
};
463
464         URL themeDir = null;
465         for (int i = 0; i < dirs.length; i++) {
466                     // System property may not be set so skip null directories.
467
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 JavaDoc filename = "resources/metacity/" + arg +
483                         "/metacity-1/metacity-theme-1.xml";
484             URL url = getClass().getResource(filename);
485             if (url != null) {
486             String JavaDoc 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             // Set userHome here because we need the privilege
498
userHome = System.getProperty("user.home");
499
500             String JavaDoc theme = System.getProperty("swing.metacitythemename");
501             if (theme != null) {
502             return theme;
503             }
504             // Note: this is a small file (< 1024 bytes) so it's not worth
505
// starting an XML parser or even to use a buffered reader.
506
URL url = new URL(new File(userHome).toURL(),
507                       ".gconf/apps/metacity/general/%25gconf.xml");
508             // Pending: verify character encoding spec for gconf
509
Reader reader = new InputStreamReader(url.openStream(), "ISO-8859-1");
510             char[] buf = new char[1024];
511             StringBuffer JavaDoc strBuf = new StringBuffer JavaDoc();
512             int n;
513             while ((n = reader.read(buf)) >= 0) {
514             strBuf.append(buf, 0, n);
515             }
516             reader.close();
517             String JavaDoc str = strBuf.toString();
518             if (str != null) {
519             String JavaDoc 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             // OK to just ignore. We'll use a fallback theme.
532
} catch (IOException ex) {
533             // OK to just ignore. We'll use a fallback theme.
534
}
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 JavaDoc themeName) {
545     return (URL)new Privileged().doPrivileged(Privileged.GET_THEME_DIR, themeName);
546     }
547
548     private static String JavaDoc getUserTheme() {
549     return (String JavaDoc)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 JavaDoc, Image> images = new HashMap();
581
582     protected Image getImage(String JavaDoc 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 JavaDoc 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             //log("Bad image url: "+ themeDir + "/" + key);
602
}
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         // Assume all rgb values are shades of gray
632
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 JavaDoc 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 JavaDoc 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             // Calculate width.
689
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 JavaDoc 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             // Leave room for three characters in the title.
709
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             // Calculate height.
718
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     } // end TitlePaneLayout
782

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 JavaDoc(titlePane.getHeight()));
791     }
792     }
793
794     protected int getInt(String JavaDoc key) {
795     Integer JavaDoc i = (Integer JavaDoc)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 JavaDoc key, boolean fallback) {
803     Boolean JavaDoc b = (Boolean JavaDoc)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 JavaDoc[] { "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 JavaDoc 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 JavaDoc 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 JavaDoc aspect_ratio = (Float JavaDoc)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 JavaDoc 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 JavaDoc arrow = getStringAttr(attrs, "arrow");
1050    String JavaDoc shadow = getStringAttr(attrs, "shadow");
1051    String JavaDoc 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 JavaDoc shadow = getStringAttr(attrs, "shadow");
1098    String JavaDoc 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 JavaDoc 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 JavaDoc 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    // Get colors from child nodes
1169
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 JavaDoc filename = getStringAttr(attrs, "filename");
1204    String JavaDoc colorizeStr = getStringAttr(attrs, "colorize");
1205    Color colorize = (colorizeStr != null) ? parseColor(colorizeStr) : null;
1206    String JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc[] {
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 JavaDoc 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 JavaDoc 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 JavaDoc position, int x, int y,
1362                 int width, int height, JInternalFrame jif) {
1363    Node piece = getNode(frame_style, "piece", new String JavaDoc[] { "position", position });
1364    if (piece != null) {
1365        Node draw_ops;
1366        String JavaDoc draw_ops_name = getStringAttr(piece, "draw_ops");
1367        if (draw_ops_name != null) {
1368        draw_ops = getNode("draw_ops", new String JavaDoc[] { "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 JavaDoc themeName, Exception JavaDoc ex) {
1394    logError(themeName, ex.toString());
1395    }
1396
1397    protected static void logError(String JavaDoc themeName, String JavaDoc msg) {
1398    if (!errorLogged) {
1399        System.err.println("Exception in Metacity for theme \""+themeName+"\": "+msg);
1400        errorLogged = true;
1401    }
1402    }
1403
1404
1405    // XML Parsing
1406

1407
1408    protected static Document getXMLDoc(final URL xmlFile)
1409                throws IOException,
1410                                       ParserConfigurationException,
1411                                       SAXException JavaDoc {
1412    if (documentBuilder == null) {
1413        documentBuilder =
1414                DocumentBuilderFactory.newInstance().newDocumentBuilder();
1415    }
1416    InputStream inputStream =
1417            (InputStream)AccessController.doPrivileged(new PrivilegedAction() {
1418                public Object JavaDoc 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 JavaDoc name) {
1436    NodeList nodes = parent.getChildNodes(); // ElementNode
1437
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 JavaDoc tagName, String JavaDoc[] 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 JavaDoc name, String JavaDoc[] 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 JavaDoc inheritFrom = getStringAttr(parent, "parent");
1463        if (inheritFrom != null) {
1464        Node inheritFromNode = getNode(parent.getParentNode(),
1465                           parent.getNodeName(),
1466                           new String JavaDoc[] { "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 JavaDoc name, String JavaDoc[] 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 JavaDoc aName = attrs[a * 2];
1487                String JavaDoc aValue = attrs[a * 2 + 1];
1488                Node attr = nodeAttrs.getNamedItem(aName);
1489                if (attr == null || !aValue.equals((String JavaDoc)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 JavaDoc getStringAttr(Node node, String JavaDoc name) {
1507    String JavaDoc value = null;
1508    NamedNodeMap attrs = node.getAttributes();
1509    if (attrs != null) {
1510        value = getStringAttr(attrs, name);
1511        if (value == null) {
1512        String JavaDoc inheritFrom = getStringAttr(attrs, "parent");
1513        if (inheritFrom != null) {
1514            Node inheritFromNode = getNode(node.getParentNode(),
1515                           node.getNodeName(),
1516                           new String JavaDoc[] { "name", inheritFrom });
1517            if (inheritFromNode != null) {
1518            value = getStringAttr(inheritFromNode, name);
1519            }
1520        }
1521        }
1522    }
1523    return value;
1524    }
1525
1526    protected String JavaDoc getStringAttr(NamedNodeMap attrs, String JavaDoc name) {
1527    Node item = attrs.getNamedItem(name);
1528    return (item != null) ? (String JavaDoc)item.getNodeValue() : null;
1529    }
1530
1531    protected boolean getBooleanAttr(Node node, String JavaDoc name, boolean fallback) {
1532    String JavaDoc 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 JavaDoc name, int fallback) {
1540    String JavaDoc str = getStringAttr(node, name);
1541    int value = fallback;
1542    if (str != null) {
1543        try {
1544        value = Integer.parseInt(str);
1545        } catch (NumberFormatException JavaDoc ex) {
1546        logError(themeName, ex);
1547        }
1548    }
1549    return value;
1550    }
1551
1552    protected float getFloatAttr(Node node, String JavaDoc name, float fallback) {
1553    String JavaDoc str = getStringAttr(node, name);
1554    float value = fallback;
1555    if (str != null) {
1556        try {
1557        value = Float.parseFloat(str);
1558        } catch (NumberFormatException JavaDoc ex) {
1559        logError(themeName, ex);
1560        }
1561    }
1562    return value;
1563    }
1564
1565
1566
1567    protected Color parseColor(String JavaDoc str) {
1568    StringTokenizer tokenizer = new StringTokenizer(str, "/");
1569    int n = tokenizer.countTokens();
1570    if (n > 1) {
1571        String JavaDoc 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 JavaDoc str) {
1595    Color c = null;
1596    if (str.startsWith("gtk:")) {
1597        int i1 = str.indexOf('[');
1598        if (i1 > 3) {
1599        String JavaDoc typeStr = str.substring(4, i1).toLowerCase();
1600        int i2 = str.indexOf(']');
1601        if (i2 > i1+1) {
1602            String JavaDoc 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 JavaDoc expr) {
1647        tokenizer = new PeekableStringTokenizer(expr, " \t+-*/%()", true);
1648        return Math.round(expression());
1649    }
1650
1651    int evaluate(String JavaDoc 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 JavaDoc 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 JavaDoc 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(); // skip right paren
1710
} else {
1711        String JavaDoc token = tokenizer.nextToken();
1712        if (Character.isDigit(token.charAt(0))) {
1713            value = Float.parseFloat(token);
1714        } else {
1715            Integer JavaDoc i = variables.get(token);
1716            if (i == null) {
1717            i = (Integer JavaDoc)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 JavaDoc token = null;
1734
1735    public PeekableStringTokenizer(String JavaDoc str, String JavaDoc delim,
1736                       boolean returnDelims) {
1737        super(str, delim, returnDelims);
1738        peek();
1739    }
1740
1741    public String JavaDoc 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 JavaDoc nextToken() {
1753        if (token != null) {
1754        String JavaDoc t = token;
1755        token = null;
1756        if (hasMoreTokens()) {
1757            peek();
1758        }
1759        return t;
1760        } else {
1761        String JavaDoc 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; // Not called
1831
}
1832
1833    public Rectangle2D getBounds2D() {
1834        return null; // Not called
1835
}
1836
1837    public int getCornerFlags() {
1838        return corners;
1839    }
1840
1841    public void setFrame(double x, double y, double w, double h) {
1842        // Not called
1843
}
1844
1845    public boolean contains(double x, double y) {
1846        return false; // Not called
1847
}
1848
1849    private int classify(double coord, double left, double right, double arcsize) {
1850        return 0; // Not called
1851
}
1852
1853    public boolean intersects(double x, double y, double w, double h) {
1854        return false; // Not called
1855
}
1856
1857    public boolean contains(double x, double y, double w, double h) {
1858        return false; // Not called
1859
}
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        // For each array:
1882
// 4 values for each point {v0, v1, v2, v3}:
1883
// point = (x + v0 * w + v1 * arcWidth,
1884
// y + v2 * h + v3 * arcHeight);
1885
private static final double CtrlPtTemplate[][] = {
1886        { 0.0, 0.0, 1.0, 0.0 }, /* BOTTOM LEFT corner */
1887        { 0.0, 0.0, 1.0, -0.5 }, /* BOTTOM LEFT arc start */
1888        { 0.0, 0.0, 1.0, -acv, /* BOTTOM LEFT arc curve */
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 }, /* BOTTOM RIGHT corner */
1892        { 1.0, -0.5, 1.0, 0.0 }, /* BOTTOM RIGHT arc start */
1893        { 1.0, -acv, 1.0, 0.0, /* BOTTOM RIGHT arc curve */
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 }, /* TOP RIGHT corner */
1897        { 1.0, 0.0, 0.0, 0.5 }, /* TOP RIGHT arc start */
1898        { 1.0, 0.0, 0.0, acv, /* TOP RIGHT arc curve */
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 }, /* TOP LEFT corner */
1902        { 0.0, 0.5, 0.0, 0.0 }, /* TOP LEFT arc start */
1903        { 0.0, acv, 0.0, 0.0, /* TOP LEFT arc curve */
1904           0.0, 0.0, 0.0, acv,
1905           0.0, 0.0, 0.0, 0.5 },
1906        {}, /* Closing path element */
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            // Don't draw anything...
1925
ctrlpts = new double[0][];
1926            types = new int[0];
1927        } else {
1928            int corners = rr.getCornerFlags();
1929            int numedges = 5; // 4xCORNER_POINT, CLOSE
1930
for (int i = 1; i < 0x10; i <<= 1) {
1931            // Add one for each corner that has a curve
1932
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; // Not called
1983
}
1984    }
1985    }
1986}
1987
1988
Popular Tags