diff java/src/uk/ac/qmul/eecs/ccmi/gui/HapticKindle.java @ 0:9418ab7b7f3f

Initial import
author Fiore Martin <fiore@eecs.qmul.ac.uk>
date Fri, 16 Dec 2011 17:35:51 +0000
parents
children 9e67171477bc
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/java/src/uk/ac/qmul/eecs/ccmi/gui/HapticKindle.java	Fri Dec 16 17:35:51 2011 +0000
@@ -0,0 +1,217 @@
+/*  
+ CCmI Editor - A Collaborative Cross-Modal Diagram Editing Tool
+  
+ Copyright (C) 2011  Queen Mary University of London (http://ccmi.eecs.qmul.ac.uk/)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+package uk.ac.qmul.eecs.ccmi.gui;
+
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+
+import javax.swing.SwingUtilities;
+
+import uk.ac.qmul.eecs.ccmi.diagrammodel.CollectionModel;
+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.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;
+
+/**
+ * 
+ * An instance of HapticListener for the diagram editor. By this class visual diagrams 
+ * can be manipulated by an haptic device.  
+ *
+ */
+public class HapticKindle extends HapticListener {
+	
+	public HapticKindle(){
+		super();
+		unselectRunnable = new Runnable(){
+			@Override
+			public void run(){
+				frame.selectHapticHighligh(null);
+			}
+		};
+		frameBackupRunnable = new Runnable(){
+			@Override
+			public void run(){
+				frame.backupOpenDiagrams();
+			}
+		};
+	}
+
+	public void setEditorFrame(EditorFrame frame){
+		this.frame = frame;
+	}
+	
+	@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;
+		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());
+			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());
+			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);
+				}
+			});
+			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;
+			}
+			
+			try {
+				SwingUtilities.invokeAndWait(new Runnable(){
+					@Override
+					public void run(){
+						if(moveSelectedElement instanceof Node){
+							Node n = (Node)moveSelectedElement;
+							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);
+
+							StringBuilder builder = new StringBuilder();
+							builder.append(DiagramElement.toLogString(n)).append(" ").append(p.getX())
+							.append(' ').append(p.getY());
+							iLog("move node start",builder.toString());
+							builder = new StringBuilder();
+							builder.append(DiagramElement.toLogString(n)).append(' ')
+							.append(x).append(' ').append(y);
+
+							iLog("move node end",builder.toString());
+							
+						}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);
+							iLog("bend edge start",builder.toString());
+							builder = new StringBuilder();
+							builder.append(DiagramElement.toLogString(e)).append(' ')
+							.append(x).append(' ').append(y);
+							iLog("bend edge end",builder.toString());
+							
+						}
+					}
+				});
+			} 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());
+			break;
+		case PLAY_SOUND :
+			switch(HapticListenerCommand.Sound.fromInt(ID) ){
+			case MAGNET_OFF : 
+				SoundFactory.getInstance().play(SoundEvent.MAGNET_OFF);
+				iLog("sticky mode off","");
+				break;
+			case MAGNET_ON : 
+				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 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");
+			break;
+		}
+	}
+	
+	private void iLog(String action, String args){
+		InteractionLog.log(INTERACTION_LOG_SOURCE,action,args);
+	}
+	
+	private Runnable unselectRunnable;
+	private Runnable frameBackupRunnable;
+	private static String INTERACTION_LOG_SOURCE = "HAPTIC"; 
+	private EditorFrame frame;
+}