1 package de.lathanda.eos.common.gui;
3 import java.io.BufferedReader;
4 import java.io.BufferedWriter;
6 import java.io.FileInputStream;
7 import java.io.FileOutputStream;
8 import java.io.IOException;
9 import java.io.InputStreamReader;
10 import java.io.OutputStreamWriter;
11 import java.util.LinkedList;
12 import java.util.TreeSet;
14 import javax.swing.JOptionPane;
15 import javax.swing.SwingUtilities;
16 import javax.swing.event.DocumentEvent;
17 import javax.swing.event.DocumentListener;
18 import javax.swing.text.AttributeSet;
19 import javax.swing.text.BadLocationException;
20 import javax.swing.text.DefaultStyledDocument;
21 import javax.swing.text.Element;
23 import de.lathanda.eos.Stop;
24 import de.lathanda.eos.base.event.CleanupListener;
25 import de.lathanda.eos.base.util.ErrorLevel;
26 import de.lathanda.eos.base.util.MessageHandler;
27 import de.lathanda.eos.base.util.MessageHandler.LogListener;
28 import de.lathanda.eos.baseparser.AbstractProgram;
29 import de.lathanda.eos.baseparser.CompilerListener;
30 import de.lathanda.eos.baseparser.Source;
31 import de.lathanda.eos.common.gui.GuiConfiguration.GuiConfigurationListener;
32 import de.lathanda.eos.vm.AbstractMachine;
33 import de.lathanda.eos.vm.DebugInfo;
34 import de.lathanda.eos.vm.DebugListener;
35 import de.lathanda.eos.vm.ErrorInformation;
36 import de.lathanda.eos.vm.Marker;
47 private static final long serialVersionUID = -7902775704808861534L;
49 private static final Object COMPILE_LOCK =
new Object();
53 private boolean compileNeeded =
false;
54 private boolean sourceDirty =
false;
55 private String path =
"";
56 private int delay = 0;
58 private String programText =
"";
61 private TreeSet<Integer> breakpoints =
new TreeSet<Integer>();
62 private TreeSet<Integer> errors =
new TreeSet<Integer>();
64 private LinkedList<UndoableEdit> undostack =
new LinkedList<>();
65 private LinkedList<UndoableEdit> redostack =
new LinkedList<>();
73 addDocumentListener(
this);
78 this.codeColorHook = codeColorHook;
79 this.autoCompleteHook = autoCompleteHook;
80 codeColorHook.
init(
this);
86 br =
new BufferedReader(
new InputStreamReader(
new FileInputStream(file),
"Utf-8"));
87 StringBuilder src =
new StringBuilder();
89 src.append(br.readLine());
93 path = file.getParent();
94 replace(0, getLength(), src.toString(),
null);
95 }
catch (BadLocationException ble) {
97 JOptionPane.showMessageDialog(
null, ble.getLocalizedMessage(),
Messages.
getString(
"InternalError.Title"),
98 JOptionPane.ERROR_MESSAGE);
105 FileOutputStream save =
null;
107 String text = this.getText(0, getLength());
108 save =
new FileOutputStream(file);
109 try (BufferedWriter bw =
new BufferedWriter(
new OutputStreamWriter(save,
"Utf-8"))) {
112 path = file.getParent();
114 }
catch (BadLocationException ble) {
116 JOptionPane.showMessageDialog(
null,
Messages.
getString(
"InternalError.Title"), ble.getLocalizedMessage(),
117 JOptionPane.ERROR_MESSAGE);
138 if (runningMachine != machine) {
140 runningMachine = machine;
142 if (runningMachine !=
null) {
143 runningMachine.
run();
149 remove(0, getLength());
151 }
catch (BadLocationException ble) {
153 JOptionPane.showMessageDialog(
null, ble.getLocalizedMessage(),
Messages.
getString(
"InternalError.Title"),
154 JOptionPane.ERROR_MESSAGE);
159 private void handleException(Exception e) {
163 e.getLocalizedMessage()));
167 if (runningMachine != machine) {
169 runningMachine = machine;
171 if (runningMachine !=
null) {
177 if (runningMachine !=
null) {
178 runningMachine.
pause();
183 if (runningMachine !=
null) {
184 runningMachine.
stop();
190 if (runningMachine != machine) {
192 runningMachine = machine;
194 if (runningMachine !=
null) {
195 runningMachine.
skip();
200 double stepsPerSecond = Math.pow(1.096478196, value);
201 delay = (int) (1000000000 / stepsPerSecond);
204 if (machine !=
null) {
210 return 1000000000 / delay;
215 synchronized (COMPILE_LOCK) {
216 while (!compileNeeded) {
219 }
catch (InterruptedException ex) {
222 compileNeeded =
false;
228 public void insertString(
int pos, String text, AttributeSet attributeSet)
throws BadLocationException {
231 }
catch (Exception e) {
234 storeInsert(pos, text.length(), text);
235 super.insertString(pos, text, attributeSet);
239 public void remove(
int offs,
int len)
throws BadLocationException {
240 storeRemove(offs, len, programText.substring(offs, offs + len));
241 super.remove(offs, len);
245 synchronized (COMPILE_LOCK) {
246 compileNeeded =
true;
248 programText = getText(0, getLength());
249 }
catch (BadLocationException ex) {
253 COMPILE_LOCK.notifyAll();
259 SwingUtilities.invokeLater(() -> compileCompleteInteral(errors, program));
262 private void compileCompleteInteral(LinkedList<ErrorInformation> errors,
AbstractProgram program) {
264 this.program = program;
272 for (Integer linenumber : breakpoints) {
276 if (errors.size() > 0) {
278 for (ErrorInformation err : errors) {
281 message.
println(err.getMessage());
284 for (ErrorInformation err : errors) {
285 if (err.getCode() !=
null) {
286 this.errors.add(err.getCode().getBeginLine());
291 message.
println(Messages.getError(
"Source.Ok"));
293 sideInformation.repaint();
302 private static final long serialVersionUID = -8345159320105291891L;
307 }
catch (BadLocationException e) {
314 remove(0, getLength());
315 }
catch (BadLocationException e) {
322 return breakpoints.contains(linenumber);
326 return errors.contains(linenumber);
330 Element root = getDefaultRootElement();
331 int linenumber = root.getElementIndex(position) + 1;
334 if (breakpoints.contains(linenumber)) {
335 breakpoints.remove(linenumber);
336 if (machine !=
null) {
340 breakpoints.add(linenumber);
341 if (machine !=
null) {
358 this.replace(0, getLength(), this.program.
prettyPrint(),
null);
359 }
catch (BadLocationException e) {
365 this.sideInformation = sideInformation;
370 SwingUtilities.invokeLater(() -> messageInteral(msg, level));
373 private void messageInteral(String msg,
ErrorLevel level) {
400 SwingUtilities.invokeLater(() -> fontsizeChangedInternal(fontsize));
403 private void fontsizeChangedInternal(
int fontsize) {
410 if (machine !=
null) {
416 private int linecount = -1;
424 int oldLineCount = linecount;
425 Element root = getDefaultRootElement();
426 linecount = root.getElementIndex(getLength()) + 1;
427 int newLines = linecount - oldLineCount;
428 if (program !=
null) {
429 int line = program.
getLine(e.getOffset());
430 if (line > 0 && newLines > 0) {
431 TreeSet<Integer> newBreakpoints =
new TreeSet<Integer>();
432 for (
int breakpoint : breakpoints) {
434 if (e.getOffset() < pos) {
435 newBreakpoints.add(breakpoint + newLines);
437 newBreakpoints.add(breakpoint);
440 breakpoints = newBreakpoints;
448 int oldLineCount = linecount;
449 linecount = getDefaultRootElement().getElementIndex(getLength()) + 1;
450 int deleteLines = oldLineCount - linecount;
451 if (program !=
null) {
452 if (deleteLines > 0) {
453 TreeSet<Integer> newBreakpoints =
new TreeSet<Integer>();
454 for (
int breakpoint : breakpoints) {
456 if (e.getOffset() + e.getLength() <= pos) {
457 newBreakpoints.add(breakpoint - deleteLines);
458 }
else if (e.getOffset() > pos) {
459 newBreakpoints.add(breakpoint);
464 breakpoints = newBreakpoints;
471 if (!undostack.isEmpty()) {
472 UndoableEdit ue = undostack.pop();
479 if (!redostack.isEmpty()) {
480 UndoableEdit ue = redostack.pop();
491 private void storeInsert(
int pos,
int length, String text) {
492 undostack.push(
new UndoableEdit(
true, pos, length, text));
496 private void storeRemove(
int pos,
int length, String text) {
497 undostack.push(
new UndoableEdit(
false, pos, length, text));
501 private class UndoableEdit {
502 final boolean insert;
507 public UndoableEdit(
boolean insert,
int pos,
int length, String text) {
509 this.insert = insert;
511 this.length = length;
518 SourceCode.super.insertString(pos, text,
null);
522 }
catch (BadLocationException e) {
531 SourceCode.super.insertString(pos, text,
null);
533 }
catch (BadLocationException e) {
static void addCleanupListener(CleanupListener cl)
synchronized void addLogListener(LogListener log)
int getNumberOfShownErrors()
synchronized void addConfigurationListener(GuiConfigurationListener cf)
static final GuiConfiguration def
static String getString(String id)
static String formatError(String id, Object... info)
void println(String line)
void setPath(String path)
void compileComplete(LinkedList< ErrorInformation > errors, AbstractProgram program)
void setSideInformation(SideInformation sideInformation)
void removeUpdate(DocumentEvent e)
void insertString(int pos, String text, AttributeSet attributeSet)
DefaultStyledDocument getOutput()
void fontsizeChanged(int fontsize)
void saveProgram(File file)
void changedUpdate(DocumentEvent e)
void debugPointReached(DebugInfo debugInfo)
boolean hasError(int linenumber)
boolean hasBreakpoint(int linenumber)
void setToggleBreakpoint(int position)
void init(AutoCompleteHook autoCompleteHook, CodeColorHook codeColorHook)
AbstractProgram getProgram()
void insertUpdate(DocumentEvent e)
void loadProgram(File file)
void message(String msg, ErrorLevel level)
AbstractMachine getMachine()
void insertString(int pos, String text, AbstractProgram program)
void unmarkExecutionPoint()
void markExecutionPoint(Marker codeRange)
void init(SourceCode source)
void markError(Marker code)
void setFontSize(int fontsize)
void addDebugListener(DebugListener debugListener)
int getBreakpointPosition(int linenumber)
void setDelay(long delay)
void removeDebugListener(DebugListener debugListener)
void setBreakpoint(int linenumber, boolean b)