View Javadoc

1   /**
2    * 
3    */
4   package org.ximtec.igesture.tool.view.admin.panel;
5   
6   import java.awt.BorderLayout;
7   import java.awt.CardLayout;
8   import java.awt.Color;
9   import java.awt.Dimension;
10  import java.awt.FlowLayout;
11  import java.awt.GridBagLayout;
12  import java.awt.event.ComponentAdapter;
13  import java.awt.event.ComponentEvent;
14  import java.awt.event.MouseAdapter;
15  import java.awt.event.MouseEvent;
16  import java.util.HashMap;
17  import java.util.List;
18  import java.util.Map;
19  
20  import javax.swing.Action;
21  import javax.swing.BorderFactory;
22  import javax.swing.JButton;
23  import javax.swing.JLabel;
24  import javax.swing.JMenuItem;
25  import javax.swing.JPanel;
26  import javax.swing.JPopupMenu;
27  
28  import org.sigtec.graphix.GridBagLayouter;
29  import org.ximtec.igesture.core.Gesture;
30  import org.ximtec.igesture.core.SampleDescriptor3D;
31  import org.ximtec.igesture.io.AbstractGestureDevice;
32  import org.ximtec.igesture.io.DeviceManagerListener;
33  import org.ximtec.igesture.io.GestureDevice;
34  import org.ximtec.igesture.io.GestureDevicePanel;
35  import org.ximtec.igesture.io.IDeviceManager;
36  import org.ximtec.igesture.tool.GestureConstants;
37  import org.ximtec.igesture.tool.core.Controller;
38  import org.ximtec.igesture.tool.gesturevisualisation.GesturePanel;
39  import org.ximtec.igesture.tool.gesturevisualisation.InputComponentPanel;
40  import org.ximtec.igesture.tool.gesturevisualisation.InputPanelFactory;
41  import org.ximtec.igesture.tool.service.DeviceManagerService;
42  import org.ximtec.igesture.tool.service.SwingMouseReaderService;
43  import org.ximtec.igesture.tool.util.FontFactory;
44  import org.ximtec.igesture.tool.util.Formatter;
45  import org.ximtec.igesture.tool.view.DeviceListPanel;
46  import org.ximtec.igesture.tool.view.DeviceListPanelListener;
47  import org.ximtec.igesture.tool.view.admin.action.AddGestureSampleAction;
48  import org.ximtec.igesture.tool.view.admin.action.ClearGestureSampleAction;
49  import org.ximtec.igesture.tool.view.admin.action.RemoveGestureSampleAction;
50  import org.ximtec.igesture.util.Constant;
51  import org.ximtec.igesture.util.additions3d.RecordedGesture3D;
52  
53  /**
54   * @author Bjorn Puype, bpuype@gmail.com
55   *
56   */
57  public class SampleDescriptor3DPanel extends DefaultDescriptorPanel<SampleDescriptor3D> implements
58  				DeviceListPanelListener, DeviceManagerListener {
59  
60  	private static final int INPUTAREA_SIZE = 200;
61  	private static final int SPACE_SIZE = 5;
62  	private static final int SAMPLE_SIZE = 100;
63  	 
64  	private GestureDevice<?, ?> gestureDevice;
65  	private GestureDevice<?, ?> currentDevice;
66  	
67  	private Map<Gesture<RecordedGesture3D>, JPanel> sampleCache;
68  	  
69  	private DeviceListPanel devicePanel;
70  	private JPanel cardPanel; 
71  	
72  	private Map<String, InputComponentPanel> panelMapping;
73  	
74  	/**
75  	 * Constructor
76  	 * @param controller
77  	 * @param descriptor
78  	 */
79  	public SampleDescriptor3DPanel(Controller controller, final SampleDescriptor3D descriptor) {
80  		super(controller, descriptor);
81  		
82  		this.sampleCache = new HashMap<Gesture<RecordedGesture3D>, JPanel>();
83  	    this.panelMapping = new HashMap<String, InputComponentPanel>();
84  	    
85  	    // component listener to handle resize actions
86  	    addComponentListener(new ComponentAdapter() {
87  	      @Override
88  	      public void componentResized(ComponentEvent e) {
89  	        initSampleSection(descriptor.getSamples());
90  	      }
91  	    });
92  
93  	    DeviceManagerService manager = controller.getLocator().getService(DeviceManagerService.IDENTIFIER, DeviceManagerService.class);
94  	    manager.addDeviceManagerListener(this);
95  	    
96  	    init(descriptor, manager);
97  	}
98  
99  	private JButton createAddSampleButton(SampleDescriptor3D sampleDescriptor3D, GestureDevice<?, ?> device) {
100 		    JButton addSampleButton = getComponentFactory().createButton(GestureConstants.GESTURE_SAMPLE_ADD,
101 		        new AddGestureSampleAction(getController(), sampleDescriptor3D, device));
102 		    Formatter.formatButton(addSampleButton);
103 		    return addSampleButton;
104 	}
105 
106 	  private JButton createClearSampleButton(GestureDevice<?,?> gestureDevice) {
107 	    JButton clearSampleButton = getComponentFactory().createButton(GestureConstants.GESTURE_SAMPLE_CLEAR,
108 	        new ClearGestureSampleAction(getController(), gestureDevice));
109 	    Formatter.formatButton(clearSampleButton);
110 	    return clearSampleButton;
111 	  }
112 
113 	  /**
114 	   * Returns the visualization of a gesture. A hash map is used to cache these
115 	   * visualizations. Otherwise every update of the view requires the computation
116 	   * of all samples.
117 	   * 
118 	   * The cache is very simple and it's elements are never removed. This simple
119 	   * implementation is sufficient, because of the short life-cycle of the
120 	   * explorer tree views.
121 	   * 
122 	   * @param sample
123 	   * @return
124 	   */
125 	  private synchronized JPanel createSampleIcon(final Gesture<RecordedGesture3D> sample) {
126 
127 	    if (sampleCache.containsKey(sample)) {
128 	      return sampleCache.get(sample);
129 	    }
130 
131 	    GesturePanel gesturePanel = InputPanelFactory.createGesturePanel(sample);
132 	    final JPanel panel = gesturePanel.getPanel(new Dimension(SAMPLE_SIZE, SAMPLE_SIZE));
133 	    panel.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY, 1));
134 	    panel.addMouseListener(new SampleIconMouseListener(new RemoveGestureSampleAction(getController(), getDescriptor(),
135 	        sample), panel));
136 	    panel.setOpaque(true);
137 	    panel.setBackground(Color.WHITE);
138 	    sampleCache.put(sample, panel);
139 
140 	    return panel;
141 
142 	  }
143 
144 	  /**
145 	   * Returns a white, square spacer element (JPanel) of the given size.
146 	   * 
147 	   * @param size
148 	   *          the size of the space element
149 	   * @return the space element
150 	   */
151 	  private JPanel createSpacerPanel(int size) {
152 	    JPanel panel = new JPanel();
153 	    panel.setLayout(null);
154 	    panel.setOpaque(true);
155 	    panel.setBackground(Color.WHITE);
156 	    panel.setPreferredSize(new Dimension(size, size));
157 	    return panel;
158 	  }
159 
160 	  /**
161 	   * Initialize the Sample Descriptor View
162 	   * 
163 	   * @param descriptor
164 	 * @param manager 
165 	   */
166 	  private void init(SampleDescriptor3D descriptor, IDeviceManager manager) {
167 	    initTitle();
168 	    initSampleSection(descriptor.getSamples());
169 	    initInputSection(manager);
170 	  }
171 
172 	  /**
173 	   * Captures a local reference of the gesture input device.
174 	   */
175 	  private void initGestureDevice() {
176 	    gestureDevice = getController().getLocator().getService(SwingMouseReaderService.IDENTIFIER, GestureDevice.class);
177 	  }
178 
179 	  /**
180 	   * Creates the input area to capture new gestures.
181 	 * @param manager 
182 	   * 
183 	   * @param descriptor
184 	   */
185 	  private void initInputSection(IDeviceManager manager) {
186 	    JPanel basePanel = new JPanel();
187 	    
188 	    // input area
189 	    basePanel.setLayout(new BorderLayout());
190 
191 	    initGestureDevice();
192 	    
193 		cardPanel = new JPanel();
194 		cardPanel.setLayout(new CardLayout());
195 		cardPanel.setSize(new Dimension(INPUTAREA_SIZE, INPUTAREA_SIZE));
196 		
197 		currentDevice = null;
198 		
199 	    
200 	    JLabel title = getComponentFactory().createLabel(GestureConstants.SAMPLE_DESCRIPTOR_3D_TITLE);
201 	    title.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
202 	    title.setFont(FontFactory.getArialBold(18));
203 	    
204 	    basePanel.add(title, BorderLayout.NORTH);
205 	    basePanel.add(cardPanel, BorderLayout.CENTER);
206 	    
207 	    devicePanel = new DeviceListPanel();
208 	    for(AbstractGestureDevice<?,?> device : manager.getDevices())
209 	    	addDevice(device);
210 	    devicePanel.addDevicePanelListener(this);
211 	    basePanel.add(devicePanel,BorderLayout.WEST);
212 	    
213 	    setBottom(basePanel);
214 	  }
215 
216 	  /**
217 	   * Visualizes the samples. The GridBagLayout is used. The number of elements
218 	   * in a row are computed dynamically. Between two gesture elements a space
219 	   * element is placed.
220 	   */
221 	  private synchronized void initSampleSection(List<Gesture<RecordedGesture3D>> samples) {
222 
223 	    JPanel panel = new JPanel();
224 
225 	    panel.setLayout(new GridBagLayout());
226 
227 	    // if the component has size 0 (before it is placed into another container
228 	    // component, don't visualize the samples
229 	    if (getWidth() > 0) {
230 
231 	      int x = 0;
232 	      int y = 1;
233 
234 	      // compute the number of samples shown in a row
235 	      int elementsPerRow = (getWidth() - 20) / (SAMPLE_SIZE + 20);
236 	      elementsPerRow = elementsPerRow * 2 - 1;
237 
238 	      // add a line of space elements before the first row
239 	      GridBagLayouter.addComponent(panel, createSpacerPanel(SPACE_SIZE), 0, 0);
240 
241 	      // iterate over all the samples
242 	      for (final Gesture<RecordedGesture3D> sample : samples) {
243 	        GridBagLayouter.addComponent(panel, createSampleIcon(sample), x, y);
244 	        GridBagLayouter.addComponent(panel, createSpacerPanel(SPACE_SIZE), x + 1, y);
245 	        if (x + 1 >= elementsPerRow) {
246 	          x = 0;
247 	          y++;
248 	          // add a line (spacer) between two sample rows
249 	          GridBagLayouter.addComponent(panel, createSpacerPanel(SPACE_SIZE), 0, y);
250 	          y++;
251 	        } else {
252 	          // element + spacer = 2
253 	          x = x + 2;
254 	        }
255 
256 	      }
257 	    }
258 
259 	    panel.setOpaque(true);
260 	    panel.setAutoscrolls(true);
261 	    setContent(panel);
262 	  }
263 
264 	  @Override
265 	  public void refreshUILogic() {
266 	    super.refreshUILogic();
267 	    gestureDevice.clear();
268 	    initSampleSection(getDescriptor().getSamples());
269 	  }
270 
271 	  /**
272 	   * Context Menu for the sample elements
273 	   * 
274 	   * @author UeliKurmann
275 	   * 
276 	   */
277 	  public static class SampleIconMouseListener extends MouseAdapter {
278 	    private final Action action;
279 	    private final JPanel gesturePanel;
280 
281 	    public SampleIconMouseListener(Action action, JPanel gesturePanel) {
282 	      this.gesturePanel = gesturePanel;
283 	      this.action = action;
284 	    }
285 
286 	    @Override
287 	    public void mouseClicked(MouseEvent arg0) {
288 	      popUp(arg0);
289 	    }
290 
291 	    @Override
292 	    public void mouseReleased(MouseEvent e) {
293 	      popUp(e);
294 	    }
295 	    
296 	    @Override
297 	    public void mousePressed(MouseEvent e) {
298 	      popUp(e);
299 	    }
300 
301 	    private void popUp(MouseEvent e) {
302 	      if (e.isPopupTrigger()) {
303 	        JPopupMenu menu = new JPopupMenu();
304 	        JMenuItem item = new JMenuItem();
305 	        item.setAction(action);
306 	        menu.add(item);
307 	        menu.show(gesturePanel, e.getX(), e.getY());
308 	      }
309 	    }
310 	  }
311 
312 		/* (non-Javadoc)
313 		 * @see org.ximtec.igesture.tool.view.DevicePanelListener#update(org.ximtec.igesture.io.AbstractGestureDevice)
314 		 */
315 		@Override
316 		public void updateDeviceListPanelListener(AbstractGestureDevice<?, ?> device) {
317 			
318 			//remove listener from current device
319 			if(currentDevice != null)//!panelMapping.isEmpty())
320 				currentDevice.removeGestureHandler(panelMapping.get(currentDevice.toString()).getGestureDevicePanel());
321 			//change input panel
322 			((CardLayout)cardPanel.getLayout()).show(cardPanel, device.toString());
323 			currentDevice = device;
324 			
325 			//add listener to new device
326 			device.addGestureHandler(panelMapping.get(device.toString()).getGestureDevicePanel());
327 			
328 			repaint();
329 //			paintAll(getGraphics());
330 		}
331 		
332 		private InputComponentPanel createInputPanel(GestureDevice<?,?> device)
333 		{
334 			InputComponentPanel inputComponentPanel = new InputComponentPanel();
335 			inputComponentPanel.setLayout(new FlowLayout());
336 			GestureDevicePanel inputPanelInstance = InputPanelFactory.createPanel(device);
337 			inputComponentPanel.setGestureDevicePanel(inputPanelInstance);			
338 			inputComponentPanel.add(inputPanelInstance);
339 			
340 			// buttons
341 		    JPanel buttonPanel = new JPanel();
342 		    buttonPanel.setLayout(new BorderLayout());
343 		    buttonPanel.add(createAddSampleButton(getDescriptor(),device),BorderLayout.NORTH);//TODO
344 		    buttonPanel.add(createClearSampleButton(device),BorderLayout.CENTER);
345 		    
346 		    inputComponentPanel.add(buttonPanel);	 
347 			
348 			return inputComponentPanel;
349 		}
350 
351 		private void addDevice(AbstractGestureDevice<?,?> device)
352 		{
353 			if(Constant.TYPE_3D == device.getDeviceType())
354 			{
355 				//add input panel
356 				InputComponentPanel panel = createInputPanel(device);
357 				panelMapping.put(device.toString(), panel);
358 				cardPanel.add(panel,device.toString());
359 				//add device to device list
360 				devicePanel.addDevice(device);
361 			}
362 		}
363 		
364 		private void removeDevice(AbstractGestureDevice<?,?> device)
365 		{
366 			if(Constant.TYPE_3D == device.getDeviceType())
367 			{
368 				devicePanel.removeDevice(device);
369 				//remove input panel
370 				InputComponentPanel panel = panelMapping.get(device.toString());
371 				cardPanel.remove(panel);
372 			}
373 		}
374 		
375 		/* (non-Javadoc)
376 		 * @see org.ximtec.igesture.tool.view.devicemanager.DeviceManagerListener#update(int, org.ximtec.igesture.io.AbstractGestureDevice)
377 		 */
378 		@Override
379 		public void updateDeviceManagerListener(int operation, AbstractGestureDevice<?, ?> device) {
380 			if(operation == DeviceManagerListener.ADD)
381 			{
382 				addDevice(device);
383 			} 
384 			else if(operation == DeviceManagerListener.REMOVE)
385 			{
386 				removeDevice(device);
387 			}
388 		}
389 
390 }