package net.cakenet.jsaton.ui.tools.script;
import net.cakenet.jsaton.util.ImageUtil;
import org.fife.ui.rtextarea.Gutter;
import org.fife.ui.rtextarea.GutterIconInfo;
import org.fife.ui.rtextarea.RTextScrollPane;
import javax.swing.*;
import javax.swing.text.BadLocationException;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class ScriptScrollPane extends RTextScrollPane implements MouseListener {
private java.util.List<BreakpointModificationListener> listeners = new LinkedList<>();
private static final Icon breakpointIcon;
private boolean breakpointsEnabled, breakpointsEditable;
private java.util.List<GutterIconInfo> breakpoints = new ArrayList<>();
public ScriptScrollPane(ScriptEditorPane scriptEditorPane) {
super(scriptEditorPane);
}
public ScriptScrollPane() {
}
public void setViewportView(Component view) {
if (!(view instanceof ScriptEditorPane))
throw new RuntimeException("Invalid view");
super.setViewportView(view);
}
public void setRowHeaderView(Component view) {
super.setRowHeaderView(view);
setIconRowHeaderEnabled(true);
Gutter g = getGutter();
Component[] components = g.getComponents();
for (Component c : components)
c.addMouseListener(this);
}
public void setBreakpointsEnabled(boolean b) {
breakpointsEnabled = b;
if (!breakpointsEnabled) {
for (GutterIconInfo g : breakpoints)
getGutter().removeTrackingIcon(g);
}
if (b && !isIconRowHeaderEnabled())
setIconRowHeaderEnabled(true);
}
public void setBreakpointsEditable(boolean b) {
breakpointsEditable = b;
}
public void addBreakpointModificationListener(BreakpointModificationListener l) {
listeners.add(l);
}
public void removeBreakpointModificationListener(BreakpointModificationListener l) {
listeners.remove(l);
}
public GutterIconInfo getBreakpointAt(int line) {
ScriptEditorPane editor = (ScriptEditorPane) getTextArea();
try {
int offs = editor.getLineStartOffset(line);
Gutter g = getGutter();
Rectangle view = editor.modelToView(offs); // null if this is on load...
if (view != null) {
for (GutterIconInfo i : g.getTrackingIcons(view.getLocation())) {
if (i.getIcon() == breakpointIcon) {
return i;
}
}
}
} catch (BadLocationException e) {
e.printStackTrace();
}
return null;
}
public void removeBreakpoint(GutterIconInfo breakpointRepresentation) {
breakpoints.remove(breakpointRepresentation);
getGutter().removeTrackingIcon(breakpointRepresentation);
try {
fire(getTextArea().getLineOfOffset(breakpointRepresentation.getMarkedOffset()), false);
} catch (BadLocationException e) {
e.printStackTrace();
}
}
public boolean removeBreakpoint(int line) {
GutterIconInfo breakpoint = getBreakpointAt(line);
if (breakpoint == null)
return false;
removeBreakpoint(breakpoint);
return true;
}
public boolean addBreakpoint(int line) {
if (getBreakpointAt(line) != null)
return false;
ScriptEditorPane editor = (ScriptEditorPane) getTextArea();
if (!editor.isBreakableLine(line))
return false;
try {
breakpoints.add(getGutter().addOffsetTrackingIcon(editor.getLineStartOffset(line), breakpointIcon, "breakpoint"));
fire(line, true);
return true;
} catch (BadLocationException e) {
e.printStackTrace();
}
return false;
}
public void mouseClicked(MouseEvent e) {
if (!breakpointsEnabled || !breakpointsEditable)
return;
try {
ScriptEditorPane editor = (ScriptEditorPane) getTextArea();
int line = editor.getLineOfOffset(editor.viewToModel(e.getPoint()));
if (removeBreakpoint(line))
return;
addBreakpoint(line);
} catch (BadLocationException e1) {
e1.printStackTrace();
}
}
private void fire(int line, boolean added) {
for (int i = 0; i < listeners.size(); i++) {
BreakpointModificationListener l = listeners.get(i);
if (l == null)
continue;
if (added)
l.breakpointAdded(line);
else
l.breakpointRemoved(line);
}
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
static {
breakpointIcon = ImageUtil.loadIcon("breakpoint.png");
}
public List<GutterIconInfo> getBreakpoints() {
return breakpoints;
}
}