diff --git a/app/src/processing/app/ui/ErrorTable.java b/app/src/processing/app/ui/ErrorTable.java index 415b8451b..9dc7df067 100644 --- a/app/src/processing/app/ui/ErrorTable.java +++ b/app/src/processing/app/ui/ErrorTable.java @@ -29,6 +29,7 @@ import java.awt.event.MouseEvent; import javax.swing.JLabel; import javax.swing.JTable; +import javax.swing.ListSelectionModel; import javax.swing.SwingConstants; import javax.swing.ToolTipManager; import javax.swing.table.DefaultTableModel; @@ -79,6 +80,8 @@ public class ErrorTable extends JTable { public ErrorTable(final Editor editor) { super(new DefaultTableModel(columnNames, 0)); + setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + this.editor = editor; JTableHeader header = getTableHeader(); @@ -102,23 +105,25 @@ public class ErrorTable extends JTable { // } addMouseListener(new MouseAdapter() { - @Override - synchronized public void mouseClicked(MouseEvent e) { - try { - int row = ((ErrorTable) e.getSource()).getSelectedRow(); - Object data = getModel().getValueAt(row, DATA_COLUMN); - int clickCount = e.getClickCount(); - if (clickCount == 1) { - editor.errorTableClick(data); - } else if (clickCount > 1) { - editor.errorTableDoubleClick(data); - } -// editor.getErrorChecker().scrollToErrorLine(row); - } catch (Exception ex) { - ex.printStackTrace(); - } - } - }); + @Override + synchronized public void mouseClicked(MouseEvent e) { + try { + int row = ((ErrorTable) e.getSource()).getSelectedRow(); + if (row >= 0 && row < getRowCount()) { + Object data = getModel().getValueAt(row, DATA_COLUMN); + int clickCount = e.getClickCount(); + if (clickCount == 1) { + editor.errorTableClick(data); + } else if (clickCount > 1) { + editor.errorTableDoubleClick(data); + } +// editor.getErrorChecker().scrollToErrorLine(row); + } + } catch (Exception ex) { + ex.printStackTrace(); + } + } + }); /* addMouseMotionListener(new MouseMotionAdapter() { diff --git a/java/src/processing/mode/java/JavaEditor.java b/java/src/processing/mode/java/JavaEditor.java index 09c2c3baf..1d15991ca 100644 --- a/java/src/processing/mode/java/JavaEditor.java +++ b/java/src/processing/mode/java/JavaEditor.java @@ -2324,6 +2324,7 @@ public class JavaEditor extends Editor { */ @Override public void setCode(SketchCode code) { + //System.out.println("tab switch: " + code.getFileName()); // set the new document in the textarea, etc. need to do this first super.setCode(code); @@ -2355,6 +2356,13 @@ public class JavaEditor extends Editor { if (getDebugger() != null && getDebugger().isStarted()) { getDebugger().startTrackingLineChanges(); } + if (errorCheckerService != null) { + if (errorColumn != null) { + getErrorPoints().clear(); + statusEmpty(); + } + errorCheckerService.request(); + } } @@ -2654,10 +2662,10 @@ public class JavaEditor extends Editor { * Handle whether the tiny red error indicator is shown near * the error button at the bottom of the PDE */ - public void updateErrorToggle() { + public void updateErrorToggle(boolean hasErrors) { footer.setNotification(errorTable.getParent(), //errorTableScrollPane, JavaMode.errorCheckEnabled && - errorCheckerService.hasErrors()); + hasErrors); // String title = Language.text("editor.footer.errors"); // if (JavaMode.errorCheckEnabled && errorCheckerService.hasErrors()) { // title += "*"; diff --git a/java/src/processing/mode/java/pdex/ASTGenerator.java b/java/src/processing/mode/java/pdex/ASTGenerator.java index 1e209c694..f20c51edc 100644 --- a/java/src/processing/mode/java/pdex/ASTGenerator.java +++ b/java/src/processing/mode/java/pdex/ASTGenerator.java @@ -1927,6 +1927,8 @@ public class ASTGenerator { @Override public void valueChanged(TreeSelectionEvent e) { Messages.log(e.toString()); + + // TODO: this should already run on EDT so why the SwingWorker? SwingWorker worker = new SwingWorker() { @Override @@ -2793,6 +2795,10 @@ public class ASTGenerator { SimpleType stp = extracTypeInfo(findDeclaration((qn.getQualifier()))); // log(qn.getQualifier() + "->" + qn.getName()); + if (stp == null) { + return null; + } + declaringClass = findDeclaration(stp.getName()); // log("QN decl class: " + getNodeAsString(declaringClass)); @@ -2810,16 +2816,15 @@ public class ASTGenerator { // .toString())); SimpleType stp = extracTypeInfo(findDeclaration((qnn.getQualifier()))); - if (stp != null) { - declaringClass = findDeclaration(stp.getName()); - constrains.clear(); - constrains.add(ASTNode.TYPE_DECLARATION); - constrains.add(ASTNode.FIELD_DECLARATION); - return definedIn(declaringClass, qnn.getName().toString(), - constrains, null); - } else { + if (stp == null) { return null; } + declaringClass = findDeclaration(stp.getName()); + constrains.clear(); + constrains.add(ASTNode.TYPE_DECLARATION); + constrains.add(ASTNode.FIELD_DECLARATION); + return definedIn(declaringClass, qnn.getName().toString(), + constrains, null); } } } else if (parent.getNodeType() == ASTNode.SIMPLE_TYPE) { @@ -3010,6 +3015,11 @@ public class ASTGenerator { // .toString())); SimpleType stp = extracTypeInfo(findDeclaration2((qnn.getQualifier()), alternateParent)); + + if (stp == null) { + return null; + } + // log(qnn.getQualifier() + "->" + qnn.getName()); declaringClass = findDeclaration2(stp.getName(), alternateParent); diff --git a/java/src/processing/mode/java/pdex/ErrorCheckerService.java b/java/src/processing/mode/java/pdex/ErrorCheckerService.java index 2797a4a29..696e3f51a 100644 --- a/java/src/processing/mode/java/pdex/ErrorCheckerService.java +++ b/java/src/processing/mode/java/pdex/ErrorCheckerService.java @@ -26,6 +26,7 @@ import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -232,8 +233,6 @@ public class ErrorCheckerService { defaultImportsOffset = pdePrepoc.getCoreImports().length + pdePrepoc.getDefaultImports().length + 1; astGenerator = new ASTGenerator(this); - lastCodeCheckResult.syntaxErrors = false; - lastCodeCheckResult.containsErrors = false; errorMsgSimplifier = new ErrorMessageSimplifier(); tempErrorLog = new TreeMap<>(); sketchChangedListener = new SketchChangedListener(); @@ -256,26 +255,6 @@ public class ErrorCheckerService { Executors.newSingleThreadScheduledExecutor(); volatile ScheduledFuture scheduledUiUpdate = null; volatile long nextUiUpdate = 0; - private Runnable uiUpdater = new Runnable() { - @Override - public void run() { - if (nextUiUpdate > 0 && - System.currentTimeMillis() >= nextUiUpdate) { - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - calcPdeOffsetsForProbList(); - updateErrorTable(); - editor.updateErrorBar(lastCodeCheckResult.problems); - editor.getTextArea().repaint(); - updatePaintedThingys(); - editor.updateErrorToggle(); - updateSketchCodeListeners(); - } - }); - } - } - }; private Runnable mainLoop = new Runnable() { @Override @@ -284,7 +263,7 @@ public class ErrorCheckerService { lastCodeCheckResult = checkCode(); - if (!hasSyntaxErrors()) { + if (!lastCodeCheckResult.syntaxErrors) { // editor.showProblemListView(Language.text("editor.footer.console")); editor.showConsole(); } @@ -326,6 +305,27 @@ public class ErrorCheckerService { } // Update UI after a delay. See #2677 long delay = nextUiUpdate - System.currentTimeMillis(); + Runnable uiUpdater = new Runnable() { + final CodeCheckResult result = lastCodeCheckResult; + + @Override + public void run() { + if (nextUiUpdate > 0 && + System.currentTimeMillis() >= nextUiUpdate) { + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + calcPdeOffsetsForProbList(result); + updateErrorTable(result.problems); + editor.updateErrorBar(result.problems); + editor.getTextArea().repaint(); + editor.updateErrorToggle(result.containsErrors); + updateSketchCodeListeners(); + } + }); + } + } + }; scheduledUiUpdate = scheduler.schedule(uiUpdater, delay, TimeUnit.MILLISECONDS); } @@ -399,6 +399,9 @@ public class ErrorCheckerService { protected void checkForMissingImports() { + // Atomic access + CodeCheckResult lastCodeCheckResult = this.lastCodeCheckResult; + if (Preferences.getBoolean(JavaMode.SUGGEST_IMPORTS_PREF)) { for (Problem p : lastCodeCheckResult.problems) { if(p.getIProblem().getID() == IProblem.UndefinedType) { @@ -617,11 +620,11 @@ public class ErrorCheckerService { /** * Calculates PDE Offsets from Java Offsets for Problems */ - private void calcPdeOffsetsForProbList() { + private void calcPdeOffsetsForProbList(CodeCheckResult codeCheckResult) { try { PlainDocument javaSource = new PlainDocument(); - javaSource.insertString(0, lastCodeCheckResult.sourceCode, null); + javaSource.insertString(0, codeCheckResult.sourceCode, null); // Code in pde tabs stored as PlainDocument List pdeTabs = new ArrayList<>(); for (SketchCode sc : editor.getSketch().getCode()) { @@ -635,16 +638,16 @@ public class ErrorCheckerService { } int pkgNameOffset = ("package " + className + ";\n").length(); // package name is added only during compile check - if (lastCodeCheckResult.sourceCodeOffset == 0) { + if (codeCheckResult.sourceCodeOffset == 0) { pkgNameOffset = 0; } - for (Problem p : lastCodeCheckResult.problems) { + for (Problem p : codeCheckResult.problems) { int prbStart = p.getIProblem().getSourceStart() - pkgNameOffset; int prbEnd = p.getIProblem().getSourceEnd() - pkgNameOffset; int javaLineNumber = p.getSourceLineNumber() - 1; // not sure if this is necessary [fry 150808] - javaLineNumber -= lastCodeCheckResult.sourceCodeOffset; + javaLineNumber -= codeCheckResult.sourceCodeOffset; // errors on the first line were setting this to -1 [fry 150808] if (javaLineNumber < 0) { javaLineNumber = 0; @@ -871,7 +874,7 @@ public class ErrorCheckerService { /** * Updates the error table in the Error Window. */ - public void updateErrorTable() { + public void updateErrorTable(List problems) { try { ErrorTable table = editor.getErrorTable(); table.clearRows(); @@ -880,7 +883,7 @@ public class ErrorCheckerService { // int index = 0; // for (int i = 0; i < problemsList.size(); i++) { Sketch sketch = editor.getSketch(); - for (Problem p : lastCodeCheckResult.problems) { + for (Problem p : problems) { String message = p.getMessage(); if (Preferences.getBoolean(JavaMode.SUGGEST_IMPORTS_PREF)) { if (p.getIProblem().getID() == IProblem.UndefinedType) { @@ -926,21 +929,6 @@ public class ErrorCheckerService { } - // TODO: why is this here and not in event handler? - /** Repaints the textarea if required */ - private void updatePaintedThingys() { -// currentTab = editor.getSketch().getCodeIndex(editor.getSketch().getCurrentCode()); - currentTab = editor.getSketch().getCurrentCodeIndex(); - //log("Tab changed " + currentTab + " LT " + lastTab); - if (currentTab != lastTab) { - request(); - lastTab = currentTab; - editor.getTextArea().repaint(); - editor.statusEmpty(); - } - } - - /** * Updates editor status bar, depending on whether the caret is on an error * line or not @@ -960,7 +948,8 @@ public class ErrorCheckerService { editor.statusMessage(errorMarker.getProblem().getMessage(), EditorStatus.COMPILER_ERROR); } - return; + } else { + editor.statusEmpty(); // No error, clear the status } } @@ -1335,6 +1324,9 @@ public class ErrorCheckerService { return; } + // Atomic access + CodeCheckResult lastCodeCheckResult = this.lastCodeCheckResult; + if (errorIndex < lastCodeCheckResult.problems.size() && errorIndex >= 0) { Problem p = lastCodeCheckResult.problems.get(errorIndex); scrollToErrorLine(p); @@ -1555,7 +1547,7 @@ public class ErrorCheckerService { //editor.clearErrorPoints(); editor.getErrorPoints().clear(); lastCodeCheckResult.problems.clear(); - updateErrorTable(); + updateErrorTable(Collections.emptyList()); updateEditorStatus(); editor.getTextArea().repaint(); editor.repaintErrorBar(); diff --git a/java/src/processing/mode/java/pdex/JavaTextArea.java b/java/src/processing/mode/java/pdex/JavaTextArea.java index 43c02fefe..dfe5c8377 100644 --- a/java/src/processing/mode/java/pdex/JavaTextArea.java +++ b/java/src/processing/mode/java/pdex/JavaTextArea.java @@ -443,7 +443,7 @@ public class JavaTextArea extends JEditTextArea { @Override protected Void doInBackground() throws Exception { Messages.log("phrase parse start"); - phrase = parsePhrase(text, caretLinePosition); + phrase = parsePhrase(text); Messages.log("phrase: " + phrase); if (phrase == null) return null; @@ -504,7 +504,7 @@ public class JavaTextArea extends JEditTextArea { suggestionWorker.execute(); } - protected static String parsePhrase(String lineText, int caretLinePosition) { + protected static String parsePhrase(final String lineText) { boolean overloading = false; @@ -535,7 +535,7 @@ public class JavaTextArea extends JEditTextArea { } } - final int currentCharIndex = caretLinePosition - 1; + final int currentCharIndex = lineText.length() - 1; { // Check if the caret is in the comment int commentStart = lineText.indexOf("//", 0); @@ -658,7 +658,7 @@ public class JavaTextArea extends JEditTextArea { position++; // Extract phrase - String phrase = lineText.substring(position, caretLinePosition).trim(); + String phrase = lineText.substring(position, lineText.length()).trim(); Messages.log(phrase); if (phrase.length() == 0 || Character.isDigit(phrase.charAt(0))) {