diff java/src/uk/ac/qmul/eecs/ccmi/gui/HapticKindle.java @ 3:9e67171477bc

PHANTOM Omni Heptic device release
author Fiore Martin <fiore@eecs.qmul.ac.uk>
date Wed, 25 Apr 2012 17:09:09 +0100
parents 9418ab7b7f3f
children d66dd5880081
line wrap: on
line diff
--- a/java/src/uk/ac/qmul/eecs/ccmi/gui/HapticKindle.java	Mon Feb 06 12:54:06 2012 +0000
+++ b/java/src/uk/ac/qmul/eecs/ccmi/gui/HapticKindle.java	Wed Apr 25 17:09:09 2012 +0100
@@ -20,6 +20,7 @@
 
 import java.awt.geom.Point2D;
 import java.awt.geom.Rectangle2D;
+import java.util.ResourceBundle;
 
 import javax.swing.SwingUtilities;
 
@@ -27,8 +28,11 @@
 import uk.ac.qmul.eecs.ccmi.diagrammodel.DiagramElement;
 import uk.ac.qmul.eecs.ccmi.haptics.HapticListener;
 import uk.ac.qmul.eecs.ccmi.haptics.HapticListenerCommand;
+import uk.ac.qmul.eecs.ccmi.main.DiagramEditorApp;
+import uk.ac.qmul.eecs.ccmi.network.Command;
+import uk.ac.qmul.eecs.ccmi.network.DiagramEventActionSource;
+import uk.ac.qmul.eecs.ccmi.sound.SoundEvent;
 import uk.ac.qmul.eecs.ccmi.sound.SoundFactory;
-import uk.ac.qmul.eecs.ccmi.sound.SoundEvent;
 import uk.ac.qmul.eecs.ccmi.speech.NarratorFactory;
 import uk.ac.qmul.eecs.ccmi.utils.InteractionLog;
 
@@ -45,94 +49,94 @@
 		unselectRunnable = new Runnable(){
 			@Override
 			public void run(){
+				EditorFrame frame = DiagramEditorApp.getFrame();
+				if((frame == null)||(frame.getActiveTab() == null))
+					return;
 				frame.selectHapticHighligh(null);
 			}
 		};
-		frameBackupRunnable = new Runnable(){
-			@Override
-			public void run(){
-				frame.backupOpenDiagrams();
-			}
-		};
 	}
 
-	public void setEditorFrame(EditorFrame frame){
-		this.frame = frame;
-	}
-	
+	/**
+	 * Implementation of the {@code executeCommand} method. All the commands that involve the 
+	 * diagram model, are executed in the Event Dispatching Thread through {@code SwingUtilities} invoke
+	 * methods. This prevents race conditions on the model and on diagram elements. 
+	 * 
+	 * @see HapticListener#executeCommand(HapticListenerCommand, int, double, double, double, double)
+	 */
 	@Override
