summaryrefslogtreecommitdiff
path: root/roombacomm-client/src/com/hackingroomba/roombacomm/RoombaRecorder.java
diff options
context:
space:
mode:
authorIdo Hadanny <ido.hadanny@gmail.com>2011-09-22 21:30:13 +0300
committerIdo Hadanny <ido.hadanny@gmail.com>2011-09-22 21:30:13 +0300
commit53b947df484159f5934898ba6c0aa69a9c869007 (patch)
tree189d5903a67765c390de8f1e3423e6b80cde57d1 /roombacomm-client/src/com/hackingroomba/roombacomm/RoombaRecorder.java
parent654ca6d59e99b5e72b05dfb917bc5888c4ba6b1b (diff)
added stuff
Diffstat (limited to 'roombacomm-client/src/com/hackingroomba/roombacomm/RoombaRecorder.java')
-rw-r--r--roombacomm-client/src/com/hackingroomba/roombacomm/RoombaRecorder.java591
1 files changed, 591 insertions, 0 deletions
diff --git a/roombacomm-client/src/com/hackingroomba/roombacomm/RoombaRecorder.java b/roombacomm-client/src/com/hackingroomba/roombacomm/RoombaRecorder.java
new file mode 100644
index 0000000..81cd305
--- /dev/null
+++ b/roombacomm-client/src/com/hackingroomba/roombacomm/RoombaRecorder.java
@@ -0,0 +1,591 @@
+/*
+ * RoombaRecorder --
+ *
+ * Copyright (c) 2006 Tod E. Kurt, tod@todbot.com, ThingM
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307 USA
+ *
+ */
+
+
+package com.hackingroomba.roombacomm;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.text.*;
+import javax.swing.filechooser.*;
+import java.util.*;
+import java.io.*;
+
+/**
+ * A simple wrapper for multiple MacroRecorderPanels
+ *
+ */
+public class RoombaRecorder extends JFrame implements WindowListener,ActionListener {
+
+ static final String helpMsg = "<html>"+
+ //"<h2> </h2>"+
+ "<h2> Roomba Movement Keyboard Shortcuts </h2>"+
+ "<ul>"+
+ "<li> arrow keys -- move Roomba"+
+ "<li> space bar -- stop Roomba"+
+ "<li> L -- blink Roomba LEDs"+
+ "<li> V -- toggle Roomba vacuum"+
+ "<li> T -- test Roomba"+
+ "<li> R -- reset Roomba"+
+ "<li> 1,2,3,4 -- adjust speed"+
+ "</ul>"+
+ "<h2> Application Control Keyboard Shortcuts </h2>"+
+ "<ul>"+
+ "<li> cmd-T -- open new tab"+
+ "<li> cmd-W -- close current tab"+
+ "<li> cmd-arrow-left/right -- cycle through tabs"+
+ "<li> cmd-X/C/V -- cut/copy/paste events between tabs"+
+ "</ul>"+
+ "</html>";
+
+ JPanel contentPane;
+ JPanel recordPanel;
+ JTabbedPane tabbedPane;
+ JButton stopButton,recordButton,playButton;
+ JCheckBox loopButton;
+ JCheckBox playAllButton;
+ JFileChooser fc;
+ File file;
+ boolean hwhandshake = false;
+ int maxRoombas = 16;
+ int lastTab = 0;
+ HashMap clipboard;
+ RoombaRecorderPanel rrpanel; // just to make some of code lines shorter
+ boolean movingForward = false; // is roomba moving forward or not
+ boolean vacuuming = false; // is roomba vacuuming or not
+ int turnval = 0;
+
+ public static void main(String[] args) {
+ new RoombaRecorder(args);
+ }
+
+ public RoombaRecorder(String[] args) {
+ super("RoombaRecorder");
+ addWindowListener(this);
+
+ for(int i=0; i < args.length; i++) {
+ if(args[i].endsWith("hwhandshake"))
+ hwhandshake = true;
+ }
+
+ clipboard = new HashMap();
+ fc = new JFileChooser();
+
+ setResizable(false);
+
+ makeMenu();
+
+ makeRecordPanel();
+
+ // Create and set up the content pane.
+ tabbedPane = new JTabbedPane();
+ tabbedPane.setOpaque(true); //content panes must be opaque
+ openNewTab();
+
+ contentPane = new JPanel(new BorderLayout());
+
+ contentPane.add(recordPanel, BorderLayout.NORTH);
+ contentPane.add(tabbedPane, BorderLayout.CENTER);
+
+ //Container content = getContentPane();
+ setContentPane(contentPane);
+
+ addBindings();
+ bindKeys();
+
+ // Display the window.
+ pack(); //setSize(400, 400);
+ setVisible(true);
+
+ //setFocusableWindowState(false); // prevent focus
+ }
+
+ void makeMenu() {
+ JMenuBar menubar = new JMenuBar();
+ JMenuItem item;
+
+ JMenu file = new JMenu("File");
+ JMenu edit = new JMenu("Edit");
+ JMenu help = new JMenu("Help");
+
+ file.setMnemonic(KeyEvent.VK_F);
+ edit.setMnemonic(KeyEvent.VK_E);
+ help.setMnemonic(KeyEvent.VK_H);
+
+ item = new JMenuItem("New Tab");
+ item.addActionListener(this);
+ file.add(item);
+ item = new JMenuItem("Close Tab");
+ item.addActionListener(this);
+ file.add(item);
+ item = new JMenuItem("Open Set");
+ item.addActionListener(this);
+ file.add(item);
+ item = new JMenuItem("Save Set");
+ item.addActionListener(this);
+ file.add(item);
+ item = new JMenuItem("Quit");
+ item.addActionListener(this);
+ file.add(item);
+
+ item = new JMenuItem("Cut");
+ item.addActionListener(this);
+ edit.add(item);
+ item = new JMenuItem("Copy");
+ item.addActionListener(this);
+ edit.add(item);
+ item = new JMenuItem("Paste");
+ item.addActionListener(this);
+ edit.add(item);
+
+ item = new JMenuItem("Help");
+ item.addActionListener(this);
+ help.add(item);
+
+ menubar.add(file);
+ menubar.add(edit);
+ menubar.add(help);
+
+ setJMenuBar(menubar);
+ }
+
+ void makeRecordPanel() {
+ recordPanel = new JPanel();
+ recordPanel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createTitledBorder("Action Record"), BorderFactory.createEmptyBorder())); //1,1,1,1)));
+ stopButton = new JButton(createImageIcon("images/but_transport_stop.png","stop"));
+ stopButton.setActionCommand("stop");
+ stopButton.addActionListener(this);
+ recordPanel.add(stopButton);
+ playButton = new JButton(createImageIcon("images/but_transport_play.png","play"));
+ playButton.setSelectedIcon(createImageIcon("images/but_transport_play_push.png","play"));
+ playButton.setActionCommand("play");
+ playButton.addActionListener(this);
+ recordPanel.add(playButton);
+ recordButton = new JButton(createImageIcon("images/but_transport_record.png","record"));
+ recordButton.setSelectedIcon(createImageIcon("images/but_transport_record_push.png","record"));
+ recordButton.setActionCommand("record");
+ recordButton.addActionListener(this);
+ recordPanel.add(recordButton);
+
+ loopButton = new JCheckBox("loop");
+ loopButton.setText("loop");
+ loopButton.setActionCommand("loop");
+ loopButton.addActionListener(this);
+ recordPanel.add(loopButton);
+
+ playAllButton = new JCheckBox("play all");
+ playAllButton.addActionListener(this);
+ recordPanel.add(playAllButton);
+ }
+
+ void addBindings() {
+ InputMap inputMap = contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
+ KeyStroke key;
+
+ //key = KeyStroke.getKeyStroke(KeyEvent.VK_SPACE,0);
+ //contentPane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).remove(key);
+
+ key = KeyStroke.getKeyStroke('T',KeyEvent.CTRL_MASK);
+ inputMap.put(key, "new-tab");
+ key = KeyStroke.getKeyStroke('T',KeyEvent.META_MASK);
+ inputMap.put(key, "new-tab");
+ key = KeyStroke.getKeyStroke('N',KeyEvent.CTRL_MASK);
+ inputMap.put(key, "new-tab");
+ key = KeyStroke.getKeyStroke('N',KeyEvent.META_MASK);
+ inputMap.put(key, "new-tab");
+
+ key = KeyStroke.getKeyStroke('W',KeyEvent.CTRL_MASK);
+ inputMap.put(key, "close-tab");
+ key = KeyStroke.getKeyStroke('W',KeyEvent.META_MASK);
+ inputMap.put(key, "close-tab");
+
+ key = KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT,KeyEvent.CTRL_MASK);
+ inputMap.put(key, "right-tab");
+ key = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT,KeyEvent.CTRL_MASK);
+ inputMap.put(key, "left-tab");
+ key = KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT,KeyEvent.META_MASK);
+ inputMap.put(key, "right-tab");
+ key = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT,KeyEvent.META_MASK);
+ inputMap.put(key, "left-tab");
+
+ key = KeyStroke.getKeyStroke('X',KeyEvent.CTRL_MASK);
+ inputMap.put(key, "cut");
+ key = KeyStroke.getKeyStroke('X',KeyEvent.META_MASK);
+ inputMap.put(key, "cut");
+ key = KeyStroke.getKeyStroke('C',KeyEvent.CTRL_MASK);
+ inputMap.put(key, "copy");
+ key = KeyStroke.getKeyStroke('C',KeyEvent.META_MASK);
+ inputMap.put(key, "copy");
+ key = KeyStroke.getKeyStroke('V',KeyEvent.CTRL_MASK);
+ inputMap.put(key, "paste");
+ key = KeyStroke.getKeyStroke('V',KeyEvent.META_MASK);
+ inputMap.put(key, "paste");
+
+ ActionMap actionMap = contentPane.getActionMap();
+ actionMap.put("new-tab", new AbstractAction() {
+ public void actionPerformed(ActionEvent e) {
+ openNewTab();
+ } });
+ actionMap.put("close-tab",new AbstractAction() {
+ public void actionPerformed(ActionEvent e) {
+ closeCurrentTab();
+ } });
+ actionMap.put("left-tab",new AbstractAction() {
+ public void actionPerformed(ActionEvent e) {
+ cycleTabLeft();
+ } });
+ actionMap.put("right-tab",new AbstractAction() {
+ public void actionPerformed(ActionEvent e) {
+ cycleTabRight();
+ } });
+ actionMap.put("cut",new AbstractAction() {
+ public void actionPerformed(ActionEvent e) {
+ clipboard = getCurrentTab().cut();
+ } });
+ actionMap.put("copy",new AbstractAction() {
+ public void actionPerformed(ActionEvent e) {
+ clipboard = getCurrentTab().copy();
+ } });
+ actionMap.put("paste",new AbstractAction() {
+ public void actionPerformed(ActionEvent e) {
+ getCurrentTab().paste(clipboard);
+ } });
+ }
+
+ /**
+ * Bind keys to actions using a custom KeyEventPostProcessor
+ * (fixme: why can't this go in the panel?)
+ */
+ void bindKeys() {
+ // ahh, the succinctness of java
+ KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
+
+ kfm.addKeyEventDispatcher( new KeyEventDispatcher() {
+ public boolean dispatchKeyEvent(KeyEvent e) {
+ String action=null;
+ if(e.getID() != KeyEvent.KEY_PRESSED)
+ return false;
+ if(e.getModifiers() != 0)
+ return false;
+ switch(e.getKeyCode()) {
+ case KeyEvent.VK_UP:
+ action = "forward";
+ movingForward=true;
+ turnval = 0;
+ break;
+ case KeyEvent.VK_DOWN:
+ action="backward";
+ movingForward=false;
+ turnval = 0;
+ break;
+ case KeyEvent.VK_LEFT:
+ if(movingForward) {
+ turnval = (turnval==0) ? 100 : turnval-turnval/2;
+ if(turnval<10) { action="spinleft"; turnval=0; }
+ else action = "turn"+turnval;
+ }
+ else action = "spinleft";
+ //action = (movingForward) ? "turn100" : "spinleft";
+ break;
+ case KeyEvent.VK_RIGHT:
+ if(movingForward) {
+ turnval = (turnval==0) ? -100 : turnval-turnval/2;
+ if(turnval>-10) { action="spinright"; turnval=0; }
+ else action = "turn"+turnval;
+ }
+ else action = "spinright";
+ //action = (movingForward) ? "turn-100" : "spinright";
+ break;
+ case KeyEvent.VK_SPACE:
+ action="stop";
+ movingForward=false;
+ turnval = 0;
+ break;
+ case KeyEvent.VK_L:
+ action="blink-leds";
+ break;
+ case KeyEvent.VK_R:
+ action="reset";
+ break;
+ case KeyEvent.VK_T:
+ action="test";
+ break;
+ case KeyEvent.VK_V:
+ vacuuming = !vacuuming;
+ action = (vacuuming) ? "vacuum-on":"vacuum-off";
+ break;
+ case KeyEvent.VK_1:
+ action="50";
+ break;
+ case KeyEvent.VK_2:
+ action="100";
+ break;
+ case KeyEvent.VK_3:
+ action="150";
+ break;
+ case KeyEvent.VK_4:
+ action="250";
+ break;
+ case KeyEvent.VK_5:
+ action="400";
+ break;
+ case KeyEvent.VK_6:
+ action="500";
+ break;
+ }
+
+ if(action!=null)
+ getCurrentTab().actionPerformed(new ActionEvent(this,0,action));
+ //System.out.println("process '"+e.getKeyCode()+"' "+e);
+ return true;
+ }
+ });
+ }
+
+ /** Implement Actionlistener */
+ public void actionPerformed(ActionEvent event) {
+ String action = event.getActionCommand();
+ //System.out.println("action:"+action+", event: "+event);
+ if("stop".equals(action)) {
+ playButton.setSelected(false);
+ recordButton.setSelected(false);
+ for(int i=0; i<tabbedPane.getTabCount(); i++) {
+ rrpanel = (RoombaRecorderPanel)tabbedPane.getComponentAt(i);
+ rrpanel.stop();
+ }
+ }
+ else if("play".equals(action)) {
+ playButton.setSelected(true);
+ recordButton.setSelected(false);
+ if( !playAllButton.isSelected() ) {
+ boolean playing = getCurrentTab().play(); // FIXME: hack
+ if(!playing) playButton.setSelected(false);
+ } else {
+ for(int i=0; i<tabbedPane.getTabCount(); i++) {
+ rrpanel= (RoombaRecorderPanel)tabbedPane.getComponentAt(i);
+ rrpanel.play();
+ }
+ }
+ }
+ else if("record".equals(action)) {
+ playButton.setSelected(false);
+ recordButton.setSelected(true);
+ if( !playAllButton.isSelected() ) {
+ getCurrentTab().record();
+ } else {
+ int ir = tabbedPane.getSelectedIndex();
+ for(int i=0; i<tabbedPane.getTabCount(); i++) {
+ rrpanel= (RoombaRecorderPanel)tabbedPane.getComponentAt(i);
+ if( i!=ir ) rrpanel.play();
+ else rrpanel.record();
+ }
+ }
+ }
+ else if("loop".equals(action)) {
+ for(int i=0; i<tabbedPane.getTabCount(); i++) {
+ rrpanel= (RoombaRecorderPanel)tabbedPane.getComponentAt(i);
+ rrpanel.setLooping(loopButton.isSelected());
+ }
+ }
+ else if("New Tab".equals(action)) {
+ openNewTab();
+ }
+ else if("Close Tab".equals(action)) {
+ closeCurrentTab();
+ }
+ else if("Open Set".equals(action)) {
+ loadSet();
+ }
+ else if("Save Set".equals(action)) {
+ saveSet();
+ }
+ else if("Save Set As...".equals(action)) {
+ file = null;
+ saveSet();
+ }
+ else if("Quit".equals(action)) {
+ closeAllTabs();
+ windowClosing(null);
+ }
+ else if("Cut".equals(action)) {
+ clipboard = getCurrentTab().cut();
+ }
+ else if("Copy".equals(action)) {
+ clipboard = getCurrentTab().copy();
+ }
+ else if("Paste".equals(action)) {
+ getCurrentTab().paste(clipboard);
+ }
+ else if("Help".equals(action)) {
+ JOptionPane.showMessageDialog(null,new JLabel(helpMsg));
+ }
+ }
+
+ public RoombaRecorderPanel getCurrentTab() {
+ return (RoombaRecorderPanel) tabbedPane.getComponentAt(tabbedPane.getSelectedIndex());
+ }
+
+ public void openNewTab() {
+ int i = tabbedPane.getTabCount();
+ if(i < maxRoombas) { // only 16 roombas supported
+ rrpanel = new RoombaRecorderPanel();
+ rrpanel.setShowHardwareHandhake(hwhandshake);
+ lastTab = lastTab+1;
+ tabbedPane.addTab("Roomba #"+lastTab, null, rrpanel);
+ tabbedPane.setSelectedIndex(lastTab-1);
+ }
+ }
+ public void closeAllTabs() {
+ int c = tabbedPane.getTabCount();
+ for( int i=0; i<c; i++)
+ closeCurrentTab();
+ lastTab = 0;
+ }
+ public void closeCurrentTab() {
+ int i = tabbedPane.getSelectedIndex();
+ rrpanel = (RoombaRecorderPanel)tabbedPane.getComponentAt(i);
+ rrpanel.disconnect();
+ tabbedPane.remove(i);
+ }
+
+ public void cycleTabLeft() {
+ int i = tabbedPane.getSelectedIndex() - 1;
+ if(i<0) i = tabbedPane.getTabCount() - 1;
+ tabbedPane.setSelectedIndex(i);
+ loopButton.setSelected( getCurrentTab().getLooping() );
+ }
+ public void cycleTabRight() {
+ int i = tabbedPane.getSelectedIndex() + 1;
+ if(i==tabbedPane.getTabCount()) i = 0;
+ tabbedPane.setSelectedIndex(i);
+ }
+
+ /**
+ * Load a save set from a chosen file
+ */
+ void loadSet() {
+ int returnVal = fc.showOpenDialog(this);
+ if (returnVal != JFileChooser.APPROVE_OPTION) {
+ System.out.println("Open command cancelled by user.");
+ return;
+ }
+ file = fc.getSelectedFile();
+ System.out.println("Opening: " + file.getName());
+ closeAllTabs();
+ try {
+ FileInputStream fis = new FileInputStream(file);
+ ObjectInputStream ois = new ObjectInputStream(fis);
+ //loopButton.setSelected( ois.readObject() );
+ ArrayList l = (ArrayList) ois.readObject();
+ System.out.println("read "+l.size()+" thingies");
+ ois.close();
+ for(int i=0; i<l.size(); i++) {
+ HashMap m = (HashMap) l.get(i);
+ openNewTab();
+ getCurrentTab().paste(m);
+ }
+ } catch(Exception e) {
+ System.out.println("Open error "+e);
+ }
+ }
+
+ /**
+ * Save the current set to a file.
+ * Will ask for a filename if one hasn't been chosen.
+ */
+ void saveSet() {
+ if( file==null ) {
+ int returnVal = fc.showSaveDialog(this);
+ if (returnVal != JFileChooser.APPROVE_OPTION) {
+ System.out.println("Open command cancelled by user.");
+ return;
+ }
+ file = fc.getSelectedFile();
+ }
+ System.out.println("Saving to: " + file.getName());
+ try {
+ int count = tabbedPane.getTabCount();
+ ArrayList l = new ArrayList();
+ for(int i=0; i< count; i++) {
+ rrpanel= (RoombaRecorderPanel)tabbedPane.getComponentAt(i);
+ l.add(rrpanel.copy());
+ }
+ FileOutputStream fos = new FileOutputStream(file);
+ ObjectOutputStream oos = new ObjectOutputStream(fos);
+ //oos.writeObject(loopButton);
+ //oos.writeObject(
+ oos.writeObject(l);
+ oos.close();
+ } catch( Exception e ) {
+ System.out.println("Save error "+e);
+ }
+ }
+
+ /** implement windowlistener */
+ public void windowClosing(WindowEvent event) {
+ //rcPanel.disconnect();
+ System.exit(0);
+ }
+ /** implement windowlistener */
+ public void windowClosed(WindowEvent event) {
+ // do nothing
+ }
+ /** implement windowlistener */
+ public void windowOpened(WindowEvent event) {
+ // do nothing
+ }
+ /** implement windowlistener */
+ public void windowActivated(WindowEvent event) {
+ // do nothing
+ }
+ /** implement windowlistener */
+ public void windowDeactivated(WindowEvent event) {
+ // do nothing
+ }
+ /** implement windowlistener */
+ public void windowIconified(WindowEvent event) {
+ // do nothing
+ }
+ /** implement windowlistener */
+ public void windowDeiconified(WindowEvent event) {
+ // do nothing
+ }
+
+
+ /** Returns an ImageIcon, or null if the path was invalid. */
+ protected static ImageIcon createImageIcon(String path,
+ String description) {
+ // yes, this is supposed to say "RoombaCommTest"
+ java.net.URL imgURL = RoombaCommPanel.class.getResource(path);
+ if (imgURL != null) {
+ return new ImageIcon(imgURL, description);
+ } else {
+ System.err.println("Couldn't find file: " + path);
+ return null;
+ }
+ }
+
+
+}
+