2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2011 - Pierre GRADIT
4 * Copyright (C) 2012 - Scilab Enterprises - Calixte DENIZET
6 * This file must be used under the terms of the CeCILL.
7 * This source file is licensed as described in the file COPYING, which
8 * you should have received as part of this distribution. The terms
9 * are also available at
10 * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
14 package org.scilab.modules.preferences;
16 import java.awt.Color;
17 import java.awt.Component;
18 import java.awt.Container;
19 import java.awt.Dimension;
20 import java.awt.FlowLayout;
21 import java.lang.reflect.Constructor;
22 import java.lang.reflect.InvocationTargetException;
25 import javax.swing.AbstractButton;
26 import javax.swing.BorderFactory;
27 import javax.swing.Box;
28 import javax.swing.JLabel;
29 import javax.swing.JPanel;
30 import javax.swing.border.Border;
31 import javax.swing.border.TitledBorder;
33 import org.scilab.modules.preferences.Component.Entry;
34 import org.scilab.modules.preferences.Component.FileSelector;
35 import org.scilab.modules.preferences.Component.Scroll;
36 import org.scilab.modules.preferences.Component.Table;
37 import org.scilab.modules.preferences.Component.Select;
39 import org.w3c.dom.Node;
40 import org.w3c.dom.NodeList;
42 /** Updates swing component to reach correspondence with dom nodes.
44 public class XUpdateVisitor {
47 * stores preceding correspondence to compute diff.
49 private Map<Component, XSentinel> matching;
51 /** Construction of visitor.
53 * @param table : previous correspondence.
55 public XUpdateVisitor(final Map<Component, XSentinel> table) {
59 /** build a component from scratch with a given node.
61 * @param view : container of the built component.
62 * @param peer : peer of the container.
63 * @param item : peer of the built component.
64 * @param index : component index in container layout.
65 * @return a built component inserted in its container.
67 public final Component build(final Container view, final Node peer, final Node item, final int index) {
68 Component component = buildPeerFor(item);
69 Object constraints = getLayoutConstraints(peer, item);
71 view.add(component, constraints, index);
73 view.add(component, constraints);
78 /** Suppress a component.
80 * @param view : container of the suppressed component.
81 * @param component : suppressed component.
83 public final void forget(final Container view, final Component component) {
84 view.remove(component);
85 matching.remove(component);
88 /** Computes a recursive diff on both tree structure
89 * to achieve correspondence.
91 * @param view : the visited container.
92 * @param peer : the visited node.
94 public final void visit(final Container view, final Node peer) {
97 NodeList nodes = peer.getChildNodes();
98 int size = nodes.getLength();
103 if (view instanceof Scroll) {
104 count = ((Scroll) view).getXComponentCount();
106 count = view.getComponentCount();
109 for (int allIndex = 0; allIndex < size; allIndex++) {
110 Node item = nodes.item(allIndex);
111 if (isVisible(item)) {
112 if (visibleIndex < count) {
113 if (view instanceof Scroll) {
114 component = ((Scroll) view).getXComponent(visibleIndex);
116 component = view.getComponent(visibleIndex);
118 sentinel = matching.get(component);
119 if (sentinel == null || !sentinel.checks(item)) {
120 forget(view, component);
121 component = build(view, peer, item, visibleIndex);
124 component = build(view, peer, item, -1);
126 if (component instanceof XComponent) {
127 // Rebuild container children.
128 Container container = (Container) component;
129 visit(container, item);
135 // Clean children tail.
136 while (visibleIndex < view.getComponentCount()) {
137 component = view.getComponent(visibleIndex);
138 if (component instanceof XComponent) {
139 forget(view, component);
145 // Sentinel sets watch.
146 sentinel = matching.get(view);
147 if (sentinel == null) {
148 sentinel = new XSentinel(view, peer);
149 matching.put(view, sentinel);
150 if (view instanceof XComponent) {
151 addListeners(view, peer, sentinel);
154 sentinel.setPeer(peer);
156 // Attribute correspondence once children rebuilt.
157 if (view instanceof XComponent) {
158 XComponent xView = (XComponent) view;
163 /** Builds the layout constraint object.
165 * @param parent : parent node
166 * @param current : current node
167 * @return layout constraint (e.g. border side for border layout)
169 final Object getLayoutConstraints(final Node parent, final Node current) {
170 if (XConfigManager.getAttribute(parent, "layout").equals("border")) {
171 return XConfigManager.getAttribute(current, "border-side");
174 if (parent.getNodeName().equals("Grid")) {
180 /** Checks whether a node is visible or not.
182 * @param node : the checked node
183 * @return its visibility
185 public final boolean isVisible(final Node node) {
186 // a. Event nodes are invisibles.
187 if (node.getNodeName().equals("mouseClicked")) {
190 if (node.getNodeName().equals("actionPerformed")) {
193 if (node.getNodeName().equals("entryChanged")) {
196 // b. Text nodes with only invisible characters are invisible.
197 if (node.getNodeName().equals("#text")) {
198 if (node.getNodeValue().replaceAll("^[ \t\n]+$", "").equals("")) {
202 // c. Chooser options are invisible.
203 if (node.getNodeName().equals("option")) {
206 // d. Table descriptors are invisible.
207 if (node.getNodeName().startsWith("table")) {
211 // d. List element are invisible.
212 if (node.getNodeName().equals("listElement")) {
216 // d. List element are invisible.
217 if (node.getNodeName().equals("html")) {
223 /** Link XSentinal as listener for the given component.
225 * @param component : listened component
226 * @param node : peer node of the component
227 * @param sentinel : listener of component, node interpreter
229 public final void addListeners(final Component component, final Node node, final XSentinel sentinel) {
230 String listener = XCommonManager.getAttribute(node, "listener");
231 if (listener.equals("ActionListener")) {
232 if (component instanceof AbstractButton) {
233 AbstractButton button = (AbstractButton) component;
234 button.addActionListener(sentinel);
237 if (component instanceof XChooser) {
238 XChooser chooser = (XChooser) component;
239 chooser.addActionListener(sentinel);
244 if (listener.equals("MouseListener")) {
245 //component.addKeyListener(sentinel); Provide focus with proper focus policy.
246 component.addMouseListener(sentinel);
250 if (listener.equals("KeyListener")) {
251 component.addKeyListener(sentinel);
255 if (listener.equals("EntryListener")) {
256 if (component instanceof Entry) {
257 ((Entry) component).getDocument().addDocumentListener(sentinel);
261 if (component instanceof FileSelector) {
262 ((FileSelector) component).addDocumentListener(sentinel);
267 if (listener.equals("TableListener")) {
268 if (component instanceof Table) {
269 Table table = (Table) component;
270 table.addTableModelListener(sentinel);
276 /** Build component from scratch with its node description.
278 * @param node : description of component
279 * @return the built component
281 @SuppressWarnings("unchecked")
282 public final Component buildPeerFor(final Node node) {
283 return ComponentFactory.getComponent(node);