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