package com.pixelmaid.dresscode.app; /*manages the code entry interface, and intializes and runs the antlr lexer and parser classes to update the canvas */ import java.awt.Color; import java.awt.Dimension; import java.awt.Event; import java.awt.Font; import java.awt.event.*; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.StringReader; import java.util.ArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.text.AttributeSet; import javax.swing.*; import javax.swing.border.EmptyBorder; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.event.UndoableEditEvent; import javax.swing.event.UndoableEditListener; import javax.swing.text.AbstractDocument; import javax.swing.text.BadLocationException; import javax.swing.text.DefaultHighlighter; import javax.swing.text.DefaultHighlighter.DefaultHighlightPainter; import javax.swing.text.DefaultStyledDocument; import javax.swing.text.Document; import javax.swing.text.DocumentFilter; import javax.swing.text.Element; import javax.swing.text.PlainDocument; import javax.swing.text.SimpleAttributeSet; import javax.swing.text.StyleConstants; import javax.swing.text.StyleContext; import javax.swing.text.TabSet; import javax.swing.text.TabStop; import javax.swing.undo.CannotRedoException; import javax.swing.undo.CannotUndoException; import javax.swing.undo.UndoManager; import com.pixelmaid.dresscode.app.ui.tools.BoolTool; import com.pixelmaid.dresscode.drawing.datatype.Point; import com.pixelmaid.dresscode.drawing.math.PolyBoolean; import com.pixelmaid.dresscode.drawing.primitive2d.Curve; import com.pixelmaid.dresscode.drawing.primitive2d.Drawable; import com.pixelmaid.dresscode.drawing.primitive2d.Line; import com.pixelmaid.dresscode.drawing.primitive2d.Polygon; class Filter extends DocumentFilter { private int promptPosition =0; public void setPrompt(int p){ promptPosition =p; } public void insertString(final FilterBypass fb, final int offset, final String string, final AttributeSet attr) throws BadLocationException { if (offset >= promptPosition) { super.insertString(fb, offset, string, attr); } } public void remove(final FilterBypass fb, final int offset, final int length) throws BadLocationException { if (offset >= promptPosition) { super.remove(fb, offset, length); } } public void replace(final FilterBypass fb, final int offset, final int length, final String text, final AttributeSet attrs) throws BadLocationException { if (offset >= promptPosition) { super.replace(fb, offset, length, text, attrs); } } } public class CodeField extends JTextPane implements DocumentListener, KeyListener{ private static final long serialVersionUID = 1L; private Document editorPaneDocument; protected UndoHandler undoHandler = new UndoHandler(); protected UndoManager undoManager = new UndoManager(); protected UndoAction undoAction = null; protected RedoAction redoAction = null; private Filter filter; private boolean unsavedChanges= false; private Pattern p = Pattern.compile("(?:/\\*(?:[^*]|(?:\\*+[^*/]))*\\*+/)|(?://.*)"); final StyleContext cont = StyleContext.getDefaultStyleContext(); final AttributeSet attr = cont.addAttribute(cont.getEmptySet(), StyleConstants.Foreground, Color.GRAY); final AttributeSet attrBlack = cont.addAttribute(cont.getEmptySet(), StyleConstants.Foreground, Color.BLACK); private DefaultStyledDocument doc; public CodeField() { super(); } public void init(int size){ this.setEditable(true); this.setPreferredSize(new Dimension(550,500)); this.setContentType("text/java"); this.setText(""); doc = new DefaultStyledDocument();/* { public void insertString (int offset, String str, AttributeSet a) throws BadLocationException { super.insertString(offset, str, a); String text = getText(0, getLength()); int before = findLastNonWordChar(text, offset); if (before < 0) before = 0; int after = findFirstNonWordChar(text, offset + str.length()); int wordL = before; int wordR = before; while (wordR <= after) { if (wordR == after || String.valueOf(text.charAt(wordR)).matches("\\W")) { if (text.substring(wordL, wordR).matches("(\\W)*(private|public|protected)")) setCharacterAttributes(wordL, wordR - wordL, attr, false); else setCharacterAttributes(wordL, wordR - wordL, attrBlack, false); wordL = wordR; } wordR++; } } public void remove (int offs, int len) throws BadLocationException { super.remove(offs, len); String text = getText(0, getLength()); int before = findLastNonWordChar(text, offs); if (before < 0) before = 0; int after = findFirstNonWordChar(text, offs); if (text.substring(before, after).matches("(\\W)*(private|public|protected)")) { setCharacterAttributes(before, after - before, attr, false); } else { setCharacterAttributes(before, after - before, attrBlack, false); } } };*/ this.setDocument(doc); StyleContext sc = StyleContext.getDefaultStyleContext(); TabSet tabs = new TabSet(new TabStop[] { new TabStop(20) }); AttributeSet paraSet = sc.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.TabSet, tabs); this.setParagraphAttributes(paraSet, false); this.setBorder(new EmptyBorder(10,10,10,10)); this.setFont(new Font("Courier", 0, size)); editorPaneDocument = this.getDocument(); editorPaneDocument.addUndoableEditListener(undoHandler); KeyStroke undoKeystroke = KeyStroke.getKeyStroke(KeyEvent.VK_Z, Event.META_MASK); KeyStroke redoKeystroke = KeyStroke.getKeyStroke(KeyEvent.VK_Y, Event.META_MASK); undoAction = new UndoAction(); this.getInputMap().put(undoKeystroke, "undoKeystroke"); this.getActionMap().put("undoKeystroke", undoAction); redoAction = new RedoAction(); this.getInputMap().put(redoKeystroke, "redoKeystroke"); this.getActionMap().put("redoKeystroke", redoAction); undoAction.setActions(undoManager,redoAction); redoAction.setActions(undoManager,undoAction); undoHandler.setActions(undoManager, undoAction, redoAction); filter = new Filter(); // filter for Stamp editor this.addKeyListener(this); } public void startFilter(int filterLength){ filter.setPrompt(filterLength); ((AbstractDocument)this.getDocument()).setDocumentFilter(filter); } public void stopFilter(){ ((AbstractDocument)this.getDocument()).setDocumentFilter(null); } public JMenuItem getRedoMenu(){ JMenuItem redoMenuItem = new JMenuItem(redoAction); redoMenuItem.setText("Redo"); return redoMenuItem; } public JMenuItem getUndoMenu(){ JMenuItem undoMenuItem = new JMenuItem(undoAction); undoMenuItem.setText("Undo"); return undoMenuItem; } public String getCode(){ return this.getText()+"\n"; } public void checkForComments(){ String txt = this.getCode(); if(txt.length()!=0){ //String [] nonComments = getCode().split("(?:/\\*(?:[^*]|(?:\\*+[^*/]))*\\*+/)|(?://.*)"); //ArrayList<String> comments = new ArrayList<String>(); Matcher m = p.matcher(getCode()); ((DefaultStyledDocument)this.getDocument()).setCharacterAttributes(0,txt.length(), attrBlack, false); while (m.find()) { int start = m.start(); int end = m.start()+m.group().length(); ((DefaultStyledDocument)this.getDocument()).setCharacterAttributes(start,end, attr, false); ((DefaultStyledDocument)this.getDocument()).setCharacterAttributes(end,txt.length(), attrBlack, false); } } } //adds a line of code to import in a shape; public void insertPath(File f) throws BadLocationException{ String fileString = "import(\""+f.getAbsolutePath()+"\");"; int caretPos = this.getCaretPosition(); this.getDocument().insertString(caretPos, fileString, null); } //clears out the code window and all stored variables //TODO: code that clears out stored variables public void clear(){ this.setText(""); } @Override public void changedUpdate(DocumentEvent arg0) { // TODO Auto-generated method stub //System.out.println("changedUpdate"); } @Override public void insertUpdate(DocumentEvent arg0) { // TODO Auto-generated method stub //System.out.println("insertUpdate"); //System.out.println(this.getText()); } @Override public void removeUpdate(DocumentEvent arg0) { // TODO Auto-generated method stub //System.out.println("removeUpdate"); } @Override public void keyPressed(KeyEvent e) { /*if(e.getKeyCode()==10){ updateCanvas(); }*/ //this.getParent().dispatchEvent(e); } @Override public void keyReleased(KeyEvent e) { // TODO Auto-generated method stub //this.getParent().dispatchEvent(e); } @Override public void keyTyped(KeyEvent e) { // TODO Auto-generated method stub //this.getParent().dispatchEvent(e); unsavedChanges = true; removeHighlights(); //checkForComments(); } public void loadFile(String filetxt) { System.out.println("load file="+filetxt); this.setText(filetxt); checkForComments(); //updateCanvas(); } public void insertCoordinate(double x, double y) { String coordString =String.format("%.2f", x)+","+String.format("%.2f", y); insertText(this.getCaretPosition(),coordString); } public void insertText(int pos, String newText) { String text = this.getText(); text = text.substring(0,pos)+ newText +text.substring(pos); this.setText(text); //checkForComments(); } public void addText(String t){ String text = this.getText(); text +=t; this.setText(text); //checkForComments(); this.setCaretPosition(this.getText().length()); } public void removeText(int pos, int endPos) { String text = this.getText(); text = text.substring(0,pos)+text.substring(endPos); this.setText(text); //checkForComments(); } public void updateVariable(String updateTxt, int line){ String text = this.getText(); String[] lines = text.split("\r\n|\r|\n"); line= line-1; int lineLength = lines[line].length(); System.out.println("line number="+line); int pos =0; for(int i=0;i<line; i++){ pos+=lines[i].length(); if(i!=0){ pos++; } System.out.println("line "+i+"="+lines[i].length()); } System.out.println("pos="+pos); System.out.println("endPos="+pos+lineLength); this.removeText(pos, pos+lineLength); this.insertText(pos, updateTxt); } public void insertMoveStatement(Drawable sD ) { String identifier = sD.getIdentifier(); int lineNum = sD.getLine(); int endPos = sD.getEndPos(); double x = sD.getOrigin().getX(); double y = sD.getOrigin().getY(); boolean over = sD.getGModified(); System.out.println("identifer="+identifier); System.out.println("lineNum="+lineNum); String text = this.getText(); String[] lines = text.split("\r\n|\r|\n"); System.out.println("num of lines="+lines.length); System.out.println("lineNum="+lineNum); int pos =0; for(int i=0;i<lineNum; i++){ pos+=lines[i].length(); if(i!=0){ pos++; } //System.out.println("line "+i+"="+lines[i]); } if(identifier!=null){ String moveText = "\nmove("+identifier+","+String.format("%.1f", x)+","+String.format("%.1f", y)+");"; if(!over){ insertText(pos,moveText); } else{ removeText(pos,endPos); insertText(pos,moveText); } sD.setEndPos(pos+moveText.length()); } else{ String moveText1 = "move("; String moveText2 = ","+String.format("%.1f", x)+","+String.format("%.1f", y)+");"; if(!over){ removeText(pos-1,pos); //remove semicolon insertText(pos-lines[lineNum-1].length(),moveText1); insertText(pos-1+moveText1.length(),moveText2); sD.setEndPos(pos-1+moveText1.length()+moveText2.length()); } else{ //removeText(pos-lines[lineNum-1].length(),pos-lines[lineNum-1].length()+moveText1.length()); String snip = this.getText().substring(pos-lines[lineNum-1].length(), pos); System.out.println("snip="+snip); int index = snip.lastIndexOf("),"); System.out.println("index="+index); int toRemove = lines[lineNum-1].length()-index-1; removeText(pos-toRemove,pos); insertText(pos-toRemove,moveText2); sD.setEndPos(pos-toRemove+moveText2.length()); } } sD.setGModified(true); } public void insertShapeStatement(Drawable created, String shape) { int point = this.getText().length()-2; System.out.println("Point ="+point); //int point = 0; String rectStart; if(point==0){ rectStart=shape+"("; } else{ rectStart= "\n"+shape+"("; } String rectEnd =");"; Point origin = created.getOrigin(); String rectStatement = rectStart+roundNum(origin.getX())+","+roundNum(origin.getY())+","+roundNum(created.getWidth())+","+roundNum(created.getHeight())+rectEnd; insertText(point,rectStatement); } public void insertCurveStatement(Curve created) { int point = this.getText().length()-2; //int point = 0; Point start = created.getStart(); Point end = created.getEnd(); Point c1 = created.getControl1(); Point c2 = created.getControl2(); String startX = String.valueOf(roundNum(start.getX())); String startY = String.valueOf(roundNum(start.getY())); String endX = String.valueOf(roundNum(end.getX())); String endY = String.valueOf(roundNum(end.getY())); String c1X = String.valueOf(roundNum(c1.getX())); String c1Y = String.valueOf(roundNum(c1.getY())); String c2X = String.valueOf(roundNum(c2.getX())); String c2Y = String.valueOf(roundNum(c2.getY())); String lineStart = "curve("; String lineEnd = ");"; String lineStatement = lineStart+startX+","+startY+","+c1X+","+c1Y+","+c2X+","+c2Y+","+endX+","+endY+lineEnd; insertText(point,lineStatement); } public void insertLineStatement(Line created) { int point = this.getText().length()-2; // int point = 0; Point start = created.getStart(); Point end = created.getEnd(); String startX = String.valueOf(roundNum(start.getX())); String startY = String.valueOf(roundNum(start.getY())); String endX = String.valueOf(roundNum(end.getX())); String endY = String.valueOf(roundNum(end.getY())); String lineStart = "line("; String lineEnd = ");"; String lineStatement = lineStart+startX+","+startY+","+endX+","+endY+lineEnd; insertText(point,lineStatement); } public void insertGesturalStatement(String polyStatement) { int point = this.getText().length()-2; // int point = 0; if(point !=0){ polyStatement = "\n"+polyStatement; } insertText(point,polyStatement); } public void removeHighlights(){ this.getHighlighter().removeAllHighlights(); } //TODO: CLEAN THIS UP- seriously this is sad code. public void highlightLine(int lineNumber) throws BadLocationException{ this.getHighlighter().removeAllHighlights(); int lineNum = lineNumber-1; System.out.println("lineNumber="+lineNumber); String text = this.getText(); ArrayList<String> lines = new ArrayList<String>(); final BufferedReader br = new BufferedReader(new StringReader(text)); String line; try { while ((line = br.readLine()) != null) { lines.add(line); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } int pos =0; for(int i=0;i<lineNum; i++){ pos+=lines.get(i).length(); if(i!=0){ pos++; } } String chunk = text.substring(pos,text.length()); if(chunk.startsWith("\n")){ chunk = chunk.substring(1,chunk.length()); } int endPos = chunk.indexOf("\n"); if(endPos<1){ endPos = text.length()-pos; } else{ endPos++; } DefaultHighlightPainter painter = new DefaultHighlighter.DefaultHighlightPainter(Color.GREEN); this.getHighlighter().addHighlight(pos,pos+endPos, painter); } //returns a clean string from a rounded double private String roundNum(double n){ return String.format("%.2f", n); } public boolean getUnsaved(){ return this.unsavedChanges; } public void setUnsaved(boolean u){ this.unsavedChanges=u; } /* public void actionPerformed(ActionEvent evt) { String text = textField.getText(); textArea.append(text + newline); textField.selectAll(); //Make sure the new text is visible, even if there //was a selection in the text area. textArea.setCaretPosition(textArea.getDocument().getLength()); }*/ } //java undo and redo action classes class UndoHandler implements UndoableEditListener { UndoManager undoManager; UndoAction undoAction; RedoAction redoAction; /** * * Messaged when the Document has created an edit, the edit is added to * <code>undoManager</code>, an instance of UndoManager. */ public void setActions(UndoManager uM, UndoAction uA, RedoAction rA){ this.undoManager=uM; this.undoAction = uA; this.redoAction = rA; } public void undoableEditHappened(UndoableEditEvent e) { if(!e.getEdit().getPresentationName().contentEquals("style change")){ undoManager.addEdit(e.getEdit()); undoAction.update(); redoAction.update(); } } } class UndoAction extends AbstractAction { /** * */ private static final long serialVersionUID = 1L; UndoManager undoManager; RedoAction redoAction; public UndoAction() { super("Undo"); setEnabled(false); } public void setActions(UndoManager uM, RedoAction rA){ this.undoManager=uM; this.redoAction = rA; } public void actionPerformed(ActionEvent e) { try { undoManager.undo(); } catch (CannotUndoException ex) { // TODO deal with this //ex.printStackTrace(); } update(); redoAction.update(); } protected void update() { if (undoManager.canUndo()) { setEnabled(true); putValue(Action.NAME, undoManager.getUndoPresentationName()); } else { setEnabled(false); putValue(Action.NAME, "Undo"); } } } class RedoAction extends AbstractAction { /** * */ private static final long serialVersionUID = 1L; UndoManager undoManager; UndoAction undoAction; public RedoAction() { super("Redo"); setEnabled(false); } public void setActions(UndoManager uM, UndoAction uA){ this.undoManager=uM; this.undoAction = uA; } public void actionPerformed(ActionEvent e) { try { undoManager.redo(); } catch (CannotRedoException ex) { // TODO deal with this ex.printStackTrace(); } update(); undoAction.update(); } protected void update() { if (undoManager.canRedo()) { setEnabled(true); putValue(Action.NAME, undoManager.getRedoPresentationName()); } else { setEnabled(false); putValue(Action.NAME, "Redo"); } } }