/*
* This file is part of the Haven & Hearth game client.
* Copyright (C) 2009 Fredrik Tolf <fredrik@dolda2000.com>, and
* Björn Johannessen <johannessen.bjorn@gmail.com>
*
* Redistribution and/or modification of this file is subject to the
* terms of the GNU Lesser General Public License, version 3, as
* published by the Free Software Foundation.
*
* 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.
*
* Other parts of this source tree adhere to other copying
* rights. Please see the file `COPYING' in the root directory of the
* source tree for details.
*
* A copy the GNU Lesser General Public License is distributed along
* with the source tree of which this file is a part in the file
* `doc/LPGL-3'. If it is missing for any reason, please see the Free
* Software Foundation's website at <http://www.fsf.org/>, or write
* to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA
*/
package haven;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
public class LineEdit {
public String line = "";
public int point = 0;
private static Text tcache = null;
private static final int C = 1;
private static final int M = 2;
public KeyHandler mode;
public abstract class KeyHandler {
public abstract boolean key(char c, int code, int mod);
}
public class PCMode extends KeyHandler {
public boolean key(char c, int code, int mod) {
if((c == 8) && (mod == 0)) {
if(point > 0) {
line = line.substring(0, point - 1) + line.substring(point);
point--;
}
} else if((c == 8) && (mod == C)) {
int b = wordstart(point);
line = line.substring(0, b) + line.substring(point);
point = b;
} else if(c == 10) {
done(line);
} else if((c == 127) && (mod == 0)) {
if(point < line.length())
line = line.substring(0, point) + line.substring(point + 1);
} else if((c == 127) && (mod == C)) {
int b = wordend(point);
line = line.substring(0, point) + line.substring(b);
} else if((c >= 32) && (mod == 0)) {
line = line.substring(0, point) + c + line.substring(point);
point++;
} else if(((c == 'v')||(c == 'V')) && (mod == C)) {
String str = Utils.getClipboard();
line = line.substring(0, point) + str + line.substring(point);
point += str.length();
} else if((code == KeyEvent.VK_LEFT) && (mod == 0)) {
if(point > 0)
point--;
} else if((code == KeyEvent.VK_LEFT) && (mod == C)) {
point = wordstart(point);
} else if((code == KeyEvent.VK_RIGHT) && (mod == 0)) {
if(point < line.length())
point++;
} else if((code == KeyEvent.VK_RIGHT) && (mod == C)) {
point = wordend(point);
} else if((code == KeyEvent.VK_HOME) && (mod == 0)) {
point = 0;
} else if((code == KeyEvent.VK_END) && (mod == 0)) {
point = line.length();
} else {
return(false);
}
return(true);
}
}
public class EmacsMode extends KeyHandler {
private int mark, yankpos, undopos;
private String last = "";
private List<String> yanklist = new ArrayList<String>();
private List<UndoState> undolist = new ArrayList<UndoState>();
{undolist.add(new UndoState());}
private class UndoState {
private String line;
private int point;
private UndoState() {
this.line = LineEdit.this.line;
this.point = LineEdit.this.point;
}
}
private void save() {
if(!undolist.get(undolist.size() - 1).line.equals(line))
undolist.add(new UndoState());
}
private void mode(String mode) {
if((mode == "") || (last != mode))
save();
last = mode;
}
private void kill(String text) {
yanklist.add(text);
}
public boolean key(char c, int code, int mod) {
if(mark > line.length())
mark = line.length();
String last = this.last;
if((c == 8) && (mod == 0)) {
mode("erase");
if(point > 0) {
line = line.substring(0, point - 1) + line.substring(point);
point--;
}
} else if((c == 8) && ((mod == C) || (mod == M))) {
mode("backward-kill-word");
save();
int b = wordstart(point);
if(last == "backward-kill-word")
yanklist.set(yanklist.size() - 1, line.substring(b, point) + yanklist.get(yanklist.size() - 1));
else
kill(line.substring(b, point));
line = line.substring(0, b) + line.substring(point);
point = b;
} else if(c == 10) {
done(line);
} else if((c == 'd') && (mod == C)) {
mode("erase");
if(point < line.length())
line = line.substring(0, point) + line.substring(point + 1);
} else if((c == 'd') && (mod == M)) {
mode("kill-word");
save();
int b = wordend(point);
if(last == "kill-word")
yanklist.set(yanklist.size() - 1, yanklist.get(yanklist.size() - 1) + line.substring(point, b));
else
kill(line.substring(point, b));
line = line.substring(0, point) + line.substring(b);
} else if((c == 'b') && (mod == C)) {
mode("move");
if(point > 0)
point--;
} else if((c == 'b') && (mod == M)) {
mode("move");
point = wordstart(point);
} else if((c == 'f') && (mod == C)) {
mode("move");
if(point < line.length())
point++;
} else if((c == 'f') && (mod == M)) {
mode("move");
point = wordend(point);
} else if((c == 'a') && (mod == C)) {
mode("move");
point = 0;
} else if((c == 'e') && (mod == C)) {
mode("move");
point = line.length();
} else if((c == 't') && (mod == C)) {
mode("transpose");
if((line.length() >= 2) && (point > 0)) {
if(point < line.length()) {
line = line.substring(0, point - 1) + line.charAt(point) + line.charAt(point - 1) + line.substring(point + 1);
point++;
} else {
line = line.substring(0, point - 2) + line.charAt(point - 1) + line.charAt(point - 2);
}
}
} else if((c == 'k') && (mod == C)) {
mode("");
kill(line.substring(point));
line = line.substring(0, point);
} else if((c == 'w') && (mod == M)) {
mode("");
if(mark < point) {
kill(line.substring(mark, point));
} else {
kill(line.substring(point, mark));
}
} else if((c == 'w') && (mod == C)) {
mode("");
if(mark < point) {
kill(line.substring(mark, point));
line = line.substring(0, mark) + line.substring(point);
} else {
kill(line.substring(point, mark));
line = line.substring(0, point) + line.substring(mark);
}
} else if((c == 'y') && (mod == C)) {
mode("yank");
save();
yankpos = yanklist.size();
if(yankpos > 0) {
String yank = yanklist.get(--yankpos);
mark = point;
line = line.substring(0, point) + yank + line.substring(point);
point = mark + yank.length();
}
} else if((c == 'y') && (mod == M)) {
mode("yank");
save();
if((last == "yank") && (yankpos > 0)) {
String yank = yanklist.get(--yankpos);
line = line.substring(0, mark) + yank + line.substring(point);
point = mark + yank.length();
}
} else if((c == ' ') && (mod == C)) {
mode("");
mark = point;
} else if((c == '_') && (mod == C)) {
mode("undo");
save();
if(last != "undo")
undopos = undolist.size() - 1;
if(undopos > 0) {
UndoState s = undolist.get(--undopos);
line = s.line;
point = s.point;
}
} else if((c >= 32) && (mod == 0)) {
mode("type");
line = line.substring(0, point) + c + line.substring(point);
point++;
} else {
return(false);
}
return(true);
}
}
public LineEdit() {
String mode = Utils.getpref("editmode", "pc");
if(mode.equals("emacs")) {
this.mode = new EmacsMode();
} else {
this.mode = new PCMode();
}
}
public LineEdit(String line) {
this();
this.line = line;
this.point = line.length();
}
public void setline(String line) {
String prev = this.line;
this.line = line;
if(point > line.length())
point = line.length();
if(!prev.equals(line))
changed();
}
public boolean key(char c, int code, int mod) {
String prev = line;
boolean ret = mode.key(c, code, mod);
if(!prev.equals(line))
changed();
return(ret);
}
public boolean key(KeyEvent ev) {
int mod = 0;
if((ev.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) != 0) mod |= C;
if((ev.getModifiersEx() & (InputEvent.META_DOWN_MASK | InputEvent.ALT_DOWN_MASK)) != 0) mod |= M;
if(ev.getID() == KeyEvent.KEY_TYPED) {
char c = ev.getKeyChar();
if(((mod & C) != 0) && (c < 32)) {
/* Undo Java's TTY Control-code mangling */
if(ev.getKeyCode() == KeyEvent.VK_BACK_SPACE) {
} else if(ev.getKeyCode() == KeyEvent.VK_ENTER) {
} else if(ev.getKeyCode() == KeyEvent.VK_TAB) {
} else if(ev.getKeyCode() == KeyEvent.VK_ESCAPE) {
} else {
if((ev.getModifiersEx() & InputEvent.SHIFT_DOWN_MASK) != 0)
c = (char)(c + 'A' - 1);
else
c = (char)(c + 'a' - 1);
}
}
return(key(c, ev.getKeyCode(), mod));
} else if(ev.getID() == KeyEvent.KEY_PRESSED) {
if(ev.getKeyChar() == KeyEvent.CHAR_UNDEFINED)
return(key('\0', ev.getKeyCode(), mod));
}
return(false);
}
private static boolean wordchar(char c) {
return(Character.isLetterOrDigit(c));
}
private int wordstart(int from) {
while((from > 0) && !wordchar(line.charAt(from - 1))) from--;
while((from > 0) && wordchar(line.charAt(from - 1))) from--;
return(from);
}
private int wordend(int from) {
while((from < line.length()) && !wordchar(line.charAt(from))) from++;
while((from < line.length()) && wordchar(line.charAt(from))) from++;
return(from);
}
protected void done(String line) {}
protected void changed() {}
public Text render(Text.Foundry f) {
if((tcache == null) || (tcache.text != line))
tcache = f.render(line);
return(tcache);
}
static {
Console.setscmd("editmode", new Console.Command() {
public void run(Console cons, String[] args) {
Utils.setpref("editmode", args[1]);
}
});
}
}