1   /****************************************************************************
2    **
3    ** This file is part of yFiles-2.6. 
4    ** 
5    ** yWorks proprietary/confidential. Use is subject to license terms.
6    **
7    ** Redistribution of this file or of an unauthorized byte-code version
8    ** of this file is strictly forbidden.
9    **
10   ** Copyright (c) 2000-2008 by yWorks GmbH, Vor dem Kreuzberg 28, 
11   ** 72070 Tuebingen, Germany. All rights reserved.
12   **
13   ***************************************************************************/
14  package demo.view.layout.tree;
15  
16  import y.base.Node;
17  import y.base.NodeCursor;
18  import y.layout.tree.AbstractRotatableNodePlacer;
19  import y.layout.tree.AbstractRotatableNodePlacer.Matrix;
20  import y.layout.tree.AbstractRotatableNodePlacer.RootAlignment;
21  import y.layout.tree.BusPlacer;
22  import y.layout.tree.DoubleLinePlacer;
23  import y.layout.tree.LeftRightPlacer;
24  import y.layout.tree.NodePlacer;
25  import y.layout.tree.SimpleNodePlacer;
26  import y.view.Arrow;
27  import y.view.EdgeRealizer;
28  import y.view.Graph2D;
29  import y.view.Graph2DSelectionEvent;
30  import y.view.Graph2DSelectionListener;
31  import y.view.LineType;
32  import y.view.PolyLineEdgeRealizer;
33  
34  import javax.swing.DefaultListCellRenderer;
35  import javax.swing.JButton;
36  import javax.swing.JComboBox;
37  import javax.swing.JLabel;
38  import javax.swing.JList;
39  import javax.swing.JPanel;
40  import javax.swing.JSplitPane;
41  import java.awt.BorderLayout;
42  import java.awt.Component;
43  import java.awt.FlowLayout;
44  import java.awt.GridBagConstraints;
45  import java.awt.GridBagLayout;
46  import java.awt.Insets;
47  import java.awt.event.ActionEvent;
48  import java.awt.event.ActionListener;
49  import java.awt.event.ItemEvent;
50  import java.awt.event.ItemListener;
51  
52  /**
53   * This demo shows some {@link NodePlacer}s that are rotatable. The NodePlacers for each node may be changed
54   * using the context menu.<br>
55   *
56   * Some NodePlacers support different {@link RootAlignment}s. Those can be selected using the context
57   * menu, too.
58   *
59   **/
60  public class RotatableNodePlacersDemo extends AbstractTreeDemo {
61    private JComboBox nodePlacerCombo;
62    private JComboBox rootAlignmentCombo;
63    private JButton rotLeftButton;
64    private JButton rotRightButton;
65    private JButton mirHorButton;
66    private JButton mirVertButton;
67  
68    public static void main( String[] args ) {
69      initLnF();
70      RotatableNodePlacersDemo demo = new RotatableNodePlacersDemo();
71      demo.start( demo.getClass().getName() );
72    }
73  
74    public RotatableNodePlacersDemo() {
75      Graph2D graph = view.getGraph2D();
76  
77      graph.addGraph2DSelectionListener( new Graph2DSelectionListener() {
78        public void onGraph2DSelectionEvent( Graph2DSelectionEvent e ) {
79          if ( view.getGraph2D().selectedNodes().ok() ) {
80            readComboValues();
81          } else {
82            setEnabled( false );
83          }
84        }
85      } );
86  
87      //Realizers
88      EdgeRealizer defaultER = graph.getDefaultEdgeRealizer();
89      defaultER.setArrow( Arrow.STANDARD );
90      ( ( PolyLineEdgeRealizer ) defaultER ).setSmoothedBends( true );
91      defaultER.setLineType( LineType.LINE_2 );
92  
93  
94      JPanel configPanel = new JPanel( new GridBagLayout() );
95      GridBagConstraints constraints = new GridBagConstraints();
96  
97      constraints.fill = GridBagConstraints.HORIZONTAL;
98      constraints.insets = new Insets( 10, 10, 10, 10 );
99      configPanel.add( new JLabel( "Settings for actual selection" ), constraints );
100 
101     constraints.gridy = 1;
102     constraints.insets = new Insets( 5, 5, 0, 0 );
103     configPanel.add( new JLabel( "NodePlacer:" ), constraints );
104 
105     constraints.gridy = 2;
106     constraints.insets = new Insets( 0, 0, 0, 0 );
107     nodePlacerCombo = new JComboBox();
108     nodePlacerCombo.addItem( "SimpleNodePlacer" );
109     nodePlacerCombo.addItem( "DoubleLinePlacer" );
110     nodePlacerCombo.addItem( "BusPlacer" );
111     nodePlacerCombo.addItem( "LeftRightPlacer" );
112     nodePlacerCombo.addItemListener( new ItemListener() {
113       public void itemStateChanged( ItemEvent e ) {
114         if ( e.getStateChange() == ItemEvent.SELECTED ) {
115           changeNodePlacersForSelection();
116         }
117       }
118     } );
119     configPanel.add( nodePlacerCombo, constraints );
120 
121     constraints.gridy = 3;
122     constraints.insets = new Insets( 5, 5, 0, 0 );
123     configPanel.add( new JLabel( "Rotation:" ), constraints );
124 
125     constraints.gridy = 4;
126     constraints.insets = new Insets( 0, 0, 0, 0 );
127 
128     JPanel rotationPanel = new JPanel();
129     configPanel.add( rotationPanel, constraints );
130     rotationPanel.setLayout( new FlowLayout() );
131     rotLeftButton = new JButton( "Left" );
132     rotLeftButton.addActionListener( new ActionListener() {
133       public void actionPerformed( ActionEvent e ) {
134         rotate( Matrix.ROT90 );
135       }
136     } );
137     rotationPanel.add( rotLeftButton );
138     rotRightButton = new JButton( "Right" );
139     rotRightButton.addActionListener( new ActionListener() {
140       public void actionPerformed( ActionEvent e ) {
141         rotate( Matrix.ROT270 );
142       }
143     } );
144     rotationPanel.add( rotRightButton );
145 
146     constraints.gridy = 6;
147     rotationPanel = new JPanel();
148     configPanel.add( rotationPanel, constraints );
149     rotationPanel.setLayout( new FlowLayout() );
150     mirHorButton = new JButton( "Mir Hor" );
151     mirHorButton.addActionListener( new ActionListener() {
152       public void actionPerformed( ActionEvent e ) {
153         rotate( Matrix.MIR_HOR );
154       }
155     } );
156     rotationPanel.add( mirHorButton );
157     mirVertButton = new JButton( "Mir Vert" );
158     mirVertButton.addActionListener( new ActionListener() {
159       public void actionPerformed( ActionEvent e ) {
160         rotate( Matrix.MIR_VERT );
161       }
162     } );
163     rotationPanel.add( mirVertButton );
164 
165 
166     constraints.gridy = 7;
167     constraints.insets = new Insets( 5, 5, 0, 0 );
168     configPanel.add( new JLabel( "Root Alignment:" ), constraints );
169 
170     constraints.gridy = 8;
171     constraints.insets = new Insets( 0, 0, 0, 0 );
172     rootAlignmentCombo = new JComboBox();
173 
174     rootAlignmentCombo.addItem( AbstractRotatableNodePlacer.RootAlignment.CENTER );
175     rootAlignmentCombo.addItem( AbstractRotatableNodePlacer.RootAlignment.CENTER_OVER_CHILDREN );
176     rootAlignmentCombo.addItem( AbstractRotatableNodePlacer.RootAlignment.MEDIAN );
177     rootAlignmentCombo.addItem( AbstractRotatableNodePlacer.RootAlignment.LEADING );
178     rootAlignmentCombo.addItem( AbstractRotatableNodePlacer.RootAlignment.LEFT );
179     rootAlignmentCombo.addItem( AbstractRotatableNodePlacer.RootAlignment.RIGHT );
180     rootAlignmentCombo.addItem( AbstractRotatableNodePlacer.RootAlignment.TRAILING );
181     rootAlignmentCombo.addItemListener( new ItemListener() {
182       public void itemStateChanged( ItemEvent e ) {
183         if ( e.getStateChange() == ItemEvent.SELECTED ) {
184           changeNodePlacersForSelection();
185         }
186       }
187     } );
188     rootAlignmentCombo.setRenderer( new DefaultListCellRenderer() {
189       public Component getListCellRendererComponent( JList list, Object value, int index, boolean isSelected, boolean cellHasFocus ) {
190         JLabel label = ( JLabel ) super.getListCellRendererComponent( list, value, index, isSelected, cellHasFocus );
191         RootAlignment rootAlignment = ( RootAlignment ) value;
192         if ( rootAlignment == RootAlignment.CENTER ) label.setText( "Center" );
193         if ( rootAlignment == RootAlignment.LEADING ) label.setText( "Leading" );
194         if ( rootAlignment == RootAlignment.LEFT ) label.setText( "Left" );
195         if ( rootAlignment == RootAlignment.RIGHT ) label.setText( "Right" );
196         if ( rootAlignment == RootAlignment.TRAILING ) label.setText( "Trailing" );
197         if ( rootAlignment == RootAlignment.MEDIAN ) label.setText( "Median" );
198         if ( rootAlignment == RootAlignment.CENTER_OVER_CHILDREN ) label.setText( "Center over children" );
199         return label;
200       }
201     } );
202     configPanel.add( rootAlignmentCombo, constraints );
203 
204     JPanel left = new JPanel( new BorderLayout() );
205     left.add( configPanel, BorderLayout.NORTH );
206 
207     JSplitPane sp = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, left, view );
208     sp.setOneTouchExpandable( true );
209     sp.setContinuousLayout( false );
210     contentPane.add( sp, BorderLayout.CENTER );
211     createSampleGraph( graph );
212 
213     setEnabled( false );
214 
215     createSampleGraph( view.getGraph2D() );
216     calcLayout();
217   }
218 
219   private void setEnabled( boolean enabled ) {
220     rootAlignmentCombo.setEnabled( enabled );
221     rotLeftButton.setEnabled( enabled );
222     rotRightButton.setEnabled( enabled );
223     mirHorButton.setEnabled( enabled );
224     mirVertButton.setEnabled( enabled );
225     nodePlacerCombo.setEnabled( enabled );
226   }
227 
228   private void rotate( Matrix rotation ) {
229     RootAlignment rootAlignment = ( RootAlignment ) rootAlignmentCombo.getSelectedItem();
230 
231     String placerName = ( String ) nodePlacerCombo.getSelectedItem();
232 
233     for ( NodeCursor nodeCursor = view.getGraph2D().selectedNodes(); nodeCursor.ok(); nodeCursor.next() ) {
234       Node node = nodeCursor.node();
235       AbstractRotatableNodePlacer oldPlacer = ( AbstractRotatableNodePlacer ) nodePlacerMap.get( node );
236       Matrix matrix = oldPlacer == null ? rotation.multiply(Matrix.DEFAULT) : rotation.multiply( oldPlacer.getModificationMatrix() );
237 
238       AbstractRotatableNodePlacer placer = createPlacer( placerName, matrix, rootAlignment );
239       nodePlacerMap.set( node, placer );
240     }
241     calcLayout();
242   }
243 
244   private boolean blockLayout;
245 
246   private void readComboValues() {
247     blockLayout = true;
248 
249     setEnabled( true );
250 
251     NodeCursor nodeCursor = view.getGraph2D().selectedNodes();
252     if ( !nodeCursor.ok() ) {
253       setEnabled( false );
254     } else {
255       Node node = nodeCursor.node();
256 
257       AbstractRotatableNodePlacer nodePlacer = ( AbstractRotatableNodePlacer ) nodePlacerMap.get( node );
258       if ( nodePlacer == null ) return;
259 
260       nodePlacerCombo.setSelectedItem( nodePlacer.getClass() );
261 
262       if ( nodePlacer instanceof SimpleNodePlacer ) {
263         rootAlignmentCombo.setSelectedItem( ( ( SimpleNodePlacer ) nodePlacer ).getRootAlignment() );
264       }
265       if ( nodePlacer instanceof DoubleLinePlacer ) {
266         rootAlignmentCombo.setSelectedItem( ( ( DoubleLinePlacer ) nodePlacer ).getRootAlignment() );
267       }
268     }
269 
270     blockLayout = false;
271   }
272 
273   private void changeNodePlacersForSelection() {
274     if ( blockLayout ) return;
275     RootAlignment rootAlignment = ( RootAlignment ) rootAlignmentCombo.getSelectedItem();
276 
277     String placerName = ( String ) nodePlacerCombo.getSelectedItem();
278 
279     for ( NodeCursor nodeCursor = view.getGraph2D().selectedNodes(); nodeCursor.ok(); nodeCursor.next() ) {
280       Node node = nodeCursor.node();
281       AbstractRotatableNodePlacer oldPlacer = ( AbstractRotatableNodePlacer ) nodePlacerMap.get( node );
282       Matrix matrix = oldPlacer.getModificationMatrix();
283 
284       AbstractRotatableNodePlacer placer = createPlacer( placerName, matrix, rootAlignment );
285       nodePlacerMap.set( node, placer );
286     }
287     calcLayout();
288   }
289 
290   private static AbstractRotatableNodePlacer createPlacer( String placerName, Matrix modificationMatrix, RootAlignment rootAlignment ) {
291     AbstractRotatableNodePlacer placer = null;
292     if ( "SimpleNodePlacer".equals( placerName ) ) {
293       placer = new SimpleNodePlacer( modificationMatrix );
294       ( ( SimpleNodePlacer ) placer ).setRootAlignment( rootAlignment );
295     } else if ( "DoubleLinePlacer".equals( placerName ) ) {
296       placer = new DoubleLinePlacer( modificationMatrix );
297       ( ( DoubleLinePlacer ) placer ).setRootAlignment( rootAlignment );
298     } else if ( "BusPlacer".equals( placerName ) ) {
299       placer = new BusPlacer( modificationMatrix );
300     } else if ( "LeftRightPlacer".equals( placerName ) ) {
301       placer = new LeftRightPlacer( modificationMatrix );
302     }
303     return placer;
304   }
305 
306   protected boolean isDeletionEnabled() {
307     return false;
308   }
309 
310   private void createSampleGraph( Graph2D graph ) {
311     graph.clear();
312     Node root = graph.createNode();
313     graph.getRealizer( root ).setFillColor( layerColors[ 0 ] );
314     nodePlacerMap.set( root, new SimpleNodePlacer() );
315     createChildren( graph, root, 3, 1, 2 );
316     calcLayout();
317   }
318 
319   private void createChildren( Graph2D graph, Node root, int children, int layer, int layers ) {
320     for ( int i = 0; i < children; i++ ) {
321       Node child = graph.createNode();
322       graph.createEdge( root, child );
323       graph.getRealizer( child ).setFillColor( layerColors[ layer % layerColors.length ] );
324 
325       Matrix rotationMatrix;
326       if ( layer == 1 ) {
327         rotationMatrix = Matrix.MIR_VERT_ROT90;
328       } else {
329         rotationMatrix = Matrix.DEFAULT;
330       }
331       if ( layers > 0 ) {
332         SimpleNodePlacer nodePlacer = new SimpleNodePlacer( rotationMatrix );
333         nodePlacerMap.set( child, nodePlacer );
334       }
335       if ( layers > 0 ) {
336         createChildren( graph, child, children, layer + 1, layers - 1 );
337       }
338     }
339   }
340 }
341