heavy refactoring to separate Java and non-Java code for Modes

This commit is contained in:
Ben Fry
2016-08-06 12:31:49 -04:00
parent e97c6bff21
commit 9f57d2a063
13 changed files with 552 additions and 258 deletions

View File

@@ -11,7 +11,6 @@ import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import javax.swing.*;
import javax.swing.border.*;
@@ -34,7 +33,7 @@ import processing.mode.java.pdex.PreprocessingService;
import processing.mode.java.pdex.ImportStatement;
import processing.mode.java.pdex.JavaTextArea;
import processing.mode.java.pdex.PDEX;
import processing.mode.java.pdex.Problem;
import processing.mode.java.pdex.JavaProblem;
import processing.mode.java.pdex.SourceUtils;
import processing.mode.java.preproc.PdePreprocessor;
import processing.mode.java.runner.Runner;
@@ -74,8 +73,6 @@ public class JavaEditor extends Editor {
protected PreprocessingService preprocessingService;
protected PDEX pdex;
protected List<Problem> problems = Collections.emptyList();
protected JavaEditor(Base base, String path, EditorState state,
Mode mode) throws EditorException {
@@ -2368,161 +2365,34 @@ public class JavaEditor extends Editor {
*/
public void setProblemList(List<Problem> problems) {
this.problems = problems;
boolean hasErrors = problems.stream().anyMatch(Problem::isError);
updateErrorTable(problems);
errorColumn.updateErrorPoints(problems);
textarea.repaint();
updateErrorToggle(hasErrors);
updateEditorStatus();
}
/**
* Updates the error table in the Error Window.
* Overridden to handle the fugly import suggestions text.
*/
@Override
public void updateErrorTable(List<Problem> problems) {
errorTable.clearRows();
for (Problem p : problems) {
JavaProblem jp = (JavaProblem) p;
String message = p.getMessage();
if (JavaMode.importSuggestEnabled &&
p.getImportSuggestions() != null &&
p.getImportSuggestions().length > 0) {
jp.getImportSuggestions() != null &&
jp.getImportSuggestions().length > 0) {
message += " (double-click for suggestions)";
}
errorTable.addRow(p, message,
sketch.getCode(p.getTabIndex()).getPrettyName(),
sketch.getCode(jp.getTabIndex()).getPrettyName(),
Integer.toString(p.getLineNumber() + 1));
// Added +1 because lineNumbers internally are 0-indexed
}
}
public void highlight(Problem p) {
if (p != null) {
highlight(p.getTabIndex(), p.getStartOffset(), p.getStartOffset());
}
}
public void highlight(int tabIndex, int startOffset, int stopOffset) {
// Switch to tab
toFront();
sketch.setCurrentCode(tabIndex);
// Make sure offsets are in bounds
int length = textarea.getDocumentLength();
startOffset = PApplet.constrain(startOffset, 0, length);
stopOffset = PApplet.constrain(stopOffset, 0, length);
// Highlight the code
textarea.select(startOffset, stopOffset);
// Scroll to error line
textarea.scrollToCaret();
repaint();
}
public List<Problem> getProblems() {
return problems;
}
/**
* Updates editor status bar, depending on whether the caret is on an error
* line or not
*/
public void updateEditorStatus() {
Problem problem = findProblem(textarea.getCaretLine());
if (problem != null) {
int type = problem.isError() ?
EditorStatus.CURSOR_LINE_ERROR : EditorStatus.CURSOR_LINE_WARNING;
statusMessage(problem.getMessage(), type);
} else {
switch (getStatusMode()) {
case EditorStatus.CURSOR_LINE_ERROR:
case EditorStatus.CURSOR_LINE_WARNING:
statusEmpty();
break;
}
}
}
/**
* @return the Problem for the first error or warning on 'line'
*/
public Problem findProblem(int line) {
JavaTextArea textArea = getJavaTextArea();
int currentTab = getSketch().getCurrentCodeIndex();
return problems.stream()
.filter(p -> p.getTabIndex() == currentTab)
.filter(p -> {
int pStartLine = p.getLineNumber();
int pEndOffset = p.getStopOffset();
int pEndLine = textArea.getLineOfOffset(pEndOffset);
return line >= pStartLine && line <= pEndLine;
})
.findFirst()
.orElse(null);
}
public List<Problem> findProblems(int line) {
JavaTextArea textArea = getJavaTextArea();
int currentTab = getSketch().getCurrentCodeIndex();
return problems.stream()
.filter(p -> p.getTabIndex() == currentTab)
.filter(p -> {
int pStartLine = p.getLineNumber();
int pEndOffset = p.getStopOffset();
int pEndLine = textArea.getLineOfOffset(pEndOffset);
return line >= pStartLine && line <= pEndLine;
})
.collect(Collectors.toList());
}
/*
public void clearErrorPoints() {
List<LineMarker> errorPoints = getErrorPoints();
synchronized (errorPoints) { // necessary?
errorPoints.clear();
}
}
*/
public void repaintErrorBar() {
errorColumn.repaint();
}
public void showConsole() {
footer.setPanel(console);
}
// /** Toggle between Console and Errors List */
// public void showProblemListView(String buttonName) {
//// CardLayout cl = (CardLayout) consoleProblemsPane.getLayout();
//// cl.show(consoleProblemsPane, buttonName);
//// ((JTabbedPane) consolePanel).setSelectedIndex(ERROR_TAB_INDEX);
// footer.setPanel(errorTableScrollPane);
// }
public void errorTableClick(Object item) {
highlight((Problem) item);
}
@Override
public void errorTableDoubleClick(Object item) {
Problem p = (Problem) item;
JavaProblem p = (JavaProblem) item;
// MouseEvent evt = null;
String[] suggs = p.getImportSuggestions();
@@ -2620,28 +2490,6 @@ public class JavaEditor extends Editor {
}
// /** Updates the error table */
// synchronized public boolean updateTable(final TableModel tableModel) {
// return errorTable.updateTable(tableModel);
// }
/**
* Handle whether the tiny red error indicator is shown near
* the error button at the bottom of the PDE
*/
public void updateErrorToggle(boolean hasErrors) {
footer.setNotification(errorTable.getParent(), hasErrors);
// String title = Language.text("editor.footer.errors");
// if (hasErrors) {
// title += "*";
// }
// ((JTabbedPane) footer).setTitleAt(ERROR_TAB_INDEX, title);
//// btnShowErrors.updateMarker(hasErrors,
//// errorBar.errorColor);
}
public boolean hasJavaTabs() {
return hasJavaTabs;
}

View File

@@ -34,11 +34,12 @@ import java.util.stream.Collectors;
import javax.swing.JPanel;
import processing.app.Mode;
import processing.app.Problem;
import processing.app.Sketch;
import processing.app.SketchCode;
import processing.app.ui.Editor;
import processing.core.PApplet;
import processing.mode.java.pdex.Problem;
import processing.mode.java.pdex.JavaProblem;
/**
@@ -51,7 +52,7 @@ import processing.mode.java.pdex.Problem;
* which displays the overall errors in a document
*/
public class MarkerColumn extends JPanel {
protected JavaEditor editor;
protected Editor editor;
// static final int WIDE = 12;
@@ -92,7 +93,7 @@ public class MarkerColumn extends JPanel {
@Override
public void paintComponent(Graphics g) {
g.drawImage(editor.getJavaTextArea().getGutterGradient(),
g.drawImage(editor.getPdeTextArea().getGutterGradient(),
0, 0, getWidth(), getHeight(), this);
int currentTabIndex = editor.getSketch().getCurrentCodeIndex();
@@ -110,7 +111,7 @@ public class MarkerColumn extends JPanel {
}
public void updateErrorPoints(final List<Problem> problems) {
public void updateErrorPoints(final List<JavaProblem> problems) {
errorPoints = problems.stream()
.map(LineMarker::new)
.collect(Collectors.toList());
@@ -131,24 +132,12 @@ public class MarkerColumn extends JPanel {
}
/*
@Override
public JToolTip createToolTip() {
return new ErrorToolTip(editor.getMode(), this);
}
*/
/** Show tooltip on hover. */
private void showMarkerHover(final int y) {
try {
LineMarker m = findClosestMarker(y);
if (m != null) {
Problem p = m.problem;
// String kind = p.isError() ?
// Language.text("editor.status.error") :
// Language.text("editor.status.warning");
// setToolTipText(kind + ": " + p.getMessage());
editor.statusToolTip(MarkerColumn.this, p.getMessage(), p.isError());
setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
}

View File

@@ -32,7 +32,7 @@ import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
public class CompletionCandidate implements Comparable<CompletionCandidate>{
public class CompletionCandidate implements Comparable<CompletionCandidate> {
private final String elementName;
private final String label; // the toString value
private final String completionString;

View File

@@ -85,7 +85,7 @@ public class ErrorMessageSimplifier {
/**
* Tones down the jargon in the ecj reported errors.
*/
public static String getSimplifiedErrorMessage(Problem problem) {
public static String getSimplifiedErrorMessage(JavaProblem problem) {
if (problem == null) return null;
IProblem iprob = problem.getIProblem();

View File

@@ -25,14 +25,14 @@ import java.util.regex.Pattern;
import org.eclipse.jdt.core.compiler.IProblem;
import processing.app.ui.ErrorTable;
import processing.app.Problem;
/**
* Wrapper class for IProblem that stores the tabIndex and line number
* according to its tab, including the original IProblem object
*/
public class Problem implements ErrorTable.Entry {
public class JavaProblem implements Problem {
/**
* The IProblem which is being wrapped
*/
@@ -73,7 +73,7 @@ public class Problem implements ErrorTable.Entry {
* @param tabIndex - The tab number to which the error belongs to
* @param lineNumber - Line number(pde code) of the error
*/
public Problem(IProblem iProblem, int tabIndex, int lineNumber) {
public JavaProblem(IProblem iProblem, int tabIndex, int lineNumber) {
this.iProblem = iProblem;
if(iProblem.isError()) {
type = ERROR;

View File

@@ -20,30 +20,29 @@ along with this program; if not, write to the Free Software Foundation, Inc.
package processing.mode.java.pdex;
import processing.mode.java.JavaInputHandler;
import processing.mode.java.JavaMode;
import processing.mode.java.JavaEditor;
import processing.mode.java.tweak.ColorControlBox;
import processing.mode.java.tweak.Handle;
import java.awt.*;
import java.awt.event.*;
import java.awt.EventQueue;
import java.awt.Point;
import java.awt.event.ComponentListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.BitSet;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.DefaultListModel;
import javax.swing.SwingWorker;
import processing.app.Messages;
import processing.app.Mode;
import processing.app.Platform;
import processing.app.syntax.JEditTextArea;
import processing.app.syntax.PdeTextArea;
import processing.app.syntax.TextAreaDefaults;
import processing.app.ui.Editor;
import processing.mode.java.JavaEditor;
import processing.mode.java.JavaInputHandler;
import processing.mode.java.JavaMode;
import processing.mode.java.tweak.ColorControlBox;
import processing.mode.java.tweak.Handle;
public class JavaTextArea extends PdeTextArea {
@@ -55,24 +54,24 @@ public class JavaTextArea extends PdeTextArea {
public JavaTextArea(TextAreaDefaults defaults, JavaEditor editor) {
super(defaults, new JavaInputHandler(editor), editor);
// TweakMode code
prevCompListeners = painter.getComponentListeners();
prevMouseListeners = painter.getMouseListeners();
prevMMotionListeners = painter.getMouseMotionListeners();
prevKeyListeners = editor.getKeyListeners();
suggestionGenerator = new CompletionGenerator();
tweakMode = false;
}
public JavaEditor getJavaEditor() {
return (JavaEditor) editor;
}
@Override
protected JavaTextAreaPainter createPainter(final TextAreaDefaults defaults) {
return new JavaTextAreaPainter(this, defaults);
}
// used by Tweak Mode
protected JavaTextAreaPainter getJavaPainter() {
return (JavaTextAreaPainter) painter;
}
@@ -142,7 +141,7 @@ public class JavaTextArea extends PdeTextArea {
super.processKeyEvent(evt);
// code completion disabled if Java tabs present
if (!editor.hasJavaTabs()) {
if (!getJavaEditor().hasJavaTabs()) {
if (evt.getID() == KeyEvent.KEY_TYPED) {
processCompletionKeys(evt);
} else if (!Platform.isMacOS() && evt.getID() == KeyEvent.KEY_RELEASED) {
@@ -285,10 +284,11 @@ public class JavaTextArea extends PdeTextArea {
}
// Adjust line number for tabbed sketches
int codeIndex = editor.getSketch().getCodeIndex(editor.getCurrentTab());
//int codeIndex = editor.getSketch().getCodeIndex(getJavaEditor().getCurrentTab());
int codeIndex = editor.getSketch().getCurrentCodeIndex();
int lineStartOffset = editor.getTextArea().getLineStartOffset(caretLineIndex);
editor.getPreprocessingService().whenDone(ps -> {
getJavaEditor().getPreprocessingService().whenDone(ps -> {
int lineNumber = ps.tabOffsetToJavaLine(codeIndex, lineStartOffset);
String phrase = null;
@@ -525,30 +525,29 @@ public class JavaTextArea extends PdeTextArea {
/**
* Calculates location of caret and displays the suggestion popup.
* Calculates location of caret and displays the suggestion pop-up.
*/
protected void showSuggestion(DefaultListModel<CompletionCandidate> listModel, String subWord) {
// TODO can this be ListModel instead? why is size() in DefaultListModel
// different from getSize() in ListModel (or are they, really?)
hideSuggestion();
if (listModel.size() == 0) {
Messages.log("TextArea: No suggestions to show.");
} else {
if (listModel.size() != 0) {
int position = getCaretPosition();
Point location = new Point();
try {
location.x = offsetToX(getCaretLine(),
position - getLineStartOffset(getCaretLine()));
location.y = lineToY(getCaretLine()) + getPainter().getLineHeight();
//log("TA position: " + location);
} catch (Exception e2) {
e2.printStackTrace();
return;
}
Point location =
new Point(offsetToX(getCaretLine(),
position - getLineStartOffset(getCaretLine())),
lineToY(getCaretLine()) + getPainter().getLineHeight());
suggestion = new CompletionPanel(this, position, subWord,
listModel, location, getJavaEditor());
requestFocusInWindow();
suggestion = new CompletionPanel(this, position, subWord,
listModel, location, editor);
requestFocusInWindow();
} catch (Exception e) {
e.printStackTrace();
}
} else {
Messages.log("TextArea: No suggestions to show.");
}
}
@@ -569,15 +568,23 @@ public class JavaTextArea extends PdeTextArea {
// save input listeners to stop/start text edit
protected final ComponentListener[] prevCompListeners;
protected final MouseListener[] prevMouseListeners;
protected final MouseMotionListener[] prevMMotionListeners;
protected final KeyListener[] prevKeyListeners;
protected ComponentListener[] baseCompListeners;
protected MouseListener[] baseMouseListeners;
protected MouseMotionListener[] baseMotionListeners;
protected KeyListener[] baseKeyListeners;
protected boolean tweakMode;
/* remove all standard interaction listeners */
public void removeAllListeners() {
public void tweakRemoveListeners() {
if (baseCompListeners == null) {
// First time in tweak mode, grab the default listeners. Moved from the
// constructor since not all listeners may have been added at that point.
baseCompListeners = painter.getComponentListeners();
baseMouseListeners = painter.getMouseListeners();
baseMotionListeners = painter.getMouseMotionListeners();
baseKeyListeners = editor.getKeyListeners();
}
ComponentListener[] componentListeners = painter.getComponentListeners();
MouseListener[] mouseListeners = painter.getMouseListeners();
MouseMotionListener[] mouseMotionListeners = painter.getMouseMotionListeners();
@@ -601,7 +608,7 @@ public class JavaTextArea extends PdeTextArea {
public void startTweakMode() {
// ignore if we are already in interactiveMode
if (!tweakMode) {
removeAllListeners();
tweakRemoveListeners();
getJavaPainter().startTweakMode();
this.editable = false;
this.caretBlinks = false;
@@ -614,8 +621,8 @@ public class JavaTextArea extends PdeTextArea {
public void stopTweakMode() {
// ignore if we are not in interactive mode
if (tweakMode) {
removeAllListeners();
addPrevListeners();
tweakRemoveListeners();
tweakRestoreBaseListeners();
getJavaPainter().stopTweakMode();
editable = true;
caretBlinks = true;
@@ -625,18 +632,18 @@ public class JavaTextArea extends PdeTextArea {
}
private void addPrevListeners() {
private void tweakRestoreBaseListeners() {
// add the original text-edit listeners
for (ComponentListener cl : prevCompListeners) {
for (ComponentListener cl : baseCompListeners) {
painter.addComponentListener(cl);
}
for (MouseListener ml : prevMouseListeners) {
for (MouseListener ml : baseMouseListeners) {
painter.addMouseListener(ml);
}
for (MouseMotionListener mml : prevMMotionListeners) {
for (MouseMotionListener mml : baseMotionListeners) {
painter.addMouseMotionListener(mml);
}
for (KeyListener kl : prevKeyListeners) {
for (KeyListener kl : baseKeyListeners) {
editor.addKeyListener(kl);
}
}

View File

@@ -23,7 +23,6 @@ package processing.mode.java.pdex;
import processing.mode.java.JavaEditor;
import processing.mode.java.tweak.*;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
@@ -44,7 +43,7 @@ import javax.swing.text.BadLocationException;
import javax.swing.text.Segment;
import javax.swing.text.Utilities;
import processing.app.Mode;
import processing.app.Problem;
import processing.app.SketchCode;
import processing.app.syntax.PdeTextAreaPainter;
import processing.app.syntax.SyntaxDocument;
@@ -228,16 +227,9 @@ public class JavaTextAreaPainter extends PdeTextAreaPainter {
/**
* Paints the underline for an error/warning line
*
* @param gfx
* the graphics context
* @param tokenMarker
* @param line
* 0-based line number: NOTE
* @param x
*/
protected void paintErrorLine(Graphics gfx, int line, int x) {
List<Problem> problems = getJavaEditor().findProblems(line);
List<Problem> problems = getEditor().findProblems(line);
for (Problem problem : problems) {
int startOffset = problem.getStartOffset();
int stopOffset = problem.getStopOffset();
@@ -314,7 +306,7 @@ public class JavaTextAreaPainter extends PdeTextAreaPainter {
public String getToolTipText(MouseEvent evt) {
int line = evt.getY() / getFontMetrics().getHeight() + textArea.getFirstLine();
if (line >= 0 || line < textArea.getLineCount()) {
List<Problem> problems = getJavaEditor().findProblems(line);
List<Problem> problems = getEditor().findProblems(line);
for (Problem problem : problems) {
int lineStart = textArea.getLineStartOffset(line);
int lineEnd = textArea.getLineStopOffset(line);

View File

@@ -72,6 +72,7 @@ import javax.swing.tree.TreeModel;
import processing.app.Language;
import processing.app.Messages;
import processing.app.Platform;
import processing.app.Problem;
import processing.app.Sketch;
import processing.app.SketchCode;
import processing.app.syntax.SyntaxDocument;
@@ -1092,7 +1093,7 @@ public class PDEX {
SketchInterval in = ps.mapJavaToSketch(start, stop);
if (in == SketchInterval.BEFORE_START) return null;
int line = ps.tabOffsetToTabLine(in.tabIndex, in.startTabOffset);
Problem p = new Problem(iproblem, in.tabIndex, line);
JavaProblem p = new JavaProblem(iproblem, in.tabIndex, line);
p.setPDEOffsets(in.startTabOffset, in.stopTabOffset);
return p;
})
@@ -1104,13 +1105,13 @@ public class PDEX {
Map<String, List<Problem>> undefinedTypeProblems = problems.stream()
// Get only problems with undefined types/names
.filter(p -> {
int id = p.getIProblem().getID();
int id = ((JavaProblem) p).getIProblem().getID();
return id == IProblem.UndefinedType ||
id == IProblem.UndefinedName ||
id == IProblem.UnresolvedVariable;
})
// Group problems by the missing type/name
.collect(Collectors.groupingBy(p -> p.getIProblem().getArguments()[0]));
.collect(Collectors.groupingBy(p -> ((JavaProblem) p).getIProblem().getArguments()[0]));
if (!undefinedTypeProblems.isEmpty()) {
final ClassPath cp = ps.searchClassPath;
@@ -1121,7 +1122,7 @@ public class PDEX {
String missingClass = entry.getKey();
List<Problem> affectedProblems = entry.getValue();
String[] suggestions = getImportSuggestions(cp, missingClass);
affectedProblems.forEach(p -> p.setImportSuggestions(suggestions));
affectedProblems.forEach(p -> ((JavaProblem) p).setImportSuggestions(suggestions));
});
}
}