-	public void executeCommand(HapticListenerCommand cmd, int ID, final double x, final double y, final double startX, final double startY) {
-		if((frame == null)||(frame.getActiveTab() == null))
-			return;
-		CollectionModel<Node,Edge> collectionModel = frame.getActiveTab().getDiagram().getCollectionModel();
-		Object monitor = collectionModel.getMonitor();
-		DiagramElement de = null;
+	public void executeCommand(HapticListenerCommand cmd, final int ID, final double x, final double y, final double startX, final double startY) {
+		final EditorFrame frame = DiagramEditorApp.getFrame();
 		switch(cmd){
-		case PLAY_ELEMENT_SOUND :
-			synchronized(monitor){
-				de = Finder.findElementByHashcode(ID, collectionModel.getElements());
-			}
-			/* can be null if the tab has been switched or closed in the meantime */
-			if(de == null)
-				return;
-			SoundFactory.getInstance().play(de.getSound());
+		case PLAY_ELEMENT_SOUND :  
+			SwingUtilities.invokeLater(new Runnable(){
+				public void run(){
+					if((frame == null)||(frame.getActiveTab() == null))
+						return;
+					CollectionModel<Node,Edge> collectionModel = frame.getActiveTab().getDiagram().getCollectionModel();
+					DiagramElement de = Finder.findElementByHashcode(ID, collectionModel.getElements());
+					/* can be null if the tab has been switched or closed in the meantime */
+					if(de == null)
+						return;
+					SoundFactory.getInstance().play(de.getSound());
+				}
+			});
 			break;
 		case PLAY_ELEMENT_SPEECH : 
-			synchronized(monitor){
-				de = Finder.findElementByHashcode(ID, collectionModel.getElements());
-			}
-			if(de == null)
-				return;
-			SoundFactory.getInstance().play(de.getSound());
-			NarratorFactory.getInstance().speak(de.getName());
-			iLog("touch",((de instanceof Node) ? "node " : "edge ")+de.getName());
+			SwingUtilities.invokeLater(new Runnable(){
+				public void run(){
+					if((frame == null)||(frame.getActiveTab() == null))
+						return;
+					CollectionModel<Node,Edge> collectionModel = frame.getActiveTab().getDiagram().getCollectionModel();
+					DiagramElement de = Finder.findElementByHashcode(ID, collectionModel.getElements());
+					if(de == null)
+						return;
+					SoundFactory.getInstance().play(de.getSound());
+					NarratorFactory.getInstance().speak(de.getName());
+					iLog("touch",((de instanceof Node) ? "node " : "edge ")+de.getName());
+				}
+			});
 			break;
 		case SELECT :
-			synchronized(monitor){
-				de = Finder.findElementByHashcode(ID, collectionModel.getElements());
-			}
-			if(de == null)
-				return;
-			final DiagramElement selectedElement = de; 
 			SwingUtilities.invokeLater(new Runnable(){
-				@Override
 				public void run(){
-					frame.selectHapticHighligh(selectedElement);
+					if((frame == null)||(frame.getActiveTab() == null))
+						return;
+					CollectionModel<Node,Edge> collectionModel = frame.getActiveTab().getDiagram().getCollectionModel();
+					DiagramElement de = Finder.findElementByHashcode(ID, collectionModel.getElements());
+					if(de == null)
+						return;
+					frame.selectHapticHighligh(de);
 				}
 			});
 			break;
 		case UNSELECT :
 			SwingUtilities.invokeLater(unselectRunnable);
 			break;
-		case MOVE :
-			DiagramPanel dPanel = frame.getActiveTab();
-			if(dPanel == null)
-				return;
-			synchronized(monitor){
-				de = Finder.findElementByHashcode(ID, collectionModel.getElements());
-			}
-			if(de == null)
-				return;
-			final DiagramElement moveSelectedElement = de;
-			final DiagramModelUpdater modelUpdater = dPanel.getDiagram().getModelUpdater();
-			if(!modelUpdater.getLock(moveSelectedElement, Lock.MOVE)){
-				iLog("Could not get lock on element for motion", DiagramElement.toLogString(moveSelectedElement));
-				NarratorFactory.getInstance().speak("Object is being moved by another user");
-				return;
-			}
-			
+		case MOVE : {
+			/* when this block is executed we already have the lock * 
+			 * on the element from the PICK_UP command execution    */
 			try {
 				SwingUtilities.invokeAndWait(new Runnable(){
 					@Override
 					public void run(){
-						if(moveSelectedElement instanceof Node){
-							Node n = (Node)moveSelectedElement;
+						if((frame == null)||(frame.getActiveTab() == null))
+							return;
+						CollectionModel<Node,Edge> collectionModel = frame.getActiveTab().getDiagram().getCollectionModel();
+						DiagramElement de = Finder.findElementByHashcode(ID, collectionModel.getElements());
+						if(de == null)
+							return;
+						DiagramModelUpdater modelUpdater = frame.getActiveTab().getDiagram().getModelUpdater();
+						if(de instanceof Node){
+							Node n = (Node)de;
 							Rectangle2D bounds = n.getBounds();
 							Point2D.Double p = new Point2D.Double(bounds.getCenterX(),bounds.getCenterY());
 							double dx = x - p.getX();
 							double dy = y - p.getY();
-							modelUpdater.translate(n, p, dx, dy);
-							modelUpdater.stopMove(n);
+							n.getMonitor().lock();
+							modelUpdater.translate(n, p, dx, dy,DiagramEventSource.HAPT);
+							modelUpdater.stopMove(n,DiagramEventSource.HAPT);
+							n.getMonitor().unlock();
 
 							StringBuilder builder = new StringBuilder();
 							builder.append(DiagramElement.toLogString(n)).append(" ").append(p.getX())
@@ -141,16 +145,16 @@
 							builder = new StringBuilder();
 							builder.append(DiagramElement.toLogString(n)).append(' ')
 							.append(x).append(' ').append(y);
-
 							iLog("move node end",builder.toString());
+						}else{
+							Edge e = (Edge)de;
+							modelUpdater.startMove(e, new Point2D.Double(startX,startY),DiagramEventSource.HAPT);
+							Point2D p  = new Point2D.Double(x,y);
+							e.getMonitor().lock();
+							modelUpdater.bend(e, p,DiagramEventSource.HAPT);
+							modelUpdater.stopMove(e,DiagramEventSource.HAPT);
+							e.getMonitor().unlock();
 							
-						}else{
-							Edge e = (Edge)moveSelectedElement;
-							modelUpdater.startMove(e, new Point2D.Double(startX,startY));
-							Point2D p  = new Point2D.Double(x,y);
-							modelUpdater.bend(e, p);
-							modelUpdater.stopMove(e);
-
 							StringBuilder builder = new StringBuilder();
 							builder.append(DiagramElement.toLogString(e)).append(' ').append(startX)
 							.append(' ').append(startY);
@@ -159,25 +163,37 @@
 							builder.append(DiagramElement.toLogString(e)).append(' ')
 							.append(x).append(' ').append(y);
 							iLog("bend edge end",builder.toString());
-							
 						}
-					}
+						modelUpdater.yieldLock(de,
+								Lock.MOVE,
+								new DiagramEventActionSource(
+										DiagramEventSource.HAPT,
+										de instanceof Node ? Command.Name.STOP_NODE_MOVE : Command.Name.STOP_EDGE_MOVE,
+										de.getId(),
+										de.getName()
+										));
+					} // run()
 				});
 			} catch (Exception e) {
 				throw new RuntimeException(e);
 			}
 			SoundFactory.getInstance().play(SoundEvent.HOOK_OFF);
-			modelUpdater.yieldLock(moveSelectedElement, Lock.MOVE);
+		}
 			break;
-		case INFO :
-			synchronized(monitor){
-				de = Finder.findElementByHashcode(ID, collectionModel.getElements());
-			}
-			if(de == null)
-				return;
-			SoundFactory.getInstance().stop();
-			NarratorFactory.getInstance().speak(de.detailedSpokenText());
-			iLog("request detailed info",((de instanceof Node) ? "node " : "edge ")+de.getName());
+		case INFO : 
+			SwingUtilities.invokeLater(new Runnable(){
+				public void run(){
+					if((frame == null)||(frame.getActiveTab() == null))
+						return;
+					CollectionModel<Node,Edge> collectionModel = frame.getActiveTab().getDiagram().getCollectionModel();
+					DiagramElement de = Finder.findElementByHashcode(ID, collectionModel.getElements());
+					if(de == null)
+						return;
+					SoundFactory.getInstance().stop();
+					NarratorFactory.getInstance().speak(de.detailedSpokenText());
+					iLog("request detailed info",((de instanceof Node) ? "node " : "edge ")+de.getName());					
+				}
+			});
 			break;
 		case PLAY_SOUND :
 			switch(HapticListenerCommand.Sound.fromInt(ID) ){
@@ -189,19 +205,50 @@
 				SoundFactory.getInstance().play(SoundEvent.MAGNET_ON);
 				iLog("sticky mode on","");
 				break;
-			case HOOK_ON : 
-				SoundFactory.getInstance().play(SoundEvent.HOOK_ON);
-				iLog("hook on","");
-				break;
 			case DRAG : SoundFactory.getInstance().play(SoundEvent.DRAG);
 				break;
 			}
 			break;
+		case PICK_UP :
+			try {
+				SwingUtilities.invokeAndWait(new Runnable (){
+					@Override
+					public void run(){
+						if((frame == null)||(frame.getActiveTab() == null))
+							return;
+						CollectionModel<Node,Edge> collectionModel = frame.getActiveTab().getDiagram().getCollectionModel();
+						DiagramElement de = Finder.findElementByHashcode(ID, collectionModel.getElements());
+						if(de == null)
+							return;
+						DiagramModelUpdater modelUpdater = frame.getActiveTab().getDiagram().getModelUpdater();
+						if(!modelUpdater.getLock(de, 
+								Lock.MOVE,
+								new DiagramEventActionSource(DiagramEventSource.HAPT, de instanceof Edge ? Command.Name.TRANSLATE_EDGE : Command.Name.TRANSLATE_NODE ,de.getId(),de.getName()))){
+							iLog("Could not get lock on element for motion", DiagramElement.toLogString(de));
+							NarratorFactory.getInstance().speak("Object is being moved by another user");
+							return;
+						}
+						frame.hPickUp(de);
+						SoundFactory.getInstance().play(SoundEvent.HOOK_ON);
+						iLog("hook on","");
+					}
+				});
+			}catch(Exception e){
+				e.printStackTrace();
+				throw new RuntimeException();	
+			}
+			break;
 		case ERROR : 
 			/* no synchronization necessary as the XMLManager looks after it*/
-			SwingUtilities.invokeLater(frameBackupRunnable);
-			NarratorFactory.getInstance().speak("Haptic device crashed. " +
-					"Unsaved diagrams saved in backup directory");
+			SwingUtilities.invokeLater(new Runnable(){
+				@Override
+				public void run(){
+					if((frame == null)||(frame.getActiveTab() == null))
+						return;
+					frame.backupOpenDiagrams();
+				}
+			});
+			NarratorFactory.getInstance().speak(ResourceBundle.getBundle(EditorFrame.class.getName()).getString("speech.haptic_device_crashed"));
 			break;
 		}
 	}
@@ -211,7 +258,6 @@
 	}
 	
 	private Runnable unselectRunnable;
-	private Runnable frameBackupRunnable;
 	private static String INTERACTION_LOG_SOURCE = "HAPTIC"; 
-	private EditorFrame frame;
+	//private EditorFrame frame;
 }