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 OtsEditor; 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 = ImageIO.read(Resource.getResourceAsStream("./Application.png")).getScaledInstance(12, 12,
61                  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      /** {@inheritDoc} */
72      @Override
73      public Component getTreeCellRendererComponent(final JTree tree, final Object value, final boolean selected,
74              final boolean expanded, final boolean leaf, final int row, final boolean hasFocus)
75      {
76          super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
77          XsdTreeNode node = (XsdTreeNode) value;
78          Icon customIcon = this.editor.getCustomIcon(node.getPathString());
79          if (customIcon != null)
80          {
81              setIcon(customIcon);
82          }
83          if (node.hasConsumer())
84          {
85              preAppend(this.consumer, false);
86          }
87          if (node.getDescription() != null)
88          {
89              preAppend(this.description, false);
90          }
91          if (node.isChoice() && !node.isInclude())
92          {
93              preAppend(this.dropdown, false);
94          }
95          if (node.isActive())
96          {
97              if (node.isInclude())
98              {
99                  setForeground(OtsEditor.INACTIVE_COLOR);
100             }
101             else
102             {
103                 setForeground(UIManager.getColor("Table.foreground"));
104             }
105             if (node.equals(this.editor.getChoiceNode()))
106             {
107                 setOpaque(true);
108                 setBackground(new Color(UIManager.getColor("Panel.background").getRGB())); // ColorUIResource is ignored
109                 setBorder(new LineBorder(UIManager.getColor("Menu.acceleratorForeground"), 1, false));
110             }
111             else
112             {
113                 if (node.isValid())
114                 {
115                     if (node.hasExpression())
116                     {
117                         setOpaque(true);
118                         setBackground(OtsEditor.EXPRESSION_COLOR);
119                     }
120                     else
121                     {
122                         setOpaque(false);
123                     }
124                 }
125                 else
126                 {
127                     setOpaque(true);
128                     setBackground(OtsEditor.INVALID_COLOR);
129                 }
130                 setBorder(new EmptyBorder(0, 0, 0, 0));
131             }
132         }
133         else
134         {
135             setOpaque(false);
136             setForeground(OtsEditor.INACTIVE_COLOR);
137             setBorder(new EmptyBorder(0, 0, 0, 0));
138         }
139         return this;
140     }
141 
142     /**
143      * Pre-/appends the provided image to the left-hand or right-hand side of the current icon.
144      * @param iconImage Image; image to pre-/append.
145      * @param prepend boolean; when true, the image is prepended rather than appended.
146      */
147     private void preAppend(final Image iconImage, final boolean prepend)
148     {
149         Icon base = getIcon();
150         int w = base.getIconWidth() + ICON_MARGIN + iconImage.getWidth(null);
151         int h = Math.max(base.getIconHeight(), iconImage.getHeight(null));
152         BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
153         Graphics g = image.getGraphics();
154         int dy = (h - base.getIconHeight()) / 2;
155         int x = prepend ? iconImage.getWidth(null) + ICON_MARGIN : 0;
156         base.paintIcon(this, g, x, dy);
157         dy = (h - iconImage.getHeight(null)) / 2;
158         x = prepend ? 0 : base.getIconWidth() + ICON_MARGIN;
159         g.drawImage(iconImage, x, dy, null);
160         setIcon(new ImageIcon(image));
161     }
162     
163 }