changeset 417:267f9748e826

(no commit message)
author one
date Wed, 31 Dec 2008 14:52:45 +0900
parents b7f42fc75a36
children d1bfcff0cdd2
files test/editortest/REPCommandReceiver.java test/editortest/REPEditor.java test/editortest/REPTextEvent.java test/editortest/REPTextListener.java test/editortest/REPTextWithJTextArea.java test/editortest/SimpleEditorForREPEditor.java test/editortest/TestSimpleEditor.java
diffstat 7 files changed, 673 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/editortest/REPCommandReceiver.java	Wed Dec 31 14:52:45 2008 +0900
@@ -0,0 +1,71 @@
+package test.editortest;
+
+import java.io.IOException;
+import java.nio.channels.SelectionKey;
+
+import rep.REPCommand;
+import rep.channel.REPSelectionKey;
+import rep.channel.REPSelector;
+import rep.channel.REPSocketChannel;
+
+public class REPCommandReceiver extends Thread{
+	
+	REPSocketChannel<REPCommand> channel;
+	boolean running = true;
+	private boolean inputLock=false;
+	long timeout = 1;
+	private int syncCounter=0;
+
+	public REPCommandReceiver(REPSocketChannel<REPCommand> channel, REPSelector<REPCommand> selector){
+		this.channel = channel;
+	}
+	
+	public void run(){
+		try {
+			mainloop();
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+	}
+	
+	private void mainloop() throws IOException {
+		
+		channel.configureBlocking(false);
+		REPSelector<REPCommand> selector = REPSelector.create();
+		channel.register(selector, SelectionKey.OP_READ);
+		while(running) {
+			if (inputLock) {
+				// No user input during merge mode (optional)
+				if (selector.select(0)>0) {
+					handle(channel.read());
+				}
+				continue;
+			} else if (selector.select(timeout)<=0) {
+				if (syncCounter>0) {
+					syncText(); // send the master editor buffer to clients. 
+				}
+				userInput();
+			}
+			// selector(timeout) returns 0, but it may contain readable channel..
+			for(REPSelectionKey<REPCommand> key : selector.selectedKeys1()) {
+				REPSocketChannel<REPCommand> ch = key.channel1();
+				handle(ch.read());
+			}
+		}
+	}
+
+	private void userInput() {
+		// TODO Auto-generated method stub
+		
+	}
+
+	private void syncText() {
+		// TODO Auto-generated method stub
+		
+	}
+
+	private void handle(REPCommand read) {
+		// TODO Auto-generated method stub
+		
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/editortest/REPEditor.java	Wed Dec 31 14:52:45 2008 +0900
@@ -0,0 +1,247 @@
+package test.editortest;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.nio.channels.SelectionKey;
+import java.util.LinkedList;
+import rep.REP;
+import rep.REPCommand;
+import rep.REPCommandPacker;
+import rep.channel.REPSelectionKey;
+import rep.channel.REPSelector;
+import rep.channel.REPSocketChannel;
+
+
+public class REPEditor extends Thread implements REPTextListener{
+	
+	private REPSocketChannel<REPCommand> channel;
+	REPSelector<REPCommand> selector;
+	private boolean running = true;
+	private boolean inputLock = false;
+	private long timeout = 1;
+	private int syncCounter = 0;
+	private LinkedList<REPCommand> userCommand = new LinkedList<REPCommand>();
+	private LinkedList<Runnable> runners = new LinkedList<Runnable>();
+	private String name = "test";
+	private int seq;
+	private int eid;
+	private int sid;
+	private REPText repText;
+	private boolean hasInputLock;
+	private boolean master;
+	private boolean syncEnable = true;
+	private LogTarget logTarget;
+	
+	public REPEditor(REPText repText, boolean master){
+		this.repText = repText;
+		this.master = master;
+		repText.addTextListener(this);
+		if(master){
+			userCommand.add(new REPCommand(REP.SMCMD_PUT,0,0,0,0,name +"-file"));
+		}else{
+			userCommand.add(new REPCommand(REP.SMCMD_JOIN, 0, 0, 0, 0, name));
+		}
+	}
+
+	public void textDeleted(REPTextEvent event) {
+		Logger.print(event.getText());
+		addUserInput(new REPCommand(REP.REPCMD_DELETE_USER, 0, 0, 0, event.getLineno(), event.getText()));
+	}
+
+	public void textInserted(REPTextEvent event) {
+		Logger.print(event.getText());
+		addUserInput(new REPCommand(REP.REPCMD_INSERT_USER, 0, 0, 0, event.getLineno(), event.getText()));
+	}
+
+	private void addUserInput(final REPCommand command) {
+		Runnable runner = new Runnable(){
+			public void run(){
+				userCommand.add(command);
+				timeout = 1;
+			}
+		};
+		synchronized(runners){
+			runners.add(runner);
+		}
+		if(selector != null){
+			selector.wakeup();
+		}
+	}
+	
+	public void run(){
+		/*
+		 * Create Socket and connect to the session manager
+		 */
+		try {
+			channel = REPSocketChannel.<REPCommand>create(new REPCommandPacker());
+		} catch (IOException e) {
+			e.printStackTrace();
+			return;
+		}
+		try {
+			InetSocketAddress semaIP = new InetSocketAddress("localhost", 8766);
+			while (!channel.connect(semaIP)){
+				Logger.print("SeMa not listen to socket yet, wait");
+			}
+		} catch (IOException e) {
+			e.printStackTrace();
+			return;
+		}
+		/*
+		 * Start editor main loop
+		 *         public REPCommand(REP cmd,int sid,int eid, int seq, int lineno,  String string) 
+		 */
+		try {
+			mainloop();
+		} catch (IOException e) {
+		}
+	}
+
+	/*
+	 * Editor main loop with input lock
+	 */
+	private void mainloop() throws IOException {
+		
+		channel.configureBlocking(false);
+		selector = REPSelector.create();
+		channel.register(selector, SelectionKey.OP_READ);
+		while(running) {
+			
+			synchronized(runners){
+				for(Runnable runner : runners){
+					runner.run();
+				}
+				runners.clear();
+			}
+			
+			if (inputLock) {
+				// No user input during merge mode (optional)
+				if (selector.select(0)>0) {
+					handle(channel.read());
+				}
+				continue;
+			} else if (selector.select(timeout)<=0) {
+				if (syncCounter>0) {
+					syncText(); // send the master editor buffer to clients. 
+				}
+				userInput();
+			}
+			// selector(timeout) returns 0, but it may contain readable channel..
+			for(REPSelectionKey<REPCommand> key : selector.selectedKeys1()) {
+				REPSocketChannel<REPCommand> ch = key.channel1();
+				handle(ch.read());
+			}
+		}
+	}
+
+	private void handle(REPCommand command) {
+		Logger.print(logTarget, command);
+		if(command == null) return;
+		switch(command.cmd){
+		case REPCMD_DELETE:
+			if(command.eid != eid){
+				String del = repText.delete(command.lineno);
+				command.setString(del);
+			}
+			forward(command);
+			break;
+		case REPCMD_INSERT:
+			if(command.eid != eid){
+				repText.insert(command.lineno, command.string);
+			}
+			forward(command);
+			break;
+		case REPCMD_NOP:
+		case REPCMD_INSERT_ACK:
+		case REPCMD_DELETE_ACK:
+			forward(command);
+			break;	
+		case SMCMD_PUT_ACK:
+			sid = command.sid;
+			eid = command.eid;
+			name += "(eid="+eid+",sid="+sid+")";
+			inputLock = false;
+			break;
+		case SMCMD_JOIN_ACK	:
+			sid = command.sid;
+			eid = command.eid;
+			name += "(eid="+eid+",sid="+sid+")";
+			inputLock = false;
+			break;
+		case SMCMD_START_MERGE :
+			// lock user input during merge (optional)
+			inputLock = hasInputLock;
+			command.cmd = REP.SMCMD_START_MERGE_ACK;
+			send(command);
+			break;
+		case SMCMD_END_MERGE :
+			inputLock = false;
+			break;
+		case SMCMD_SYNC:
+			// start contents sync with newly joined editor
+			command.cmd = REP.SMCMD_SYNC_ACK;
+			forward(command);
+			//if (cmd.eid==eid) {
+			if (master && syncEnable ) {
+				syncCounter = 1;
+				timeout = 1;
+			}
+			break;
+		}
+	}
+
+	private void userInput() {
+		Logger.print();
+		REPCommand command = userCommand.poll();
+		if(command != null){
+			switch(command.cmd){
+			case REPCMD_DELETE_USER:
+				send(command);
+				break;
+			case REPCMD_INSERT_USER:
+				send(command);
+				break;
+			case SMCMD_PUT:
+			case SMCMD_JOIN:
+				send(command);
+				break;
+			}
+		}else{
+			if(syncCounter == 0){
+				timeout = 0;
+			}
+		}
+	}
+
+	private void forward(REPCommand command) {
+		REPCommand cmd = new REPCommand(command);
+		channel.write(cmd);
+	}
+
+	private void send(REPCommand command) {
+		REPCommand cmd = new REPCommand(command);
+		cmd.setSEQID(seq++);
+		cmd.setEID(eid);
+		cmd.setSID(sid);
+		channel.write(cmd);
+	}
+
+	private void syncText() {
+		if(syncCounter>repText.size()){
+			syncCounter = 0;
+		}else {
+			if(inputLock) return;
+			int i = syncCounter - 1;
+			REPCommand del = new REPCommand(REP.REPCMD_DELETE_USER, sid, eid, 0, i, repText.get(i));
+			REPCommand ins = new REPCommand(REP.REPCMD_INSERT_USER, sid, eid, 0, i, repText.get(i));
+			send(del);
+			send(ins);
+			syncCounter++;
+		}
+	}
+	
+	public void setLogTarget(LogTarget target){
+		logTarget = target;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/editortest/REPTextEvent.java	Wed Dec 31 14:52:45 2008 +0900
@@ -0,0 +1,20 @@
+package test.editortest;
+
+public class REPTextEvent {
+
+	private int lineno;
+	private String text;
+
+	public REPTextEvent(int lineno, String text) {
+		this.lineno = lineno;
+		this.text = text;
+	}
+	
+	public int getLineno(){
+		return lineno;
+	}
+	
+	public String getText(){
+		return text;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/editortest/REPTextListener.java	Wed Dec 31 14:52:45 2008 +0900
@@ -0,0 +1,9 @@
+package test.editortest;
+
+public interface REPTextListener {
+	
+	public void textInserted(REPTextEvent event);
+	
+	public void textDeleted(REPTextEvent event);
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/editortest/REPTextWithJTextArea.java	Wed Dec 31 14:52:45 2008 +0900
@@ -0,0 +1,156 @@
+package test.editortest;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.swing.JButton;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.text.BadLocationException;
+
+public class REPTextWithJTextArea implements REPText, DocumentListener, ActionListener {
+
+	private JTextArea textArea;
+	private String BR = System.getProperty("line.separator");
+	private LinkedList<REPTextListener> textListenerList = new LinkedList<REPTextListener>();
+	private JTextField lineField;
+	private JTextField textField;
+	private JButton deleteButton;
+	private JButton insertButton;
+
+	public REPTextWithJTextArea(JTextArea textArea, JTextField lineField, JTextField textField, JButton deleteButton, JButton insertButton) {
+		this.textArea = textArea;
+		this.lineField = lineField;
+		this.textField = textField;
+		this.deleteButton = deleteButton;
+		this.insertButton = insertButton;
+		textArea.getDocument().addDocumentListener(this);
+		textField.addActionListener(this);
+		deleteButton.addActionListener(this);
+		insertButton.addActionListener(this);
+	}
+
+	public String delete(int lineno) {
+		for(int i = size(); i <= lineno; i++){
+			increaseLine();
+		}
+		
+		String del = getLineText(lineno);
+		try {
+			int start = textArea.getLineStartOffset(lineno);
+			int end = textArea.getLineEndOffset(lineno);
+			textArea.replaceRange("", start, end);
+		} catch (BadLocationException e) {
+			e.printStackTrace();
+		}
+		return del;
+	}
+
+	public void insert(int lineno, String text) {
+		for(int i = size(); i <= lineno; i++){
+			increaseLine();
+		}
+		
+		String text2 = text + BR;
+		try {
+			int offset = textArea.getLineStartOffset(lineno);
+			textArea.insert(text2, offset);
+		} catch (BadLocationException e) {
+			e.printStackTrace();
+		}
+	}
+	
+	private void increaseLine(){
+		textArea.append(BR);
+	}
+	
+	private String getLineText(int lineno){
+		String text = null;
+		try {
+			int start = textArea.getLineStartOffset(lineno);
+			int end = textArea.getLineEndOffset(lineno);
+			text = textArea.getText(start, end-start);
+			String text2 = text.replace(BR, "");
+			text = text2;
+		} catch (BadLocationException e) {
+			e.printStackTrace();
+		}
+		return text;
+	}
+
+	public int size() {
+		return textArea.getLineCount();
+	}
+
+	public String get(int i) {
+		return getLineText(i);
+	}
+
+	public List<String> list() {
+		LinkedList<String> list = new LinkedList<String>();
+		for(int i = 0; i < size(); i++){
+			list.add(getLineText(i));
+		}
+		return list;
+	}
+
+	public void addTextListener(REPTextListener listener) {
+		textListenerList.add(listener);
+	}
+
+	public void changedUpdate(DocumentEvent e) {
+		Logger.print(e);
+	}
+
+	public void insertUpdate(DocumentEvent e) {
+		Logger.print(e);
+		
+	}
+
+	public void removeUpdate(DocumentEvent e) {
+		Logger.print(e);
+	}
+
+	public void actionPerformed(ActionEvent e) {
+		if(e.getSource() == textField){
+			userInsert();
+			textField.setText("");
+		}else if(e.getSource() == deleteButton){
+			userDelete();
+		}else if(e.getSource() == insertButton){
+			userInsert();
+		}
+	}
+
+	private void userDelete() {
+		int lineno = 0;
+		try {
+			lineno = Integer.parseInt((lineField.getText()));
+			if(lineno < 0) lineno = 0;
+		}catch(NumberFormatException e){}
+		
+		String del = delete(lineno);
+		for(REPTextListener listener : textListenerList){
+			listener.textDeleted(new REPTextEvent(lineno, del));
+		}
+	}
+
+	private void userInsert() {
+		int lineno;
+		try {
+			lineno = Integer.parseInt((lineField.getText()));
+		}catch(NumberFormatException e){
+			lineno = 0;
+		}
+		String text = textField.getText();
+		insert(lineno, text);
+		for(REPTextListener listener : textListenerList){
+			listener.textInserted(new REPTextEvent(lineno, text));
+		}
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/editortest/SimpleEditorForREPEditor.java	Wed Dec 31 14:52:45 2008 +0900
@@ -0,0 +1,129 @@
+package test.editortest;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+import javax.swing.JToolBar;
+
+public class SimpleEditorForREPEditor extends JFrame implements ActionListener, LogTarget{
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+	private JButton putButton;
+	private JButton joinButton;
+	private JTextField lineField;
+	private JTextField textField;
+	private JTextArea textArea;
+	private JScrollPane scrollPane1;
+	private JTextArea console;
+	private JScrollPane scrollPane2;
+	private JSplitPane splitPane;
+	private String BR = System.getProperty("line.separator");
+	private JButton deleteButton;
+	private JButton insertButton;
+	
+	public SimpleEditorForREPEditor(String title){
+		super(title);
+		setSize(new Dimension(640, 480));
+		setLayout(new BorderLayout());
+		
+		setToolBar();
+		setEditor();
+		setConsole();
+		setSplitPane();
+	}
+	
+	private void setToolBar() {
+		JToolBar toolbar = new JToolBar();
+		putButton = new JButton("put");
+		joinButton = new JButton("join");
+		putButton.addActionListener(this);
+		joinButton.addActionListener(this);
+		
+		JLabel label1 = new JLabel("line");
+		JLabel label2 = new JLabel("text");
+		lineField = new JTextField();
+		textField = new JTextField();
+		
+		deleteButton = new JButton("delete");
+		insertButton = new JButton("insert");
+		
+		toolbar.add(putButton);
+		toolbar.add(joinButton);
+		toolbar.addSeparator();
+		toolbar.add(label1);
+		toolbar.add(lineField);
+		toolbar.add(label2);
+		toolbar.add(textField);
+		toolbar.addSeparator();
+		toolbar.add(deleteButton);
+		toolbar.add(insertButton);
+		
+		add(toolbar, BorderLayout.NORTH);
+	}
+	
+	private void setEditor(){
+		textArea = new JTextArea();
+		textArea.setEditable(false);
+		textArea.setFont(new Font("Monaco", Font.PLAIN, textArea.getFont().getSize()));
+		
+		scrollPane1 = new JScrollPane(textArea);
+	}
+	
+	private void setConsole(){
+		console = new JTextArea();
+		console.setFont(new Font("Monaco", Font.PLAIN, console.getFont().getSize()-2));
+		console.setEditable(false);
+		scrollPane2 = new JScrollPane(console);
+	}
+	
+	private void setSplitPane(){
+		splitPane = new JSplitPane();
+		splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
+		splitPane.add(scrollPane1, JSplitPane.TOP);
+		splitPane.add(scrollPane2, JSplitPane.BOTTOM);
+		splitPane.setDividerLocation(300);
+		add(splitPane, BorderLayout.CENTER);
+	}
+
+	public void actionPerformed(ActionEvent e) {
+		if(e.getSource() == putButton){
+			repPut();
+		}else if(e.getSource() == joinButton){
+			repJoin();
+		}
+	}
+
+	private void repPut() {
+		REPEditor repEditor = new REPEditor(new REPTextWithJTextArea(textArea, lineField, textField, deleteButton, insertButton), true);
+		repEditor.start();
+		repEditor.setLogTarget(this);
+		putButton.setEnabled(false);
+		joinButton.setEnabled(false);
+	}
+
+	private void repJoin() {
+		REPEditor repEditor = new REPEditor(new REPTextWithJTextArea(textArea, lineField, textField, deleteButton, insertButton), false);
+		repEditor.start();
+		repEditor.setLogTarget(this);
+		putButton.setEnabled(false);
+		joinButton.setEnabled(false);
+	}
+
+	public void printLog(String msg) {
+		console.append(msg + BR);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/editortest/TestSimpleEditor.java	Wed Dec 31 14:52:45 2008 +0900
@@ -0,0 +1,41 @@
+package test.editortest;
+
+import java.io.IOException;
+
+import test.AutoSelectManager;
+
+public class TestSimpleEditor {
+
+	/**
+	 * @param args
+	 * @throws IOException 
+	 * @throws InterruptedException 
+	 */
+	public static void main(final String[] args) throws InterruptedException, IOException {
+		
+		Runnable runnable = new Runnable(){
+			public void run(){
+				try {
+					AutoSelectManager.main(args);
+				} catch (InterruptedException e) {
+					e.printStackTrace();
+				} catch (IOException e) {
+					e.printStackTrace();
+				}
+			}
+		};
+		
+		Thread thread = new Thread(runnable);
+		thread.start();
+		
+		SimpleEditorForREPEditor editor1 = new SimpleEditorForREPEditor("test1");
+		editor1.setVisible(true);
+		
+		SimpleEditorForREPEditor editor2 = new SimpleEditorForREPEditor("test2");
+		editor2.setVisible(true);
+		
+		SimpleEditorForREPEditor editor3 = new SimpleEditorForREPEditor("test3");
+		editor3.setVisible(true);
+	}
+
+}