package TaiGameCore; import java.awt.BorderLayout; import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.ClipboardOwner; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayList; import java.util.Scanner; import javax.swing.JFrame; import javax.swing.JTextArea; public class TaiScriptEditor extends GameDataBase{ public TaiScriptEditor(){ this(""); } public TaiScriptEditor(String hash) { super(hash); if (Selection==null){ Selection = new TaiScriptTxtInfo(""); } } public static char LINE_END_SUBCHAR = (char)5; public ArrayList<String> Editing; public int CaretLine; public int CaretPosition; public TaiScriptTxtInfo Selection; public void insert(char c) { if (!Selection.TemporaryDisable){ deleteSelection(); } String line = Editing.get(CaretLine); if (BoundedMaxColumns>0 && line.length() >= BoundedMaxColumns){ return; } String before = line.substring(0,CaretPosition); String after = line.substring(CaretPosition); Editing.set(CaretLine, before+c+after); CaretPosition++; hasUnsavedChanges = true; } public void line() { line(true); //Autotab } public void line(boolean autoTab) { if (!Selection.TemporaryDisable){ deleteSelection(); } if (BoundedMaxLines>0 && Editing.size() >= BoundedMaxLines){ return; //Don't do it! } String line = Editing.get(CaretLine); //Detect the indentation: String cloneWhitespace = ""; if (autoTab){ for(char k : line.toCharArray()){ if (k!='\t'){ break; } cloneWhitespace+='\t'; //Copy the number of tabs. } } String before = line.substring(0,CaretPosition); String after = cloneWhitespace + line.substring(CaretPosition,line.length()-1); //Split the line, inserting the second half before the next. Editing.set(CaretLine, before+LINE_END_SUBCHAR); Editing.add(CaretLine+1,after+LINE_END_SUBCHAR); CaretPosition = cloneWhitespace.length(); //put cursor at same level as line CaretLine++; hasUnsavedChanges = true; } /** * This is sort of a hack, it sets a full line of text. Note that the selection, * the caret line, etc etc are all cleared. */ public void setLine(String text, int line){ //resetCaret(); CaretPosition = Math.min(CaretPosition,text.length()-1); while(Editing.size() <= line){ Editing.add(""+LINE_END_SUBCHAR); } Editing.set(line,text+LINE_END_SUBCHAR); hasUnsavedChanges = true; } public void backspace() { if (!Selection.TemporaryDisable){ deleteSelection(); } else { if (CaretPosition>0){ Selection = new TaiScriptTxtInfo(CaretLine,CaretPosition,CaretLine,CaretPosition-1); } else if (CaretLine>0){ Selection = new TaiScriptTxtInfo(CaretLine,CaretPosition,CaretLine-1, Editing.get(CaretLine-1).length()-1); } else { return; //Uhh... Can't do a backspace here! } deleteSelection(); } } public void deleteSelection(){ boolean recurseBackwards = Selection.isBackwards(); if (!recurseBackwards){ recurseBackwards=true; Selection.flip(); } //Meh, This one can always go backwards. if (recurseBackwards){ int indexOnEnd = -1; if (Selection.LineEnd==Selection.LineBegin){ indexOnEnd = Selection.CharBegin; } removeOnLine(Selection.LineEnd, Selection.CharEnd, indexOnEnd); if (Selection.LineEnd!=Selection.LineBegin){ Editing.set(Selection.LineEnd, getContentLine(Selection.LineEnd)+getContentLine(Selection.LineBegin).substring(Selection.CharBegin)+LINE_END_SUBCHAR); } int numRemoved = 0; for(int line = Selection.LineBegin; line > Selection.LineEnd; line--){ Editing.remove(line); numRemoved++; } Selection.LineBegin = CaretLine = Selection.LineEnd; Selection.CharBegin = CaretPosition = Selection.CharEnd; } //At the end, make an empty selection. Selection.TemporaryDisable = true; } public String getSelection(){ StringWriter sr = new StringWriter(); PrintWriter out = new PrintWriter(sr); boolean selectionWasBackwards = Selection.isBackwards(); if (selectionWasBackwards){ //So, make it forwards. Selection.flip(); }; int charLoc = Selection.CharBegin; boolean isOneLiner = (Selection.LineEnd - Selection.LineBegin == 0); for(int line = Selection.LineBegin; line <= Selection.LineEnd; line++){ if (line==Selection.LineEnd){ out.print(getContentLine(line).substring(charLoc,Selection.CharEnd)); } else { out.println(getContentLine(line).substring(charLoc)); charLoc=0; //For next line. } } if (selectionWasBackwards){ //Flip it back. Selection.flip(); }; if (!isOneLiner){ out.println(); //Peel this off when pasting. } return sr.toString(); } /** * Returns the line without the lineSubChar Ending... */ private String getContentLine(int lineEnd) { return Editing.get(lineEnd).substring(0,Editing.get(lineEnd).length()-1); } /** * TODO: may Crash! */ private void removeOnLine(int line, int start, int end) { String after = ""; if (end!=-1){ after = Editing.get(line).substring(end); } String result = Editing.get(line).substring(0,start)+after; if (!result.endsWith(""+LINE_END_SUBCHAR)){ result+=LINE_END_SUBCHAR; } Editing.set(line,result); hasUnsavedChanges = true; } public void caretLeft() { if (CaretPosition==0){ if (CaretLine==0){ return; //Nothing to do. } CaretLine--; CaretPosition = Editing.get(CaretLine).length()-1; } else { CaretPosition--; } } public void caretRight() { if (CaretPosition==Editing.get(CaretLine).length()-1){ if (CaretLine==Editing.size()-1){ return;//Nothing to do. } CaretLine++; CaretPosition = 0; } else { CaretPosition++; } } public void tab() { insert('\t'); } public void caretDown() { int toShiftRight = CaretPosition; if (CaretLine==Editing.size()-1){ return; //Can't. } CaretLine++; CaretPosition = Math.min(toShiftRight,Editing.get(CaretLine).length()-1); } public void caretUp() { int toShiftRight = CaretPosition; if (CaretLine==0){ return; //Can't; } CaretLine--; CaretPosition = Math.min(toShiftRight,Editing.get(CaretLine).length()-1); } public static String getClipboardContents(){ String result = ""; Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); //odd: the Object param of getContents is not currently used Transferable contents = clipboard.getContents(null); boolean hasTransferableText = (contents != null) && contents.isDataFlavorSupported(DataFlavor.stringFlavor) ; if ( hasTransferableText ) { try { result = (String)contents.getTransferData(DataFlavor.stringFlavor); } catch (UnsupportedFlavorException ex){ //highly unlikely since we are using a standard DataFlavor System.out.println(ex); ex.printStackTrace(); } catch (IOException ex) { System.out.println(ex); ex.printStackTrace(); } } return result; } public void copy() { setClipboardContents(getSelection()); } public void insertText(String[] lines){ for(String sr : lines){ for(char c : sr.toCharArray()){ insert(c); } } } /** * Splits val on lines. * @param val */ public void insertText(String val) { Scanner sr = new Scanner(val); while(sr.hasNextLine()){ String line = sr.nextLine(); for(char c : line.toCharArray()){ insert(c); } if (sr.hasNextLine()){ line(false); //No autotab here. } } } private void setClipboardContents(String aString){ StringSelection stringSelection = new StringSelection( aString ); Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); clipboard.setContents( stringSelection, new ClipboardOwner(){ public void lostOwnership(Clipboard clipboard, Transferable contents) { } }); } public void paste() { String val = getClipboardContents(); insertText(val); } private boolean hasUnsavedChanges; private int BoundedMaxLines = 0; private int BoundedMaxColumns = 0; public void setSaved(boolean b) { hasUnsavedChanges = !b; } public boolean hasUnsavedChanges(){ return hasUnsavedChanges; } public void selectAll() { CaretLine = 0; CaretPosition = 0; Selection = new TaiScriptTxtInfo(0,0,Editing.size()-1,Editing.get(Editing.size()-1).length()-1); } public void selectLine(int lineNum){ if (lineNum>=Editing.size() || lineNum<0){ throw new ArrayIndexOutOfBoundsException("index: "+lineNum+" size: "+Editing.size()); } CaretLine = lineNum; CaretPosition = 0; Selection = new TaiScriptTxtInfo(CaretLine,0,CaretLine,Editing.get(CaretLine).length()-1); } /** * 0 means unlimited. * * Restricts the number of lines to 'i' and the number of columns to 'j'. */ public void sizeRestrictions(int i, int j) { BoundedMaxLines = i; BoundedMaxColumns = j; } public void resetCaret(){ CaretLine = 0; CaretPosition = 0; Selection = new TaiScriptTxtInfo(0,0,0,0); Selection.TemporaryDisable = true; } public void clear() { Editing.clear(); resetCaret(); Editing.add(""+LINE_END_SUBCHAR); hasUnsavedChanges = false; } public void clearBlanks(){ if (BoundedMaxLines==0){ throw new RuntimeException("ClearBlanks can only be used on editors that have locked # of lines"); } clear(); for(; Editing.size() < BoundedMaxLines;){ Editing.add(""+LINE_END_SUBCHAR); } } /** * Calls clear, then puts a blank line in Editing (most like a new file.) * IF you are calling this to prepare for loading an input file, use clear() instead. */ public void newFile(){ clear(); Editing.add(""+LINE_END_SUBCHAR); } public void autoWrittenDeSerializeCode(){ customDeserializeEditing(); CaretLine = ((IntEntry)readField("CaretLine", new IntEntry())).getInt(); CaretPosition = ((IntEntry)readField("CaretPosition", new IntEntry())).getInt(); String Selection_strTmp= ((StringEntry)readField("Selection", new StringEntry(""))).getString(); if (Selection_strTmp.length()>0){ Selection = new TaiScriptTxtInfo(Selection_strTmp); } hasUnsavedChanges = ((IntEntry)readField("hasUnsavedChanges", new IntEntry())).getInt()==1; BoundedMaxLines = ((IntEntry)readField("BoundedMaxLines", new IntEntry())).getInt(); BoundedMaxColumns = ((IntEntry)readField("BoundedMaxColumns", new IntEntry())).getInt(); } private void customDeserializeEditing() { String got = ((StringEntry)readField("Editing", new StringEntry(""+LINE_END_SUBCHAR))).getString(); Scanner in = new Scanner(got); Editing = new ArrayList<String>(); while(in.hasNextLine()){ Editing.add(in.nextLine()); } if (got.length()==0){ newFile(); } } public void autoWrittenSerializeCode(){ customSerializeEditing(); writeField("CaretLine", new IntEntry(CaretLine)); writeField("CaretPosition", new IntEntry(CaretPosition)); writeField("Selection", new StringEntry(Selection!=null?Selection.hashToString():"")); writeField("hasUnsavedChanges", new IntEntry(hasUnsavedChanges?1:0)); writeField("BoundedMaxLines", new IntEntry(BoundedMaxLines)); writeField("BoundedMaxColumns", new IntEntry(BoundedMaxColumns)); } private void customSerializeEditing() { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); for(String k : Editing){ pw.println(k); } writeField("Editing", new StringEntry(sw.toString())); } }