1
14 package demo.view.graphexplorer;
15
16 import demo.view.DemoBase;
17 import y.option.AbstractItemEditor;
18 import y.option.ConstraintManager;
19 import y.option.DefaultCompoundEditor;
20 import y.option.DefaultEditorFactory;
21 import y.option.Editor;
22 import y.option.ItemEditor;
23 import y.option.OptionHandler;
24 import y.option.OptionItem;
25 import y.option.OptionSection;
26 import y.option.PropertyChangeReporter;
27
28 import java.awt.Dimension;
29 import java.awt.Font;
30 import java.awt.GridBagConstraints;
31 import java.awt.GridBagLayout;
32 import java.awt.Insets;
33 import java.awt.event.ActionListener;
34 import java.beans.PropertyChangeEvent;
35 import java.beans.PropertyChangeListener;
36 import java.util.Map;
37 import javax.swing.BorderFactory;
38 import javax.swing.Box;
39 import javax.swing.BoxLayout;
40 import javax.swing.JButton;
41 import javax.swing.JComboBox;
42 import javax.swing.JComponent;
43 import javax.swing.JLabel;
44 import javax.swing.JPanel;
45 import javax.swing.UIManager;
46
47
50 class GraphExplorerOptionHandler extends OptionHandler {
51 static final String ATTRIBUTE_LAYOUT_CALLBACK =
52 "GraphExplorerOptionHandler.layoutCallback";
53
54 static final byte ID_LAYOUT_ORTHOGONAL = 0;
55 static final byte ID_LAYOUT_ORGANIC = 1;
56 static final byte ID_LAYOUT_HIERARCHIC = 2;
57 static final byte ID_LAYOUT_BALLOON = 3;
58 static final byte ID_LAYOUT_CIRCULAR = 4;
59
60 static final byte EDGE_TYPE_ALL = 0;
61 static final byte EDGE_TYPE_OUT = 1;
62 static final byte EDGE_TYPE_IN = 2;
63
64 private static final String EXPLORE_NODES = "Explore Nodes";
65 private static final String EXPLORE_NEIGHBORS = "Neighbors";
66 private static final String EXPLORE_SUCCESSORS = "Successors";
67 private static final String EXPLORE_PREDECESSORS = "Predecessors";
68 private static final String LAYOUT = "Layout";
69 private static final String LAYOUT_ORTHOGONAL = "Orthogonal";
70 private static final String LAYOUT_ORGANIC = "Organic";
71 private static final String LAYOUT_HIERARCHIC = "Hierarchic";
72 private static final String LAYOUT_BALLOON = "Balloon";
73 private static final String LAYOUT_CIRCULAR = "Circular";
74 private static final String MAX_NEW_NODES = "Max New Nodes on Click";
75 private static final String ENABLE_FILTER = "Filter Neighbors";
76 private static final String MAX_NEIGHBOR_DIST = "Max Neighbor Distance";
77
78 GraphExplorerOptionHandler() {
79 super("Option Table");
80 useSection("General");
81 addEnum(LAYOUT, new String[]{
82 LAYOUT_ORGANIC,
83 LAYOUT_ORTHOGONAL,
84 LAYOUT_HIERARCHIC,
85 LAYOUT_BALLOON,
86 LAYOUT_CIRCULAR
87 }, 1);
88 addEnum(EXPLORE_NODES, new String[]{
89 EXPLORE_NEIGHBORS,
90 EXPLORE_SUCCESSORS,
91 EXPLORE_PREDECESSORS
92 }, 0);
93 addInt(MAX_NEW_NODES, 10, 1, 100);
94 useSection("Filter");
95 addBool(ENABLE_FILTER, true);
96 addInt(MAX_NEIGHBOR_DIST, 4, 1, 100);
97
98 final ConstraintManager constraints = new ConstraintManager(this);
99 constraints.setEnabledOnValueEquals(ENABLE_FILTER, Boolean.TRUE, MAX_NEIGHBOR_DIST);
100 }
101
102
107 int getMaxNewNodes() {
108 return getInt(MAX_NEW_NODES);
109 }
110
111
119 int getMaxDist() {
120 if (getBool(ENABLE_FILTER)) {
121 return getInt(MAX_NEIGHBOR_DIST);
122 } else {
123 return -1;
124 }
125 }
126
127
133 byte getExplorationEdgeType() {
134 final String exploration = getString(EXPLORE_NODES);
135 if (EXPLORE_NEIGHBORS.equals(exploration)) {
136 return EDGE_TYPE_ALL;
137 } else if (EXPLORE_SUCCESSORS.equals(exploration)) {
138 return EDGE_TYPE_OUT;
139 } else if (EXPLORE_PREDECESSORS.equals(exploration)) {
140 return EDGE_TYPE_IN;
141 } else {
142 return EDGE_TYPE_ALL;
143 }
144 }
145
146
153 byte getLayoutId() {
154 final String layout = getString(LAYOUT);
155 if (layout.equals(LAYOUT_HIERARCHIC)) {
156 return ID_LAYOUT_HIERARCHIC;
157 } else if (layout.equals(LAYOUT_ORGANIC)) {
158 return ID_LAYOUT_ORGANIC;
159 } else if (layout.equals(LAYOUT_BALLOON)) {
160 return ID_LAYOUT_BALLOON;
161 } else if (layout.equals(LAYOUT_CIRCULAR)) {
162 return ID_LAYOUT_CIRCULAR;
163 } else {
164 return ID_LAYOUT_ORTHOGONAL;
165 }
166 }
167
168
172 JComponent createEditorComponent() {
173 final SimpleEditorFactory factory = new SimpleEditorFactory();
174 final Editor editor = factory.createEditor(this);
175
176 final JComponent optionComponent = editor.getComponent();
177 optionComponent.setPreferredSize(new Dimension(400, 250));
178 optionComponent.setMaximumSize(new Dimension(400, 250));
179 return optionComponent;
180 }
181
182
186 private static final class SimpleEditorFactory extends DefaultEditorFactory {
187 public Editor createEditor( final OptionHandler handler, final Map attributes ) {
188 final SimpleEditor editor = new SimpleEditor(handler, this);
189 handler.addEditor(editor);
190 return editor;
191 }
192 }
193
194
198 private static final class SimpleEditor extends DefaultCompoundEditor {
199 private final JComponent component;
200
201 SimpleEditor( final OptionHandler handler, final SimpleEditorFactory factory ) {
202 final Font font;
203 final Font cbf;
204 if ("javax.swing.plaf.metal.MetalLookAndFeel".equals(UIManager.getLookAndFeel().getClass().getName())) {
205 font = new JLabel().getFont().deriveFont(Font.PLAIN);
206 cbf = font.deriveFont((float) (font.getSize() - 2));
207 } else {
208 font = new JLabel().getFont();
209 cbf = font;
210 }
211
212 final int sc = handler.sectionCount();
213 final JLabel[][] labels = new JLabel[sc][];
214 final JComponent[][] controls = new JComponent[sc][];
215
216 int maxW = 0;
217
218 JButton lb = null;
219
220 final String handlerName = handler.getName();
221 for (int i = 0; i < sc; ++i) {
222 final OptionSection section = handler.section(i);
223 section.setAttribute(OptionSection.ATTRIBUTE_CONTEXT, handlerName);
224
225 final int ic = section.itemCount();
226 labels[i] = new JLabel[ic];
227 controls[i] = new JComponent[ic];
228 for (int j = 0; j < ic; ++j) {
229 final OptionItem item = section.item(j);
230
231 final Object attr = item.getAttribute(ATTRIBUTE_LAYOUT_CALLBACK);
232 if (attr instanceof ActionListener) {
233 lb = createLayoutButton();
234 lb.addActionListener((ActionListener) attr);
235 }
236
237 labels[i][j] = createLabel(item.getName(), font);
238 final Dimension s1 = labels[i][j].getPreferredSize();
239 if (maxW < s1.width) {
240 maxW = s1.width;
241 }
242
243 final ItemEditor editor = factory.createEditor(item);
244 editor.setAutoCommit(true);
245 addEditor(editor);
246 if (editor instanceof PropertyChangeReporter) {
247 final JLabel label = labels[i][j];
248 ((PropertyChangeReporter) editor).addPropertyChangeListener(
249 AbstractItemEditor.PROPERTY_ENABLED,
250 new PropertyChangeListener() {
251 public void propertyChange( final PropertyChangeEvent e ) {
252 label.setEnabled(((Boolean) e.getNewValue()).booleanValue());
253 }
254 });
255 }
256
257 controls[i][j] = editor.getComponent();
258 if (controls[i][j] instanceof JComboBox) {
259 controls[i][j].setFont(cbf);
260 }
261 }
262 }
263
264 final int margin = 5;
265
266 final Box main = new Box(BoxLayout.Y_AXIS);
267 for (int i = 0; i < sc; ++i) {
268 final OptionSection section = handler.section(i);
269
270 final JPanel sectionPane = new JPanel(new GridBagLayout());
271 sectionPane.setBorder(BorderFactory.createTitledBorder(section.getName()));
272
273 final GridBagConstraints gbc = new GridBagConstraints();
274 gbc.anchor = GridBagConstraints.WEST;
275
276 final int ic = section.itemCount();
277 for (int j = 0; j < ic; ++j) {
278 final int topInset = j == 0 ? 3 : margin;
279 final int bottomInset = j == ic - 1 ? margin : 0;
280
281 gbc.insets = new Insets(topInset, margin, bottomInset, 0);
282 gbc.fill = GridBagConstraints.NONE;
283 gbc.gridx = 0;
284 gbc.gridy = j;
285 gbc.weightx = 0.0;
286 gbc.weighty = 0.0;
287 final JLabel jl = labels[i][j];
288 jl.setPreferredSize(new Dimension(maxW, jl.getPreferredSize().height));
289 sectionPane.add(jl, gbc);
290
291 gbc.insets = new Insets(topInset, margin, bottomInset, 0);
292 gbc.fill = GridBagConstraints.HORIZONTAL;
293 gbc.gridx = 1;
294 gbc.weightx = 1.0;
295 sectionPane.add(controls[i][j], gbc);
296
297 if (lb != null) {
298 gbc.insets = new Insets(topInset, 1, bottomInset, margin);
299 gbc.fill = GridBagConstraints.BOTH;
300 gbc.gridx = 2;
301 gbc.weightx = 0.0;
302 if (section.item(j).getAttribute(ATTRIBUTE_LAYOUT_CALLBACK) instanceof ActionListener) {
303 sectionPane.add(lb, gbc);
304 } else {
305 sectionPane.add(createSpacer(lb), gbc);
306 }
307 }
308 }
309
310 main.add(sectionPane);
311 if (i != sc - 1) {
312 main.add(Box.createRigidArea(new Dimension(margin, margin)));
313 }
314 }
315
316 component = new JPanel(new GridBagLayout());
317 final GridBagConstraints gbc = new GridBagConstraints();
318 gbc.anchor = GridBagConstraints.NORTHWEST;
319 gbc.fill = GridBagConstraints.HORIZONTAL;
320 gbc.gridx = 0;
321 gbc.gridy = 0;
322 gbc.weightx = 1.0;
323 gbc.weighty = 0.0;
324 component.add(main, gbc);
325
326 gbc.fill = GridBagConstraints.BOTH;
327 gbc.gridy = 1;
328 gbc.weighty = 1.0;
329 component.add(new JPanel(), gbc);
330 }
331
332 public JComponent getComponent() {
333 return component;
334 }
335
336 private static JLabel createLabel( final String name, final Font font ) {
337 final JLabel jl = new JLabel(name);
338 jl.setFont(font);
339 return jl;
340 }
341
342 private static JComponent createSpacer( final JComponent jc ) {
343 final Dimension s = jc.getPreferredSize();
344 final JPanel jp = new JPanel();
345 jp.setPreferredSize(s);
346 jp.setSize(s);
347 jp.setMinimumSize(s);
348 jp.setMaximumSize(s);
349 return jp;
350 }
351
352 private static JButton createLayoutButton() {
353 if (DemoBase.SHARED_LAYOUT_ICON == null) {
354 return new JButton("Layout");
355 } else {
356 final JButton jb = new JButton();
357 jb.setIcon(DemoBase.SHARED_LAYOUT_ICON);
358 jb.setMargin(new Insets(0, 0, 0, 0));
359 jb.setToolTipText("Layout");
360 return jb;
361 }
362 }
363 }
364 }
365