diff --git a/pdex/src/processing/mode/experimental/ASTGenerator.java b/pdex/src/processing/mode/experimental/ASTGenerator.java index d65c4d900..23d37464e 100644 --- a/pdex/src/processing/mode/experimental/ASTGenerator.java +++ b/pdex/src/processing/mode/experimental/ASTGenerator.java @@ -980,18 +980,18 @@ public class ASTGenerator { String[] resources = classPath.findResources("", regExpResourceFilter); for (String matchedClass2 : resources) { - matchedClass2 = matchedClass2.replace('/', '.'); + matchedClass2 = matchedClass2.replace('/', '.'); //package name String matchedClass = matchedClass2.substring(0, matchedClass2 .length() - 6); int d = matchedClass.lastIndexOf('.'); if (ignorableImport(matchedClass2,matchedClass.substring(d + 1))) continue; - matchedClass = matchedClass.substring(d + 1); - candidates - .add(new CompletionCandidate(matchedClass, matchedClass - + " : " + matchedClass2.substring(0, d), matchedClass, - CompletionCandidate.PREDEF_CLASS)); + matchedClass = matchedClass.substring(d + 1); //class name + candidates.add(new CompletionCandidate(matchedClass, "" + + matchedClass + " : " + "" + + matchedClass2.substring(0, d) + "", matchedClass + + "", CompletionCandidate.PREDEF_CLASS)); // display package name in grey //log("-> " + className); } } @@ -3307,6 +3307,68 @@ public class ASTGenerator { } return null; } + + public String[] getSuggestImports(final String className){ + if(ignoredImportSuggestions == null) { + ignoredImportSuggestions = new TreeSet(); + } else { + if(ignoredImportSuggestions.contains(className)) { + log("Ignoring import suggestions for " + className); + return null; + } + } + + log("Looking for class " + className); + RegExpResourceFilter regf = new RegExpResourceFilter( + Pattern.compile(".*"), + Pattern + .compile(className + + ".class", + Pattern.CASE_INSENSITIVE)); + String[] resources = classPath + .findResources("", regf); + ArrayList candidates = new ArrayList(); + for (String res : resources) { + candidates.add(res); + } + + // log("Couldn't find import for class " + className); + + for (Library lib : editor.dmode.contribLibraries) { + ClassPath cp = factory.createFromPath(lib.getClassPath()); + resources = cp.findResources("", regf); + for (String res : resources) { + candidates.add(res); + log("Res: " + res); + } + } + + if (editor.getSketch().hasCodeFolder()) { + File codeFolder = editor.getSketch().getCodeFolder(); + // get a list of .jar files in the "code" folder + // (class files in subfolders should also be picked up) + ClassPath cp = factory.createFromPath(Base + .contentsToClassPath(codeFolder)); + resources = cp.findResources("", regf); + for (String res : resources) { + candidates.add(res); + log("Res: " + res); + } + } + + resources = new String[candidates.size()]; + for (int i = 0; i < resources.length; i++) { + resources[i] = candidates.get(i).replace('/', '.') + .substring(0, candidates.get(i).length() - 6); + } + +// ArrayList ans = new ArrayList(); +// for (int i = 0; i < resources.length; i++) { +// ans.add(resources[i]); +// } + + return resources; + } protected JFrame frmImportSuggest; private TreeSet ignoredImportSuggestions; diff --git a/pdex/src/processing/mode/experimental/ErrorCheckerService.java b/pdex/src/processing/mode/experimental/ErrorCheckerService.java index 1ab2ddae6..753f8066a 100644 --- a/pdex/src/processing/mode/experimental/ErrorCheckerService.java +++ b/pdex/src/processing/mode/experimental/ErrorCheckerService.java @@ -404,7 +404,7 @@ public class ErrorCheckerService implements Runnable{ if (args.length > 0) { String missingClass = args[0]; log("Will suggest for type:" + missingClass); - astGenerator.suggestImports(missingClass); + //astGenerator.suggestImports(missingClass); } } } @@ -1006,6 +1006,30 @@ public class ErrorCheckerService implements Runnable{ if (tempErrorLog.size() < 200) tempErrorLog.put(problemsList.get(i).getMessage(), problemsList .get(i).getIProblem()); + + if(!ExperimentalMode.importSuggestEnabled) continue; + Problem p = problemsList.get(i); + if(p.getIProblem().getID() == IProblem.UndefinedType) { + String args[] = p.getIProblem().getArguments(); + if (args.length > 0) { + String missingClass = args[0]; +// log("Will suggest for type:" + missingClass); + //astGenerator.suggestImports(missingClass); + String[] si = astGenerator.getSuggestImports(missingClass); + if(si != null && si.length > 0){ +// log("Suggested imps"); +// for (int j = 0; j < si.length; j++) { +// log(si[j]); +// } + p.setImportSuggestions(si); + errorData[i][0] = "" + + problemsList.get(i).getMessage() + + " (Import Suggestions available)"; + } + + } + } + } DefaultTableModel tm = new DefaultTableModel(errorData, diff --git a/pdex/src/processing/mode/experimental/Problem.java b/pdex/src/processing/mode/experimental/Problem.java index 6fa029188..2cae43ce7 100644 --- a/pdex/src/processing/mode/experimental/Problem.java +++ b/pdex/src/processing/mode/experimental/Problem.java @@ -22,6 +22,7 @@ package processing.mode.experimental; +import java.util.ArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -63,6 +64,11 @@ public class Problem { * The type of error - WARNING or ERROR. */ private int type; + + /** + * If the error is a 'cannot find type' contains the list of suggested imports + */ + private String[] importSuggestions; public static final int ERROR = 1, WARNING = 2; @@ -147,6 +153,14 @@ public class Problem { type = WARNING; else throw new IllegalArgumentException("Illegal Problem type passed to Problem.setType(int)"); } + + public String[] getImportSuggestions() { + return importSuggestions; + } + + public void setImportSuggestions(String[] a) { + importSuggestions = a; + } private static Pattern pattern; private static Matcher matcher; diff --git a/pdex/src/processing/mode/experimental/XQErrorTable.java b/pdex/src/processing/mode/experimental/XQErrorTable.java index b3609c897..2dd4bd2b6 100755 --- a/pdex/src/processing/mode/experimental/XQErrorTable.java +++ b/pdex/src/processing/mode/experimental/XQErrorTable.java @@ -22,15 +22,31 @@ package processing.mode.experimental; Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +import java.awt.Color; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionListener; +import java.awt.event.WindowEvent; +import java.awt.event.WindowFocusListener; +import javax.swing.BoxLayout; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JPanel; import javax.swing.JTable; +import javax.swing.ListSelectionModel; +import javax.swing.SwingConstants; import javax.swing.SwingWorker; +import javax.swing.ToolTipManager; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; import javax.swing.table.JTableHeader; import javax.swing.table.TableModel; +import javax.swing.text.BadLocationException; import processing.app.Language; +import static processing.mode.experimental.ExperimentalMode.log; /** * Custom JTable implementation for XQMode. Minor tweaks and addtions. @@ -76,7 +92,7 @@ public class XQErrorTable extends JTable { this.addMouseListener(new MouseAdapter() { @Override - synchronized public void mouseReleased(MouseEvent e) { + synchronized public void mouseClicked(MouseEvent e) { try { errorCheckerService.scrollToErrorLine(((XQErrorTable) e .getSource()).getSelectedRow()); @@ -87,7 +103,60 @@ public class XQErrorTable extends JTable { + e); } } + +// public void mouseMoved(MouseEvent evt) { +// log(evt); +//// String tip = null; +//// java.awt.Point p = evt.getPoint(); +// int rowIndex = rowAtPoint(evt.getPoint()); +// int colIndex = columnAtPoint(evt.getPoint()); +// synchronized (errorCheckerService.problemsList) { +// if (rowIndex < errorCheckerService.problemsList.size()) { +// Problem p = errorCheckerService.problemsList.get(rowIndex); +// if (p.getImportSuggestions() != null +// && p.getImportSuggestions().length > 0) { +// log("Import Suggestions available"); +// } +// } +// } +//// return super.getToolTipText(evt); +// } }); + + final XQErrorTable thisTable = this; + + this.addMouseMotionListener(new MouseMotionListener() { + + @Override + public void mouseMoved(MouseEvent evt) { +// log(evt); +// String tip = null; +// java.awt.Point p = evt.getPoint(); + int rowIndex = rowAtPoint(evt.getPoint()); + int colIndex = columnAtPoint(evt.getPoint()); + synchronized (errorCheckerService.problemsList) { + if (rowIndex < errorCheckerService.problemsList.size()) { + Problem p = errorCheckerService.problemsList.get(rowIndex); + if (p.getImportSuggestions() != null + && p.getImportSuggestions().length > 0) { + String[] list = p.getImportSuggestions(); + String className = list[0].substring(list[0].lastIndexOf('.') + 1); + String[] temp = new String[list.length]; + for (int i = 0; i < list.length; i++) { + temp[i] = "Import '" + className + "' (" + list[i] + ")"; + } + showImportSuggestion(temp, evt.getXOnScreen(), evt.getYOnScreen() - 3 * thisTable.getFont().getSize()); + } + } + + } + } + + @Override + public void mouseDragged(MouseEvent e) { + + } + }); // Handles the resizing of columns. When mouse press is detected on // table header, Stop updating the table, store new values of column @@ -111,8 +180,9 @@ public class XQErrorTable extends JTable { } } }); + + ToolTipManager.sharedInstance().registerComponent(this); } - /** * Updates table contents with new data @@ -163,5 +233,79 @@ public class XQErrorTable extends JTable { } return true; } + JFrame frmImportSuggest; + private void showImportSuggestion(String list[], int x, int y){ + if(frmImportSuggest != null) { +// frmImportSuggest.setVisible(false); +// frmImportSuggest = null; + return; + } + final JList classList = new JList(list); + classList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + frmImportSuggest = new JFrame(); + + frmImportSuggest.setUndecorated(true); + frmImportSuggest.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + JPanel panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); + panel.setBackground(Color.WHITE); + frmImportSuggest.setBackground(Color.WHITE); + panel.add(classList); + JLabel label = new JLabel("

(Click to insert)
"); + label.setBackground(Color.WHITE); + label.setHorizontalTextPosition(SwingConstants.CENTER); + panel.add(label); + panel.validate(); + frmImportSuggest.getContentPane().add(panel); + frmImportSuggest.pack(); + + final DebugEditor editor = errorCheckerService.getEditor(); + classList.addListSelectionListener(new ListSelectionListener() { + + @Override + public void valueChanged(ListSelectionEvent e) { + if (classList.getSelectedValue() != null) { + try { + String t = classList.getSelectedValue().trim(); + log(t); + int x = t.indexOf('('); + String impString = "import " + t.substring(x + 1, t.indexOf(')')) + ";\n"; + int ct = editor.getSketch().getCurrentCodeIndex(); + editor.getSketch().setCurrentCode(0); + editor.textArea().getDocument().insertString(0, impString, null); + editor.getSketch().setCurrentCode(ct); + } catch (BadLocationException ble) { + log("Failed to insert import"); + ble.printStackTrace(); + } + } + frmImportSuggest.setVisible(false); + frmImportSuggest.dispose(); + frmImportSuggest = null; + } + }); + + frmImportSuggest.addWindowFocusListener(new WindowFocusListener() { + + @Override + public void windowLostFocus(WindowEvent e) { + if (frmImportSuggest != null) { + frmImportSuggest.dispose(); + frmImportSuggest = null; + } + } + + @Override + public void windowGainedFocus(WindowEvent e) { + + } + }); + frmImportSuggest.setLocation(x, y); + frmImportSuggest.setBounds(x, y, 250, 100); + frmImportSuggest.pack(); + frmImportSuggest.setVisible(true); + + } + }