Mercurial > hg > ccmieditor
view 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 source
/* 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 java.util.ResourceBundle; 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.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.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(){ EditorFrame frame = DiagramEditorApp.getFrame(); if((frame == null)||(frame.getActiveTab() == null)) return; frame.selectHapticHighligh(null); } }; } /** * 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, 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 : 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 : 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 : 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; frame.selectHapticHighligh(de); } }); break; case UNSELECT : SwingUtilities.invokeLater(unselectRunnable); break; 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((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(); 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()) .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)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(); 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()); } 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); } break; 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) ){ 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 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(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; } } private void iLog(String action, String args){ InteractionLog.log(INTERACTION_LOG_SOURCE,action,args); } private Runnable unselectRunnable; private static String INTERACTION_LOG_SOURCE = "HAPTIC"; //private EditorFrame frame; }