package net.cakenet.jsaton.ui.tools.script;
import net.cakenet.jsaton.script.Script;
import net.cakenet.jsaton.script.debug.BreakInformation;
import net.cakenet.jsaton.script.debug.DebugFrame;
import net.cakenet.jsaton.script.debug.DebugObject;
import net.cakenet.jsaton.ui.tools.script.ruby.RubyFoldParser;
import net.cakenet.jsaton.ui.tools.script.ruby.RubyScriptEditorPane;
import net.cakenet.jsaton.ui.tools.snippet.SnippetManager;
import org.fife.ui.rsyntaxtextarea.*;
import org.fife.ui.rsyntaxtextarea.folding.FoldParserManager;
import org.fife.ui.rtextarea.GutterIconInfo;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.SimpleAttributeSet;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
public class ScriptEditorPane extends TextEditorPane implements DocumentListener, PropertyChangeListener {
protected ErrorStrip errorStrip;
private ScriptEditor editor;
public Script script;
public ScriptEditorPane(ScriptEditor editor) {
this.script = editor.script;
this.editor = editor;
errorStrip = new ErrorStrip(this);
errorStrip.setFollowCaret(false);
addPropertyChangeListener(this);
}
public void copy() {
SnippetManager.instance.addSnippet(getSelectedText());
}
public void cut() {
copy();
Document d = getDocument();
int start = getSelectionStart();
int end = getSelectionEnd();
try {
d.remove(start, end - start);
} catch (BadLocationException e) {
/**/
}
}
public void paste() {
Document d = getDocument();
int start = getSelectionStart();
int end = getSelectionEnd();
if (start != end) {
try {
d.remove(start, end - start);
} catch (BadLocationException e) {
/**/
}
}
Transferable content = getToolkit().getSystemClipboard().getContents(this);
if (content.isDataFlavorSupported(DataFlavor.stringFlavor)) {
try {
d.insertString(start, (String) content.getTransferData(DataFlavor.stringFlavor), new SimpleAttributeSet());
} catch (Exception e) {
e.printStackTrace();
}
}
}
public ErrorStrip getErrorStrip() {
return errorStrip;
}
public boolean isBreakableLine(int line) {
return true;
}
public void insertUpdate(DocumentEvent documentEvent) {
revalidateBreakpoints(documentEvent);
super.insertUpdate(documentEvent);
}
public void removeUpdate(DocumentEvent documentEvent) {
revalidateBreakpoints(documentEvent);
super.removeUpdate(documentEvent);
}
public String getToolTipText(MouseEvent e) {
if (script.isDebug()) {
BreakInformation info = script.getBreakInfo();
if (info != null) {
// We're broken, if this is a variable, we can show information about it :D
// Todo: other context stuff...
try {
int offs = viewToModel(e.getPoint());
int line = getLineOfOffset(offs);
Token list = getTokenListForLine(line);
while (list != null) {
if (offs >= list.offset && offs <= list.offset + list.textCount) {
// This is our token!
int type = list.type;
switch (type) {
case TokenTypes.VARIABLE:
case TokenTypes.IDENTIFIER:
String identifier = list.getLexeme();
// Iterate in order and try to find a value...
for (DebugFrame frame : info.frames) {
for (DebugObject obj : frame.variables) {
if (identifier.equals(obj.getName()))
return obj.toString();
}
// Also check self...
DebugObject self = frame.self;
if (self == null)
continue;
for (int i = 0, count = self.size(); i < count; i++) {
DebugObject obj = self.get(i);
if (identifier.equals(obj.getName()))
return obj.toString();
}
}
break;
}
break;
}
list = list.getNextToken();
}
} catch (BadLocationException e1) {
e1.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
}
return super.getToolTipText(e); //To change body of overridden methods use File | Settings | File Templates.
}
public void revalidateBreakpoints(DocumentEvent documentEvent) {
script.setScript(getText());
java.util.List<GutterIconInfo> breakpointInfo = editor.scrollPane.getBreakpoints();
try {
for (int i = 0; i < breakpointInfo.size(); i++) {
GutterIconInfo b = breakpointInfo.get(i);
int line = getLineOfOffset(b.getMarkedOffset());
if (!isBreakableLine(line)) {
editor.removeBreakpoint(line);
i--;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
static {
FoldParserManager.get().addFoldParserMapping(RSyntaxTextArea.SYNTAX_STYLE_RUBY, new RubyFoldParser());
}
public static ScriptEditorPane paneFor(Script script, ScriptEditor editor) {
switch (script.language) {
case RUBY:
return new RubyScriptEditorPane(editor);
default:
throw new RuntimeException("No editor defined for lang: " + script.language);
}
}
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("TextEditorPane.dirty")) {
String title = script.getName();
if (isDirty())
title += "*";
editor.setTitle(title);
}
}
}