View Javadoc
1   package org.opentrafficsim.editor.render;
2   
3   import java.awt.Color;
4   import java.awt.Component;
5   import java.awt.Graphics;
6   import java.awt.Image;
7   import java.awt.image.BufferedImage;
8   import java.io.IOException;
9   
10  import javax.imageio.ImageIO;
11  import javax.swing.Icon;
12  import javax.swing.ImageIcon;
13  import javax.swing.JTree;
14  import javax.swing.UIManager;
15  import javax.swing.border.EmptyBorder;
16  import javax.swing.border.LineBorder;
17  import javax.swing.tree.DefaultTreeCellRenderer;
18  
19  import org.opentrafficsim.base.Resource;
20  import org.opentrafficsim.editor.OtsEditor;
21  import org.opentrafficsim.editor.XsdTreeNode;
22  
23  /**
24   * Renderer for the nodes in the tree.
25   * <p>
26   * Copyright (c) 2023-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
27   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
28   * </p>
29   * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
30   */
31  public class XsdTreeCellRenderer extends DefaultTreeCellRenderer
32  {
33  
34      /** */
35      private static final long serialVersionUID = 20230221L;
36  
37      /** Number of pixels between icons when they are combined. */
38      private static final int ICON_MARGIN = 3;
39  
40      /** Editor. */
41      private final OtsEditor editor;
42  
43      /** Image for nodes with a consumer, typically an editor. */
44      private final Image consumer;
45  
46      /** Image for nodes with a description. */
47      private final Image description;
48  
49      /** Icon for option nodes, indicating a drop-down can be show. */
50      private final Image dropdown;
51  
52      /**
53       * Constructor. Loads icons.
54       * @param editor editor.
55       * @throws IOException if an icon could not be loaded from resources.
56       */
57      public XsdTreeCellRenderer(final OtsEditor editor) throws IOException
58      {
59          this.editor = editor;
60          this.consumer =
61                  ImageIO.read(Resource.getResourceAsStream("./Application.png")).getScaledInstance(12, 12, Image.SCALE_SMOOTH);
62          this.description =
63                  ImageIO.read(Resource.getResourceAsStream("./Info.png")).getScaledInstance(10, 10, Image.SCALE_SMOOTH);
64          this.dropdown = ImageIO.read(Resource.getResourceAsStream("./dropdown.png"));
65  
66          this.leafIcon = new ImageIcon(ImageIO.read(Resource.getResourceAsStream("/Eclipse_file.png")));
67          this.openIcon = new ImageIcon(ImageIO.read(Resource.getResourceAsStream("/Eclipse_folder_open.png")));
68          this.closedIcon = new ImageIcon(ImageIO.read(Resource.getResourceAsStream("/Eclipse_folder.png")));
69      }
70  
71      @Override
72      public Component getTreeCellRendererComponent(final JTree tree, final Object value, final boolean selected,
73              final boolean expanded, final boolean leaf, final int row, final boolean hasFocus)
74      {
75          super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
76          XsdTreeNode node = (XsdTreeNode) value;
77          Icon customIcon = this.editor.getCustomIcon(node.getPathString());
78          if (customIcon != null)
79          {
80              setIcon(customIcon);
81          }
82          if (node.hasConsumer())
83          {
84              preAppend(this.consumer, false);
85          }
86          if (node.getDescription() != null)
87          {
88              preAppend(this.description, false);
89          }
90          if (node.isChoice() && !node.isInclude())
91          {
92              preAppend(this.dropdown, false);
93          }
94          if (node.isActive())
95          {
96              if (node.isInclude())
97              {
98                  setForeground(OtsEditor.INACTIVE_COLOR);
99              }
100             else
101             {
102                 setForeground(UIManager.getColor("Table.foreground"));
103             }
104             if (node.equals(this.editor.getChoiceNode()))
105             {
106                 setOpaque(true);
107                 setBackground(new Color(UIManager.getColor("Panel.background").getRGB())); // ColorUIResource is ignored
108                 setBorder(new LineBorder(UIManager.getColor("Menu.acceleratorForeground"), 1, false));
109             }
110             else
111             {
112                 if (node.isValid())
113                 {
114                     if (node.hasExpression())
115                     {
116                         setOpaque(true);
117                         setBackground(OtsEditor.EXPRESSION_COLOR);
118                     }
119                     else
120                     {
121                         setOpaque(false);
122                     }
123                 }
124                 else
125                 {
126                     setOpaque(true);
127                     setBackground(OtsEditor.INVALID_COLOR);
128                 }
129                 setBorder(new EmptyBorder(0, 0, 0, 0));
130             }
131         }
132         else
133         {
134             setOpaque(false);
135             setForeground(OtsEditor.INACTIVE_COLOR);
136             setBorder(new EmptyBorder(0, 0, 0, 0));
137         }
138         return this;
139     }
140 
141     /**
142      * Pre-/appends the provided image to the left-hand or right-hand side of the current icon.
143      * @param iconImage image to pre-/append.
144      * @param prepend when true, the image is prepended rather than appended.
145      */
146     private void preAppend(final Image iconImage, final boolean prepend)
147     {
148         Icon base = getIcon();
149         int w = base.getIconWidth() + ICON_MARGIN + iconImage.getWidth(null);
150         int h = Math.max(base.getIconHeight(), iconImage.getHeight(null));
151         BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
152         Graphics g = image.getGraphics();
153         int dy = (h - base.getIconHeight()) / 2;
154         int x = prepend ? iconImage.getWidth(null) + ICON_MARGIN : 0;
155         base.paintIcon(this, g, x, dy);
156         dy = (h - iconImage.getHeight(null)) / 2;
157         x = prepend ? 0 : base.getIconWidth() + ICON_MARGIN;
158         g.drawImage(iconImage, x, dy, null);
159         setIcon(new ImageIcon(image));
160     }
161 
162 }