View Javadoc

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