mirror of
https://github.com/processing/processing4.git
synced 2026-02-13 18:35:37 +01:00
removing extra dir
This commit is contained in:
@@ -1,23 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="lib" path="mode/com.ibm.icu_4.4.2.v20110823.jar"/>
|
||||
<classpathentry kind="lib" path="mode/CompilationChecker.jar"/>
|
||||
<classpathentry kind="lib" path="mode/jdi.jar"/>
|
||||
<classpathentry kind="lib" path="mode/jdimodel.jar"/>
|
||||
<classpathentry kind="lib" path="mode/org.eclipse.core.contenttype_3.4.200.v20120523-2004.jar"/>
|
||||
<classpathentry kind="lib" path="mode/org.eclipse.core.jobs_3.5.300.v20120622-204750.jar"/>
|
||||
<classpathentry kind="lib" path="mode/org.eclipse.core.resources_3.8.1.v20120802-154922.jar"/>
|
||||
<classpathentry kind="lib" path="mode/org.eclipse.core.runtime_3.8.0.v20120521-2346.jar"/>
|
||||
<classpathentry kind="lib" path="mode/org.eclipse.equinox.common_3.6.100.v20120522-1841.jar"/>
|
||||
<classpathentry kind="lib" path="mode/org.eclipse.equinox.preferences_3.5.0.v20120522-1841.jar"/>
|
||||
<classpathentry kind="lib" path="mode/org.eclipse.jdt.core_3.8.2.v20120814-155456.jar"/>
|
||||
<classpathentry kind="lib" path="mode/org.eclipse.jdt.debug_3.7.101.v20120725-115645.jar"/>
|
||||
<classpathentry kind="lib" path="mode/org.eclipse.osgi_3.8.1.v20120830-144521.jar"/>
|
||||
<classpathentry kind="lib" path="mode/org.eclipse.text_3.5.200.v20120523-1310.jar"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/processing-app"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/processing-core"/>
|
||||
<classpathentry kind="lib" path="/processing-app/lib/org-netbeans-swing-outline.jar"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
@@ -1,17 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<launchConfiguration type="org.eclipse.ant.AntBuilderLaunchConfigurationType">
|
||||
<stringAttribute key="org.eclipse.ant.ui.ATTR_ANT_AFTER_CLEAN_TARGETS" value="install,"/>
|
||||
<stringAttribute key="org.eclipse.ant.ui.ATTR_ANT_AUTO_TARGETS" value="install,"/>
|
||||
<stringAttribute key="org.eclipse.ant.ui.ATTR_ANT_MANUAL_TARGETS" value="install,"/>
|
||||
<booleanAttribute key="org.eclipse.ant.ui.ATTR_TARGETS_UPDATED" value="true"/>
|
||||
<booleanAttribute key="org.eclipse.ant.ui.DEFAULT_VM_INSTALL" value="false"/>
|
||||
<booleanAttribute key="org.eclipse.debug.core.capture_output" value="false"/>
|
||||
<booleanAttribute key="org.eclipse.debug.ui.ATTR_CONSOLE_OUTPUT_ON" value="false"/>
|
||||
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="org.eclipse.ant.ui.AntClasspathProvider"/>
|
||||
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="true"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="processing-experimental"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/processing-experimental/build.xml}"/>
|
||||
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/>
|
||||
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
|
||||
</launchConfiguration>
|
||||
1
pdex/experimental/.gitignore
vendored
1
pdex/experimental/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
bin
|
||||
@@ -1,27 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>processing-experimental</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
|
||||
<triggers>auto,full,incremental,</triggers>
|
||||
<arguments>
|
||||
<dictionary>
|
||||
<key>LaunchConfigHandle</key>
|
||||
<value><project>/.externalToolBuilders/Auto_Builder.launch</value>
|
||||
</dictionary>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -1,11 +0,0 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
||||
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||
org.eclipse.jdt.core.compiler.compliance=1.6
|
||||
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.source=1.6
|
||||
@@ -1,65 +0,0 @@
|
||||
TODO List for Experimental Mode Plus- GSOC 2013
|
||||
|
||||
This would also be a break down of my thought process and ideas as I tackle various tasks. Also lines are fairly long. Make sure you turn on word wrap. ;)
|
||||
|
||||
Manindra Moharana (me@mkmoharana.com)
|
||||
|
||||
* : Todo, x : Done, ? : Undecided Todo, ! : Critical, + : Minor Todo
|
||||
|
||||
Code Completion
|
||||
==============
|
||||
The big stuff:
|
||||
x! Code competition for local code is working with recursive look up.
|
||||
x! Code completion with library code, non-nested seems to be broken, fix it. Fixed.
|
||||
x Completion for external classes - ArrayList, HashMap, etc.
|
||||
*! Recursive lookup for compiled(library) code!
|
||||
*! Library CC for nested would be tricky. Need to jump from local->compiled code while searching recursively. Recursive find's current implementation is based on ASTNode return type. Afaik, no way to instantiate orphaned
|
||||
ASTNode objects(or did I miss it?). ASTNode objects have to be created only from the main ast instance. But I need to find a way to switch to compiled instances from local class instance.
|
||||
*! May be I should just implement recursive find for compiled code first, see how it goes and hopefully it would give me some ideas about how to integrating the two.
|
||||
x! Should I implement wrapper for ASTNode? - possibly needed for code completion with compiled and non-compiled code. Done.
|
||||
* Trie implementation would be lower priority, "premature optimisation is pure evil". Get all features of CC working good enough and then plan this.
|
||||
*+ Differentiating between multiple statements on the same line. How to?
|
||||
|
||||
Finer details
|
||||
* Obj a1; a1.-> completion doesn't work before it is instantiated. Look into that.
|
||||
* printStuff(int,float,String) - completion endings have to be appropriate. Right now it's just printStuff(,,). Cursor positioning also needs to be taken care of. Argument list as tooltip if possible?
|
||||
* Sorted list of completion candidates - fields, then methods. It's unsorted presently.
|
||||
*! p5 enhanced stuff in java, how does it fit in with everything else, and edge cases. Possibly add support for them.
|
||||
* Reflection API - getMethods vs getDeclaredMethods.
|
||||
* Need to add offset correction to ASTGenerator and its lookup methods. Or leave it for later?
|
||||
|
||||
Offset Mapping
|
||||
==============
|
||||
First major hurdle is offset mapping
|
||||
*! pde<->java code offset : precise conversion needed
|
||||
x for the above, I've decide to first implement a sketch outline like feature, which would highlight an AST element precisely in the pde code. This would ensure I've got the mapping working properly. And may lead to a future feature.
|
||||
* This is precise upto a certain line. Once on a line, pde stuff have to be taken into consideration.
|
||||
x Edge case - multiple statements in a single line
|
||||
x PDE specific enhancements will also have to be tackled like int(), # literals. The length of the node returned needs to be modified to make up for extra chars added like PApplet.parseFloat, etc. Also the 2nd or futher pde enhancements in the same line means even the beginning offset would need adjustment. Meh.
|
||||
* The above is almost working. There are some offset issues when multiple pde statements are in the same line, but I guess it's good enough for now to proceed ahead. Will keep a close watch for potential bugs.
|
||||
|
||||
Refactoring
|
||||
===========
|
||||
Refactoring would work only when code is compiler error free. I plan to do a find replace type op on the compile ready code.
|
||||
1. First identify the declaration of the variable in the AST. We'll then make a list of all its occurrences.
|
||||
2. DFS through the AST, for each (SimpleName)instance of the word in code, find if the matched word is the same one whose declaration we found.
|
||||
x Edge Case: For renaming a TypeDeclaration, the declaration of SimpleName instance of the TD and it's constructor(s) aren't added to the list generated by DFS. So for renaming TD, will have to manually add the TD SimpleName and it's constructors' SimpleNames to the a list of declaration nodes that can be positively matched against.
|
||||
x Renaming any constructor is equivalent to renaming the TD
|
||||
3. Find corresponding PDE offsets of the SimpleNames, rename in each line.
|
||||
x Edge Case: Need to take displaced offsets on a line, due to pde enhancements, into consideration.
|
||||
4. All the changes in code would be made in a separate copy of the code(?). After all the renaming is done, allow it only if the new code compiles. Basically an undo should be possible in case of conflicts.
|
||||
* Undo misbehaves here, handle carefully.
|
||||
* Handle saving. If sketch closed after renaming w/o saving find bugs.
|
||||
* Refactoring ui
|
||||
* Add support for word select on right click and rename, mouse co-ordinates need to obtained carefully
|
||||
|
||||
Quick Navigation
|
||||
================
|
||||
x Ctrl + Click on an element to scroll to its definition in code
|
||||
x Local Vars
|
||||
x Local Methods
|
||||
x Local Classes
|
||||
x Recursive lookup, a.b().c()
|
||||
x Now highlihgting the declaration name, rather than the whole declaration.
|
||||
*+ A silly bug where the name of the first field declaration isn't highlighted correctly. Seems to be happening if there's a javadoc or multiline comment near about the top.
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<project name="Processing PDE" default="build">
|
||||
|
||||
<target name="clean" description="Clean the build directories">
|
||||
<delete dir="bin" />
|
||||
<delete file="mode/experimental.jar" />
|
||||
</target>
|
||||
|
||||
<target name="compile" description="Compile sources">
|
||||
<condition property="core-built">
|
||||
<available file="../core/library/core.jar" />
|
||||
</condition>
|
||||
<fail unless="core-built"
|
||||
message="Please build the core library first and make sure it sits in ../core/library/core.jar" />
|
||||
|
||||
<mkdir dir="bin" />
|
||||
|
||||
<!-- ant seems to nuke ${java.home} for some reason, pointing at the JRE
|
||||
subfolder instead of the actual JDK found at JAVA_HOME.
|
||||
To avoid this, we grab the actual JAVA_HOME environment variable
|
||||
and use that to specify the location of tools.jar. -->
|
||||
<!-- if someone is better with ant please help clean this up -->
|
||||
<property environment="env" />
|
||||
<property name="java_home" value="${env.JAVA_HOME}" />
|
||||
<available file="${env.JAVA_HOME}/lib/tools.jar"
|
||||
property="java_tools_found" />
|
||||
|
||||
<condition property="linux">
|
||||
<and>
|
||||
<os family="unix" />
|
||||
<not>
|
||||
<os family="mac" />
|
||||
</not>
|
||||
</and>
|
||||
</condition>
|
||||
<fail if="linux" unless="java_tools_found"
|
||||
message="The JAVA_HOME variable must be set to the location of a full JDK. For instance, on Ubuntu Linux, this might be /usr/lib/jvm/java-6-sun." />
|
||||
|
||||
<condition property="windows">
|
||||
<os family="windows" />
|
||||
</condition>
|
||||
<fail if="windows" unless="java_tools_found"
|
||||
message="The JAVA_HOME variable must be set to the location of a full JDK. For instance, on Windows, this might be c:\jdk1.6.0_19." />
|
||||
|
||||
<javac source="1.6"
|
||||
target="1.6"
|
||||
destdir="bin"
|
||||
encoding="UTF-8"
|
||||
includeAntRuntime="false"
|
||||
classpath="../core/library/core.jar; ${env.JAVA_HOME}/lib/tools.jar; ../app/lib/ant.jar; ../app/lib/ant-launcher.jar; ../app/lib/antlr.jar; ../app/lib/apple.jar; ../app/lib/jdt-core.jar; ../app/lib/jna.jar; ../app/lib/org-netbeans-swing-outline.jar; ../app/pde.jar; mode/CompilationChecker.jar; mode/com.ibm.icu_4.4.2.v20110823.jar; mode/jdi.jar; mode/jdimodel.jar; mode/org.eclipse.core.contenttype_3.4.200.v20120523-2004.jar; mode/org.eclipse.core.jobs_3.5.300.v20120622-204750.jar; mode/org.eclipse.core.resources_3.8.1.v20120802-154922.jar; mode/org.eclipse.core.runtime_3.8.0.v20120521-2346.jar; mode/org.eclipse.equinox.common_3.6.100.v20120522-1841.jar; mode/org.eclipse.equinox.preferences_3.5.0.v20120522-1841.jar; mode/org.eclipse.jdt.core_3.8.2.v20120814-155456.jar; mode/org.eclipse.jdt.debug_3.7.101.v20120725-115645.jar; mode/org.eclipse.osgi_3.8.1.v20120830-144521.jar; mode/org.eclipse.text_3.5.200.v20120523-1310.jar;mode/classpath-explorer-1.0.jar; mode/jsoup-1.7.1.jar;"
|
||||
debug="off">
|
||||
<src path="src" />
|
||||
</javac>
|
||||
</target>
|
||||
|
||||
<target name="build" depends="compile" description="Build Experimental mode">
|
||||
<jar basedir="bin" destfile="mode/experimental.jar" />
|
||||
</target>
|
||||
|
||||
<target name="install" depends="build">
|
||||
<copy todir="../app/modes/experimental/mode">
|
||||
<fileset file="mode/experimental.jar" />
|
||||
</copy>
|
||||
</target>
|
||||
</project>
|
||||
1
pdex/experimental/mode/.gitignore
vendored
1
pdex/experimental/mode/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
experimental.jar
|
||||
@@ -1,5 +0,0 @@
|
||||
Packages from Eclipse 4.2.1:
|
||||
http://download.eclipse.org/eclipse/downloads/
|
||||
|
||||
The jdi.jar and jdimodel.jar files are unpacked
|
||||
from the org.eclipse.jdt.debug JAR file.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,425 +0,0 @@
|
||||
package processing.mode.experimental;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.TreeMap;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTNode;
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.jdt.core.dom.ExpressionStatement;
|
||||
import org.eclipse.jdt.core.dom.FieldDeclaration;
|
||||
import org.eclipse.jdt.core.dom.MethodDeclaration;
|
||||
import org.eclipse.jdt.core.dom.MethodInvocation;
|
||||
import org.eclipse.jdt.core.dom.QualifiedName;
|
||||
import org.eclipse.jdt.core.dom.SimpleName;
|
||||
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
|
||||
import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor;
|
||||
import org.eclipse.jdt.core.dom.TypeDeclaration;
|
||||
|
||||
public class ASTNodeWrapper {
|
||||
private ASTNode Node;
|
||||
|
||||
private String label;
|
||||
|
||||
private int lineNumber;
|
||||
|
||||
//private int apiLevel;
|
||||
|
||||
/*
|
||||
* TODO: Every ASTNode object in ASTGenerator.codetree is stored as a
|
||||
* ASTNodeWrapper instance. So how resource heavy would it be to store a
|
||||
* pointer to ECS in every instance of ASTNodeWrapper? Currently I will rather
|
||||
* pass an ECS pointer in the argument when I need to access a method which
|
||||
* requires a method defined in ECS, i.e, only on demand.
|
||||
* Bad design choice for ECS methods? IDK, yet.
|
||||
*/
|
||||
|
||||
public ASTNodeWrapper(ASTNode node) {
|
||||
if (node == null){
|
||||
return;
|
||||
}
|
||||
this.Node = node;
|
||||
label = getNodeAsString(node);
|
||||
if (label == null)
|
||||
label = node.toString();
|
||||
lineNumber = getLineNumber(node);
|
||||
label += " | Line " + lineNumber;
|
||||
//apiLevel = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* For this node, finds various offsets (java code).
|
||||
* Note that line start offset for this node is int[2] - int[1]
|
||||
* @return int[]{line number, line number start offset, node start offset,
|
||||
* node length}
|
||||
*/
|
||||
public int[] getJavaCodeOffsets(ErrorCheckerService ecs) {
|
||||
int nodeOffset = Node.getStartPosition(), nodeLength = Node
|
||||
.getLength();
|
||||
ASTNode thisNode = Node;
|
||||
while (thisNode.getParent() != null) {
|
||||
if (getLineNumber(thisNode.getParent()) == lineNumber) {
|
||||
thisNode = thisNode.getParent();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* There's an edge case here - multiple statements in a single line.
|
||||
* After identifying the statement with the line number, I'll have to
|
||||
* look at previous tree nodes in the same level for same line number.
|
||||
* The correct line start offset would be the line start offset of
|
||||
* the first node with this line number.
|
||||
*
|
||||
* Using linear search for now. P.S: Eclipse AST iterators are messy.
|
||||
* TODO: binary search might improve speed by 0.001%?
|
||||
*/
|
||||
|
||||
int altStartPos = thisNode.getStartPosition();
|
||||
thisNode = thisNode.getParent();
|
||||
|
||||
Iterator<StructuralPropertyDescriptor> it = thisNode
|
||||
.structuralPropertiesForType().iterator();
|
||||
boolean flag = true;
|
||||
while (it.hasNext()) {
|
||||
StructuralPropertyDescriptor prop = (StructuralPropertyDescriptor) it
|
||||
.next();
|
||||
if (prop.isChildListProperty()) {
|
||||
List<ASTNode> nodelist = (List<ASTNode>) thisNode
|
||||
.getStructuralProperty(prop);
|
||||
for (ASTNode cnode : nodelist) {
|
||||
if (getLineNumber(cnode) == lineNumber) {
|
||||
if (flag) {
|
||||
altStartPos = cnode.getStartPosition();
|
||||
// System.out.println("multi...");
|
||||
|
||||
flag = false;
|
||||
} else {
|
||||
if(cnode == Node){
|
||||
// loop only till the current node.
|
||||
break;
|
||||
}
|
||||
// We've located the first node in the line.
|
||||
// Now normalize offsets till Node
|
||||
//altStartPos += normalizeOffsets(cnode);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println("Altspos " + altStartPos);
|
||||
int pdeoffsets[] = getPDECodeOffsets(ecs);
|
||||
String pdeCode = ecs.getPDECodeAtLine(pdeoffsets[0],pdeoffsets[1] - 1).trim();
|
||||
int vals[] = createOffsetMapping(pdeCode,nodeOffset - altStartPos,nodeLength);
|
||||
if (vals != null)
|
||||
return new int[] {
|
||||
lineNumber, nodeOffset + vals[0] - altStartPos, vals[1] };
|
||||
else
|
||||
return new int[] { lineNumber, nodeOffset - altStartPos, nodeLength };
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param source
|
||||
* @param inpOffset
|
||||
* @param nodeLen
|
||||
* @return int[0] - difference in start offset, int[1] - node length
|
||||
*/
|
||||
private int[] createOffsetMapping(String source, int inpOffset, int nodeLen) {
|
||||
|
||||
int ret[][] = getOffsetMapping(source);
|
||||
if(ret == null){
|
||||
// no offset mapping needed
|
||||
return null;
|
||||
}
|
||||
int javaCodeMap[] = ret[0];
|
||||
int pdeCodeMap[] = ret[1];
|
||||
int pi = 1, pj = 1;
|
||||
pj = 0;
|
||||
pi = 0;
|
||||
int count = 1;
|
||||
// first find the java code index
|
||||
pj = inpOffset;
|
||||
|
||||
int startIndex = javaCodeMap[pj];
|
||||
|
||||
// find beginning
|
||||
while (pdeCodeMap[pi] != startIndex && pi < pdeCodeMap.length)
|
||||
pi++;
|
||||
int startoffDif = pi - pj;
|
||||
int stopindex = javaCodeMap[pj + nodeLen - 1];
|
||||
System.out.println(startIndex + "SI,St" + stopindex + "sod " + startoffDif);
|
||||
|
||||
// count till stopindex
|
||||
while (pdeCodeMap[pi] < stopindex && pi < pdeCodeMap.length) {
|
||||
pi++;
|
||||
count++;
|
||||
}
|
||||
|
||||
// System.out.println("PDE maps from " + pdeeCodeMap[pi]);
|
||||
|
||||
System.out.println("pde len " + count);
|
||||
return new int[] { startoffDif, count };
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates offset mapping between java and pde code
|
||||
*
|
||||
* @param source
|
||||
* @return int[0] - java code offsets, int[1] = pde code offsets
|
||||
*/
|
||||
public int[][] getOffsetMapping(String source){
|
||||
|
||||
/*
|
||||
* This is some tricky shiz. So detailed explanation follows:
|
||||
*
|
||||
* The main issue here is that pde enhancements like color vars, # literals
|
||||
* and int() type casting deviate from standard java. But I need to exact
|
||||
* index matching for pde and java versions of snippets.For ex:
|
||||
* "color col = #ffaadd;" <-PDE version
|
||||
* "int col = 0xffffaadd;" <-Converted to Java
|
||||
*
|
||||
* For exact index mapping, I need to know at which indices either is
|
||||
* deviating from the other and by what amount. Turns out, it isn't quite
|
||||
* easy.(1) First I take the pde version of the code as an argument(pde
|
||||
* version fetched from the editor directly). I then find all instances
|
||||
* which need to be converted to pure java, marking those indices and the
|
||||
* index correction needed. (2) Now all java conversions are applied after
|
||||
* marking the offsets. This ensures that the index order isn't disturbed by
|
||||
* one at a time conversions as done in preprocessCode() in ECS. Took me
|
||||
* sometime to figure out this was a bug. (3) Next I create a tables(two
|
||||
* separate arrays) which allows me to look it up for matching any index
|
||||
* between pde or java version of the snippet. This also lets me find out
|
||||
* any difference in length between both versions.
|
||||
*
|
||||
* Keep in mind though, dark magic was involved in creating the final lookup
|
||||
* table.
|
||||
*
|
||||
* TODO: This is a work in progress. There may be more bugs here in hiding.
|
||||
*/
|
||||
|
||||
System.out.println("Src:" + source);
|
||||
String sourceAlt = new String(source);
|
||||
TreeMap<Integer, Integer> offsetmap = new TreeMap<Integer, Integer>();
|
||||
|
||||
// Find all #[web color]
|
||||
// Should be 6 digits only.
|
||||
final String webColorRegexp = "#{1}[A-F|a-f|0-9]{6}\\W";
|
||||
Pattern webPattern = Pattern.compile(webColorRegexp);
|
||||
Matcher webMatcher = webPattern.matcher(sourceAlt);
|
||||
while (webMatcher.find()) {
|
||||
// System.out.println("Found at: " + webMatcher.start());
|
||||
// System.out.println("-> " + found);
|
||||
offsetmap.put(webMatcher.end() - 1, 3);
|
||||
}
|
||||
|
||||
// Find all color data types
|
||||
final String colorTypeRegex = "color(?![a-zA-Z0-9_])(?=\\[*)(?!(\\s*\\())";
|
||||
Pattern colorPattern = Pattern.compile(colorTypeRegex);
|
||||
Matcher colorMatcher = colorPattern.matcher(sourceAlt);
|
||||
while (colorMatcher.find()) {
|
||||
// System.out.print("Start index: " + colorMatcher.start());
|
||||
// System.out.println(" End index: " + colorMatcher.end() + " ");
|
||||
// System.out.println("-->" + colorMatcher.group() + "<--");
|
||||
offsetmap.put(colorMatcher.end() - 1, -2);
|
||||
}
|
||||
|
||||
// Find all int(), char()
|
||||
String dataTypeFunc[] = { "int", "char", "float", "boolean", "byte" };
|
||||
|
||||
for (String dataType : dataTypeFunc) {
|
||||
String dataTypeRegexp = "\\b" + dataType + "\\s*\\(";
|
||||
Pattern pattern = Pattern.compile(dataTypeRegexp);
|
||||
Matcher matcher = pattern.matcher(sourceAlt);
|
||||
|
||||
while (matcher.find()) {
|
||||
// System.out.print("Start index: " + matcher.start());
|
||||
// System.out.println(" End index: " + matcher.end() + " ");
|
||||
// System.out.println("-->" + matcher.group() + "<--");
|
||||
offsetmap.put(matcher.end() - 1, ("PApplet.parse").length());
|
||||
}
|
||||
matcher.reset();
|
||||
sourceAlt = matcher.replaceAll("PApplet.parse"
|
||||
+ Character.toUpperCase(dataType.charAt(0)) + dataType.substring(1)
|
||||
+ "(");
|
||||
|
||||
}
|
||||
if(offsetmap.isEmpty()){
|
||||
System.out.println("No offset matching needed.");
|
||||
return null;
|
||||
}
|
||||
// replace with 0xff[webcolor] and others
|
||||
webMatcher = webPattern.matcher(sourceAlt);
|
||||
while (webMatcher.find()) {
|
||||
// System.out.println("Found at: " + webMatcher.start());
|
||||
String found = sourceAlt.substring(webMatcher.start(), webMatcher.end());
|
||||
// System.out.println("-> " + found);
|
||||
sourceAlt = webMatcher.replaceFirst("0xff" + found.substring(1));
|
||||
webMatcher = webPattern.matcher(sourceAlt);
|
||||
}
|
||||
|
||||
colorMatcher = colorPattern.matcher(sourceAlt);
|
||||
sourceAlt = colorMatcher.replaceAll("int");
|
||||
|
||||
System.out.println(sourceAlt);
|
||||
|
||||
// Create code map. Beware! Dark magic ahead.
|
||||
int javaCodeMap[] = new int[source.length() * 2];
|
||||
int pdeCodeMap[] = new int[source.length() * 2];
|
||||
int pi = 1, pj = 1;
|
||||
int keySum = 0;
|
||||
for (Integer key : offsetmap.keySet()) {
|
||||
for (; pi < key +keySum; pi++) {
|
||||
javaCodeMap[pi] = javaCodeMap[pi - 1] + 1;
|
||||
}
|
||||
for (; pj < key; pj++) {
|
||||
pdeCodeMap[pj] = pdeCodeMap[pj - 1] + 1;
|
||||
}
|
||||
|
||||
System.out.println(key + ":" + offsetmap.get(key));
|
||||
|
||||
int kval = offsetmap.get(key);
|
||||
if (kval > 0) {
|
||||
// repeat java offsets
|
||||
pi--;
|
||||
pj--;
|
||||
for (int i = 0; i < kval; i++, pi++, pj++) {
|
||||
javaCodeMap[pi] = javaCodeMap[pi - 1];
|
||||
pdeCodeMap[pj] = pdeCodeMap[pj - 1] + 1;
|
||||
}
|
||||
} else {
|
||||
// repeat pde offsets
|
||||
pi--;
|
||||
pj--;
|
||||
for (int i = 0; i < -kval; i++, pi++, pj++) {
|
||||
javaCodeMap[pi] = javaCodeMap[pi - 1] + 1;
|
||||
pdeCodeMap[pj] = pdeCodeMap[pj - 1];
|
||||
}
|
||||
}
|
||||
|
||||
// after each adjustment, the key values need to keep
|
||||
// up with changed offset
|
||||
keySum += kval;
|
||||
}
|
||||
|
||||
javaCodeMap[pi] = javaCodeMap[pi - 1] + 1;
|
||||
pdeCodeMap[pj] = pdeCodeMap[pj - 1] + 1;
|
||||
|
||||
while (pi < sourceAlt.length()) {
|
||||
javaCodeMap[pi] = javaCodeMap[pi - 1] + 1;
|
||||
pi++;
|
||||
}
|
||||
while (pj < source.length()) {
|
||||
pdeCodeMap[pj] = pdeCodeMap[pj - 1] + 1;
|
||||
pj++;
|
||||
}
|
||||
|
||||
// deubg o/p
|
||||
for (int i = 0; i < pdeCodeMap.length; i++) {
|
||||
if (pdeCodeMap[i] > 0 || javaCodeMap[i] > 0 || i == 0) {
|
||||
if (i < source.length())
|
||||
System.out.print(source.charAt(i));
|
||||
System.out.print(pdeCodeMap[i] + " - " + javaCodeMap[i]);
|
||||
if (i < sourceAlt.length())
|
||||
System.out.print(sourceAlt.charAt(i));
|
||||
System.out.print(" <-[" + i + "]");
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
System.out.println();
|
||||
|
||||
return new int[][]{javaCodeMap,pdeCodeMap};
|
||||
}
|
||||
|
||||
public int[][] getOffsetMapping(ErrorCheckerService ecs){
|
||||
int pdeoffsets[] = getPDECodeOffsets(ecs);
|
||||
String pdeCode = ecs.getPDECodeAtLine(pdeoffsets[0],pdeoffsets[1] - 1).trim();
|
||||
return getOffsetMapping(pdeCode);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param ecs
|
||||
* - ErrorCheckerService instance
|
||||
* @return int[0] - tab number, int[1] - line number in the int[0] tab, int[2]
|
||||
* - line start offset, int[3] - offset from line start int[2] and
|
||||
* int[3] are on TODO
|
||||
*/
|
||||
public int[] getPDECodeOffsets(ErrorCheckerService ecs) {
|
||||
return ecs.JavaToPdeOffsets(lineNumber + 1, Node.getStartPosition());
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public ASTNode getNode() {
|
||||
return Node;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public int getNodeType() {
|
||||
return Node.getNodeType();
|
||||
}
|
||||
|
||||
public int getLineNumber() {
|
||||
return lineNumber;
|
||||
}
|
||||
|
||||
private static int getLineNumber(ASTNode node) {
|
||||
return ((CompilationUnit) node.getRoot()).getLineNumber(node
|
||||
.getStartPosition());
|
||||
}
|
||||
|
||||
static private String getNodeAsString(ASTNode node) {
|
||||
if (node == null)
|
||||
return "NULL";
|
||||
String className = node.getClass().getName();
|
||||
int index = className.lastIndexOf(".");
|
||||
if (index > 0)
|
||||
className = className.substring(index + 1);
|
||||
|
||||
// if(node instanceof BodyDeclaration)
|
||||
// return className;
|
||||
|
||||
String value = className;
|
||||
|
||||
if (node instanceof TypeDeclaration)
|
||||
value = ((TypeDeclaration) node).getName().toString() + " | " + className;
|
||||
else if (node instanceof MethodDeclaration)
|
||||
value = ((MethodDeclaration) node).getName().toString() + " | "
|
||||
+ className;
|
||||
else if (node instanceof MethodInvocation)
|
||||
value = ((MethodInvocation) node).getName().toString() + " | "
|
||||
+ className;
|
||||
else if (node instanceof FieldDeclaration)
|
||||
value = ((FieldDeclaration) node).toString() + " FldDecl| ";
|
||||
else if (node instanceof SingleVariableDeclaration)
|
||||
value = ((SingleVariableDeclaration) node).getName() + " - "
|
||||
+ ((SingleVariableDeclaration) node).getType() + " | SVD ";
|
||||
else if (node instanceof ExpressionStatement)
|
||||
value = node.toString() + className;
|
||||
else if (node instanceof SimpleName)
|
||||
value = ((SimpleName) node).getFullyQualifiedName() + " | " + className;
|
||||
else if (node instanceof QualifiedName)
|
||||
value = node.toString() + " | " + className;
|
||||
else if (className.startsWith("Variable"))
|
||||
value = node.toString() + " | " + className;
|
||||
else if (className.endsWith("Type"))
|
||||
value = node.toString() + " |" + className;
|
||||
value += " [" + node.getStartPosition() + ","
|
||||
+ (node.getStartPosition() + node.getLength()) + "]";
|
||||
value += " Line: "
|
||||
+ ((CompilationUnit) node.getRoot()).getLineNumber(node
|
||||
.getStartPosition());
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Martin Leopold <m@martinleopold.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
package processing.mode.experimental;
|
||||
|
||||
import com.sun.jdi.ArrayReference;
|
||||
import com.sun.jdi.ClassNotLoadedException;
|
||||
import com.sun.jdi.InvalidTypeException;
|
||||
import com.sun.jdi.Value;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Specialized {@link VariableNode} for representing single fields in an array.
|
||||
* Overrides {@link #setValue} to properly change the value of the encapsulated
|
||||
* array field.
|
||||
*
|
||||
* @author Martin Leopold <m@martinleopold.com>
|
||||
*/
|
||||
public class ArrayFieldNode extends VariableNode {
|
||||
|
||||
protected ArrayReference array;
|
||||
protected int index;
|
||||
|
||||
/**
|
||||
* Construct an {@link ArrayFieldNode}.
|
||||
*
|
||||
* @param name the name
|
||||
* @param type the type
|
||||
* @param value the value
|
||||
* @param array a reference to the array
|
||||
* @param index the index inside the array
|
||||
*/
|
||||
public ArrayFieldNode(String name, String type, Value value, ArrayReference array, int index) {
|
||||
super(name, type, value);
|
||||
this.array = array;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(Value value) {
|
||||
try {
|
||||
array.setValue(index, value);
|
||||
} catch (InvalidTypeException ex) {
|
||||
Logger.getLogger(ArrayFieldNode.class.getName()).log(Level.SEVERE, null, ex);
|
||||
} catch (ClassNotLoadedException ex) {
|
||||
Logger.getLogger(ArrayFieldNode.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Martin Leopold <m@martinleopold.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
package processing.mode.experimental;
|
||||
|
||||
import com.sun.jdi.ReferenceType;
|
||||
|
||||
/**
|
||||
* Listener to be notified when a class is loaded in the debugger. Used by
|
||||
* {@link LineBreakpoint}s to activate themselves as soon as the respective
|
||||
* class is loaded.
|
||||
*
|
||||
* @author Martin Leopold <m@martinleopold.com>
|
||||
*/
|
||||
public interface ClassLoadListener {
|
||||
|
||||
/**
|
||||
* Event handler called when a class is loaded.
|
||||
*
|
||||
* @param theClass the class
|
||||
*/
|
||||
public void classLoaded(ReferenceType theClass);
|
||||
}
|
||||
@@ -1,367 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Martin Leopold <m@martinleopold.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
package processing.mode.experimental;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Method;
|
||||
import processing.app.Base;
|
||||
import processing.app.SketchException;
|
||||
import processing.core.PApplet;
|
||||
|
||||
/**
|
||||
* Copied from processing.mode.java.Compiler, just added -g switch to generate
|
||||
* debugging info.
|
||||
*
|
||||
* @author Martin Leopold <m@martinleopold.com>
|
||||
*/
|
||||
public class Compiler extends processing.mode.java.Compiler {
|
||||
/**
|
||||
* Compile with ECJ. See http://j.mp/8paifz for documentation.
|
||||
*
|
||||
* @return true if successful.
|
||||
* @throws RunnerException Only if there's a problem. Only then.
|
||||
*/
|
||||
// public boolean compile(Sketch sketch,
|
||||
// File srcFolder,
|
||||
// File binFolder,
|
||||
// String primaryClassName,
|
||||
// String sketchClassPath,
|
||||
// String bootClassPath) throws RunnerException {
|
||||
static public boolean compile(DebugBuild build) throws SketchException {
|
||||
|
||||
// This will be filled in if anyone gets angry
|
||||
SketchException exception = null;
|
||||
boolean success = false;
|
||||
|
||||
String baseCommand[] = new String[] {
|
||||
"-g",
|
||||
"-Xemacs",
|
||||
//"-noExit", // not necessary for ecj
|
||||
"-source", "1.6",
|
||||
"-target", "1.6",
|
||||
"-classpath", build.getClassPath(),
|
||||
"-nowarn", // we're not currently interested in warnings (works in ecj)
|
||||
"-d", build.getBinFolder().getAbsolutePath() // output the classes in the buildPath
|
||||
};
|
||||
//PApplet.println(baseCommand);
|
||||
|
||||
// make list of code files that need to be compiled
|
||||
// String[] sourceFiles = new String[sketch.getCodeCount()];
|
||||
// int sourceCount = 0;
|
||||
// sourceFiles[sourceCount++] =
|
||||
// new File(buildPath, primaryClassName + ".java").getAbsolutePath();
|
||||
//
|
||||
// for (SketchCode code : sketch.getCode()) {
|
||||
// if (code.isExtension("java")) {
|
||||
// String path = new File(buildPath, code.getFileName()).getAbsolutePath();
|
||||
// sourceFiles[sourceCount++] = path;
|
||||
// }
|
||||
// }
|
||||
String[] sourceFiles = Base.listFiles(build.getSrcFolder(), false, ".java");
|
||||
|
||||
// String[] command = new String[baseCommand.length + sourceFiles.length];
|
||||
// System.arraycopy(baseCommand, 0, command, 0, baseCommand.length);
|
||||
// // append each of the files to the command string
|
||||
// System.arraycopy(sourceFiles, 0, command, baseCommand.length, sourceCount);
|
||||
String[] command = PApplet.concat(baseCommand, sourceFiles);
|
||||
|
||||
//PApplet.println(command);
|
||||
|
||||
try {
|
||||
// Load errors into a local StringBuffer
|
||||
final StringBuffer errorBuffer = new StringBuffer();
|
||||
|
||||
// Create single method dummy writer class to slurp errors from ecj
|
||||
Writer internalWriter = new Writer() {
|
||||
public void write(char[] buf, int off, int len) {
|
||||
errorBuffer.append(buf, off, len);
|
||||
}
|
||||
|
||||
public void flush() { }
|
||||
|
||||
public void close() { }
|
||||
};
|
||||
// Wrap as a PrintWriter since that's what compile() wants
|
||||
PrintWriter writer = new PrintWriter(internalWriter);
|
||||
|
||||
//result = com.sun.tools.javac.Main.compile(command, writer);
|
||||
|
||||
PrintWriter outWriter = new PrintWriter(System.out);
|
||||
|
||||
// Version that's not dynamically loaded
|
||||
//CompilationProgress progress = null;
|
||||
//success = BatchCompiler.compile(command, outWriter, writer, progress);
|
||||
|
||||
// Version that *is* dynamically loaded. First gets the mode class loader
|
||||
// so that it can grab the compiler JAR files from it.
|
||||
ClassLoader loader = build.getMode().getJavaModeClassLoader();
|
||||
//ClassLoader loader = build.getMode().getClassLoader();
|
||||
try {
|
||||
Class batchClass =
|
||||
Class.forName("org.eclipse.jdt.core.compiler.batch.BatchCompiler", false, loader);
|
||||
Class progressClass =
|
||||
Class.forName("org.eclipse.jdt.core.compiler.CompilationProgress", false, loader);
|
||||
Class[] compileArgs =
|
||||
new Class[] { String[].class, PrintWriter.class, PrintWriter.class, progressClass };
|
||||
Method compileMethod = batchClass.getMethod("compile", compileArgs);
|
||||
success = (Boolean)
|
||||
compileMethod.invoke(null, new Object[] { command, outWriter, writer, null });
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new SketchException("Unknown error inside the compiler.");
|
||||
}
|
||||
|
||||
// Close out the stream for good measure
|
||||
writer.flush();
|
||||
writer.close();
|
||||
|
||||
BufferedReader reader =
|
||||
new BufferedReader(new StringReader(errorBuffer.toString()));
|
||||
//System.err.println(errorBuffer.toString());
|
||||
|
||||
String line = null;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
//System.out.println("got line " + line); // debug
|
||||
|
||||
// get first line, which contains file name, line number,
|
||||
// and at least the first line of the error message
|
||||
String errorFormat = "([\\w\\d_]+.java):(\\d+):\\s*(.*):\\s*(.*)\\s*";
|
||||
String[] pieces = PApplet.match(line, errorFormat);
|
||||
//PApplet.println(pieces);
|
||||
|
||||
// if it's something unexpected, die and print the mess to the console
|
||||
if (pieces == null) {
|
||||
exception = new SketchException("Cannot parse error text: " + line);
|
||||
exception.hideStackTrace();
|
||||
// Send out the rest of the error message to the console.
|
||||
System.err.println(line);
|
||||
while ((line = reader.readLine()) != null) {
|
||||
System.err.println(line);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// translate the java filename and line number into a un-preprocessed
|
||||
// location inside a source file or tab in the environment.
|
||||
String dotJavaFilename = pieces[1];
|
||||
// Line numbers are 1-indexed from javac
|
||||
int dotJavaLineIndex = PApplet.parseInt(pieces[2]) - 1;
|
||||
String errorMessage = pieces[4];
|
||||
|
||||
exception = build.placeException(errorMessage,
|
||||
dotJavaFilename,
|
||||
dotJavaLineIndex);
|
||||
/*
|
||||
int codeIndex = 0; //-1;
|
||||
int codeLine = -1;
|
||||
|
||||
// first check to see if it's a .java file
|
||||
for (int i = 0; i < sketch.getCodeCount(); i++) {
|
||||
SketchCode code = sketch.getCode(i);
|
||||
if (code.isExtension("java")) {
|
||||
if (dotJavaFilename.equals(code.getFileName())) {
|
||||
codeIndex = i;
|
||||
codeLine = dotJavaLineIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if it's not a .java file, codeIndex will still be 0
|
||||
if (codeIndex == 0) { // main class, figure out which tab
|
||||
//for (int i = 1; i < sketch.getCodeCount(); i++) {
|
||||
for (int i = 0; i < sketch.getCodeCount(); i++) {
|
||||
SketchCode code = sketch.getCode(i);
|
||||
|
||||
if (code.isExtension("pde")) {
|
||||
if (code.getPreprocOffset() <= dotJavaLineIndex) {
|
||||
codeIndex = i;
|
||||
//System.out.println("i'm thinkin file " + i);
|
||||
codeLine = dotJavaLineIndex - code.getPreprocOffset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//System.out.println("code line now " + codeLine);
|
||||
exception = new RunnerException(errorMessage, codeIndex, codeLine, -1, false);
|
||||
*/
|
||||
|
||||
if (exception == null) {
|
||||
exception = new SketchException(errorMessage);
|
||||
}
|
||||
|
||||
// for a test case once message parsing is implemented,
|
||||
// use new Font(...) since that wasn't getting picked up properly.
|
||||
|
||||
/*
|
||||
if (errorMessage.equals("cannot find symbol")) {
|
||||
handleCannotFindSymbol(reader, exception);
|
||||
|
||||
} else if (errorMessage.indexOf("is already defined") != -1) {
|
||||
reader.readLine(); // repeats the line of code w/ error
|
||||
int codeColumn = caretColumn(reader.readLine());
|
||||
exception = new RunnerException(errorMessage,
|
||||
codeIndex, codeLine, codeColumn);
|
||||
|
||||
} else if (errorMessage.startsWith("package") &&
|
||||
errorMessage.endsWith("does not exist")) {
|
||||
// Because imports are stripped out and re-added to the 0th line of
|
||||
// the preprocessed code, codeLine will always be wrong for imports.
|
||||
exception = new RunnerException("P" + errorMessage.substring(1) +
|
||||
". You might be missing a library.");
|
||||
} else {
|
||||
exception = new RunnerException(errorMessage);
|
||||
}
|
||||
*/
|
||||
if (errorMessage.startsWith("The import ") &&
|
||||
errorMessage.endsWith("cannot be resolved")) {
|
||||
// The import poo cannot be resolved
|
||||
//import poo.shoe.blah.*;
|
||||
//String what = errorMessage.substring("The import ".length());
|
||||
String[] m = PApplet.match(errorMessage, "The import (.*) cannot be resolved");
|
||||
//what = what.substring(0, what.indexOf(' '));
|
||||
if (m != null) {
|
||||
// System.out.println("'" + m[1] + "'");
|
||||
if (m[1].equals("processing.xml")) {
|
||||
exception.setMessage("processing.xml no longer exists, this code needs to be updated for 2.0.");
|
||||
System.err.println("The processing.xml library has been replaced " +
|
||||
"with a new 'XML' class that's built-in.");
|
||||
handleCrustyCode();
|
||||
|
||||
} else {
|
||||
exception.setMessage("The package " +
|
||||
"\u201C" + m[1] + "\u201D" +
|
||||
" does not exist. " +
|
||||
"You might be missing a library.");
|
||||
System.err.println("Libraries must be " +
|
||||
"installed in a folder named 'libraries' " +
|
||||
"inside the 'sketchbook' folder.");
|
||||
}
|
||||
}
|
||||
|
||||
// // Actually create the folder and open it for the user
|
||||
// File sketchbookLibraries = Base.getSketchbookLibrariesFolder();
|
||||
// if (!sketchbookLibraries.exists()) {
|
||||
// if (sketchbookLibraries.mkdirs()) {
|
||||
// Base.openFolder(sketchbookLibraries);
|
||||
// }
|
||||
// }
|
||||
|
||||
} else if (errorMessage.endsWith("cannot be resolved to a type")) {
|
||||
// xxx cannot be resolved to a type
|
||||
//xxx c;
|
||||
|
||||
String what = errorMessage.substring(0, errorMessage.indexOf(' '));
|
||||
|
||||
if (what.equals("BFont") ||
|
||||
what.equals("BGraphics") ||
|
||||
what.equals("BImage")) {
|
||||
exception.setMessage(what + " has been replaced with P" + what.substring(1));
|
||||
handleCrustyCode();
|
||||
|
||||
} else {
|
||||
exception.setMessage("Cannot find a class or type " +
|
||||
"named \u201C" + what + "\u201D");
|
||||
}
|
||||
|
||||
} else if (errorMessage.endsWith("cannot be resolved")) {
|
||||
// xxx cannot be resolved
|
||||
//println(xxx);
|
||||
|
||||
String what = errorMessage.substring(0, errorMessage.indexOf(' '));
|
||||
|
||||
if (what.equals("LINE_LOOP") ||
|
||||
what.equals("LINE_STRIP")) {
|
||||
exception.setMessage("LINE_LOOP and LINE_STRIP are not available, " +
|
||||
"please update your code.");
|
||||
handleCrustyCode();
|
||||
|
||||
} else if (what.equals("framerate")) {
|
||||
exception.setMessage("framerate should be changed to frameRate.");
|
||||
handleCrustyCode();
|
||||
|
||||
} else if (what.equals("screen")) {
|
||||
exception.setMessage("Change screen.width and screen.height to " +
|
||||
"displayWidth and displayHeight.");
|
||||
handleCrustyCode();
|
||||
|
||||
} else if (what.equals("screenWidth") ||
|
||||
what.equals("screenHeight")) {
|
||||
exception.setMessage("Change screenWidth and screenHeight to " +
|
||||
"displayWidth and displayHeight.");
|
||||
handleCrustyCode();
|
||||
|
||||
} else {
|
||||
exception.setMessage("Cannot find anything " +
|
||||
"named \u201C" + what + "\u201D");
|
||||
}
|
||||
|
||||
} else if (errorMessage.startsWith("Duplicate")) {
|
||||
// "Duplicate nested type xxx"
|
||||
// "Duplicate local variable xxx"
|
||||
|
||||
} else {
|
||||
String[] parts = null;
|
||||
|
||||
// The method xxx(String) is undefined for the type Temporary_XXXX_XXXX
|
||||
//xxx("blah");
|
||||
// The method xxx(String, int) is undefined for the type Temporary_XXXX_XXXX
|
||||
//xxx("blah", 34);
|
||||
// The method xxx(String, int) is undefined for the type PApplet
|
||||
//PApplet.sub("ding");
|
||||
String undefined =
|
||||
"The method (\\S+\\(.*\\)) is undefined for the type (.*)";
|
||||
parts = PApplet.match(errorMessage, undefined);
|
||||
if (parts != null) {
|
||||
if (parts[1].equals("framerate(int)")) {
|
||||
exception.setMessage("framerate() no longer exists, use frameRate() instead.");
|
||||
handleCrustyCode();
|
||||
|
||||
} else if (parts[1].equals("push()")) {
|
||||
exception.setMessage("push() no longer exists, use pushMatrix() instead.");
|
||||
handleCrustyCode();
|
||||
|
||||
} else if (parts[1].equals("pop()")) {
|
||||
exception.setMessage("pop() no longer exists, use popMatrix() instead.");
|
||||
handleCrustyCode();
|
||||
|
||||
} else {
|
||||
String mess = "The function " + parts[1] + " does not exist.";
|
||||
exception.setMessage(mess);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (exception != null) {
|
||||
// The stack trace just shows that this happened inside the compiler,
|
||||
// which is a red herring. Don't ever show it for compiler stuff.
|
||||
exception.hideStackTrace();
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
String bigSigh = "Error while compiling. (" + e.getMessage() + ")";
|
||||
exception = new SketchException(bigSigh);
|
||||
e.printStackTrace();
|
||||
success = false;
|
||||
}
|
||||
// In case there was something else.
|
||||
if (exception != null) throw exception;
|
||||
|
||||
return success;
|
||||
}
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
package processing.mode.experimental;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTNode;
|
||||
import org.eclipse.jdt.core.dom.MethodDeclaration;
|
||||
|
||||
public class CompletionCandidate implements Comparable<CompletionCandidate>{
|
||||
|
||||
private String definingClass;
|
||||
|
||||
private String elementName; //
|
||||
|
||||
private String label; // the toString value
|
||||
|
||||
private String completionString;
|
||||
|
||||
private int type;
|
||||
|
||||
public static final int METHOD = 0, FIELD = 1, LOCAL_VAR = 3;
|
||||
|
||||
public CompletionCandidate(String name, String className, String label,
|
||||
int TYPE) {
|
||||
definingClass = className;
|
||||
elementName = name;
|
||||
if (label.length() > 0)
|
||||
this.label = label;
|
||||
else
|
||||
this.label = name;
|
||||
this.type = TYPE;
|
||||
if (type == METHOD) {
|
||||
this.label += "()";
|
||||
}
|
||||
completionString = this.label;
|
||||
}
|
||||
|
||||
public CompletionCandidate(Method method) {
|
||||
definingClass = method.getDeclaringClass().getName();
|
||||
elementName = method.getName();
|
||||
type = METHOD;
|
||||
StringBuffer label = new StringBuffer(method.getName() + "(");
|
||||
StringBuffer cstr = new StringBuffer(method.getName() + "(");
|
||||
for (int i = 0; i < method.getParameterTypes().length; i++) {
|
||||
label.append(method.getParameterTypes()[i].getSimpleName());
|
||||
if (i < method.getParameterTypes().length - 1) {
|
||||
label.append(",");
|
||||
cstr.append(",");
|
||||
}
|
||||
}
|
||||
|
||||
label.append(")");
|
||||
cstr.append(")");
|
||||
this.label = label.toString();
|
||||
this.completionString = cstr.toString();
|
||||
}
|
||||
|
||||
public CompletionCandidate(MethodDeclaration method) {
|
||||
definingClass = "";
|
||||
elementName = method.getName().toString();
|
||||
type = METHOD;
|
||||
List<ASTNode> params = (List<ASTNode>) method
|
||||
.getStructuralProperty(MethodDeclaration.PARAMETERS_PROPERTY);
|
||||
StringBuffer label = new StringBuffer(elementName + "(");
|
||||
StringBuffer cstr = new StringBuffer(method.getName() + "(");
|
||||
for (int i = 0; i < params.size(); i++) {
|
||||
label.append(params.get(i).toString());
|
||||
if (i < params.size() - 1){
|
||||
label.append(",");
|
||||
cstr.append(",");
|
||||
}
|
||||
}
|
||||
label.append(")");
|
||||
cstr.append(")");
|
||||
this.label = label.toString();
|
||||
this.completionString = cstr.toString();
|
||||
}
|
||||
|
||||
public CompletionCandidate(Field f) {
|
||||
definingClass = f.getDeclaringClass().getName();
|
||||
elementName = f.getName();
|
||||
type = FIELD;
|
||||
label = f.getName();
|
||||
completionString = elementName;
|
||||
}
|
||||
|
||||
public CompletionCandidate(String name, String className) {
|
||||
definingClass = className;
|
||||
elementName = name;
|
||||
label = name;
|
||||
completionString = name;
|
||||
}
|
||||
|
||||
public CompletionCandidate(String name) {
|
||||
definingClass = "";
|
||||
elementName = name;
|
||||
label = name;
|
||||
completionString = name;
|
||||
}
|
||||
|
||||
public String getDefiningClass() {
|
||||
return definingClass;
|
||||
}
|
||||
|
||||
public String getElementName() {
|
||||
return elementName;
|
||||
}
|
||||
|
||||
public String getCompletionString() {
|
||||
return completionString;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public int compareTo(CompletionCandidate cc) {
|
||||
if(type != cc.getType()){
|
||||
return cc.getType() - type;
|
||||
}
|
||||
|
||||
return (elementName.compareTo(cc.getElementName()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
package processing.mode.experimental;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Point;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.ListSelectionModel;
|
||||
import javax.swing.text.BadLocationException;
|
||||
|
||||
import processing.app.syntax.JEditTextArea;
|
||||
|
||||
public class CompletionPanel {
|
||||
private JList list;
|
||||
|
||||
private JPopupMenu popupMenu;
|
||||
|
||||
private String subWord;
|
||||
|
||||
private final int insertionPosition;
|
||||
|
||||
private TextArea textarea;
|
||||
|
||||
private JScrollPane scrollPane;
|
||||
|
||||
public CompletionPanel(JEditTextArea textarea, int position, String subWord,
|
||||
CompletionCandidate[] items, Point location) {
|
||||
this.textarea = (TextArea) textarea;
|
||||
this.insertionPosition = position;
|
||||
if (subWord.indexOf('.') != -1)
|
||||
this.subWord = subWord.substring(subWord.lastIndexOf('.') + 1);
|
||||
else
|
||||
this.subWord = subWord;
|
||||
popupMenu = new JPopupMenu();
|
||||
popupMenu.removeAll();
|
||||
popupMenu.setOpaque(false);
|
||||
popupMenu.setBorder(null);
|
||||
scrollPane = new JScrollPane();
|
||||
scrollPane.setViewportView(list = createSuggestionList(position, items));
|
||||
popupMenu.add(scrollPane, BorderLayout.CENTER);
|
||||
this.textarea.errorCheckerService.astGenerator
|
||||
.updateJavaDoc((CompletionCandidate) list.getSelectedValue());
|
||||
popupMenu.show(textarea, location.x, textarea.getBaseline(0, 0)
|
||||
+ location.y);
|
||||
|
||||
}
|
||||
|
||||
public void hide() {
|
||||
popupMenu.setVisible(false);
|
||||
}
|
||||
|
||||
public boolean isVisible() {
|
||||
return popupMenu.isVisible();
|
||||
}
|
||||
|
||||
public JList createSuggestionList(final int position,
|
||||
final CompletionCandidate[] items) {
|
||||
|
||||
JList list = new JList(items);
|
||||
list.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY, 1));
|
||||
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
list.setSelectedIndex(0);
|
||||
list.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (e.getClickCount() == 2) {
|
||||
insertSelection();
|
||||
hideSuggestion();
|
||||
}
|
||||
}
|
||||
});
|
||||
return list;
|
||||
}
|
||||
|
||||
public boolean insertSelection() {
|
||||
if (list.getSelectedValue() != null) {
|
||||
try {
|
||||
final String selectedSuggestion = ((CompletionCandidate) list
|
||||
.getSelectedValue()).getCompletionString().substring(subWord.length());
|
||||
textarea.getDocument().insertString(insertionPosition,
|
||||
selectedSuggestion, null);
|
||||
textarea.setCaretPosition(insertionPosition
|
||||
+ selectedSuggestion.length());
|
||||
return true;
|
||||
} catch (BadLocationException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
hideSuggestion();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void hideSuggestion() {
|
||||
hide();
|
||||
//textarea.errorCheckerService.astGenerator.jdocWindowVisible(false);
|
||||
}
|
||||
|
||||
public void moveUp() {
|
||||
if (list.getSelectedIndex() == 0) {
|
||||
scrollPane.getVerticalScrollBar().setValue(scrollPane.getVerticalScrollBar().getMaximum());
|
||||
selectIndex(list.getModel().getSize() - 1);
|
||||
return;
|
||||
} else {
|
||||
int index = Math.max(list.getSelectedIndex() - 1, 0);
|
||||
selectIndex(index);
|
||||
}
|
||||
int step = scrollPane.getVerticalScrollBar().getMaximum()
|
||||
/ list.getModel().getSize();
|
||||
scrollPane.getVerticalScrollBar().setValue(scrollPane
|
||||
.getVerticalScrollBar()
|
||||
.getValue()
|
||||
- step);
|
||||
textarea.errorCheckerService.astGenerator
|
||||
.updateJavaDoc((CompletionCandidate) list.getSelectedValue());
|
||||
|
||||
}
|
||||
|
||||
public void moveDown() {
|
||||
if (list.getSelectedIndex() == list.getModel().getSize() - 1) {
|
||||
scrollPane.getVerticalScrollBar().setValue(0);
|
||||
selectIndex(0);
|
||||
return;
|
||||
} else {
|
||||
int index = Math.min(list.getSelectedIndex() + 1, list.getModel()
|
||||
.getSize() - 1);
|
||||
selectIndex(index);
|
||||
}
|
||||
textarea.errorCheckerService.astGenerator
|
||||
.updateJavaDoc((CompletionCandidate) list.getSelectedValue());
|
||||
int step = scrollPane.getVerticalScrollBar().getMaximum()
|
||||
/ list.getModel().getSize();
|
||||
scrollPane.getVerticalScrollBar().setValue(scrollPane
|
||||
.getVerticalScrollBar()
|
||||
.getValue()
|
||||
+ step);
|
||||
}
|
||||
|
||||
private void selectIndex(int index) {
|
||||
list.setSelectedIndex(index);
|
||||
// final int position = textarea.getCaretPosition();
|
||||
// SwingUtilities.invokeLater(new Runnable() {
|
||||
// @Override
|
||||
// public void run() {
|
||||
// textarea.setCaretPosition(position);
|
||||
// };
|
||||
// });
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Martin Leopold <m@martinleopold.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
package processing.mode.experimental;
|
||||
|
||||
import java.io.File;
|
||||
import processing.app.Sketch;
|
||||
import processing.app.SketchException;
|
||||
import processing.mode.java.JavaBuild;
|
||||
|
||||
/**
|
||||
* Copied from processing.mode.java.JavaBuild, just changed compiler.
|
||||
*
|
||||
* @author Martin Leopold <m@martinleopold.com>
|
||||
*/
|
||||
public class DebugBuild extends JavaBuild {
|
||||
|
||||
public DebugBuild(Sketch sketch) {
|
||||
super(sketch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Preprocess and compile sketch. Copied from
|
||||
* processing.mode.java.JavaBuild, just changed compiler.
|
||||
*
|
||||
* @param srcFolder
|
||||
* @param binFolder
|
||||
* @param sizeWarning
|
||||
* @return main class name or null on compile failure
|
||||
* @throws SketchException
|
||||
*/
|
||||
@Override
|
||||
public String build(File srcFolder, File binFolder, boolean sizeWarning) throws SketchException {
|
||||
this.srcFolder = srcFolder;
|
||||
this.binFolder = binFolder;
|
||||
|
||||
// Base.openFolder(srcFolder);
|
||||
// Base.openFolder(binFolder);
|
||||
|
||||
// run the preprocessor
|
||||
String classNameFound = preprocess(srcFolder, sizeWarning);
|
||||
|
||||
// compile the program. errors will happen as a RunnerException
|
||||
// that will bubble up to whomever called build().
|
||||
// Compiler compiler = new Compiler(this);
|
||||
// String bootClasses = System.getProperty("sun.boot.class.path");
|
||||
// if (compiler.compile(this, srcFolder, binFolder, primaryClassName, getClassPath(), bootClasses)) {
|
||||
|
||||
if (Compiler.compile(this)) { // use compiler with debug info enabled (-g switch flicked)
|
||||
sketchClassName = classNameFound;
|
||||
return classNameFound;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ExperimentalMode getMode() {
|
||||
return (ExperimentalMode)mode;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Martin Leopold <m@martinleopold.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
package processing.mode.experimental;
|
||||
|
||||
import com.sun.jdi.VirtualMachine;
|
||||
import processing.app.RunnerListener;
|
||||
import processing.app.SketchException;
|
||||
import processing.app.exec.StreamRedirectThread;
|
||||
import processing.mode.java.JavaBuild;
|
||||
import processing.mode.java.runner.MessageSiphon;
|
||||
|
||||
/**
|
||||
* Runs a {@link JavaBuild}. Launches the build in a new debuggee VM.
|
||||
*
|
||||
* @author Martin Leopold <m@martinleopold.com>
|
||||
*/
|
||||
public class DebugRunner extends processing.mode.java.runner.Runner {
|
||||
|
||||
// important inherited fields
|
||||
// protected VirtualMachine vm;
|
||||
public DebugRunner(JavaBuild build, RunnerListener listener) throws SketchException {
|
||||
super(build, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch the virtual machine. Simple non-blocking launch. VM starts
|
||||
* suspended.
|
||||
*
|
||||
* @return debuggee VM or null on failure
|
||||
*/
|
||||
public VirtualMachine launch() {
|
||||
// String[] machineParamList = getMachineParams();
|
||||
// String[] sketchParamList = getSketchParams(false);
|
||||
// /*
|
||||
// * System.out.println("vm launch sketch params:"); for (int i=0;
|
||||
// * i<sketchParamList.length; i++) {
|
||||
// * System.out.println(sketchParamList[i]); } System.out.println("vm
|
||||
// * launch machine params:"); for (int i=0; i<machineParamList.length;
|
||||
// * i++) { System.out.println(machineParamList[i]); }
|
||||
// *
|
||||
// */
|
||||
// vm = launchVirtualMachine(machineParamList, sketchParamList); // will return null on failure
|
||||
if (launchVirtualMachine(false)) { // will return null on failure
|
||||
redirectStreams(vm);
|
||||
}
|
||||
return vm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect a VMs output and error streams to System.out and System.err
|
||||
*
|
||||
* @param vm the VM
|
||||
*/
|
||||
protected void redirectStreams(VirtualMachine vm) {
|
||||
MessageSiphon ms = new MessageSiphon(process.getErrorStream(), this);
|
||||
errThread = ms.getThread();
|
||||
outThread = new StreamRedirectThread("VM output reader", process.getInputStream(), System.out);
|
||||
errThread.start();
|
||||
outThread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Additional access to the virtual machine. TODO: may not be needed
|
||||
*
|
||||
* @return debugge VM or null if not running
|
||||
*/
|
||||
public VirtualMachine vm() {
|
||||
return vm;
|
||||
}
|
||||
}
|
||||
@@ -1,249 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Martin Leopold <m@martinleopold.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
package processing.mode.experimental;
|
||||
|
||||
import java.awt.Image;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import processing.app.Base;
|
||||
import processing.app.Editor;
|
||||
import processing.mode.java.JavaToolbar;
|
||||
|
||||
/**
|
||||
* Custom toolbar for the editor window. Preserves original button numbers
|
||||
* ({@link JavaToolbar#RUN}, {@link JavaToolbar#STOP}, {@link JavaToolbar#NEW},
|
||||
* {@link JavaToolbar#OPEN}, {@link JavaToolbar#SAVE}, {@link JavaToolbar#EXPORT})
|
||||
* which can be used e.g. in {@link #activate} and
|
||||
* {@link #deactivate}.
|
||||
*
|
||||
* @author Martin Leopold <m@martinleopold.com>
|
||||
*/
|
||||
public class DebugToolbar extends JavaToolbar {
|
||||
// preserve original button id's, but re-define so they are accessible
|
||||
// (they are used by DebugEditor, so they want to be public)
|
||||
|
||||
static protected final int RUN = 100; // change this, to be able to get it's name via getTitle()
|
||||
static protected final int DEBUG = JavaToolbar.RUN;
|
||||
|
||||
static protected final int CONTINUE = 101;
|
||||
static protected final int STEP = 102;
|
||||
static protected final int TOGGLE_BREAKPOINT = 103;
|
||||
static protected final int TOGGLE_VAR_INSPECTOR = 104;
|
||||
|
||||
static protected final int STOP = JavaToolbar.STOP;
|
||||
|
||||
static protected final int NEW = JavaToolbar.NEW;
|
||||
static protected final int OPEN = JavaToolbar.OPEN;
|
||||
static protected final int SAVE = JavaToolbar.SAVE;
|
||||
static protected final int EXPORT = JavaToolbar.EXPORT;
|
||||
|
||||
|
||||
// the sequence of button ids. (this maps button position = index to button ids)
|
||||
static protected final int[] buttonSequence = {
|
||||
DEBUG, CONTINUE, STEP, STOP, TOGGLE_BREAKPOINT, TOGGLE_VAR_INSPECTOR,
|
||||
NEW, OPEN, SAVE, EXPORT
|
||||
};
|
||||
|
||||
|
||||
public DebugToolbar(Editor editor, Base base) {
|
||||
super(editor, base);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize buttons. Loads images and adds the buttons to the toolbar.
|
||||
*/
|
||||
@Override
|
||||
public void init() {
|
||||
Image[][] images = loadImages();
|
||||
for (int idx = 0; idx < buttonSequence.length; idx++) {
|
||||
int id = buttonId(idx);
|
||||
addButton(getTitle(id, false), getTitle(id, true), images[idx], id == NEW || id == TOGGLE_BREAKPOINT);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the title for a toolbar button. Displayed in the toolbar when
|
||||
* hovering over a button.
|
||||
* @param id id of the toolbar button
|
||||
* @param shift true if shift is pressed
|
||||
* @return the title
|
||||
*/
|
||||
public static String getTitle(int id, boolean shift) {
|
||||
switch (id) {
|
||||
case DebugToolbar.RUN:
|
||||
return JavaToolbar.getTitle(JavaToolbar.RUN, shift);
|
||||
case STOP:
|
||||
return JavaToolbar.getTitle(JavaToolbar.STOP, shift);
|
||||
case NEW:
|
||||
return JavaToolbar.getTitle(JavaToolbar.NEW, shift);
|
||||
case OPEN:
|
||||
return JavaToolbar.getTitle(JavaToolbar.OPEN, shift);
|
||||
case SAVE:
|
||||
return JavaToolbar.getTitle(JavaToolbar.SAVE, shift);
|
||||
case EXPORT:
|
||||
return JavaToolbar.getTitle(JavaToolbar.EXPORT, shift);
|
||||
case DEBUG:
|
||||
if (shift) {
|
||||
return "Run";
|
||||
} else {
|
||||
return "Debug";
|
||||
}
|
||||
case CONTINUE:
|
||||
return "Continue";
|
||||
case TOGGLE_BREAKPOINT:
|
||||
return "Toggle Breakpoint";
|
||||
case STEP:
|
||||
if (shift) {
|
||||
return "Step Into";
|
||||
} else {
|
||||
return "Step";
|
||||
}
|
||||
case TOGGLE_VAR_INSPECTOR:
|
||||
return "Variable Inspector";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Event handler called when a toolbar button is clicked.
|
||||
* @param e the mouse event
|
||||
* @param idx index (i.e. position) of the toolbar button clicked
|
||||
*/
|
||||
@Override
|
||||
public void handlePressed(MouseEvent e, int idx) {
|
||||
boolean shift = e.isShiftDown();
|
||||
DebugEditor deditor = (DebugEditor) editor;
|
||||
int id = buttonId(idx); // convert index/position to button id
|
||||
|
||||
switch (id) {
|
||||
// case DebugToolbar.RUN:
|
||||
// super.handlePressed(e, JavaToolbar.RUN);
|
||||
// break;
|
||||
case STOP:
|
||||
Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Stop' toolbar button");
|
||||
super.handlePressed(e, JavaToolbar.STOP);
|
||||
break;
|
||||
case NEW:
|
||||
Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'New' toolbar button");
|
||||
super.handlePressed(e, JavaToolbar.NEW);
|
||||
break;
|
||||
case OPEN:
|
||||
Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Open' toolbar button");
|
||||
super.handlePressed(e, JavaToolbar.OPEN);
|
||||
break;
|
||||
case SAVE:
|
||||
Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Save' toolbar button");
|
||||
super.handlePressed(e, JavaToolbar.SAVE);
|
||||
break;
|
||||
case EXPORT:
|
||||
Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Export' toolbar button");
|
||||
super.handlePressed(e, JavaToolbar.EXPORT);
|
||||
break;
|
||||
case DEBUG:
|
||||
deditor.handleStop(); // Close any running sketches
|
||||
if (shift) {
|
||||
Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Run' toolbar button");
|
||||
deditor.handleRun();
|
||||
} else {
|
||||
Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Debug' toolbar button");
|
||||
deditor.dbg.startDebug();
|
||||
}
|
||||
break;
|
||||
case CONTINUE:
|
||||
Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Continue' toolbar button");
|
||||
deditor.dbg.continueDebug();
|
||||
break;
|
||||
case TOGGLE_BREAKPOINT:
|
||||
Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Toggle Breakpoint' toolbar button");
|
||||
deditor.dbg.toggleBreakpoint();
|
||||
break;
|
||||
case STEP:
|
||||
if (shift) {
|
||||
Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Step Into' toolbar button");
|
||||
deditor.dbg.stepInto();
|
||||
} else {
|
||||
Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Step' toolbar button");
|
||||
deditor.dbg.stepOver();
|
||||
}
|
||||
break;
|
||||
// case STEP_INTO:
|
||||
// deditor.dbg.stepInto();
|
||||
// break;
|
||||
// case STEP_OUT:
|
||||
// deditor.dbg.stepOut();
|
||||
// break;
|
||||
case TOGGLE_VAR_INSPECTOR:
|
||||
Logger.getLogger(DebugToolbar.class.getName()).log(Level.INFO, "Invoked 'Variable Inspector' toolbar button");
|
||||
deditor.toggleVariableInspector();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Activate (light up) a button.
|
||||
* @param id the button id
|
||||
*/
|
||||
@Override
|
||||
public void activate(int id) {
|
||||
//System.out.println("activate button idx: " + buttonIndex(id));
|
||||
super.activate(buttonIndex(id));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set a button to be inactive.
|
||||
* @param id the button id
|
||||
*/
|
||||
@Override
|
||||
public void deactivate(int id) {
|
||||
//System.out.println("deactivate button idx: " + buttonIndex(id));
|
||||
super.deactivate(buttonIndex(id));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get button position (index) from it's id.
|
||||
* @param buttonId the button id
|
||||
* ({@link #RUN}, {@link #DEBUG}, {@link #CONTINUE}), {@link #STEP}, ...)
|
||||
* @return the button index
|
||||
*/
|
||||
protected int buttonIndex(int buttonId) {
|
||||
for (int i = 0; i < buttonSequence.length; i++) {
|
||||
if (buttonSequence[i] == buttonId) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the button id from its position (index).
|
||||
* @param buttonIdx the button index
|
||||
* @return the button id
|
||||
* ({@link #RUN}, {@link #DEBUG}, {@link #CONTINUE}), {@link #STEP}, ...)
|
||||
*/
|
||||
protected int buttonId(int buttonIdx) {
|
||||
return buttonSequence[buttonIdx];
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,385 +0,0 @@
|
||||
/*
|
||||
Part of the XQMode project - https://github.com/Manindra29/XQMode
|
||||
|
||||
Under Google Summer of Code 2012 -
|
||||
http://www.google-melange.com/gsoc/homepage/google/gsoc2012
|
||||
|
||||
Copyright (C) 2012 Manindra Moharana
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2
|
||||
as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.mode.experimental;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Cursor;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseMotionListener;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.SwingWorker;
|
||||
|
||||
import processing.app.Base;
|
||||
import processing.app.SketchCode;
|
||||
|
||||
/**
|
||||
* The bar on the left of the text area which displays all errors as rectangles. <br>
|
||||
* <br>
|
||||
* All errors and warnings of a sketch are drawn on the bar, clicking on one,
|
||||
* scrolls to the tab and location. Error messages displayed on hover. Markers
|
||||
* are not in sync with the error line. Similar to eclipse's right error bar
|
||||
* which displays the overall errors in a document
|
||||
*
|
||||
* @author Manindra Moharana <me@mkmoharana.com>
|
||||
*
|
||||
*/
|
||||
public class ErrorBar extends JPanel {
|
||||
/**
|
||||
* Preferred height of the component
|
||||
*/
|
||||
protected int preferredHeight;
|
||||
|
||||
/**
|
||||
* Preferred height of the component
|
||||
*/
|
||||
protected int preferredWidth = 12;
|
||||
|
||||
/**
|
||||
* Height of marker
|
||||
*/
|
||||
public static final int errorMarkerHeight = 4;
|
||||
|
||||
/**
|
||||
* Color of Error Marker
|
||||
*/
|
||||
public Color errorColor = new Color(0xED2630);
|
||||
|
||||
/**
|
||||
* Color of Warning Marker
|
||||
*/
|
||||
public Color warningColor = new Color(0xFFC30E);
|
||||
|
||||
/**
|
||||
* Background color of the component
|
||||
*/
|
||||
public Color backgroundColor = new Color(0x2C343D);
|
||||
|
||||
/**
|
||||
* DebugEditor instance
|
||||
*/
|
||||
protected DebugEditor editor;
|
||||
|
||||
/**
|
||||
* ErrorCheckerService instance
|
||||
*/
|
||||
protected ErrorCheckerService errorCheckerService;
|
||||
|
||||
/**
|
||||
* Stores error markers displayed PER TAB along the error bar.
|
||||
*/
|
||||
protected ArrayList<ErrorMarker> errorPoints = new ArrayList<ErrorMarker>();
|
||||
|
||||
/**
|
||||
* Stores previous list of error markers.
|
||||
*/
|
||||
protected ArrayList<ErrorMarker> errorPointsOld = new ArrayList<ErrorMarker>();
|
||||
|
||||
public void paintComponent(Graphics g) {
|
||||
Graphics2D g2d = (Graphics2D) g;
|
||||
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
|
||||
RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
g.setColor(backgroundColor);
|
||||
g.fillRect(0, 0, getWidth(), getHeight());
|
||||
|
||||
for (ErrorMarker emarker : errorPoints) {
|
||||
if (emarker.type == ErrorMarker.Error) {
|
||||
g.setColor(errorColor);
|
||||
} else {
|
||||
g.setColor(warningColor);
|
||||
}
|
||||
g.fillRect(2, emarker.y, (getWidth() - 3), errorMarkerHeight);
|
||||
}
|
||||
}
|
||||
|
||||
public Dimension getPreferredSize() {
|
||||
return new Dimension(preferredWidth, preferredHeight);
|
||||
}
|
||||
|
||||
public Dimension getMinimumSize() {
|
||||
return getPreferredSize();
|
||||
}
|
||||
|
||||
public ErrorBar(DebugEditor editor, int height, ExperimentalMode mode) {
|
||||
this.editor = editor;
|
||||
this.preferredHeight = height;
|
||||
this.errorCheckerService = editor.errorCheckerService;
|
||||
errorColor = mode.getThemeColor("errorbar.errorcolor", errorColor);
|
||||
warningColor = mode
|
||||
.getThemeColor("errorbar.warningcolor", warningColor);
|
||||
backgroundColor = mode.getThemeColor("errorbar.backgroundcolor",
|
||||
backgroundColor);
|
||||
addListeners();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update error markers in the error bar.
|
||||
*
|
||||
* @param problems
|
||||
* - List of problems.
|
||||
*/
|
||||
synchronized public void updateErrorPoints(final ArrayList<Problem> problems) {
|
||||
|
||||
// NOTE TO SELF: ErrorMarkers are calculated for the present tab only
|
||||
// Error Marker index in the arraylist is LOCALIZED for current tab.
|
||||
// Also, need to do the update in the UI thread to prevent concurrency issues.
|
||||
final int fheight = this.getHeight();
|
||||
SwingWorker worker = new SwingWorker() {
|
||||
|
||||
protected Object doInBackground() throws Exception {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void done() {
|
||||
int totalLines = 0;
|
||||
int currentTab = 0;
|
||||
for (SketchCode sc : editor.getSketch().getCode()) {
|
||||
if (sc.isExtension("pde")) {
|
||||
try {
|
||||
if (editor.getSketch().getCurrentCode().equals(sc)) {
|
||||
// Adding + 1 to len because \n gets appended
|
||||
// for each
|
||||
// sketchcode extracted during processPDECode()
|
||||
totalLines = Base.countLines(sc.getDocument()
|
||||
.getText(0,
|
||||
sc.getDocument().getLength())) + 1;
|
||||
break;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
currentTab++;
|
||||
}
|
||||
// System.out.println("Total lines: " + totalLines);
|
||||
|
||||
errorPointsOld.clear();
|
||||
for (ErrorMarker marker : errorPoints) {
|
||||
errorPointsOld.add(marker);
|
||||
}
|
||||
errorPoints.clear();
|
||||
|
||||
// Each problem.getSourceLine() will have an extra line added
|
||||
// because of
|
||||
// class declaration in the beginning as well as default imports
|
||||
for (Problem problem : problems) {
|
||||
if (problem.tabIndex == currentTab) {
|
||||
// Ratio of error line to total lines
|
||||
float y = (problem.lineNumber - errorCheckerService.defaultImportsOffset)
|
||||
/ ((float) totalLines);
|
||||
// Ratio multiplied by height of the error bar
|
||||
y *= fheight - 15; // -15 is just a vertical offset
|
||||
errorPoints.add(new ErrorMarker(problem, (int) y,
|
||||
problem.isError() ? ErrorMarker.Error
|
||||
: ErrorMarker.Warning));
|
||||
// System.out.println("Y: " + y);
|
||||
}
|
||||
}
|
||||
|
||||
repaint();
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
worker.execute(); // I eat concurrency bugs for breakfast.
|
||||
} catch (Exception exp) {
|
||||
System.out.println("Errorbar update markers is slacking."
|
||||
+ exp.getMessage());
|
||||
// e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if new errors have popped up in the sketch since the last check
|
||||
*
|
||||
* @return true - if errors have changed
|
||||
*/
|
||||
public boolean errorPointsChanged() {
|
||||
if (errorPointsOld.size() != errorPoints.size()) {
|
||||
editor.getTextArea().repaint();
|
||||
// System.out.println("2 Repaint " + System.currentTimeMillis());
|
||||
return true;
|
||||
}
|
||||
|
||||
else {
|
||||
for (int i = 0; i < errorPoints.size(); i++) {
|
||||
if (errorPoints.get(i).y != errorPointsOld.get(i).y) {
|
||||
editor.getTextArea().repaint();
|
||||
// System.out.println("3 Repaint " +
|
||||
// System.currentTimeMillis());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add various mouse listeners.
|
||||
*/
|
||||
protected void addListeners() {
|
||||
|
||||
this.addMouseListener(new MouseAdapter() {
|
||||
|
||||
// Find out which error/warning the user has clicked
|
||||
// and then scroll to that
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public void mouseClicked(final MouseEvent e) {
|
||||
SwingWorker worker = new SwingWorker() {
|
||||
|
||||
protected Object doInBackground() throws Exception {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void done() {
|
||||
for (ErrorMarker eMarker : errorPoints) {
|
||||
// -2 and +2 are extra allowance, clicks in the
|
||||
// vicinity of the markers register that way
|
||||
if (e.getY() >= eMarker.y - 2
|
||||
&& e.getY() <= eMarker.y + 2
|
||||
+ errorMarkerHeight) {
|
||||
int currentTabErrorIndex = errorPoints
|
||||
.indexOf(eMarker);
|
||||
// System.out.println("Index: " +
|
||||
// currentTabErrorIndex);
|
||||
int currentTab = editor.getSketch()
|
||||
.getCodeIndex(
|
||||
editor.getSketch()
|
||||
.getCurrentCode());
|
||||
|
||||
int totalErrorIndex = currentTabErrorIndex;
|
||||
|
||||
for (int i = 0; i < errorCheckerService.problemsList
|
||||
.size(); i++) {
|
||||
Problem p = errorCheckerService.problemsList
|
||||
.get(i);
|
||||
if (p.tabIndex < currentTab) {
|
||||
totalErrorIndex++;
|
||||
}
|
||||
if (p.tabIndex == currentTab) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
errorCheckerService
|
||||
.scrollToErrorLine(totalErrorIndex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
worker.execute();
|
||||
} catch (Exception exp) {
|
||||
System.out.println("Errorbar mouseClicked is slacking."
|
||||
+ exp.getMessage());
|
||||
// e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
// Tooltip on hover
|
||||
this.addMouseMotionListener(new MouseMotionListener() {
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public void mouseMoved(final MouseEvent e) {
|
||||
// System.out.println(e);
|
||||
SwingWorker worker = new SwingWorker() {
|
||||
|
||||
protected Object doInBackground() throws Exception {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void done() {
|
||||
|
||||
for (ErrorMarker eMarker : errorPoints) {
|
||||
if (e.getY() >= eMarker.y - 2
|
||||
&& e.getY() <= eMarker.y + 2
|
||||
+ errorMarkerHeight) {
|
||||
// System.out.println("Index: " +
|
||||
// errorPoints.indexOf(y));
|
||||
int currentTab = editor.getSketch()
|
||||
.getCodeIndex(
|
||||
editor.getSketch()
|
||||
.getCurrentCode());
|
||||
int currentTabErrorCount = 0;
|
||||
|
||||
for (int i = 0; i < errorPoints.size(); i++) {
|
||||
Problem p = errorPoints.get(i).problem;
|
||||
if (p.tabIndex == currentTab) {
|
||||
if (currentTabErrorCount == errorPoints
|
||||
.indexOf(eMarker)) {
|
||||
// System.out.println("Roger that.");
|
||||
String msg = (p.isError() ? "Error: "
|
||||
: "Warning: ")
|
||||
+ p.message;
|
||||
setToolTipText(msg);
|
||||
setCursor(Cursor
|
||||
.getPredefinedCursor(Cursor.HAND_CURSOR));
|
||||
return;
|
||||
} else {
|
||||
currentTabErrorCount++;
|
||||
// System.out.println("Still looking..");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
// Reset cursor and tooltip
|
||||
else {
|
||||
setToolTipText("");
|
||||
setCursor(Cursor
|
||||
.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
try {
|
||||
worker.execute();
|
||||
} catch (Exception exp) {
|
||||
System.out
|
||||
.println("Errorbar mousemoved Worker is slacking."
|
||||
+ exp.getMessage());
|
||||
// e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDragged(MouseEvent arg0) {
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,36 +0,0 @@
|
||||
package processing.mode.experimental;
|
||||
/**
|
||||
* Error markers displayed on the Error Bar.
|
||||
*
|
||||
* @author Manindra Moharana <me@mkmoharana.com>
|
||||
*
|
||||
*/
|
||||
public class ErrorMarker {
|
||||
/**
|
||||
* y co-ordinate of the marker
|
||||
*/
|
||||
public int y;
|
||||
/**
|
||||
* Type of marker: Error or Warning?
|
||||
*/
|
||||
public int type = -1;
|
||||
/**
|
||||
* Error Type constant
|
||||
*/
|
||||
public static final int Error = 1;
|
||||
/**
|
||||
* Warning Type constant
|
||||
*/
|
||||
public static final int Warning = 2;
|
||||
/**
|
||||
* Problem that the error marker represents
|
||||
* @see Problem
|
||||
*/
|
||||
public Problem problem;
|
||||
|
||||
public ErrorMarker(Problem problem, int y, int type) {
|
||||
this.problem = problem;
|
||||
this.y = y;
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
@@ -1,374 +0,0 @@
|
||||
/*
|
||||
Part of the XQMode project - https://github.com/Manindra29/XQMode
|
||||
|
||||
Under Google Summer of Code 2012 -
|
||||
http://www.google-melange.com/gsoc/homepage/google/gsoc2012
|
||||
|
||||
Copyright (C) 2012 Manindra Moharana
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2
|
||||
as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.mode.experimental;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Frame;
|
||||
import java.awt.Point;
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.awt.event.ComponentListener;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.WindowConstants;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.table.TableModel;
|
||||
|
||||
import processing.app.Editor;
|
||||
import processing.app.Toolkit;
|
||||
|
||||
/**
|
||||
* Error Window that displays a tablular list of errors. Clicking on an error
|
||||
* scrolls to its location in the code.
|
||||
*
|
||||
* @author Manindra Moharana <me@mkmoharana.com>
|
||||
*
|
||||
*/
|
||||
public class ErrorWindow extends JFrame {
|
||||
|
||||
private JPanel contentPane;
|
||||
/**
|
||||
* The table displaying the errors
|
||||
*/
|
||||
protected XQErrorTable errorTable;
|
||||
/**
|
||||
* Scroll pane that contains the Error Table
|
||||
*/
|
||||
protected JScrollPane scrollPane;
|
||||
|
||||
protected DebugEditor thisEditor;
|
||||
private JFrame thisErrorWindow;
|
||||
|
||||
/**
|
||||
* Handles the sticky Problem window
|
||||
*/
|
||||
private DockTool2Base Docker;
|
||||
|
||||
protected ErrorCheckerService errorCheckerService;
|
||||
|
||||
/**
|
||||
* Preps up ErrorWindow
|
||||
*
|
||||
* @param editor
|
||||
* - Editor
|
||||
* @param ecs - ErrorCheckerService
|
||||
*/
|
||||
public ErrorWindow(DebugEditor editor, ErrorCheckerService ecs) {
|
||||
thisErrorWindow = this;
|
||||
errorCheckerService = ecs;
|
||||
thisEditor = editor;
|
||||
setTitle("Problems");
|
||||
prepareFrame();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up ErrorWindow
|
||||
*/
|
||||
protected void prepareFrame() {
|
||||
Toolkit.setIcon(this);
|
||||
setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);
|
||||
// Default size: setBounds(100, 100, 458, 160);
|
||||
setBounds(100, 100, 458, 160); // Yeah, I hardcode such things sometimes. Hate me.
|
||||
|
||||
contentPane = new JPanel();
|
||||
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
|
||||
setContentPane(contentPane);
|
||||
contentPane.setLayout(new BorderLayout(0, 0));
|
||||
|
||||
scrollPane = new JScrollPane();
|
||||
contentPane.add(scrollPane);
|
||||
|
||||
errorTable = new XQErrorTable(errorCheckerService);
|
||||
scrollPane.setViewportView(errorTable);
|
||||
|
||||
try {
|
||||
Docker = new DockTool2Base();
|
||||
addListeners();
|
||||
} catch (Exception e) {
|
||||
System.out.println("addListeners() acted silly.");
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (thisEditor != null) {
|
||||
setLocation(new Point(thisEditor.getLocation().x
|
||||
+ thisEditor.getWidth(), thisEditor.getLocation().y));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the error table with new data(Table Model). Called from Error
|
||||
* Checker Service.
|
||||
*
|
||||
* @param tableModel
|
||||
* - Table Model
|
||||
* @return True - If error table was updated successfully.
|
||||
*/
|
||||
synchronized public boolean updateTable(final TableModel tableModel) {
|
||||
// XQErrorTable handles evrything now
|
||||
return errorTable.updateTable(tableModel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds various listeners to components of EditorWindow and to the Editor
|
||||
* window
|
||||
*/
|
||||
protected void addListeners() {
|
||||
|
||||
if (thisErrorWindow == null)
|
||||
System.out.println("ERW null");
|
||||
|
||||
thisErrorWindow.addComponentListener(new ComponentListener() {
|
||||
|
||||
@Override
|
||||
public void componentShown(ComponentEvent e) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentResized(ComponentEvent e) {
|
||||
Docker.tryDocking();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentMoved(ComponentEvent e) {
|
||||
Docker.tryDocking();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentHidden(ComponentEvent e) {
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
thisErrorWindow.addWindowListener(new WindowAdapter() {
|
||||
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e) {
|
||||
thisEditor.problemWindowMenuCB.setSelected(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowDeiconified(WindowEvent e) {
|
||||
thisEditor.setExtendedState(Frame.NORMAL);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
if (thisEditor == null) {
|
||||
System.out.println("Editor null");
|
||||
return;
|
||||
}
|
||||
|
||||
thisEditor.addWindowListener(new WindowAdapter() {
|
||||
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowClosed(WindowEvent e) {
|
||||
errorCheckerService.pauseThread();
|
||||
errorCheckerService.stopThread(); // Bye bye thread.
|
||||
thisErrorWindow.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowIconified(WindowEvent e) {
|
||||
thisErrorWindow.setExtendedState(Frame.ICONIFIED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void windowDeiconified(WindowEvent e) {
|
||||
thisErrorWindow.setExtendedState(Frame.NORMAL);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
thisEditor.addComponentListener(new ComponentListener() {
|
||||
|
||||
@Override
|
||||
public void componentShown(ComponentEvent e) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentResized(ComponentEvent e) {
|
||||
if (Docker.isDocked()) {
|
||||
Docker.dock();
|
||||
} else {
|
||||
Docker.tryDocking();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentMoved(ComponentEvent e) {
|
||||
|
||||
if (Docker.isDocked()) {
|
||||
Docker.dock();
|
||||
} else {
|
||||
Docker.tryDocking();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentHidden(ComponentEvent e) {
|
||||
// System.out.println("ed hidden");
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implements the docking feature of the tool - The frame sticks to the
|
||||
* editor and once docked, moves along with it as the editor is resized,
|
||||
* moved, or closed.
|
||||
*
|
||||
* This class has been borrowed from Tab Manager tool by Thomas Diewald. It
|
||||
* has been slightly modified and used here.
|
||||
*
|
||||
* @author Thomas Diewald , http://thomasdiewald.com
|
||||
*/
|
||||
private class DockTool2Base {
|
||||
|
||||
private int docking_border = 0;
|
||||
private int dock_on_editor_y_offset_ = 0;
|
||||
private int dock_on_editor_x_offset_ = 0;
|
||||
|
||||
// ///////////////////////////////
|
||||
// ____2____
|
||||
// | |
|
||||
// | |
|
||||
// 0 | editor | 1
|
||||
// | |
|
||||
// |_________|
|
||||
// 3
|
||||
// ///////////////////////////////
|
||||
|
||||
// public void reset() {
|
||||
// dock_on_editor_y_offset_ = 0;
|
||||
// dock_on_editor_x_offset_ = 0;
|
||||
// docking_border = 0;
|
||||
// }
|
||||
|
||||
public boolean isDocked() {
|
||||
return (docking_border >= 0);
|
||||
}
|
||||
|
||||
private final int MAX_GAP_ = 20;
|
||||
|
||||
//
|
||||
public void tryDocking() {
|
||||
if (thisEditor == null)
|
||||
return;
|
||||
Editor editor = thisEditor;
|
||||
Frame frame = thisErrorWindow;
|
||||
|
||||
int ex = editor.getX();
|
||||
int ey = editor.getY();
|
||||
int ew = editor.getWidth();
|
||||
int eh = editor.getHeight();
|
||||
|
||||
int fx = frame.getX();
|
||||
int fy = frame.getY();
|
||||
int fw = frame.getWidth();
|
||||
int fh = frame.getHeight();
|
||||
|
||||
if (((fy > ey) && (fy < ey + eh))
|
||||
|| ((fy + fh > ey) && (fy + fh < ey + eh))) {
|
||||
int dis_border_left = Math.abs(ex - (fx + fw));
|
||||
int dis_border_right = Math.abs((ex + ew) - (fx));
|
||||
|
||||
if (dis_border_left < MAX_GAP_ || dis_border_right < MAX_GAP_) {
|
||||
docking_border = (dis_border_left < dis_border_right) ? 0
|
||||
: 1;
|
||||
dock_on_editor_y_offset_ = fy - ey;
|
||||
dock();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (((fx > ex) && (fx < ex + ew))
|
||||
|| ((fx + fw > ey) && (fx + fw < ex + ew))) {
|
||||
int dis_border_top = Math.abs(ey - (fy + fh));
|
||||
int dis_border_bot = Math.abs((ey + eh) - (fy));
|
||||
|
||||
if (dis_border_top < MAX_GAP_ || dis_border_bot < MAX_GAP_) {
|
||||
docking_border = (dis_border_top < dis_border_bot) ? 2 : 3;
|
||||
dock_on_editor_x_offset_ = fx - ex;
|
||||
dock();
|
||||
return;
|
||||
}
|
||||
}
|
||||
docking_border = -1;
|
||||
}
|
||||
|
||||
public void dock() {
|
||||
if (thisEditor == null)
|
||||
return;
|
||||
Editor editor = thisEditor;
|
||||
Frame frame = thisErrorWindow;
|
||||
|
||||
int ex = editor.getX();
|
||||
int ey = editor.getY();
|
||||
int ew = editor.getWidth();
|
||||
int eh = editor.getHeight();
|
||||
|
||||
// int fx = frame.getX();
|
||||
// int fy = frame.getY();
|
||||
int fw = frame.getWidth();
|
||||
int fh = frame.getHeight();
|
||||
|
||||
int x = 0, y = 0;
|
||||
if (docking_border == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (docking_border == 0) {
|
||||
x = ex - fw;
|
||||
y = ey + dock_on_editor_y_offset_;
|
||||
}
|
||||
if (docking_border == 1) {
|
||||
x = ex + ew;
|
||||
y = ey + dock_on_editor_y_offset_;
|
||||
}
|
||||
|
||||
if (docking_border == 2) {
|
||||
x = ex + dock_on_editor_x_offset_;
|
||||
y = ey - fh;
|
||||
}
|
||||
if (docking_border == 3) {
|
||||
x = ex + dock_on_editor_x_offset_;
|
||||
y = ey + eh;
|
||||
}
|
||||
frame.setLocation(x, y);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,171 +0,0 @@
|
||||
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
Part of the Processing project - http://processing.org
|
||||
|
||||
Copyright (c) 2012 The Processing Foundation
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2
|
||||
as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.mode.experimental;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.logging.FileHandler;
|
||||
import java.util.logging.Handler;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import processing.app.Base;
|
||||
import processing.app.Editor;
|
||||
import processing.app.EditorState;
|
||||
import processing.app.Mode;
|
||||
import processing.mode.java.JavaMode;
|
||||
|
||||
|
||||
/**
|
||||
* Experimental Mode for Processing, combines Debug Mode and XQMode and
|
||||
* starts us working toward our next generation editor/debugger setup.
|
||||
*/
|
||||
public class ExperimentalMode extends JavaMode {
|
||||
public static final boolean VERBOSE_LOGGING = true;
|
||||
//public static final boolean VERBOSE_LOGGING = false;
|
||||
public static final int LOG_SIZE = 512 * 1024; // max log file size (in bytes)
|
||||
|
||||
|
||||
public ExperimentalMode(Base base, File folder) {
|
||||
super(base, folder);
|
||||
|
||||
// use libraries folder from javamode. will make sketches using core libraries work, as well as import libraries and examples menus
|
||||
for (Mode m : base.getModeList()) {
|
||||
if (m.getClass() == JavaMode.class) {
|
||||
JavaMode jMode = (JavaMode) m;
|
||||
librariesFolder = jMode.getLibrariesFolder();
|
||||
rebuildLibraryList();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch examples and reference from java mode
|
||||
// thx to Manindra (https://github.com/martinleopold/DebugMode/issues/4)
|
||||
examplesFolder = Base.getContentFile("modes/java/examples");
|
||||
// https://github.com/martinleopold/DebugMode/issues/6
|
||||
referenceFolder = Base.getContentFile("modes/java/reference");
|
||||
|
||||
// set logging level
|
||||
Logger globalLogger = Logger.getLogger("");
|
||||
//Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); // doesn't work on os x
|
||||
if (VERBOSE_LOGGING) {
|
||||
globalLogger.setLevel(Level.INFO);
|
||||
} else {
|
||||
globalLogger.setLevel(Level.WARNING);
|
||||
}
|
||||
|
||||
// enable logging to file
|
||||
try {
|
||||
// settings is writable for built-in modes, mode folder is not writable
|
||||
File logFolder = Base.getSettingsFile("debug");
|
||||
if (!logFolder.exists()) {
|
||||
logFolder.mkdir();
|
||||
}
|
||||
File logFile = new File(logFolder, "DebugMode.%g.log");
|
||||
Handler handler = new FileHandler(logFile.getAbsolutePath(), LOG_SIZE, 10, false);
|
||||
globalLogger.addHandler(handler);
|
||||
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(ExperimentalMode.class.getName()).log(Level.SEVERE, null, ex);
|
||||
} catch (SecurityException ex) {
|
||||
Logger.getLogger(ExperimentalMode.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
|
||||
// disable initial chattiness for now
|
||||
// // output version from manifest file
|
||||
// Package p = ExperimentalMode.class.getPackage();
|
||||
// String titleAndVersion = p.getImplementationTitle() + " (v" + p.getImplementationVersion() + ")";
|
||||
// //System.out.println(titleAndVersion);
|
||||
// Logger.getLogger(ExperimentalMode.class.getName()).log(Level.INFO, titleAndVersion);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "Experimental";
|
||||
}
|
||||
|
||||
|
||||
public File[] getKeywordFiles() {
|
||||
return new File[] {
|
||||
Base.getContentFile("modes/java/keywords.txt")
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new editor associated with this mode.
|
||||
*/
|
||||
@Override
|
||||
public Editor createEditor(Base base, String path, EditorState state) {
|
||||
return new DebugEditor(base, path, state, this);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load a String value from theme.txt
|
||||
*
|
||||
* @param attribute the attribute key to load
|
||||
* @param defaultValue the default value
|
||||
* @return the attributes value, or the default value if the attribute
|
||||
* couldn't be loaded
|
||||
*/
|
||||
public String loadThemeString(String attribute, String defaultValue) {
|
||||
String newString = theme.get(attribute);
|
||||
if (newString != null) {
|
||||
return newString;
|
||||
}
|
||||
Logger.getLogger(getClass().getName()).log(Level.WARNING, "Error loading String: {0}", attribute);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load a Color value from theme.txt
|
||||
*
|
||||
* @param attribute the attribute key to load
|
||||
* @param defaultValue the default value
|
||||
* @return the attributes value, or the default value if the attribute
|
||||
* couldn't be loaded
|
||||
*/
|
||||
public Color getThemeColor(String attribute, Color defaultValue) {
|
||||
Color newColor = theme.getColor(attribute);
|
||||
if (newColor != null) {
|
||||
return newColor;
|
||||
}
|
||||
System.out.println("error loading color: " + attribute);
|
||||
Logger.getLogger(ExperimentalMode.class.getName()).log(Level.WARNING, "Error loading Color: {0}", attribute);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
|
||||
public ClassLoader getJavaModeClassLoader() {
|
||||
for (Mode m : base.getModeList()) {
|
||||
if (m.getClass() == JavaMode.class) {
|
||||
JavaMode jMode = (JavaMode) m;
|
||||
return jMode.getClassLoader();
|
||||
}
|
||||
}
|
||||
// badness
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Martin Leopold <m@martinleopold.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
package processing.mode.experimental;
|
||||
|
||||
import com.sun.jdi.ClassNotLoadedException;
|
||||
import com.sun.jdi.Field;
|
||||
import com.sun.jdi.InvalidTypeException;
|
||||
import com.sun.jdi.ObjectReference;
|
||||
import com.sun.jdi.Value;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Specialized {@link VariableNode} for representing fields. Overrides
|
||||
* {@link #setValue} to properly change the value of the encapsulated field.
|
||||
*
|
||||
* @author Martin Leopold <m@martinleopold.com>
|
||||
*/
|
||||
public class FieldNode extends VariableNode {
|
||||
|
||||
protected Field field;
|
||||
protected ObjectReference obj;
|
||||
|
||||
/**
|
||||
* Construct a {@link FieldNode}.
|
||||
*
|
||||
* @param name the name
|
||||
* @param type the type
|
||||
* @param value the value
|
||||
* @param field the field
|
||||
* @param obj a reference to the object containing the field
|
||||
*/
|
||||
public FieldNode(String name, String type, Value value, Field field, ObjectReference obj) {
|
||||
super(name, type, value);
|
||||
this.field = field;
|
||||
this.obj = obj;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(Value value) {
|
||||
try {
|
||||
obj.setValue(field, value);
|
||||
} catch (InvalidTypeException ex) {
|
||||
Logger.getLogger(FieldNode.class.getName()).log(Level.SEVERE, null, ex);
|
||||
} catch (ClassNotLoadedException ex) {
|
||||
Logger.getLogger(FieldNode.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
Part of the XQMode project - https://github.com/Manindra29/XQMode
|
||||
|
||||
Under Google Summer of Code 2012 -
|
||||
http://www.google-melange.com/gsoc/homepage/google/gsoc2012
|
||||
|
||||
Copyright (C) 2012 Manindra Moharana
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2
|
||||
as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.mode.experimental;
|
||||
|
||||
/**
|
||||
* Wrapper for import statements
|
||||
*
|
||||
* @author Manindra Moharana <me@mkmoharana.com>
|
||||
*
|
||||
*/
|
||||
public class ImportStatement {
|
||||
/**
|
||||
* Ex: processing.opengl.*, java.util.*
|
||||
*/
|
||||
String importName;
|
||||
/**
|
||||
* Which tab does it belong to?
|
||||
*/
|
||||
int tab;
|
||||
|
||||
/**
|
||||
* Line number(pde code) of the import
|
||||
*/
|
||||
int lineNumber;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param importName - Ex: processing.opengl.*, java.util.*
|
||||
* @param tab - Which tab does it belong to?
|
||||
* @param lineNumber - Line number(pde code) of the import
|
||||
*/
|
||||
public ImportStatement(String importName, int tab, int lineNumber) {
|
||||
this.importName = importName;
|
||||
this.tab = tab;
|
||||
this.lineNumber = lineNumber;
|
||||
}
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
package processing.mode.experimental;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.util.Iterator;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
public class JavadocHelper {
|
||||
|
||||
public static void loadJavaDoc(TreeMap<String, String> jdocMap, File p5Ref){
|
||||
Document doc;
|
||||
|
||||
//Pattern pat = Pattern.compile("\\w+");
|
||||
try {
|
||||
if (p5Ref == null) {
|
||||
System.out.println("P5 Ref location null");
|
||||
p5Ref = new File(
|
||||
"/home/quarkninja/Workspaces/processing-workspace/processing/build/linux/work/modes/java/reference");
|
||||
}
|
||||
|
||||
FileFilter fileFilter = new FileFilter() {
|
||||
public boolean accept(File file) {
|
||||
if(!file.getName().endsWith("_.html"))
|
||||
return false;
|
||||
int k = 0;
|
||||
for (int i = 0; i < file.getName().length(); i++) {
|
||||
if(file.getName().charAt(i)== '_')
|
||||
k++;
|
||||
if(k > 1)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
for (File docFile : p5Ref.listFiles(fileFilter)) {
|
||||
|
||||
doc = Jsoup.parse(docFile, null);
|
||||
Elements elm = doc.getElementsByClass("ref-item");
|
||||
String msg = "";
|
||||
String methodName = docFile.getName().substring(0, docFile.getName().indexOf('_'));
|
||||
//System.out.println(methodName);
|
||||
for (Iterator it = elm.iterator(); it.hasNext();) {
|
||||
Element ele = (Element) it.next();
|
||||
msg = "<html><body> <strong><div style=\"width: 300px; text-justification: justify;\"></strong><table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" class=\"ref-item\">"
|
||||
+ ele.html() + "</table></div></html></body></html>";
|
||||
//mat.replaceAll("");
|
||||
msg = msg.replaceAll("img src=\"", "img src=\""
|
||||
+ p5Ref.toURI().toURL().toString() + "/");
|
||||
//System.out.println(ele.text());
|
||||
}
|
||||
jdocMap.put(methodName, msg);
|
||||
}
|
||||
System.out.println("JDoc loaded "+jdocMap.size());
|
||||
/* File javaDocFile = new File(
|
||||
"/home/quarkninja/Workspaces/processing-workspace/processing/build/javadoc/core/processing/core/PApplet.html");
|
||||
//SimpleOpenNI.SimpleOpenNI
|
||||
doc = Jsoup.parse(javaDocFile, null);
|
||||
|
||||
String msg = "";
|
||||
Elements elm = doc.getElementsByTag("pre");
|
||||
// Elements desc = doc.getElementsByTag("dl");
|
||||
//System.out.println(elm.toString());
|
||||
|
||||
for (Iterator iterator = elm.iterator(); iterator.hasNext();) {
|
||||
Element element = (Element) iterator.next();
|
||||
|
||||
//System.out.println(element.text());
|
||||
// if (element.nextElementSibling() != null)
|
||||
// System.out.println(element.nextElementSibling().text());
|
||||
//System.out.println("-------------------");
|
||||
msg = "<html><body> <strong><div style=\"width: 300px; text-justification: justify;\"></strong>"
|
||||
+ element.html()
|
||||
+ element.nextElementSibling()
|
||||
+ "</div></html></body></html>";
|
||||
int k = 0;
|
||||
Matcher matcher = pat.matcher(element.text());
|
||||
ArrayList<String> parts = new ArrayList<String>();
|
||||
while (matcher.find()) {
|
||||
// System.out.print("Start index: " + matcher.start());
|
||||
// System.out.print(" End index: " + matcher.end() + " ");
|
||||
if (k == 0 && !matcher.group().equals("public")) {
|
||||
k = -1;
|
||||
break;
|
||||
}
|
||||
// System.out.print(matcher.group() + " ");
|
||||
parts.add(matcher.group());
|
||||
k++;
|
||||
}
|
||||
if (k <= 0 || parts.size() < 3)
|
||||
continue;
|
||||
int i = 0;
|
||||
if (parts.get(i).equals("public"))
|
||||
i++;
|
||||
if (parts.get(i).equals("static") || parts.get(i).equals("final")
|
||||
|| parts.get(i).equals("class"))
|
||||
i++;
|
||||
if (parts.get(i).equals("static") || parts.get(i).equals("final"))
|
||||
i++;
|
||||
// System.out.println("Ret Type " + parts.get(i));
|
||||
|
||||
i++; // return type
|
||||
|
||||
//System.out.println("Name " + parts.get(i));
|
||||
jdocMap.put(parts.get(i), msg);
|
||||
}
|
||||
|
||||
// for (String key : jdocMap.keySet()) {
|
||||
// System.out.println("Method: " + key);
|
||||
// System.out.println("Method: " + jdocMap.get(key));
|
||||
// }
|
||||
*
|
||||
*/
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,218 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Martin Leopold <m@martinleopold.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
package processing.mode.experimental;
|
||||
|
||||
import com.sun.jdi.AbsentInformationException;
|
||||
import com.sun.jdi.Location;
|
||||
import com.sun.jdi.ReferenceType;
|
||||
import com.sun.jdi.request.BreakpointRequest;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Model/Controller of a line breakpoint. Can be set before or while debugging.
|
||||
* Adds a highlight using the debuggers view ({@link DebugEditor}).
|
||||
*
|
||||
* @author Martin Leopold <m@martinleopold.com>
|
||||
*/
|
||||
public class LineBreakpoint implements ClassLoadListener {
|
||||
|
||||
protected Debugger dbg; // the debugger
|
||||
protected LineID line; // the line this breakpoint is set on
|
||||
protected BreakpointRequest bpr; // the request on the VM's event request manager
|
||||
protected ReferenceType theClass; // the class containing this breakpoint, null when not yet loaded
|
||||
|
||||
/**
|
||||
* Create a {@link LineBreakpoint}. If in a debug session, will try to
|
||||
* immediately set the breakpoint. If not in a debug session or the
|
||||
* corresponding class is not yet loaded the breakpoint will activate on
|
||||
* class load.
|
||||
*
|
||||
* @param line the line id to create the breakpoint on
|
||||
* @param dbg the {@link Debugger}
|
||||
*/
|
||||
public LineBreakpoint(LineID line, Debugger dbg) {
|
||||
this.line = line;
|
||||
line.startTracking(dbg.editor().getTab(line.fileName()).getDocument());
|
||||
this.dbg = dbg;
|
||||
theClass = dbg.getClass(className()); // try to get the class immediately, may return null if not yet loaded
|
||||
set(); // activate the breakpoint (show highlight, attach if debugger is running)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link LineBreakpoint} on a line in the current tab.
|
||||
*
|
||||
* @param lineIdx the line index of the current tab to create the breakpoint
|
||||
* on
|
||||
* @param dbg the {@link Debugger}
|
||||
*/
|
||||
// TODO: remove and replace by {@link #LineBreakpoint(LineID line, Debugger dbg)}
|
||||
public LineBreakpoint(int lineIdx, Debugger dbg) {
|
||||
this(dbg.editor().getLineIDInCurrentTab(lineIdx), dbg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the line id this breakpoint is on.
|
||||
*
|
||||
* @return the line id
|
||||
*/
|
||||
public LineID lineID() {
|
||||
return line;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if this breakpoint is on a certain line.
|
||||
*
|
||||
* @param testLine the line id to test
|
||||
* @return true if this breakpoint is on the given line
|
||||
*/
|
||||
public boolean isOnLine(LineID testLine) {
|
||||
return line.equals(testLine);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach this breakpoint to the VM. Creates and enables a
|
||||
* {@link BreakpointRequest}. VM needs to be paused.
|
||||
*/
|
||||
protected void attach() {
|
||||
if (!dbg.isPaused()) {
|
||||
Logger.getLogger(LineBreakpoint.class.getName()).log(Level.WARNING, "can't attach breakpoint, debugger not paused");
|
||||
return;
|
||||
}
|
||||
|
||||
if (theClass == null) {
|
||||
Logger.getLogger(LineBreakpoint.class.getName()).log(Level.WARNING, "can't attach breakpoint, class not loaded: {0}", className());
|
||||
return;
|
||||
}
|
||||
|
||||
// find line in java space
|
||||
LineID javaLine = dbg.sketchToJavaLine(line);
|
||||
if (javaLine == null) {
|
||||
Logger.getLogger(LineBreakpoint.class.getName()).log(Level.WARNING, "couldn't find line {0} in the java code", line);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
List<Location> locations = theClass.locationsOfLine(javaLine.lineIdx() + 1);
|
||||
if (locations.isEmpty()) {
|
||||
Logger.getLogger(LineBreakpoint.class.getName()).log(Level.WARNING, "no location found for line {0} -> {1}", new Object[]{line, javaLine});
|
||||
return;
|
||||
}
|
||||
// use first found location
|
||||
bpr = dbg.vm().eventRequestManager().createBreakpointRequest(locations.get(0));
|
||||
bpr.enable();
|
||||
Logger.getLogger(LineBreakpoint.class.getName()).log(Level.INFO, "attached breakpoint to {0} -> {1}", new Object[]{line, javaLine});
|
||||
} catch (AbsentInformationException ex) {
|
||||
Logger.getLogger(Debugger.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detach this breakpoint from the VM. Deletes the
|
||||
* {@link BreakpointRequest}.
|
||||
*/
|
||||
protected void detach() {
|
||||
if (bpr != null) {
|
||||
dbg.vm().eventRequestManager().deleteEventRequest(bpr);
|
||||
bpr = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this breakpoint. Adds the line highlight. If Debugger is paused also
|
||||
* attaches the breakpoint by calling {@link #attach()}.
|
||||
*/
|
||||
protected void set() {
|
||||
dbg.addClassLoadListener(this); // class may not yet be loaded
|
||||
dbg.editor().addBreakpointedLine(line);
|
||||
if (theClass != null && dbg.isPaused()) { // class is loaded
|
||||
// immediately activate the breakpoint
|
||||
attach();
|
||||
}
|
||||
if (dbg.editor().isInCurrentTab(line)) {
|
||||
dbg.editor().getSketch().setModified(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove this breakpoint. Clears the highlight and detaches the breakpoint
|
||||
* if the debugger is paused.
|
||||
*/
|
||||
public void remove() {
|
||||
dbg.removeClassLoadListener(this);
|
||||
//System.out.println("removing " + line.lineIdx());
|
||||
dbg.editor().removeBreakpointedLine(line.lineIdx());
|
||||
if (dbg.isPaused()) {
|
||||
// immediately remove the breakpoint
|
||||
detach();
|
||||
}
|
||||
line.stopTracking();
|
||||
if (dbg.editor().isInCurrentTab(line)) {
|
||||
dbg.editor().getSketch().setModified(true);
|
||||
}
|
||||
}
|
||||
|
||||
// public void enable() {
|
||||
// }
|
||||
//
|
||||
// public void disable() {
|
||||
// }
|
||||
@Override
|
||||
public String toString() {
|
||||
return line.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the class this breakpoint belongs to. Needed for fetching
|
||||
* the right location to create a breakpoint request.
|
||||
*
|
||||
* @return the class name
|
||||
*/
|
||||
protected String className() {
|
||||
if (line.fileName().endsWith(".pde")) {
|
||||
// standard tab
|
||||
ReferenceType mainClass = dbg.getMainClass();
|
||||
if (mainClass == null) {
|
||||
return null;
|
||||
}
|
||||
return dbg.getMainClass().name();
|
||||
}
|
||||
|
||||
if (line.fileName().endsWith(".java")) {
|
||||
// pure java tab
|
||||
return line.fileName().substring(0, line.fileName().lastIndexOf(".java"));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event handler called when a class is loaded in the debugger. Causes the
|
||||
* breakpoint to be attached, if its class was loaded.
|
||||
*
|
||||
* @param theClass the class that was just loaded.
|
||||
*/
|
||||
@Override
|
||||
public void classLoaded(ReferenceType theClass) {
|
||||
// check if our class is being loaded
|
||||
if (theClass.name().equals(className())) {
|
||||
this.theClass = theClass;
|
||||
attach();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,196 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Martin Leopold <m@martinleopold.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
package processing.mode.experimental;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Model/Controller for a highlighted source code line. Implements a custom
|
||||
* background color and a text based marker placed in the left-hand gutter area.
|
||||
*
|
||||
* @author Martin Leopold <m@martinleopold.com>
|
||||
*/
|
||||
public class LineHighlight implements LineListener {
|
||||
|
||||
protected DebugEditor editor; // the view, used for highlighting lines by setting a background color
|
||||
protected Color bgColor; // the background color for highlighting lines
|
||||
protected LineID lineID; // the id of the line
|
||||
protected String marker; //
|
||||
protected Color markerColor;
|
||||
protected int priority = 0;
|
||||
protected static Set<LineHighlight> allHighlights = new HashSet();
|
||||
|
||||
protected static boolean isHighestPriority(LineHighlight hl) {
|
||||
for (LineHighlight check : allHighlights) {
|
||||
if (check.lineID().equals(hl.lineID()) && check.priority() > hl.priority()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link LineHighlight}.
|
||||
*
|
||||
* @param lineID the line id to highlight
|
||||
* @param bgColor the background color used for highlighting
|
||||
* @param editor the {@link DebugEditor}
|
||||
*/
|
||||
public LineHighlight(LineID lineID, Color bgColor, DebugEditor editor) {
|
||||
this.lineID = lineID;
|
||||
this.bgColor = bgColor;
|
||||
this.editor = editor;
|
||||
lineID.addListener(this);
|
||||
lineID.startTracking(editor.getTab(lineID.fileName()).getDocument()); // TODO: overwrite a previous doc?
|
||||
paint(); // already checks if on current tab
|
||||
allHighlights.add(this);
|
||||
}
|
||||
|
||||
public void setPriority(int p) {
|
||||
this.priority = p;
|
||||
}
|
||||
|
||||
public int priority() {
|
||||
return priority;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link LineHighlight} on the current tab.
|
||||
*
|
||||
* @param lineIdx the line index on the current tab to highlight
|
||||
* @param bgColor the background color used for highlighting
|
||||
* @param editor the {@link DebugEditor}
|
||||
*/
|
||||
// TODO: Remove and replace by {@link #LineHighlight(LineID lineID, Color bgColor, DebugEditor editor)}
|
||||
public LineHighlight(int lineIdx, Color bgColor, DebugEditor editor) {
|
||||
this(editor.getLineIDInCurrentTab(lineIdx), bgColor, editor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a text based marker displayed in the left hand gutter area of this
|
||||
* highlighted line.
|
||||
*
|
||||
* @param marker the marker text
|
||||
*/
|
||||
public void setMarker(String marker) {
|
||||
this.marker = marker;
|
||||
paint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a text based marker displayed in the left hand gutter area of this
|
||||
* highlighted line. Also use a custom text color.
|
||||
*
|
||||
* @param marker the marker text
|
||||
* @param markerColor the text color
|
||||
*/
|
||||
public void setMarker(String marker, Color markerColor) {
|
||||
this.markerColor = markerColor;
|
||||
setMarker(marker);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the line id of this {@link LineHighlight}.
|
||||
*
|
||||
* @return the line id
|
||||
*/
|
||||
public LineID lineID() {
|
||||
return lineID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the color for highlighting this line.
|
||||
*
|
||||
* @return the highlight color.
|
||||
*/
|
||||
public Color getColor() {
|
||||
return bgColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if this highlight is on a certain line.
|
||||
*
|
||||
* @param testLine the line to test
|
||||
* @return true if this highlight is on the given line
|
||||
*/
|
||||
public boolean isOnLine(LineID testLine) {
|
||||
return lineID.equals(testLine);
|
||||
}
|
||||
|
||||
/**
|
||||
* Event handler for line number changes (due to editing). Will remove the
|
||||
* highlight from the old line number and repaint it at the new location.
|
||||
*
|
||||
* @param line the line that has changed
|
||||
* @param oldLineIdx the old line index (0-based)
|
||||
* @param newLineIdx the new line index (0-based)
|
||||
*/
|
||||
@Override
|
||||
public void lineChanged(LineID line, int oldLineIdx, int newLineIdx) {
|
||||
// clear old line
|
||||
if (editor.isInCurrentTab(new LineID(line.fileName(), oldLineIdx))) {
|
||||
editor.textArea().clearLineBgColor(oldLineIdx);
|
||||
editor.textArea().clearGutterText(oldLineIdx);
|
||||
}
|
||||
|
||||
// paint new line
|
||||
// but only if it's on top -> fixes current line being hidden by breakpoint moving it down.
|
||||
// lineChanged events seem to come in inverse order of startTracking the LineID. (and bp is created first...)
|
||||
if (LineHighlight.isHighestPriority(this)) {
|
||||
paint();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify this line highlight that it is no longer used. Call this for
|
||||
* cleanup before the {@link LineHighlight} is discarded.
|
||||
*/
|
||||
public void dispose() {
|
||||
lineID.removeListener(this);
|
||||
lineID.stopTracking();
|
||||
allHighlights.remove(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* (Re-)paint this line highlight.
|
||||
*/
|
||||
public void paint() {
|
||||
if (editor.isInCurrentTab(lineID)) {
|
||||
editor.textArea().setLineBgColor(lineID.lineIdx(), bgColor);
|
||||
if (marker != null) {
|
||||
if (markerColor != null) {
|
||||
editor.textArea().setGutterText(lineID.lineIdx(), marker, markerColor);
|
||||
} else {
|
||||
editor.textArea().setGutterText(lineID.lineIdx(), marker);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear this line highlight.
|
||||
*/
|
||||
public void clear() {
|
||||
if (editor.isInCurrentTab(lineID)) {
|
||||
editor.textArea().clearLineBgColor(lineID.lineIdx());
|
||||
editor.textArea().clearGutterText(lineID.lineIdx());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,269 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Martin Leopold <m@martinleopold.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
package processing.mode.experimental;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.event.DocumentListener;
|
||||
import javax.swing.text.BadLocationException;
|
||||
import javax.swing.text.Document;
|
||||
import javax.swing.text.Element;
|
||||
import javax.swing.text.Position;
|
||||
|
||||
/**
|
||||
* Describes an ID for a code line. Comprised of a file name and a (0-based)
|
||||
* line number. Can track changes to the line number due to text editing by
|
||||
* attaching a {@link Document}. Registered {@link LineListener}s are notified
|
||||
* of changes to the line number.
|
||||
*
|
||||
* @author Martin Leopold <m@martinleopold.com>
|
||||
*/
|
||||
public class LineID implements DocumentListener {
|
||||
|
||||
protected String fileName; // the filename
|
||||
protected int lineIdx; // the line number, 0-based
|
||||
protected Document doc; // the Document to use for line number tracking
|
||||
protected Position pos; // the Position acquired during line number tracking
|
||||
protected Set<LineListener> listeners = new HashSet(); // listeners for line number changes
|
||||
|
||||
public LineID(String fileName, int lineIdx) {
|
||||
this.fileName = fileName;
|
||||
this.lineIdx = lineIdx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file name of this line.
|
||||
*
|
||||
* @return the file name
|
||||
*/
|
||||
public String fileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the (0-based) line number of this line.
|
||||
*
|
||||
* @return the line index (i.e. line number, starting at 0)
|
||||
*/
|
||||
public synchronized int lineIdx() {
|
||||
return lineIdx;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return toString().hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether this {@link LineID} is equal to another object. Two
|
||||
* {@link LineID}'s are equal when both their fileName and lineNo are equal.
|
||||
*
|
||||
* @param obj the object to test for equality
|
||||
* @return {@code true} if equal
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final LineID other = (LineID) obj;
|
||||
if ((this.fileName == null) ? (other.fileName != null) : !this.fileName.equals(other.fileName)) {
|
||||
return false;
|
||||
}
|
||||
if (this.lineIdx != other.lineIdx) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output a string representation in the form fileName:lineIdx+1. Note this
|
||||
* uses a 1-based line number as is customary for human-readable line
|
||||
* numbers.
|
||||
*
|
||||
* @return the string representation of this line ID
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return fileName + ":" + (lineIdx + 1);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Retrieve a copy of this line ID.
|
||||
// *
|
||||
// * @return the copy
|
||||
// */
|
||||
// @Override
|
||||
// public LineID clone() {
|
||||
// return new LineID(fileName, lineIdx);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Attach a {@link Document} to enable line number tracking when editing.
|
||||
* The position to track is before the first non-whitespace character on the
|
||||
* line. Edits happening before that position will cause the line number to
|
||||
* update accordingly. Multiple {@link #startTracking} calls will replace
|
||||
* the tracked document. Whoever wants a tracked line should track it and
|
||||
* add itself as listener if necessary.
|
||||
* ({@link LineHighlight}, {@link LineBreakpoint})
|
||||
*
|
||||
* @param doc the {@link Document} to use for line number tracking
|
||||
*/
|
||||
public synchronized void startTracking(Document doc) {
|
||||
//System.out.println("tracking: " + this);
|
||||
if (doc == null) {
|
||||
return; // null arg
|
||||
}
|
||||
if (doc == this.doc) {
|
||||
return; // already tracking that doc
|
||||
}
|
||||
try {
|
||||
Element line = doc.getDefaultRootElement().getElement(lineIdx);
|
||||
if (line == null) {
|
||||
return; // line doesn't exist
|
||||
}
|
||||
String lineText = doc.getText(line.getStartOffset(), line.getEndOffset() - line.getStartOffset());
|
||||
// set tracking position at (=before) first non-white space character on line
|
||||
pos = doc.createPosition(line.getStartOffset() + nonWhiteSpaceOffset(lineText));
|
||||
this.doc = doc;
|
||||
doc.addDocumentListener(this);
|
||||
} catch (BadLocationException ex) {
|
||||
Logger.getLogger(LineID.class.getName()).log(Level.SEVERE, null, ex);
|
||||
pos = null;
|
||||
this.doc = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify this {@link LineID} that it is no longer in use. Will stop
|
||||
* position tracking. Call this when this {@link LineID} is no longer
|
||||
* needed.
|
||||
*/
|
||||
public synchronized void stopTracking() {
|
||||
if (doc != null) {
|
||||
doc.removeDocumentListener(this);
|
||||
doc = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the tracked position. Will notify listeners if line number has
|
||||
* changed.
|
||||
*/
|
||||
protected synchronized void updatePosition() {
|
||||
if (doc != null && pos != null) {
|
||||
// track position
|
||||
int offset = pos.getOffset();
|
||||
int oldLineIdx = lineIdx;
|
||||
lineIdx = doc.getDefaultRootElement().getElementIndex(offset); // offset to lineNo
|
||||
if (lineIdx != oldLineIdx) {
|
||||
for (LineListener l : listeners) {
|
||||
if (l != null) {
|
||||
l.lineChanged(this, oldLineIdx, lineIdx);
|
||||
} else {
|
||||
listeners.remove(l); // remove null listener
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add listener to be notified when the line number changes.
|
||||
*
|
||||
* @param l the listener to add
|
||||
*/
|
||||
public void addListener(LineListener l) {
|
||||
listeners.add(l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a listener for line number changes.
|
||||
*
|
||||
* @param l the listener to remove
|
||||
*/
|
||||
public void removeListener(LineListener l) {
|
||||
listeners.remove(l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the offset of the first non-whitespace character in a string.
|
||||
*
|
||||
* @param str the string to examine
|
||||
* @return offset of first non-whitespace character in str
|
||||
*/
|
||||
protected static int nonWhiteSpaceOffset(String str) {
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
if (!Character.isWhitespace(str.charAt(i))) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return str.length();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the {@link Document} registered using {@link #startTracking}
|
||||
* is edited. This happens when text is inserted or removed.
|
||||
*
|
||||
* @param de
|
||||
*/
|
||||
protected void editEvent(DocumentEvent de) {
|
||||
//System.out.println("document edit @ " + de.getOffset());
|
||||
if (de.getOffset() <= pos.getOffset()) {
|
||||
updatePosition();
|
||||
//System.out.println("updating, new line no: " + lineNo);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link DocumentListener} callback. Called when text is inserted.
|
||||
*
|
||||
* @param de
|
||||
*/
|
||||
@Override
|
||||
public void insertUpdate(DocumentEvent de) {
|
||||
editEvent(de);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link DocumentListener} callback. Called when text is removed.
|
||||
*
|
||||
* @param de
|
||||
*/
|
||||
@Override
|
||||
public void removeUpdate(DocumentEvent de) {
|
||||
editEvent(de);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link DocumentListener} callback. Called when attributes are changed.
|
||||
* Not used.
|
||||
*
|
||||
* @param de
|
||||
*/
|
||||
@Override
|
||||
public void changedUpdate(DocumentEvent de) {
|
||||
// not needed.
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Martin Leopold <m@martinleopold.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
package processing.mode.experimental;
|
||||
|
||||
/**
|
||||
* A Listener for line number changes.
|
||||
*
|
||||
* @author Martin Leopold <m@martinleopold.com>
|
||||
*/
|
||||
public interface LineListener {
|
||||
|
||||
/**
|
||||
* Event handler for line number changes (due to editing).
|
||||
*
|
||||
* @param line the line that has changed
|
||||
* @param oldLineIdx the old line index (0-based)
|
||||
* @param newLineIdx the new line index (0-based)
|
||||
*/
|
||||
void lineChanged(LineID line, int oldLineIdx, int newLineIdx);
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Martin Leopold <m@martinleopold.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
package processing.mode.experimental;
|
||||
|
||||
import com.sun.jdi.ClassNotLoadedException;
|
||||
import com.sun.jdi.InvalidTypeException;
|
||||
import com.sun.jdi.LocalVariable;
|
||||
import com.sun.jdi.StackFrame;
|
||||
import com.sun.jdi.Value;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Specialized {@link VariableNode} for representing local variables. Overrides
|
||||
* {@link #setValue} to properly change the value of the encapsulated local
|
||||
* variable.
|
||||
*
|
||||
* @author Martin Leopold <m@martinleopold.com>
|
||||
*/
|
||||
public class LocalVariableNode extends VariableNode {
|
||||
|
||||
protected LocalVariable var;
|
||||
protected StackFrame frame;
|
||||
|
||||
/**
|
||||
* Construct a {@link LocalVariableNode}.
|
||||
*
|
||||
* @param name the name
|
||||
* @param type the type
|
||||
* @param value the value
|
||||
* @param var the local variable
|
||||
* @param frame the stack frame containing the local variable
|
||||
*/
|
||||
public LocalVariableNode(String name, String type, Value value, LocalVariable var, StackFrame frame) {
|
||||
super(name, type, value);
|
||||
this.var = var;
|
||||
this.frame = frame;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(Value value) {
|
||||
try {
|
||||
frame.setValue(var, value);
|
||||
} catch (InvalidTypeException ex) {
|
||||
Logger.getLogger(LocalVariableNode.class.getName()).log(Level.SEVERE, null, ex);
|
||||
} catch (ClassNotLoadedException ex) {
|
||||
Logger.getLogger(LocalVariableNode.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
@@ -1,160 +0,0 @@
|
||||
/*
|
||||
Part of the XQMode project - https://github.com/Manindra29/XQMode
|
||||
|
||||
Under Google Summer of Code 2012 -
|
||||
http://www.google-melange.com/gsoc/homepage/google/gsoc2012
|
||||
|
||||
Copyright (C) 2012 Manindra Moharana
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2
|
||||
as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.mode.experimental;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.eclipse.jdt.core.compiler.IProblem;
|
||||
|
||||
/**
|
||||
* Wrapper class for IProblem.
|
||||
*
|
||||
* Stores the tabIndex and line number according to its tab, including the
|
||||
* original IProblem object
|
||||
*
|
||||
* @author Manindra Moharana <me@mkmoharana.com>
|
||||
*
|
||||
*/
|
||||
public class Problem {
|
||||
/**
|
||||
* The IProblem which is being wrapped
|
||||
*/
|
||||
private IProblem iProblem;
|
||||
/**
|
||||
* The tab number to which the error belongs to
|
||||
*/
|
||||
public int tabIndex;
|
||||
/**
|
||||
* Line number(pde code) of the error
|
||||
*/
|
||||
public int lineNumber;
|
||||
|
||||
/**
|
||||
* Error Message. Processed form of IProblem.getMessage()
|
||||
*/
|
||||
public String message;
|
||||
|
||||
/**
|
||||
* The type of error - WARNING or ERROR.
|
||||
*/
|
||||
public int type;
|
||||
|
||||
public static final int ERROR = 1, WARNING = 2;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param iProblem - The IProblem which is being wrapped
|
||||
* @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) {
|
||||
this.iProblem = iProblem;
|
||||
if(iProblem.isError()) {
|
||||
type = ERROR;
|
||||
}
|
||||
else if(iProblem.isWarning()) {
|
||||
type = WARNING;
|
||||
}
|
||||
this.tabIndex = tabIndex;
|
||||
this.lineNumber = lineNumber;
|
||||
this.message = process(iProblem);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return new String("TAB " + tabIndex + ",LN " + lineNumber + ",PROB: "
|
||||
+ message);
|
||||
}
|
||||
|
||||
public boolean isError(){
|
||||
return type == ERROR;
|
||||
}
|
||||
|
||||
public boolean isWarning(){
|
||||
return type == WARNING;
|
||||
}
|
||||
|
||||
public String getMessage(){
|
||||
return message;
|
||||
}
|
||||
|
||||
public IProblem getIProblem(){
|
||||
return iProblem;
|
||||
}
|
||||
|
||||
public void setType(int ProblemType){
|
||||
if(ProblemType == ERROR)
|
||||
type = ERROR;
|
||||
else if(ProblemType == WARNING)
|
||||
type = WARNING;
|
||||
else throw new IllegalArgumentException("Illegal Problem type passed to Problem.setType(int)");
|
||||
}
|
||||
|
||||
private static Pattern pattern;
|
||||
private static Matcher matcher;
|
||||
|
||||
private static final String tokenRegExp = "\\b token\\b";
|
||||
|
||||
public static String process(IProblem problem) {
|
||||
return process(problem.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes error messages and attempts to make them a bit more english like.
|
||||
* Currently performs:
|
||||
* <li>Remove all instances of token. "Syntax error on token 'blah', delete this token"
|
||||
* becomes "Syntax error on 'blah', delete this"
|
||||
* @param message - The message to be processed
|
||||
* @return String - The processed message
|
||||
*/
|
||||
public static String process(String message) {
|
||||
// Remove all instances of token
|
||||
// "Syntax error on token 'blah', delete this token"
|
||||
if(message == null) return null;
|
||||
pattern = Pattern.compile(tokenRegExp);
|
||||
matcher = pattern.matcher(message);
|
||||
message = matcher.replaceAll("");
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
// Split camel case words into separate words.
|
||||
// "VaraibleDeclaration" becomes "Variable Declaration"
|
||||
// But sadly "PApplet" become "P Applet" and so on.
|
||||
public static String splitCamelCaseWord(String word) {
|
||||
String newWord = "";
|
||||
for (int i = 1; i < word.length(); i++) {
|
||||
if (Character.isUpperCase(word.charAt(i))) {
|
||||
// System.out.println(word.substring(0, i) + " "
|
||||
// + word.substring(i));
|
||||
newWord += word.substring(0, i) + " ";
|
||||
word = word.substring(i);
|
||||
i = 1;
|
||||
}
|
||||
}
|
||||
newWord += word;
|
||||
// System.out.println(newWord);
|
||||
return newWord.trim();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,630 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Martin Leopold <m@martinleopold.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
package processing.mode.experimental;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Cursor;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Point;
|
||||
import java.awt.event.ComponentListener;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.KeyListener;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.awt.event.MouseMotionListener;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.text.BadLocationException;
|
||||
|
||||
import processing.app.syntax.JEditTextArea;
|
||||
import processing.app.syntax.TextAreaDefaults;
|
||||
|
||||
/**
|
||||
* Customized text area. Adds support for line background colors.
|
||||
*
|
||||
* @author Martin Leopold <m@martinleopold.com>
|
||||
*/
|
||||
public class TextArea extends JEditTextArea {
|
||||
|
||||
protected MouseListener[] mouseListeners; // cached mouselisteners, these are wrapped by MouseHandler
|
||||
|
||||
protected DebugEditor editor; // the editor
|
||||
|
||||
// line properties
|
||||
protected Map<Integer, Color> lineColors = new HashMap(); // contains line background colors
|
||||
|
||||
// left-hand gutter properties
|
||||
protected int gutterPadding = 3; // [px] space added to the left and right of gutter chars
|
||||
|
||||
protected Color gutterBgColor = new Color(252, 252, 252); // gutter background color
|
||||
|
||||
protected Color gutterLineColor = new Color(233, 233, 233); // color of vertical separation line
|
||||
|
||||
protected String breakpointMarker = "<>"; // the text marker for highlighting breakpoints in the gutter
|
||||
|
||||
protected String currentLineMarker = "->"; // the text marker for highlighting the current line in the gutter
|
||||
|
||||
protected Map<Integer, String> gutterText = new HashMap(); // maps line index to gutter text
|
||||
|
||||
protected Map<Integer, Color> gutterTextColors = new HashMap(); // maps line index to gutter text color
|
||||
|
||||
protected TextAreaPainter customPainter;
|
||||
|
||||
protected ErrorCheckerService errorCheckerService;
|
||||
|
||||
public TextArea(TextAreaDefaults defaults, DebugEditor editor) {
|
||||
super(defaults);
|
||||
this.editor = editor;
|
||||
|
||||
// replace the painter:
|
||||
// first save listeners, these are package-private in JEditTextArea, so not accessible
|
||||
ComponentListener[] componentListeners = painter.getComponentListeners();
|
||||
mouseListeners = painter.getMouseListeners();
|
||||
MouseMotionListener[] mouseMotionListeners = painter
|
||||
.getMouseMotionListeners();
|
||||
|
||||
remove(painter);
|
||||
|
||||
// set new painter
|
||||
customPainter = new TextAreaPainter(this, defaults);
|
||||
painter = customPainter;
|
||||
|
||||
// set listeners
|
||||
for (ComponentListener cl : componentListeners) {
|
||||
painter.addComponentListener(cl);
|
||||
}
|
||||
|
||||
for (MouseMotionListener mml : mouseMotionListeners) {
|
||||
painter.addMouseMotionListener(mml);
|
||||
}
|
||||
|
||||
// use a custom mouse handler instead of directly using mouseListeners
|
||||
MouseHandler mouseHandler = new MouseHandler();
|
||||
painter.addMouseListener(mouseHandler);
|
||||
painter.addMouseMotionListener(mouseHandler);
|
||||
addCompletionPopupListner();
|
||||
add(CENTER, painter);
|
||||
|
||||
// load settings from theme.txt
|
||||
ExperimentalMode theme = (ExperimentalMode) editor.getMode();
|
||||
gutterBgColor = theme.getThemeColor("gutter.bgcolor", gutterBgColor);
|
||||
gutterLineColor = theme.getThemeColor("gutter.linecolor", gutterLineColor);
|
||||
gutterPadding = theme.getInteger("gutter.padding");
|
||||
breakpointMarker = theme.loadThemeString("breakpoint.marker",
|
||||
breakpointMarker);
|
||||
currentLineMarker = theme.loadThemeString("currentline.marker",
|
||||
currentLineMarker);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets ErrorCheckerService and loads theme for TextArea(XQMode)
|
||||
*
|
||||
* @param ecs
|
||||
* @param mode
|
||||
*/
|
||||
public void setECSandThemeforTextArea(ErrorCheckerService ecs,
|
||||
ExperimentalMode mode) {
|
||||
errorCheckerService = ecs;
|
||||
customPainter.setECSandTheme(ecs, mode);
|
||||
}
|
||||
|
||||
public void processKeyEvent(KeyEvent evt) {
|
||||
if (evt.getID() == KeyEvent.KEY_PRESSED) {
|
||||
if (evt.getKeyCode() == KeyEvent.VK_DOWN && suggestion != null) {
|
||||
if (suggestion.isVisible()) {
|
||||
//System.out.println("KeyDown");
|
||||
suggestion.moveDown();
|
||||
return;
|
||||
}
|
||||
} else if (evt.getKeyCode() == KeyEvent.VK_UP && suggestion != null) {
|
||||
if (suggestion.isVisible()) {
|
||||
//System.out.println("KeyUp");
|
||||
suggestion.moveUp();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (evt.getKeyChar() == KeyEvent.VK_ENTER) {
|
||||
if (suggestion != null) {
|
||||
if (suggestion.isVisible()){
|
||||
if (suggestion.insertSelection()) {
|
||||
final int position = getCaretPosition();
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
//getDocument().remove(position - 1, 1);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (evt.getKeyChar() == KeyEvent.VK_BACK_SPACE) {
|
||||
System.out.println("BK Key");
|
||||
}
|
||||
}
|
||||
|
||||
super.processKeyEvent(evt);
|
||||
if (evt.getID() == KeyEvent.KEY_TYPED) {
|
||||
errorCheckerService.textModified.incrementAndGet();
|
||||
System.out.println(" Typing: " + fetchPhrase(evt) + " "
|
||||
+ (evt.getKeyChar() == KeyEvent.VK_BACK_SPACE));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private String fetchPhrase(KeyEvent evt) {
|
||||
int off = getCaretPosition();
|
||||
System.out.print("off " + off);
|
||||
if (off < 0)
|
||||
return null;
|
||||
int line = getCaretLine();
|
||||
if (line < 0)
|
||||
return null;
|
||||
String s = getLineText(line);
|
||||
System.out.print("lin " + line);
|
||||
/*
|
||||
* if (s == null) return null; else if (s.length() == 0) return null;
|
||||
*/
|
||||
// else {
|
||||
//System.out.print(s + " len " + s.length());
|
||||
|
||||
int x = getCaretPosition() - getLineStartOffset(line) - 1, x2 = x + 1, x1 = x - 1;
|
||||
if(x >= s.length() || x < 0)
|
||||
return null; //TODO: Does this check cause problems? Verify.
|
||||
System.out.print(" x char: " + s.charAt(x));
|
||||
//int xLS = off - getLineStartNonWhiteSpaceOffset(line);
|
||||
char keyChar = evt.getKeyChar();
|
||||
if (keyChar == KeyEvent.VK_BACK_SPACE || keyChar == KeyEvent.VK_DELETE)
|
||||
; // accepted these keys
|
||||
else if (keyChar == KeyEvent.CHAR_UNDEFINED)
|
||||
|
||||
return null;
|
||||
|
||||
String word = (x < s.length() ? s.charAt(x) : "") + "";
|
||||
if (s.trim().length() == 1) {
|
||||
// word = ""
|
||||
// + (keyChar == KeyEvent.CHAR_UNDEFINED ? s.charAt(x - 1) : keyChar);
|
||||
//word = (x < s.length()?s.charAt(x):"") + "";
|
||||
word = word.trim();
|
||||
if (word.endsWith("."))
|
||||
word = word.substring(0, word.length() - 1);
|
||||
errorCheckerService.astGenerator.updatePredictions(word, line
|
||||
+ errorCheckerService.mainClassOffset);
|
||||
return word;
|
||||
}
|
||||
// if (keyChar == KeyEvent.VK_BACK_SPACE || keyChar == KeyEvent.VK_DELETE)
|
||||
// ; // accepted these keys
|
||||
// else if (!(Character.isLetterOrDigit(keyChar) || keyChar == '_' || keyChar == '$'))
|
||||
// return null;
|
||||
int i = 0;
|
||||
int closeB = 0;
|
||||
|
||||
while (true) {
|
||||
i++;
|
||||
//TODO: currently works on single line only. "a. <new line> b()" won't be detected
|
||||
if (x1 >= 0) {
|
||||
// if (s.charAt(x1) != ';' && s.charAt(x1) != ',' && s.charAt(x1) != '(')
|
||||
if (Character.isLetterOrDigit(s.charAt(x1)) || s.charAt(x1) == '_'
|
||||
|| s.charAt(x1) == '.' || s.charAt(x1) == ')') {
|
||||
|
||||
if (s.charAt(x1) == ')') {
|
||||
word = s.charAt(x1--) + word;
|
||||
closeB++;
|
||||
while (x1 >= 0 && closeB > 0) {
|
||||
word = s.charAt(x1) + word;
|
||||
if (s.charAt(x1) == '(')
|
||||
closeB--;
|
||||
if (s.charAt(x1) == ')')
|
||||
closeB++;
|
||||
x1--;
|
||||
}
|
||||
} else {
|
||||
word = s.charAt(x1--) + word;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
// if (x2 >= 0 && x2 < s.length()) {
|
||||
// if (Character.isLetterOrDigit(s.charAt(x2)) || s.charAt(x2) == '_'
|
||||
// || s.charAt(x2) == '$')
|
||||
// word = word + s.charAt(x2++);
|
||||
// else
|
||||
// x2 = -1;
|
||||
// } else
|
||||
// x2 = -1;
|
||||
|
||||
// if (x1 < 0 )//&& x2 < 0
|
||||
// break;
|
||||
if (i > 200) {
|
||||
// time out!
|
||||
System.err.println("Whoopsy! :P");
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if (keyChar != KeyEvent.CHAR_UNDEFINED)
|
||||
|
||||
if (Character.isDigit(word.charAt(0)))
|
||||
return null;
|
||||
word = word.trim();
|
||||
// if (word.endsWith("."))
|
||||
// word = word.substring(0, word.length() - 1);
|
||||
errorCheckerService.astGenerator.updatePredictions(word, line
|
||||
+ errorCheckerService.mainClassOffset);
|
||||
//showSuggestionLater();
|
||||
return word;
|
||||
|
||||
//}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the total width of the gutter area.
|
||||
*
|
||||
* @return gutter width in pixels
|
||||
*/
|
||||
protected int getGutterWidth() {
|
||||
FontMetrics fm = painter.getFontMetrics();
|
||||
// System.out.println("fm: " + (fm == null));
|
||||
// System.out.println("editor: " + (editor == null));
|
||||
//System.out.println("BPBPBPBPB: " + (editor.breakpointMarker == null));
|
||||
|
||||
int textWidth = Math.max(fm.stringWidth(breakpointMarker),
|
||||
fm.stringWidth(currentLineMarker));
|
||||
return textWidth + 2 * gutterPadding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the width of margins applied to the left and right of the gutter
|
||||
* text.
|
||||
*
|
||||
* @return margins in pixels
|
||||
*/
|
||||
protected int getGutterMargins() {
|
||||
return gutterPadding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the gutter text of a specific line.
|
||||
*
|
||||
* @param lineIdx
|
||||
* the line index (0-based)
|
||||
* @param text
|
||||
* the text
|
||||
*/
|
||||
public void setGutterText(int lineIdx, String text) {
|
||||
gutterText.put(lineIdx, text);
|
||||
painter.invalidateLine(lineIdx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the gutter text and color of a specific line.
|
||||
*
|
||||
* @param lineIdx
|
||||
* the line index (0-based)
|
||||
* @param text
|
||||
* the text
|
||||
* @param textColor
|
||||
* the text color
|
||||
*/
|
||||
public void setGutterText(int lineIdx, String text, Color textColor) {
|
||||
gutterTextColors.put(lineIdx, textColor);
|
||||
setGutterText(lineIdx, text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the gutter text of a specific line.
|
||||
*
|
||||
* @param lineIdx
|
||||
* the line index (0-based)
|
||||
*/
|
||||
public void clearGutterText(int lineIdx) {
|
||||
gutterText.remove(lineIdx);
|
||||
painter.invalidateLine(lineIdx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all gutter text.
|
||||
*/
|
||||
public void clearGutterText() {
|
||||
for (int lineIdx : gutterText.keySet()) {
|
||||
painter.invalidateLine(lineIdx);
|
||||
}
|
||||
gutterText.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the gutter text of a specific line.
|
||||
*
|
||||
* @param lineIdx
|
||||
* the line index (0-based)
|
||||
* @return the gutter text
|
||||
*/
|
||||
public String getGutterText(int lineIdx) {
|
||||
return gutterText.get(lineIdx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the gutter text color for a specific line.
|
||||
*
|
||||
* @param lineIdx
|
||||
* the line index
|
||||
* @return the gutter text color
|
||||
*/
|
||||
public Color getGutterTextColor(int lineIdx) {
|
||||
return gutterTextColors.get(lineIdx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the background color of a line.
|
||||
*
|
||||
* @param lineIdx
|
||||
* 0-based line number
|
||||
* @param col
|
||||
* the background color to set
|
||||
*/
|
||||
public void setLineBgColor(int lineIdx, Color col) {
|
||||
lineColors.put(lineIdx, col);
|
||||
painter.invalidateLine(lineIdx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the background color of a line.
|
||||
*
|
||||
* @param lineIdx
|
||||
* 0-based line number
|
||||
*/
|
||||
public void clearLineBgColor(int lineIdx) {
|
||||
lineColors.remove(lineIdx);
|
||||
painter.invalidateLine(lineIdx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all line background colors.
|
||||
*/
|
||||
public void clearLineBgColors() {
|
||||
for (int lineIdx : lineColors.keySet()) {
|
||||
painter.invalidateLine(lineIdx);
|
||||
}
|
||||
lineColors.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a lines background color.
|
||||
*
|
||||
* @param lineIdx
|
||||
* 0-based line number
|
||||
* @return the color or null if no color was set for the specified line
|
||||
*/
|
||||
public Color getLineBgColor(int lineIdx) {
|
||||
return lineColors.get(lineIdx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a character offset to a horizontal pixel position inside the text
|
||||
* area. Overridden to take gutter width into account.
|
||||
*
|
||||
* @param line
|
||||
* the 0-based line number
|
||||
* @param offset
|
||||
* the character offset (0 is the first character on a line)
|
||||
* @return the horizontal position
|
||||
*/
|
||||
@Override
|
||||
public int _offsetToX(int line, int offset) {
|
||||
return super._offsetToX(line, offset) + getGutterWidth();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a horizontal pixel position to a character offset. Overridden to
|
||||
* take gutter width into account.
|
||||
*
|
||||
* @param line
|
||||
* the 0-based line number
|
||||
* @param x
|
||||
* the horizontal pixel position
|
||||
* @return he character offset (0 is the first character on a line)
|
||||
*/
|
||||
@Override
|
||||
public int xToOffset(int line, int x) {
|
||||
return super.xToOffset(line, x - getGutterWidth());
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom mouse handler. Implements double clicking in the gutter area to
|
||||
* toggle breakpoints, sets default cursor (instead of text cursor) in the
|
||||
* gutter area.
|
||||
*/
|
||||
protected class MouseHandler implements MouseListener, MouseMotionListener {
|
||||
|
||||
protected int lastX; // previous horizontal positon of the mouse cursor
|
||||
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent me) {
|
||||
// forward to standard listeners
|
||||
for (MouseListener ml : mouseListeners) {
|
||||
ml.mouseClicked(me);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed(MouseEvent me) {
|
||||
// check if this happened in the gutter area
|
||||
if (me.getX() < getGutterWidth()) {
|
||||
if (me.getButton() == MouseEvent.BUTTON1 && me.getClickCount() == 2) {
|
||||
int line = me.getY() / painter.getFontMetrics().getHeight()
|
||||
+ firstLine;
|
||||
if (line >= 0 && line <= getLineCount() - 1) {
|
||||
editor.gutterDblClicked(line);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// forward to standard listeners
|
||||
for (MouseListener ml : mouseListeners) {
|
||||
ml.mousePressed(me);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent me) {
|
||||
// forward to standard listeners
|
||||
for (MouseListener ml : mouseListeners) {
|
||||
ml.mouseReleased(me);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent me) {
|
||||
// forward to standard listeners
|
||||
for (MouseListener ml : mouseListeners) {
|
||||
ml.mouseEntered(me);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(MouseEvent me) {
|
||||
// forward to standard listeners
|
||||
for (MouseListener ml : mouseListeners) {
|
||||
ml.mouseExited(me);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDragged(MouseEvent me) {
|
||||
// No need to forward since the standard MouseMotionListeners are called anyway
|
||||
// nop
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseMoved(MouseEvent me) {
|
||||
// No need to forward since the standard MouseMotionListeners are called anyway
|
||||
if (me.getX() < getGutterWidth()) {
|
||||
if (lastX >= getGutterWidth()) {
|
||||
painter.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
|
||||
}
|
||||
} else {
|
||||
if (lastX < getGutterWidth()) {
|
||||
painter.setCursor(new Cursor(Cursor.TEXT_CURSOR));
|
||||
}
|
||||
}
|
||||
lastX = me.getX();
|
||||
}
|
||||
}
|
||||
|
||||
private CompletionPanel suggestion;
|
||||
|
||||
//JEditTextArea textarea;
|
||||
|
||||
private void addCompletionPopupListner() {
|
||||
this.addKeyListener(new KeyListener() {
|
||||
|
||||
@Override
|
||||
public void keyTyped(KeyEvent e) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyReleased(KeyEvent e) {
|
||||
if (Character.isLetterOrDigit(e.getKeyChar())
|
||||
|| e.getKeyChar() == KeyEvent.VK_BACK_SPACE
|
||||
|| e.getKeyChar() == KeyEvent.VK_DELETE) {
|
||||
// SwingUtilities.invokeLater(new Runnable() {
|
||||
// @Override
|
||||
// public void run() {
|
||||
// showSuggestion();
|
||||
// }
|
||||
//
|
||||
// });
|
||||
} else if (Character.isWhitespace(e.getKeyChar())) {
|
||||
hideSuggestion();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void showSuggestionLater(final CompletionCandidate[] items) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
showSuggestion(items);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
protected void showSuggestion(CompletionCandidate[] items) {
|
||||
hideSuggestion();
|
||||
final int position = getCaretPosition();
|
||||
Point location = new Point();
|
||||
try {
|
||||
location.x = offsetToX(getCaretLine(), position
|
||||
- getLineStartOffset(getCaretLine()));
|
||||
location.y = lineToY(getCaretLine())
|
||||
+ getPainter().getFontMetrics().getHeight();
|
||||
} catch (Exception e2) {
|
||||
e2.printStackTrace();
|
||||
return;
|
||||
}
|
||||
String text = getText();
|
||||
int start = Math.max(0, position - 1);
|
||||
while (start > 0) {
|
||||
if (!Character.isWhitespace(text.charAt(start))) {
|
||||
start--;
|
||||
} else {
|
||||
start++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (start > position) {
|
||||
return;
|
||||
}
|
||||
final String subWord = text.substring(start, position);
|
||||
if (subWord.length() < 2) {
|
||||
return;
|
||||
}
|
||||
suggestion = new CompletionPanel(this, position, subWord, items, location);
|
||||
// requestFocusInWindow();
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
requestFocusInWindow();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void hideSuggestion() {
|
||||
if (suggestion != null) {
|
||||
suggestion.hide();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,488 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Martin Leopold <m@martinleopold.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
package processing.mode.experimental;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
|
||||
import javax.swing.text.BadLocationException;
|
||||
import javax.swing.text.Segment;
|
||||
import javax.swing.text.Utilities;
|
||||
|
||||
import processing.app.syntax.TextAreaDefaults;
|
||||
import processing.app.syntax.TokenMarker;
|
||||
|
||||
/**
|
||||
* Customized line painter. Adds support for background colors, left hand gutter
|
||||
* area with background color and text.
|
||||
*
|
||||
* @author Martin Leopold <m@martinleopold.com>
|
||||
*/
|
||||
public class TextAreaPainter extends processing.app.syntax.TextAreaPainter {
|
||||
|
||||
protected TextArea ta; // we need the subclassed textarea
|
||||
|
||||
protected ErrorCheckerService errorCheckerService;
|
||||
|
||||
/**
|
||||
* Error line underline color
|
||||
*/
|
||||
public Color errorColor = new Color(0xED2630);
|
||||
|
||||
/**
|
||||
* Warning line underline color
|
||||
*/
|
||||
|
||||
public Color warningColor = new Color(0xFFC30E);
|
||||
|
||||
/**
|
||||
* Color of Error Marker
|
||||
*/
|
||||
public Color errorMarkerColor = new Color(0xED2630);
|
||||
|
||||
/**
|
||||
* Color of Warning Marker
|
||||
*/
|
||||
public Color warningMarkerColor = new Color(0xFFC30E);
|
||||
|
||||
static int ctrlMask = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
|
||||
|
||||
public TextAreaPainter(TextArea textArea, TextAreaDefaults defaults) {
|
||||
super(textArea, defaults);
|
||||
ta = textArea;
|
||||
addMouseListener(new MouseAdapter() {
|
||||
public void mouseClicked(MouseEvent evt) {
|
||||
// System.out.println( " Meta,Ctrl "+ (evt.getModifiers() & ctrlMask));
|
||||
if (evt.isControlDown())
|
||||
handleCtrlClick(evt);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// public void processKeyEvent(KeyEvent evt) {
|
||||
// System.out.println(evt);
|
||||
// }
|
||||
|
||||
void handleCtrlClick(MouseEvent evt) {
|
||||
System.out.println("--handleCtrlClick--");
|
||||
int off = ta.xyToOffset(evt.getX(), evt.getY());
|
||||
if (off < 0)
|
||||
return;
|
||||
int line = ta.getLineOfOffset(off);
|
||||
if (line < 0)
|
||||
return;
|
||||
String s = ta.getLineText(line);
|
||||
if (s == null)
|
||||
return;
|
||||
else if (s.length() == 0)
|
||||
return;
|
||||
else {
|
||||
int x = ta.xToOffset(line, evt.getX()), x2 = x + 1, x1 = x - 1;
|
||||
int xLS = off - ta.getLineStartNonWhiteSpaceOffset(line);
|
||||
if (x < 0 || x >= s.length())
|
||||
return;
|
||||
String word = s.charAt(x) + "";
|
||||
if (s.charAt(x) == ' ')
|
||||
return;
|
||||
if (!(Character.isLetterOrDigit(s.charAt(x)) || s.charAt(x) == '_' || s
|
||||
.charAt(x) == '$'))
|
||||
return;
|
||||
int i = 0;
|
||||
while (true) {
|
||||
i++;
|
||||
if (x1 >= 0 && x1 < s.length()) {
|
||||
if (Character.isLetter(s.charAt(x1)) || s.charAt(x1) == '_') {
|
||||
word = s.charAt(x1--) + word;
|
||||
} else
|
||||
x1 = -1;
|
||||
} else
|
||||
x1 = -1;
|
||||
|
||||
if (x2 >= 0 && x2 < s.length()) {
|
||||
if (Character.isLetterOrDigit(s.charAt(x2)) || s.charAt(x2) == '_'
|
||||
|| s.charAt(x2) == '$')
|
||||
word = word + s.charAt(x2++);
|
||||
else
|
||||
x2 = -1;
|
||||
} else
|
||||
x2 = -1;
|
||||
|
||||
if (x1 < 0 && x2 < 0)
|
||||
break;
|
||||
if (i > 200) {
|
||||
// time out!
|
||||
System.err.println("Whoopsy! :P");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (Character.isDigit(word.charAt(0)))
|
||||
return;
|
||||
|
||||
System.out.print(errorCheckerService.mainClassOffset + line);
|
||||
System.out.print("|" + line + "| offset " + xLS + word + " <= \n");
|
||||
errorCheckerService.astGenerator.scrollToDeclaration(line
|
||||
+ errorCheckerService.mainClassOffset, word, xLS);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadTheme(ExperimentalMode mode) {
|
||||
errorColor = mode.getThemeColor("editor.errorcolor", errorColor);
|
||||
warningColor = mode.getThemeColor("editor.warningcolor", warningColor);
|
||||
errorMarkerColor = mode.getThemeColor("editor.errormarkercolor",
|
||||
errorMarkerColor);
|
||||
warningMarkerColor = mode.getThemeColor("editor.warningmarkercolor",
|
||||
warningMarkerColor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Paint a line. Paints the gutter (with background color and text) then the
|
||||
* line (background color and text).
|
||||
*
|
||||
* @param gfx
|
||||
* the graphics context
|
||||
* @param tokenMarker
|
||||
* @param line
|
||||
* 0-based line number
|
||||
* @param x
|
||||
* horizontal position
|
||||
*/
|
||||
@Override
|
||||
protected void paintLine(Graphics gfx, TokenMarker tokenMarker, int line,
|
||||
int x) {
|
||||
|
||||
// paint gutter
|
||||
paintGutterBg(gfx, line, x);
|
||||
|
||||
paintLineBgColor(gfx, line, x + ta.getGutterWidth());
|
||||
|
||||
paintGutterLine(gfx, line, x);
|
||||
|
||||
// paint gutter symbol
|
||||
paintGutterText(gfx, line, x);
|
||||
|
||||
paintErrorLine(gfx, line, x);
|
||||
|
||||
super.paintLine(gfx, tokenMarker, line, x + ta.getGutterWidth());
|
||||
}
|
||||
|
||||
/**
|
||||
* Paint the gutter background (solid color).
|
||||
*
|
||||
* @param gfx
|
||||
* the graphics context
|
||||
* @param line
|
||||
* 0-based line number
|
||||
* @param x
|
||||
* horizontal position
|
||||
*/
|
||||
protected void paintGutterBg(Graphics gfx, int line, int x) {
|
||||
gfx.setColor(ta.gutterBgColor);
|
||||
int y = ta.lineToY(line) + fm.getLeading() + fm.getMaxDescent();
|
||||
gfx.fillRect(0, y, ta.getGutterWidth(), fm.getHeight());
|
||||
}
|
||||
|
||||
/**
|
||||
* Paint the vertical gutter separator line.
|
||||
*
|
||||
* @param gfx
|
||||
* the graphics context
|
||||
* @param line
|
||||
* 0-based line number
|
||||
* @param x
|
||||
* horizontal position
|
||||
*/
|
||||
protected void paintGutterLine(Graphics gfx, int line, int x) {
|
||||
int y = ta.lineToY(line) + fm.getLeading() + fm.getMaxDescent();
|
||||
gfx.setColor(ta.gutterLineColor);
|
||||
gfx.drawLine(ta.getGutterWidth(), y, ta.getGutterWidth(),
|
||||
y + fm.getHeight());
|
||||
}
|
||||
|
||||
/**
|
||||
* Paint the gutter text.
|
||||
*
|
||||
* @param gfx
|
||||
* the graphics context
|
||||
* @param line
|
||||
* 0-based line number
|
||||
* @param x
|
||||
* horizontal position
|
||||
*/
|
||||
protected void paintGutterText(Graphics gfx, int line, int x) {
|
||||
String text = ta.getGutterText(line);
|
||||
if (text == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
gfx.setFont(getFont());
|
||||
Color textColor = ta.getGutterTextColor(line);
|
||||
if (textColor == null) {
|
||||
gfx.setColor(getForeground());
|
||||
} else {
|
||||
gfx.setColor(textColor);
|
||||
}
|
||||
int y = ta.lineToY(line) + fm.getHeight();
|
||||
|
||||
// draw 4 times to make it appear bold, displaced 1px to the right, to the bottom and bottom right.
|
||||
//int len = text.length() > ta.gutterChars ? ta.gutterChars : text.length();
|
||||
Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()),
|
||||
ta.getGutterMargins(), y, gfx, this, 0);
|
||||
Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()),
|
||||
ta.getGutterMargins() + 1, y, gfx, this, 0);
|
||||
Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()),
|
||||
ta.getGutterMargins(), y + 1, gfx, this, 0);
|
||||
Utilities.drawTabbedText(new Segment(text.toCharArray(), 0, text.length()),
|
||||
ta.getGutterMargins() + 1, y + 1, gfx, this, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Paint the background color of a line.
|
||||
*
|
||||
* @param gfx
|
||||
* the graphics context
|
||||
* @param line
|
||||
* 0-based line number
|
||||
* @param x
|
||||
*/
|
||||
protected void paintLineBgColor(Graphics gfx, int line, int x) {
|
||||
int y = ta.lineToY(line);
|
||||
y += fm.getLeading() + fm.getMaxDescent();
|
||||
int height = fm.getHeight();
|
||||
|
||||
// get the color
|
||||
Color col = ta.getLineBgColor(line);
|
||||
//System.out.print("bg line " + line + ": ");
|
||||
// no need to paint anything
|
||||
if (col == null) {
|
||||
//System.out.println("none");
|
||||
return;
|
||||
}
|
||||
// paint line background
|
||||
gfx.setColor(col);
|
||||
gfx.fillRect(0, y, getWidth(), height);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
|
||||
if (errorCheckerService == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (errorCheckerService.problemsList == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean notFound = true;
|
||||
boolean isWarning = false;
|
||||
|
||||
// Check if current line contains an error. If it does, find if it's an
|
||||
// error or warning
|
||||
for (ErrorMarker emarker : errorCheckerService.getEditor().errorBar.errorPoints) {
|
||||
if (emarker.problem.lineNumber == line + 1) {
|
||||
notFound = false;
|
||||
if (emarker.type == ErrorMarker.Warning) {
|
||||
isWarning = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (notFound) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine co-ordinates
|
||||
// System.out.println("Hoff " + ta.getHorizontalOffset() + ", " +
|
||||
// horizontalAdjustment);
|
||||
int y = ta.lineToY(line);
|
||||
y += fm.getLeading() + fm.getMaxDescent();
|
||||
int height = fm.getHeight();
|
||||
int start = ta.getLineStartOffset(line);
|
||||
|
||||
try {
|
||||
String linetext = null;
|
||||
|
||||
try {
|
||||
linetext = ta.getDocument().getText(start,
|
||||
ta.getLineStopOffset(line) - start
|
||||
- 1);
|
||||
} catch (BadLocationException bl) {
|
||||
// Error in the import statements or end of code.
|
||||
// System.out.print("BL caught. " + ta.getLineCount() + " ,"
|
||||
// + line + " ,");
|
||||
// System.out.println((ta.getLineStopOffset(line) - start - 1));
|
||||
return;
|
||||
}
|
||||
|
||||
// Take care of offsets
|
||||
int aw = fm.stringWidth(trimRight(linetext)) + ta.getHorizontalOffset(); // apparent width. Whitespaces
|
||||
// to the left of line + text
|
||||
// width
|
||||
int rw = fm.stringWidth(linetext.trim()); // real width
|
||||
int x1 = 0 + (aw - rw), y1 = y + fm.getHeight() - 2, x2 = x1 + rw;
|
||||
// Adding offsets for the gutter
|
||||
x1 += 20;
|
||||
x2 += 20;
|
||||
|
||||
// gfx.fillRect(x1, y, rw, height);
|
||||
|
||||
// Let the painting begin!
|
||||
gfx.setColor(errorMarkerColor);
|
||||
if (isWarning) {
|
||||
gfx.setColor(warningMarkerColor);
|
||||
}
|
||||
gfx.fillRect(1, y + 2, 3, height - 2);
|
||||
|
||||
gfx.setColor(errorColor);
|
||||
if (isWarning) {
|
||||
gfx.setColor(warningColor);
|
||||
}
|
||||
int xx = x1;
|
||||
|
||||
// Draw the jagged lines
|
||||
while (xx < x2) {
|
||||
gfx.drawLine(xx, y1, xx + 2, y1 + 1);
|
||||
xx += 2;
|
||||
gfx.drawLine(xx, y1 + 1, xx + 2, y1);
|
||||
xx += 2;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out
|
||||
.println("Looks like I messed up! XQTextAreaPainter.paintLine() : "
|
||||
+ e);
|
||||
//e.printStackTrace();
|
||||
}
|
||||
|
||||
// Won't highlight the line. Select the text instead.
|
||||
// gfx.setColor(Color.RED);
|
||||
// gfx.fillRect(2, y, 3, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Trims out trailing whitespaces (to the right)
|
||||
*
|
||||
* @param string
|
||||
* @return - String
|
||||
*/
|
||||
private String trimRight(String string) {
|
||||
String newString = "";
|
||||
for (int i = 0; i < string.length(); i++) {
|
||||
if (string.charAt(i) != ' ') {
|
||||
newString = string.substring(0, i) + string.trim();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return newString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets ErrorCheckerService and loads theme for TextAreaPainter(XQMode)
|
||||
*
|
||||
* @param ecs
|
||||
* @param mode
|
||||
*/
|
||||
public void setECSandTheme(ErrorCheckerService ecs, ExperimentalMode mode) {
|
||||
this.errorCheckerService = ecs;
|
||||
loadTheme(mode);
|
||||
}
|
||||
|
||||
public String getToolTipText(java.awt.event.MouseEvent evt) {
|
||||
int off = ta.xyToOffset(evt.getX(), evt.getY());
|
||||
if (off < 0)
|
||||
return null;
|
||||
int line = ta.getLineOfOffset(off);
|
||||
if (line < 0)
|
||||
return null;
|
||||
String s = ta.getLineText(line);
|
||||
if (s == null)
|
||||
return evt.toString();
|
||||
else if (s.length() == 0)
|
||||
return null;
|
||||
else {
|
||||
int x = ta.xToOffset(line, evt.getX()), x2 = x + 1, x1 = x - 1;
|
||||
int xLS = off - ta.getLineStartNonWhiteSpaceOffset(line);
|
||||
if (x < 0 || x >= s.length())
|
||||
return null;
|
||||
String word = s.charAt(x) + "";
|
||||
if (s.charAt(x) == ' ')
|
||||
return null;
|
||||
if (!(Character.isLetterOrDigit(s.charAt(x)) || s.charAt(x) == '_' || s
|
||||
.charAt(x) == '$'))
|
||||
return null;
|
||||
int i = 0;
|
||||
while (true) {
|
||||
i++;
|
||||
if (x1 >= 0 && x1 < s.length()) {
|
||||
if (Character.isLetter(s.charAt(x1)) || s.charAt(x1) == '_') {
|
||||
word = s.charAt(x1--) + word;
|
||||
} else
|
||||
x1 = -1;
|
||||
} else
|
||||
x1 = -1;
|
||||
|
||||
if (x2 >= 0 && x2 < s.length()) {
|
||||
if (Character.isLetterOrDigit(s.charAt(x2)) || s.charAt(x2) == '_'
|
||||
|| s.charAt(x2) == '$')
|
||||
word = word + s.charAt(x2++);
|
||||
else
|
||||
x2 = -1;
|
||||
} else
|
||||
x2 = -1;
|
||||
|
||||
if (x1 < 0 && x2 < 0)
|
||||
break;
|
||||
if (i > 200) {
|
||||
// time out!
|
||||
System.err.println("Whoopsy! :P");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (Character.isDigit(word.charAt(0)))
|
||||
return null;
|
||||
String tooltipText = errorCheckerService.astGenerator
|
||||
.getLabelForASTNode(line + errorCheckerService.mainClassOffset, word,
|
||||
xLS);
|
||||
|
||||
System.out.print(errorCheckerService.mainClassOffset + " MCO ");
|
||||
System.out.print("|" + line + "| offset " + xLS + word + " <= offf: "+off+ "\n");
|
||||
if (tooltipText != null)
|
||||
return tooltipText;
|
||||
return word;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Martin Leopold <m@martinleopold.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
package processing.mode.experimental;
|
||||
|
||||
import com.sun.jdi.event.EventSet;
|
||||
|
||||
/**
|
||||
* Interface for VM callbacks.
|
||||
*
|
||||
* @author Martin Leopold <m@martinleopold.com>
|
||||
*/
|
||||
public interface VMEventListener {
|
||||
|
||||
/**
|
||||
* Receive an event from the VM. Events are sent in batches. See
|
||||
* documentation of EventSet for more information.
|
||||
*
|
||||
* @param es Set of events
|
||||
*/
|
||||
void vmEvent(EventSet es);
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Martin Leopold <m@martinleopold.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
package processing.mode.experimental;
|
||||
|
||||
import com.sun.jdi.VMDisconnectedException;
|
||||
import com.sun.jdi.event.EventQueue;
|
||||
import com.sun.jdi.event.EventSet;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Reader Thread for VM Events. Constantly monitors a VMs EventQueue for new
|
||||
* events and forwards them to an VMEventListener.
|
||||
*
|
||||
* @author Martin Leopold <m@martinleopold.com>
|
||||
*/
|
||||
public class VMEventReader extends Thread {
|
||||
|
||||
EventQueue eventQueue;
|
||||
VMEventListener listener;
|
||||
|
||||
/**
|
||||
* Construct a VMEventReader. Needs to be kicked off with start() once
|
||||
* constructed.
|
||||
*
|
||||
* @param eventQueue The queue to read events from. Can be obtained from a
|
||||
* VirtualMachine via eventQueue().
|
||||
* @param listener the listener to forward events to.
|
||||
*/
|
||||
public VMEventReader(EventQueue eventQueue, VMEventListener listener) {
|
||||
super("VM Event Thread");
|
||||
this.eventQueue = eventQueue;
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
while (true) {
|
||||
EventSet eventSet = eventQueue.remove();
|
||||
listener.vmEvent(eventSet);
|
||||
/*
|
||||
* for (Event e : eventSet) { System.out.println("VM Event: " +
|
||||
* e.toString()); }
|
||||
*/
|
||||
}
|
||||
} catch (VMDisconnectedException e) {
|
||||
Logger.getLogger(VMEventReader.class.getName()).log(Level.INFO, "VMEventReader quit on VM disconnect");
|
||||
} catch (Exception e) {
|
||||
Logger.getLogger(VMEventReader.class.getName()).log(Level.SEVERE, "VMEventReader quit", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<Form version="1.3" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
|
||||
<SyntheticProperties>
|
||||
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
|
||||
</SyntheticProperties>
|
||||
<AuxValues>
|
||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
|
||||
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
|
||||
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
|
||||
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
|
||||
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout>
|
||||
<DimensionLayout dim="0">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<EmptySpace min="0" pref="400" max="32767" attributes="0"/>
|
||||
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
|
||||
<Component id="scrollPane" alignment="0" pref="400" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<EmptySpace min="0" pref="300" max="32767" attributes="0"/>
|
||||
<Group type="103" rootIndex="1" groupAlignment="0" attributes="0">
|
||||
<Component id="scrollPane" alignment="1" pref="300" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
</Layout>
|
||||
<SubComponents>
|
||||
<Container class="javax.swing.JScrollPane" name="scrollPane">
|
||||
<AuxValues>
|
||||
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
|
||||
</AuxValues>
|
||||
|
||||
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
|
||||
<SubComponents>
|
||||
<Component class="org.netbeans.swing.outline.Outline" name="tree">
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="4"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
</Form>
|
||||
@@ -1,929 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Martin Leopold <m@martinleopold.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
package processing.mode.experimental;
|
||||
|
||||
import com.sun.jdi.Value;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Image;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.swing.DefaultCellEditor;
|
||||
import javax.swing.GrayFilter;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.UIDefaults;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.event.TreeExpansionEvent;
|
||||
import javax.swing.event.TreeExpansionListener;
|
||||
import javax.swing.table.TableColumn;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
import javax.swing.tree.ExpandVetoException;
|
||||
import javax.swing.tree.MutableTreeNode;
|
||||
import javax.swing.tree.TreeNode;
|
||||
import javax.swing.tree.TreePath;
|
||||
import org.netbeans.swing.outline.DefaultOutlineCellRenderer;
|
||||
import org.netbeans.swing.outline.DefaultOutlineModel;
|
||||
import org.netbeans.swing.outline.ExtTreeWillExpandListener;
|
||||
import org.netbeans.swing.outline.OutlineModel;
|
||||
import org.netbeans.swing.outline.RenderDataProvider;
|
||||
import org.netbeans.swing.outline.RowModel;
|
||||
|
||||
/**
|
||||
* Variable Inspector window.
|
||||
*
|
||||
* @author Martin Leopold <m@martinleopold.com>
|
||||
*/
|
||||
public class VariableInspector extends javax.swing.JFrame {
|
||||
|
||||
protected DefaultMutableTreeNode rootNode; // the root node (invisible)
|
||||
protected DefaultMutableTreeNode builtins; // node for Processing built-in variables
|
||||
protected DefaultTreeModel treeModel; // data model for the tree column
|
||||
protected OutlineModel model; // data model for the whole Outline (tree and other columns)
|
||||
protected List<DefaultMutableTreeNode> callStack; // the call stack
|
||||
protected List<VariableNode> locals; // current local variables
|
||||
protected List<VariableNode> thisFields; // all fields of the current this-object
|
||||
protected List<VariableNode> declaredThisFields; // declared i.e. non-inherited fields of this
|
||||
protected DebugEditor editor; // the editor
|
||||
protected Debugger dbg; // the debugger
|
||||
protected List<TreePath> expandedNodes = new ArrayList(); // list of expanded tree paths. (using list to maintain the order of expansion)
|
||||
protected boolean p5mode = true; // processing / "advanced" mode flag (currently not used
|
||||
|
||||
/**
|
||||
* Creates new form VariableInspector
|
||||
*/
|
||||
public VariableInspector(DebugEditor editor) {
|
||||
this.editor = editor;
|
||||
this.dbg = editor.dbg();
|
||||
|
||||
initComponents();
|
||||
|
||||
// setup Outline
|
||||
rootNode = new DefaultMutableTreeNode("root");
|
||||
builtins = new DefaultMutableTreeNode("Processing");
|
||||
treeModel = new DefaultTreeModel(rootNode); // model for the tree column
|
||||
model = DefaultOutlineModel.createOutlineModel(treeModel, new VariableRowModel(), true, "Name"); // model for all columns
|
||||
|
||||
ExpansionHandler expansionHandler = new ExpansionHandler();
|
||||
model.getTreePathSupport().addTreeWillExpandListener(expansionHandler);
|
||||
model.getTreePathSupport().addTreeExpansionListener(expansionHandler);
|
||||
tree.setModel(model);
|
||||
tree.setRootVisible(false);
|
||||
tree.setRenderDataProvider(new OutlineRenderer());
|
||||
tree.setColumnHidingAllowed(false); // disable visible columns button (shows by default when right scroll bar is visible)
|
||||
tree.setAutoscrolls(false);
|
||||
|
||||
// set custom renderer and editor for value column, since we are using a custom class for values (VariableNode)
|
||||
TableColumn valueColumn = tree.getColumnModel().getColumn(1);
|
||||
valueColumn.setCellRenderer(new ValueCellRenderer());
|
||||
valueColumn.setCellEditor(new ValueCellEditor());
|
||||
|
||||
//System.out.println("renderer: " + tree.getDefaultRenderer(String.class).getClass());
|
||||
//System.out.println("editor: " + tree.getDefaultEditor(String.class).getClass());
|
||||
|
||||
callStack = new ArrayList();
|
||||
locals = new ArrayList();
|
||||
thisFields = new ArrayList();
|
||||
declaredThisFields = new ArrayList();
|
||||
|
||||
this.setTitle(editor.getSketch().getName());
|
||||
|
||||
// for (Entry<Object, Object> entry : UIManager.getDefaults().entrySet()) {
|
||||
// System.out.println(entry.getKey());
|
||||
// }
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(String title) {
|
||||
super.setTitle(title + " | Variable Inspector");
|
||||
}
|
||||
|
||||
/**
|
||||
* Model for a Outline Row (excluding the tree column). Column 0 is "Value".
|
||||
* Column 1 is "Type". Handles setting and getting values. TODO: Maybe use a
|
||||
* TableCellRenderer instead of this to also have a different icon based on
|
||||
* expanded state. See:
|
||||
* http://kickjava.com/src/org/netbeans/swing/outline/DefaultOutlineCellRenderer.java.htm
|
||||
*/
|
||||
protected class VariableRowModel implements RowModel {
|
||||
|
||||
protected String[] columnNames = {"Value", "Type"};
|
||||
protected int[] editableTypes = {VariableNode.TYPE_BOOLEAN, VariableNode.TYPE_FLOAT, VariableNode.TYPE_INTEGER, VariableNode.TYPE_STRING, VariableNode.TYPE_FLOAT, VariableNode.TYPE_DOUBLE, VariableNode.TYPE_LONG, VariableNode.TYPE_SHORT, VariableNode.TYPE_CHAR};
|
||||
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
if (p5mode) {
|
||||
return 1; // only show value in p5 mode
|
||||
} else {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValueFor(Object o, int i) {
|
||||
if (o instanceof VariableNode) {
|
||||
VariableNode var = (VariableNode) o;
|
||||
switch (i) {
|
||||
case 0:
|
||||
return var; // will be converted to an appropriate String by ValueCellRenderer
|
||||
case 1:
|
||||
return var.getTypeName();
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class getColumnClass(int i) {
|
||||
if (i == 0) {
|
||||
return VariableNode.class;
|
||||
}
|
||||
return String.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCellEditable(Object o, int i) {
|
||||
if (i == 0 && o instanceof VariableNode) {
|
||||
VariableNode var = (VariableNode) o;
|
||||
//System.out.println("type: " + var.getTypeName());
|
||||
for (int type : editableTypes) {
|
||||
if (var.getType() == type) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValueFor(Object o, int i, Object o1) {
|
||||
VariableNode var = (VariableNode) o;
|
||||
String stringValue = (String) o1;
|
||||
|
||||
Value value = null;
|
||||
try {
|
||||
switch (var.getType()) {
|
||||
case VariableNode.TYPE_INTEGER:
|
||||
value = dbg.vm().mirrorOf(Integer.parseInt(stringValue));
|
||||
break;
|
||||
case VariableNode.TYPE_BOOLEAN:
|
||||
value = dbg.vm().mirrorOf(Boolean.parseBoolean(stringValue));
|
||||
break;
|
||||
case VariableNode.TYPE_FLOAT:
|
||||
value = dbg.vm().mirrorOf(Float.parseFloat(stringValue));
|
||||
break;
|
||||
case VariableNode.TYPE_STRING:
|
||||
value = dbg.vm().mirrorOf(stringValue);
|
||||
break;
|
||||
case VariableNode.TYPE_LONG:
|
||||
value = dbg.vm().mirrorOf(Long.parseLong(stringValue));
|
||||
break;
|
||||
case VariableNode.TYPE_BYTE:
|
||||
value = dbg.vm().mirrorOf(Byte.parseByte(stringValue));
|
||||
break;
|
||||
case VariableNode.TYPE_DOUBLE:
|
||||
value = dbg.vm().mirrorOf(Double.parseDouble(stringValue));
|
||||
break;
|
||||
case VariableNode.TYPE_SHORT:
|
||||
value = dbg.vm().mirrorOf(Short.parseShort(stringValue));
|
||||
break;
|
||||
case VariableNode.TYPE_CHAR:
|
||||
// TODO: better char support
|
||||
if (stringValue.length() > 0) {
|
||||
value = dbg.vm().mirrorOf(stringValue.charAt(0));
|
||||
}
|
||||
break;
|
||||
}
|
||||
} catch (NumberFormatException ex) {
|
||||
Logger.getLogger(VariableRowModel.class.getName()).log(Level.INFO, "invalid value entered for {0}: {1}", new Object[]{var.getName(), stringValue});
|
||||
}
|
||||
if (value != null) {
|
||||
var.setValue(value);
|
||||
Logger.getLogger(VariableRowModel.class.getName()).log(Level.INFO, "new value set: {0}", var.getStringValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnName(int i) {
|
||||
return columnNames[i];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renderer for the tree portion of the outline component. Handles icons,
|
||||
* text color and tool tips.
|
||||
*/
|
||||
protected class OutlineRenderer implements RenderDataProvider {
|
||||
|
||||
protected Icon[][] icons;
|
||||
protected static final int ICON_SIZE = 16; // icon size (square, size=width=height)
|
||||
|
||||
public OutlineRenderer() {
|
||||
// load icons
|
||||
icons = loadIcons("theme/var-icons.gif");
|
||||
}
|
||||
|
||||
/**
|
||||
* Load multiple icons (horizotal) with multiple states (vertical) from
|
||||
* a single file.
|
||||
*
|
||||
* @param fileName file path in the mode folder.
|
||||
* @return a nested array (first index: icon, second index: state) or
|
||||
* null if the file wasn't found.
|
||||
*/
|
||||
protected ImageIcon[][] loadIcons(String fileName) {
|
||||
ExperimentalMode mode = editor.mode();
|
||||
File file = mode.getContentFile(fileName);
|
||||
if (!file.exists()) {
|
||||
Logger.getLogger(OutlineRenderer.class.getName()).log(Level.SEVERE, "icon file not found: {0}", file.getAbsolutePath());
|
||||
return null;
|
||||
}
|
||||
Image allIcons = mode.loadImage(fileName);
|
||||
int cols = allIcons.getWidth(null) / ICON_SIZE;
|
||||
int rows = allIcons.getHeight(null) / ICON_SIZE;
|
||||
ImageIcon[][] iconImages = new ImageIcon[cols][rows];
|
||||
|
||||
for (int i = 0; i < cols; i++) {
|
||||
for (int j = 0; j < rows; j++) {
|
||||
//Image image = createImage(ICON_SIZE, ICON_SIZE);
|
||||
Image image = new BufferedImage(ICON_SIZE, ICON_SIZE, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics g = image.getGraphics();
|
||||
g.drawImage(allIcons, -i * ICON_SIZE, -j * ICON_SIZE, null);
|
||||
iconImages[i][j] = new ImageIcon(image);
|
||||
}
|
||||
}
|
||||
return iconImages;
|
||||
}
|
||||
|
||||
protected Icon getIcon(int type, int state) {
|
||||
if (type < 0 || type > icons.length - 1) {
|
||||
return null;
|
||||
}
|
||||
return icons[type][state];
|
||||
}
|
||||
|
||||
protected VariableNode toVariableNode(Object o) {
|
||||
if (o instanceof VariableNode) {
|
||||
return (VariableNode) o;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected Icon toGray(Icon icon) {
|
||||
if (icon instanceof ImageIcon) {
|
||||
Image grayImage = GrayFilter.createDisabledImage(((ImageIcon) icon).getImage());
|
||||
return new ImageIcon(grayImage);
|
||||
}
|
||||
// Cannot convert
|
||||
return icon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName(Object o) {
|
||||
return o.toString(); // VariableNode.toString() returns name; (for sorting)
|
||||
// VariableNode var = toVariableNode(o);
|
||||
// if (var != null) {
|
||||
// return var.getName();
|
||||
// } else {
|
||||
// return o.toString();
|
||||
// }
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHtmlDisplayName(Object o) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getBackground(Object o) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getForeground(Object o) {
|
||||
if (tree.isEnabled()) {
|
||||
return null; // default
|
||||
} else {
|
||||
return Color.GRAY;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTooltipText(Object o) {
|
||||
VariableNode var = toVariableNode(o);
|
||||
if (var != null) {
|
||||
return var.getDescription();
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getIcon(Object o) {
|
||||
VariableNode var = toVariableNode(o);
|
||||
if (var != null) {
|
||||
if (tree.isEnabled()) {
|
||||
return getIcon(var.getType(), 0);
|
||||
} else {
|
||||
return getIcon(var.getType(), 1);
|
||||
}
|
||||
} else {
|
||||
if (o instanceof TreeNode) {
|
||||
// TreeNode node = (TreeNode) o;
|
||||
// AbstractLayoutCache layout = tree.getLayoutCache();
|
||||
UIDefaults defaults = UIManager.getDefaults();
|
||||
|
||||
boolean isLeaf = model.isLeaf(o);
|
||||
Icon icon;
|
||||
if (isLeaf) {
|
||||
icon = defaults.getIcon("Tree.leafIcon");
|
||||
} else {
|
||||
icon = defaults.getIcon("Tree.closedIcon");
|
||||
}
|
||||
|
||||
if (!tree.isEnabled()) {
|
||||
return toGray(icon);
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
}
|
||||
return null; // use standard icon
|
||||
//UIManager.getIcon(o);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: could probably extend the simpler javax.swing.table.DefaultTableCellRenderer here
|
||||
/**
|
||||
* Renderer for the value column. Uses an italic font for null values and
|
||||
* Object values ("instance of ..."). Uses a gray color when tree is not
|
||||
* enabled.
|
||||
*/
|
||||
protected class ValueCellRenderer extends DefaultOutlineCellRenderer {
|
||||
|
||||
public ValueCellRenderer() {
|
||||
super();
|
||||
}
|
||||
|
||||
protected void setItalic(boolean on) {
|
||||
if (on) {
|
||||
setFont(new Font(getFont().getName(), Font.ITALIC, getFont().getSize()));
|
||||
} else {
|
||||
setFont(new Font(getFont().getName(), Font.PLAIN, getFont().getSize()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
|
||||
Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
|
||||
|
||||
if (!tree.isEnabled()) {
|
||||
setForeground(Color.GRAY);
|
||||
} else {
|
||||
setForeground(Color.BLACK);
|
||||
}
|
||||
|
||||
if (value instanceof VariableNode) {
|
||||
VariableNode var = (VariableNode) value;
|
||||
|
||||
if (var.getValue() == null || var.getType() == VariableNode.TYPE_OBJECT) {
|
||||
setItalic(true);
|
||||
} else {
|
||||
setItalic(false);
|
||||
}
|
||||
value = var.getStringValue();
|
||||
}
|
||||
|
||||
setValue(value);
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Editor for the value column. Will show an empty string when editing
|
||||
* String values that are null.
|
||||
*/
|
||||
protected class ValueCellEditor extends DefaultCellEditor {
|
||||
|
||||
public ValueCellEditor() {
|
||||
super(new JTextField());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
|
||||
if (!(value instanceof VariableNode)) {
|
||||
return super.getTableCellEditorComponent(table, value, isSelected, row, column);
|
||||
}
|
||||
VariableNode var = (VariableNode) value;
|
||||
if (var.getType() == VariableNode.TYPE_STRING && var.getValue() == null) {
|
||||
return super.getTableCellEditorComponent(table, "", isSelected, row, column);
|
||||
} else {
|
||||
return super.getTableCellEditorComponent(table, var.getStringValue(), isSelected, row, column);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for expanding and collapsing tree nodes. Implements lazy loading
|
||||
* of tree data (on expand).
|
||||
*/
|
||||
protected class ExpansionHandler implements ExtTreeWillExpandListener, TreeExpansionListener {
|
||||
|
||||
@Override
|
||||
public void treeWillExpand(TreeExpansionEvent tee) throws ExpandVetoException {
|
||||
//System.out.println("will expand");
|
||||
Object last = tee.getPath().getLastPathComponent();
|
||||
if (!(last instanceof VariableNode)) {
|
||||
return;
|
||||
}
|
||||
VariableNode var = (VariableNode) last;
|
||||
// load children
|
||||
// if (!dbg.isPaused()) {
|
||||
// System.out.println("throwing veto");
|
||||
// //throw new ExpandVetoException(tee, "Debugger busy");
|
||||
// } else {
|
||||
var.removeAllChildren(); // TODO: should we only load it once?
|
||||
// TODO: don't filter in advanced mode
|
||||
//System.out.println("loading children for: " + var);
|
||||
// true means include inherited
|
||||
var.addChildren(filterNodes(dbg.getFields(var.getValue(), 0, true), new ThisFilter()));
|
||||
// }
|
||||
}
|
||||
|
||||
@Override
|
||||
public void treeWillCollapse(TreeExpansionEvent tee) throws ExpandVetoException {
|
||||
//throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void treeExpanded(TreeExpansionEvent tee) {
|
||||
//System.out.println("expanded: " + tee.getPath());
|
||||
if (!expandedNodes.contains(tee.getPath())) {
|
||||
expandedNodes.add(tee.getPath());
|
||||
}
|
||||
|
||||
// TreePath newPath = tee.getPath();
|
||||
// if (expandedLast != null) {
|
||||
// // test each node of the path for equality
|
||||
// for (int i = 0; i < expandedLast.getPathCount(); i++) {
|
||||
// if (i < newPath.getPathCount()) {
|
||||
// Object last = expandedLast.getPathComponent(i);
|
||||
// Object cur = newPath.getPathComponent(i);
|
||||
// System.out.println(last + " =? " + cur + ": " + last.equals(cur) + "/" + (last.hashCode() == cur.hashCode()));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// System.out.println("path equality: " + newPath.equals(expandedLast));
|
||||
// expandedLast = newPath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void treeCollapsed(TreeExpansionEvent tee) {
|
||||
//System.out.println("collapsed: " + tee.getPath());
|
||||
|
||||
// first remove all children of collapsed path
|
||||
// this makes sure children do not appear before parents in the list.
|
||||
// (children can't be expanded before their parents)
|
||||
List<TreePath> removalList = new ArrayList();
|
||||
for (TreePath path : expandedNodes) {
|
||||
if (path.getParentPath().equals(tee.getPath())) {
|
||||
removalList.add(path);
|
||||
}
|
||||
}
|
||||
for (TreePath path : removalList) {
|
||||
expandedNodes.remove(path);
|
||||
}
|
||||
// remove collapsed path
|
||||
expandedNodes.remove(tee.getPath());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void treeExpansionVetoed(TreeExpansionEvent tee, ExpandVetoException eve) {
|
||||
//System.out.println("expansion vetoed");
|
||||
// nop
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called from within the constructor to initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is always
|
||||
* regenerated by the Form Editor.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
|
||||
private void initComponents() {
|
||||
|
||||
scrollPane = new javax.swing.JScrollPane();
|
||||
tree = new org.netbeans.swing.outline.Outline();
|
||||
|
||||
scrollPane.setViewportView(tree);
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
|
||||
getContentPane().setLayout(layout);
|
||||
layout.setHorizontalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGap(0, 400, Short.MAX_VALUE)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(scrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE))
|
||||
);
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGap(0, 300, Short.MAX_VALUE)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(scrollPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE))
|
||||
);
|
||||
|
||||
pack();
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
// /**
|
||||
// * @param args the command line arguments
|
||||
// */
|
||||
// public static void main(String args[]) {
|
||||
// /*
|
||||
// * Set the Nimbus look and feel
|
||||
// */
|
||||
// //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
|
||||
// /*
|
||||
// * If Nimbus (introduced in Java SE 6) is not available, stay with the
|
||||
// * default look and feel. For details see
|
||||
// * http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
|
||||
// */
|
||||
// try {
|
||||
// javax.swing.UIManager.setLookAndFeel(javax.swing.UIManager.getSystemLookAndFeelClassName());
|
||||
// } catch (ClassNotFoundException ex) {
|
||||
// java.util.logging.Logger.getLogger(VariableInspector.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
|
||||
// } catch (InstantiationException ex) {
|
||||
// java.util.logging.Logger.getLogger(VariableInspector.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
|
||||
// } catch (IllegalAccessException ex) {
|
||||
// java.util.logging.Logger.getLogger(VariableInspector.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
|
||||
// } catch (javax.swing.UnsupportedLookAndFeelException ex) {
|
||||
// java.util.logging.Logger.getLogger(VariableInspector.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
|
||||
// }
|
||||
// //</editor-fold>
|
||||
//
|
||||
// /*
|
||||
// * Create and display the form
|
||||
// */
|
||||
// run(new VariableInspector());
|
||||
// }
|
||||
protected static void run(final VariableInspector vi) {
|
||||
/*
|
||||
* Create and display the form
|
||||
*/
|
||||
java.awt.EventQueue.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
vi.setVisible(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JScrollPane scrollPane;
|
||||
protected org.netbeans.swing.outline.Outline tree;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
|
||||
/**
|
||||
* Access the root node of the tree.
|
||||
*
|
||||
* @return the root node
|
||||
*/
|
||||
public DefaultMutableTreeNode getRootNode() {
|
||||
return rootNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlock the inspector window. Rebuild after this to avoid ... dots in the
|
||||
* trees labels
|
||||
*/
|
||||
public void unlock() {
|
||||
tree.setEnabled(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock the inspector window. Cancels open edits.
|
||||
*/
|
||||
public void lock() {
|
||||
if (tree.getCellEditor() != null) {
|
||||
//tree.getCellEditor().stopCellEditing(); // force quit open edit
|
||||
tree.getCellEditor().cancelCellEditing(); // cancel an open edit
|
||||
}
|
||||
tree.setEnabled(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the inspector windows data. Rebuild after this to make changes
|
||||
* visible.
|
||||
*/
|
||||
public void reset() {
|
||||
rootNode.removeAllChildren();
|
||||
// clear local data for good measure (in case someone rebuilds)
|
||||
callStack.clear();
|
||||
locals.clear();
|
||||
thisFields.clear();
|
||||
declaredThisFields.clear();
|
||||
expandedNodes.clear();
|
||||
// update
|
||||
treeModel.nodeStructureChanged(rootNode);
|
||||
}
|
||||
|
||||
// public void setAdvancedMode() {
|
||||
// p5mode = false;
|
||||
// }
|
||||
//
|
||||
// public void setP5Mode() {
|
||||
// p5mode = true;
|
||||
// }
|
||||
//
|
||||
// public void toggleMode() {
|
||||
// if (p5mode) {
|
||||
// setAdvancedMode();
|
||||
// } else {
|
||||
// setP5Mode();
|
||||
// }
|
||||
// }
|
||||
/**
|
||||
* Update call stack data.
|
||||
*
|
||||
* @param nodes a list of nodes that represent the call stack.
|
||||
* @param title the title to be used when labeling or otherwise grouping
|
||||
* call stack data.
|
||||
*/
|
||||
public void updateCallStack(List<DefaultMutableTreeNode> nodes, String title) {
|
||||
callStack = nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update locals data.
|
||||
*
|
||||
* @param nodes a list of {@link VariableNode} to be shown as local
|
||||
* variables in the inspector.
|
||||
* @param title the title to be used when labeling or otherwise grouping
|
||||
* locals data.
|
||||
*/
|
||||
public void updateLocals(List<VariableNode> nodes, String title) {
|
||||
locals = nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update this-fields data.
|
||||
*
|
||||
* @param nodes a list of {@link VariableNode}s to be shown as this-fields
|
||||
* in the inspector.
|
||||
* @param title the title to be used when labeling or otherwise grouping
|
||||
* this-fields data.
|
||||
*/
|
||||
public void updateThisFields(List<VariableNode> nodes, String title) {
|
||||
thisFields = nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update declared (non-inherited) this-fields data.
|
||||
*
|
||||
* @param nodes a list of {@link VariableNode}s to be shown as declared
|
||||
* this-fields in the inspector.
|
||||
* @param title the title to be used when labeling or otherwise grouping
|
||||
* declared this-fields data.
|
||||
*/
|
||||
public void updateDeclaredThisFields(List<VariableNode> nodes, String title) {
|
||||
declaredThisFields = nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rebuild the outline tree from current data. Uses the data provided by
|
||||
* {@link #updateCallStack}, {@link #updateLocals}, {@link #updateThisFields}
|
||||
* and {@link #updateDeclaredThisFields}
|
||||
*/
|
||||
public void rebuild() {
|
||||
rootNode.removeAllChildren();
|
||||
if (p5mode) {
|
||||
// add all locals to root
|
||||
addAllNodes(rootNode, locals);
|
||||
|
||||
// add non-inherited this fields
|
||||
addAllNodes(rootNode, filterNodes(declaredThisFields, new LocalHidesThisFilter(locals, LocalHidesThisFilter.MODE_PREFIX)));
|
||||
|
||||
// add p5 builtins in a new folder
|
||||
builtins.removeAllChildren();
|
||||
addAllNodes(builtins, filterNodes(thisFields, new P5BuiltinsFilter()));
|
||||
if (builtins.getChildCount() > 0) { // skip builtins in certain situations e.g. in pure java tabs.
|
||||
rootNode.add(builtins);
|
||||
}
|
||||
|
||||
// notify tree (using model) changed a node and its children
|
||||
// http://stackoverflow.com/questions/2730851/how-to-update-jtree-elements
|
||||
// needs to be done before expanding paths!
|
||||
treeModel.nodeStructureChanged(rootNode);
|
||||
|
||||
// handle node expansions
|
||||
for (TreePath path : expandedNodes) {
|
||||
//System.out.println("re-expanding: " + path);
|
||||
path = synthesizePath(path);
|
||||
if (path != null) {
|
||||
tree.expandPath(path);
|
||||
} else {
|
||||
//System.out.println("couldn't synthesize path");
|
||||
}
|
||||
}
|
||||
|
||||
// this expansion causes problems when sorted and stepping
|
||||
//tree.expandPath(new TreePath(new Object[]{rootNode, builtins}));
|
||||
|
||||
} else {
|
||||
// TODO: implement advanced mode here
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-build a {@link TreePath} from a previous path using equals-checks
|
||||
* starting at the root node. This is used to use paths from previous trees
|
||||
* for use on the current tree.
|
||||
*
|
||||
* @param path the path to synthesize.
|
||||
* @return the rebuilt path, usable on the current tree.
|
||||
*/
|
||||
protected TreePath synthesizePath(TreePath path) {
|
||||
//System.out.println("synthesizing: " + path);
|
||||
if (path.getPathCount() == 0 || !rootNode.equals(path.getPathComponent(0))) {
|
||||
return null;
|
||||
}
|
||||
Object[] newPath = new Object[path.getPathCount()];
|
||||
newPath[0] = rootNode;
|
||||
TreeNode currentNode = rootNode;
|
||||
for (int i = 0; i < path.getPathCount() - 1; i++) {
|
||||
// get next node
|
||||
for (int j = 0; j < currentNode.getChildCount(); j++) {
|
||||
TreeNode nextNode = currentNode.getChildAt(j);
|
||||
if (nextNode.equals(path.getPathComponent(i + 1))) {
|
||||
currentNode = nextNode;
|
||||
newPath[i + 1] = nextNode;
|
||||
//System.out.println("found node " + (i+1) + ": " + nextNode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (newPath[i + 1] == null) {
|
||||
//System.out.println("didn't find node");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return new TreePath(newPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter a list of nodes using a {@link VariableNodeFilter}.
|
||||
*
|
||||
* @param nodes the list of nodes to filter.
|
||||
* @param filter the filter to be used.
|
||||
* @return the filtered list.
|
||||
*/
|
||||
protected List<VariableNode> filterNodes(List<VariableNode> nodes, VariableNodeFilter filter) {
|
||||
List<VariableNode> filtered = new ArrayList();
|
||||
for (VariableNode node : nodes) {
|
||||
if (filter.accept(node)) {
|
||||
filtered.add(node);
|
||||
}
|
||||
}
|
||||
return filtered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all nodes in a list to a root node.
|
||||
*
|
||||
* @param root the root node to add to.
|
||||
* @param nodes the list of nodes to add.
|
||||
*/
|
||||
protected void addAllNodes(DefaultMutableTreeNode root, List<? extends MutableTreeNode> nodes) {
|
||||
for (MutableTreeNode node : nodes) {
|
||||
root.add(node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A filter for {@link VariableNode}s.
|
||||
*/
|
||||
public interface VariableNodeFilter {
|
||||
|
||||
/**
|
||||
* Check whether the filter accepts a {@link VariableNode}.
|
||||
*
|
||||
* @param var the input node
|
||||
* @return true when the filter accepts the input node otherwise false.
|
||||
*/
|
||||
public boolean accept(VariableNode var);
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link VariableNodeFilter} that accepts Processing built-in variable
|
||||
* names.
|
||||
*/
|
||||
public class P5BuiltinsFilter implements VariableNodeFilter {
|
||||
|
||||
protected String[] p5Builtins = {
|
||||
"focused",
|
||||
"frameCount",
|
||||
"frameRate",
|
||||
"height",
|
||||
"online",
|
||||
"screen",
|
||||
"width",
|
||||
"mouseX",
|
||||
"mouseY",
|
||||
"pmouseX",
|
||||
"pmouseY",
|
||||
"key",
|
||||
"keyCode",
|
||||
"keyPressed"
|
||||
};
|
||||
|
||||
@Override
|
||||
public boolean accept(VariableNode var) {
|
||||
return Arrays.asList(p5Builtins).contains(var.getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link VariableNodeFilter} that rejects implicit this references.
|
||||
* (Names starting with "this$")
|
||||
*/
|
||||
public class ThisFilter implements VariableNodeFilter {
|
||||
|
||||
@Override
|
||||
public boolean accept(VariableNode var) {
|
||||
return !var.getName().startsWith("this$");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link VariableNodeFilter} that either rejects this-fields if hidden by
|
||||
* a local, or prefixes its name with "this."
|
||||
*/
|
||||
public class LocalHidesThisFilter implements VariableNodeFilter {
|
||||
|
||||
/**
|
||||
* Reject a this-field if hidden by a local.
|
||||
*/
|
||||
public static final int MODE_HIDE = 0; // don't show hidden this fields
|
||||
/**
|
||||
* Prefix a this-fields name with "this." if hidden by a local.
|
||||
*/
|
||||
public static final int MODE_PREFIX = 1; // prefix hidden this fields with "this."
|
||||
protected List<VariableNode> locals;
|
||||
protected int mode;
|
||||
|
||||
/**
|
||||
* Construct a {@link LocalHidesThisFilter}.
|
||||
*
|
||||
* @param locals a list of locals to check against
|
||||
* @param mode either {@link #MODE_HIDE} or {@link #MODE_PREFIX}
|
||||
*/
|
||||
public LocalHidesThisFilter(List<VariableNode> locals, int mode) {
|
||||
this.locals = locals;
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean accept(VariableNode var) {
|
||||
// check if the same name appears in the list of locals i.e. the local hides the field
|
||||
for (VariableNode local : locals) {
|
||||
if (var.getName().equals(local.getName())) {
|
||||
switch (mode) {
|
||||
case MODE_PREFIX:
|
||||
var.setName("this." + var.getName());
|
||||
return true;
|
||||
case MODE_HIDE:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,358 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Martin Leopold <m@martinleopold.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
package processing.mode.experimental;
|
||||
|
||||
import com.sun.jdi.ArrayReference;
|
||||
import com.sun.jdi.ObjectReference;
|
||||
import com.sun.jdi.StringReference;
|
||||
import com.sun.jdi.Value;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import javax.swing.tree.MutableTreeNode;
|
||||
import javax.swing.tree.TreeNode;
|
||||
|
||||
/**
|
||||
* Model for a variable in the variable inspector. Has a type and name and
|
||||
* optionally a value. Can have sub-variables (as is the case for objects, and
|
||||
* arrays).
|
||||
*
|
||||
* @author Martin Leopold <m@martinleopold.com>
|
||||
*/
|
||||
public class VariableNode implements MutableTreeNode {
|
||||
|
||||
public static final int TYPE_UNKNOWN = -1;
|
||||
public static final int TYPE_OBJECT = 0;
|
||||
public static final int TYPE_ARRAY = 1;
|
||||
public static final int TYPE_INTEGER = 2;
|
||||
public static final int TYPE_FLOAT = 3;
|
||||
public static final int TYPE_BOOLEAN = 4;
|
||||
public static final int TYPE_CHAR = 5;
|
||||
public static final int TYPE_STRING = 6;
|
||||
public static final int TYPE_LONG = 7;
|
||||
public static final int TYPE_DOUBLE = 8;
|
||||
public static final int TYPE_BYTE = 9;
|
||||
public static final int TYPE_SHORT = 10;
|
||||
public static final int TYPE_VOID = 11;
|
||||
protected String type;
|
||||
protected String name;
|
||||
protected Value value;
|
||||
protected List<MutableTreeNode> children = new ArrayList();
|
||||
protected MutableTreeNode parent;
|
||||
|
||||
/**
|
||||
* Construct a {@link VariableNode}.
|
||||
* @param name the name
|
||||
* @param type the type
|
||||
* @param value the value
|
||||
*/
|
||||
public VariableNode(String name, String type, Value value) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public void setValue(Value value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public Value getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a String representation of this variable nodes value.
|
||||
*
|
||||
* @return a String representing the value.
|
||||
*/
|
||||
public String getStringValue() {
|
||||
String str;
|
||||
if (value != null) {
|
||||
if (getType() == TYPE_OBJECT) {
|
||||
str = "instance of " + type;
|
||||
} else if (getType() == TYPE_ARRAY) {
|
||||
//instance of int[5] (id=998) --> instance of int[5]
|
||||
str = value.toString().substring(0, value.toString().lastIndexOf(" "));
|
||||
} else if (getType() == TYPE_STRING) {
|
||||
str = ((StringReference) value).value(); // use original string value (without quotes)
|
||||
} else {
|
||||
str = value.toString();
|
||||
}
|
||||
} else {
|
||||
str = "null";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
public String getTypeName() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
if (type == null) {
|
||||
return TYPE_UNKNOWN;
|
||||
}
|
||||
if (type.endsWith("[]")) {
|
||||
return TYPE_ARRAY;
|
||||
}
|
||||
if (type.equals("int")) {
|
||||
return TYPE_INTEGER;
|
||||
}
|
||||
if (type.equals("long")) {
|
||||
return TYPE_LONG;
|
||||
}
|
||||
if (type.equals("byte")) {
|
||||
return TYPE_BYTE;
|
||||
}
|
||||
if (type.equals("short")) {
|
||||
return TYPE_SHORT;
|
||||
}
|
||||
if (type.equals("float")) {
|
||||
return TYPE_FLOAT;
|
||||
}
|
||||
if (type.equals("double")) {
|
||||
return TYPE_DOUBLE;
|
||||
}
|
||||
if (type.equals("char")) {
|
||||
return TYPE_CHAR;
|
||||
}
|
||||
if (type.equals("java.lang.String")) {
|
||||
return TYPE_STRING;
|
||||
}
|
||||
if (type.equals("boolean")) {
|
||||
return TYPE_BOOLEAN;
|
||||
}
|
||||
if (type.equals("void")) {
|
||||
return TYPE_VOID; //TODO: check if this is correct
|
||||
}
|
||||
return TYPE_OBJECT;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a {@link VariableNode} as child.
|
||||
*
|
||||
* @param c the {@link VariableNode} to add.
|
||||
*/
|
||||
public void addChild(VariableNode c) {
|
||||
children.add(c);
|
||||
c.setParent(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add multiple {@link VariableNode}s as children.
|
||||
*
|
||||
* @param children the list of {@link VariableNode}s to add.
|
||||
*/
|
||||
public void addChildren(List<VariableNode> children) {
|
||||
for (VariableNode child : children) {
|
||||
addChild(child);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TreeNode getChildAt(int i) {
|
||||
return children.get(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChildCount() {
|
||||
return children.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TreeNode getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIndex(TreeNode tn) {
|
||||
return children.indexOf(tn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getAllowsChildren() {
|
||||
if (value == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// handle strings
|
||||
if (getType() == TYPE_STRING) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// handle arrays
|
||||
if (getType() == TYPE_ARRAY) {
|
||||
ArrayReference array = (ArrayReference) value;
|
||||
return array.length() > 0;
|
||||
}
|
||||
// handle objects
|
||||
if (getType() == TYPE_OBJECT) { // this also rules out null
|
||||
// check if this object has any fields
|
||||
ObjectReference obj = (ObjectReference) value;
|
||||
return !obj.referenceType().visibleFields().isEmpty();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This controls the default icon and disclosure triangle.
|
||||
*
|
||||
* @return true, will show "folder" icon and disclosure triangle.
|
||||
*/
|
||||
@Override
|
||||
public boolean isLeaf() {
|
||||
//return children.size() == 0;
|
||||
return !getAllowsChildren();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration children() {
|
||||
return Collections.enumeration(children);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a String representation of this {@link VariableNode}.
|
||||
*
|
||||
* @return the name of the variable (for sorting to work).
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName(); // for sorting
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a String description of this {@link VariableNode}. Contains the type,
|
||||
* name and value.
|
||||
*
|
||||
* @return the description
|
||||
*/
|
||||
public String getDescription() {
|
||||
String str = "";
|
||||
if (type != null) {
|
||||
str += type + " ";
|
||||
}
|
||||
str += name;
|
||||
str += " = " + getStringValue();
|
||||
return str;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insert(MutableTreeNode mtn, int i) {
|
||||
children.add(i, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(int i) {
|
||||
MutableTreeNode mtn = children.remove(i);
|
||||
if (mtn != null) {
|
||||
mtn.setParent(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(MutableTreeNode mtn) {
|
||||
children.remove(mtn);
|
||||
mtn.setParent(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all children from this {@link VariableNode}.
|
||||
*/
|
||||
public void removeAllChildren() {
|
||||
for (MutableTreeNode mtn : children) {
|
||||
mtn.setParent(null);
|
||||
}
|
||||
children.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUserObject(Object o) {
|
||||
if (o instanceof Value) {
|
||||
value = (Value) o;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFromParent() {
|
||||
parent.remove(this);
|
||||
this.parent = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParent(MutableTreeNode mtn) {
|
||||
parent = mtn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for equality. To be equal, two {@link VariableNode}s need to have
|
||||
* equal type, name and value.
|
||||
*
|
||||
* @param obj the object to test for equality with this {@link VariableNode}
|
||||
* @return true if the given object is equal to this {@link VariableNode}
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final VariableNode other = (VariableNode) obj;
|
||||
if ((this.type == null) ? (other.type != null) : !this.type.equals(other.type)) {
|
||||
//System.out.println("type not equal");
|
||||
return false;
|
||||
}
|
||||
if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
|
||||
//System.out.println("name not equal");
|
||||
return false;
|
||||
}
|
||||
if (this.value != other.value && (this.value == null || !this.value.equals(other.value))) {
|
||||
//System.out.println("value not equal");
|
||||
return false;
|
||||
}
|
||||
// if (this.parent != other.parent && (this.parent == null || !this.parent.equals(other.parent))) {
|
||||
// System.out.println("parent not equal: " + this.parent + "/" + other.parent);
|
||||
// return false;
|
||||
// }
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hash code based on type, name and value.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 3;
|
||||
hash = 97 * hash + (this.type != null ? this.type.hashCode() : 0);
|
||||
hash = 97 * hash + (this.name != null ? this.name.hashCode() : 0);
|
||||
hash = 97 * hash + (this.value != null ? this.value.hashCode() : 0);
|
||||
// hash = 97 * hash + (this.parent != null ? this.parent.hashCode() : 0);
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
package processing.mode.experimental;
|
||||
|
||||
/*
|
||||
Part of the XQMode project - https://github.com/Manindra29/XQMode
|
||||
|
||||
Under Google Summer of Code 2012 -
|
||||
http://www.google-melange.com/gsoc/homepage/google/gsoc2012
|
||||
|
||||
Copyright (C) 2012 Manindra Moharana
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2
|
||||
as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
|
||||
/**
|
||||
* Toggle Button displayed in the editor line status panel for toggling bewtween
|
||||
* console and problems list. Glorified JPanel.
|
||||
*
|
||||
* @author Manindra Moharana <me@mkmoharana.com>
|
||||
*
|
||||
*/
|
||||
|
||||
public class XQConsoleToggle extends JPanel implements MouseListener {
|
||||
public static final String[] text = { "Console", "Errors" };
|
||||
|
||||
private boolean toggleText = true;
|
||||
private boolean toggleBG = true;
|
||||
|
||||
/**
|
||||
* Height of the component
|
||||
*/
|
||||
protected int height;
|
||||
protected DebugEditor editor;
|
||||
protected String buttonName;
|
||||
|
||||
public XQConsoleToggle(DebugEditor editor, String buttonName, int height) {
|
||||
this.editor = editor;
|
||||
this.height = height;
|
||||
this.buttonName = buttonName;
|
||||
}
|
||||
|
||||
public Dimension getPreferredSize() {
|
||||
return new Dimension(70, height);
|
||||
}
|
||||
|
||||
public Dimension getMinimumSize() {
|
||||
return getPreferredSize();
|
||||
}
|
||||
|
||||
public Dimension getMaximumSize() {
|
||||
return getPreferredSize();
|
||||
}
|
||||
|
||||
public void paintComponent(Graphics g) {
|
||||
Graphics2D g2d = (Graphics2D) g;
|
||||
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
|
||||
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
||||
|
||||
// On mouse hover, text and background color are changed.
|
||||
if (toggleBG) {
|
||||
g.setColor(new Color(0xff9DA7B0));
|
||||
g.fillRect(0, 0, this.getWidth(), this.getHeight());
|
||||
g.setColor(new Color(0xff29333D));
|
||||
g.fillRect(0, 0, 4, this.getHeight());
|
||||
g.setColor(Color.BLACK);
|
||||
} else {
|
||||
g.setColor(Color.DARK_GRAY);
|
||||
g.fillRect(0, 0, this.getWidth(), this.getHeight());
|
||||
g.setColor(new Color(0xff29333D));
|
||||
g.fillRect(0, 0, 4, this.getHeight());
|
||||
g.setColor(Color.WHITE);
|
||||
}
|
||||
|
||||
g.drawString(buttonName, getWidth() / 2 + 2 // + 2 is a offset
|
||||
- getFontMetrics(getFont()).stringWidth(buttonName) / 2,
|
||||
this.getHeight() - 6);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent arg0) {
|
||||
|
||||
this.repaint();
|
||||
try {
|
||||
editor.toggleView(buttonName);
|
||||
} catch (Exception e) {
|
||||
System.out.println(e);
|
||||
// e.printStackTrace();
|
||||
}
|
||||
toggleText = !toggleText;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent arg0) {
|
||||
toggleBG = !toggleBG;
|
||||
this.repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(MouseEvent arg0) {
|
||||
toggleBG = !toggleBG;
|
||||
this.repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed(MouseEvent arg0) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent arg0) {
|
||||
}
|
||||
}
|
||||
@@ -1,166 +0,0 @@
|
||||
package processing.mode.experimental;
|
||||
|
||||
/*
|
||||
Part of the XQMode project - https://github.com/Manindra29/XQMode
|
||||
|
||||
Under Google Summer of Code 2012 -
|
||||
http://www.google-melange.com/gsoc/homepage/google/gsoc2012
|
||||
|
||||
Copyright (C) 2012 Manindra Moharana
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2
|
||||
as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.SwingWorker;
|
||||
import javax.swing.table.JTableHeader;
|
||||
import javax.swing.table.TableModel;
|
||||
|
||||
/**
|
||||
* Custom JTable implementation for XQMode. Minor tweaks and addtions.
|
||||
*
|
||||
* @author Manindra Moharana <me@mkmoharana.com>
|
||||
*
|
||||
*/
|
||||
public class XQErrorTable extends JTable {
|
||||
|
||||
/**
|
||||
* Column Names of JTable
|
||||
*/
|
||||
public static final String[] columnNames = { "Problem", "Tab", "Line" };
|
||||
|
||||
/**
|
||||
* Column Widths of JTable.
|
||||
*/
|
||||
public int[] columnWidths = { 600, 100, 50 }; // Default Values
|
||||
|
||||
/**
|
||||
* Is the column being resized?
|
||||
*/
|
||||
private boolean columnResizing = false;
|
||||
|
||||
/**
|
||||
* ErrorCheckerService instance
|
||||
*/
|
||||
protected ErrorCheckerService errorCheckerService;
|
||||
|
||||
@Override
|
||||
public boolean isCellEditable(int rowIndex, int colIndex) {
|
||||
return false; // Disallow the editing of any cell
|
||||
}
|
||||
|
||||
public XQErrorTable(final ErrorCheckerService errorCheckerService) {
|
||||
this.errorCheckerService = errorCheckerService;
|
||||
for (int i = 0; i < this.getColumnModel().getColumnCount(); i++) {
|
||||
this.getColumnModel().getColumn(i)
|
||||
.setPreferredWidth(columnWidths[i]);
|
||||
}
|
||||
|
||||
this.getTableHeader().setReorderingAllowed(false);
|
||||
|
||||
this.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
synchronized public void mouseReleased(MouseEvent e) {
|
||||
try {
|
||||
errorCheckerService.scrollToErrorLine(((XQErrorTable) e
|
||||
.getSource()).getSelectedRow());
|
||||
// System.out.print("Row clicked: "
|
||||
// + ((XQErrorTable) e.getSource()).getSelectedRow());
|
||||
} catch (Exception e1) {
|
||||
System.out.println("Exception XQErrorTable mouseReleased "
|
||||
+ e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Handles the resizing of columns. When mouse press is detected on
|
||||
// table header, Stop updating the table, store new values of column
|
||||
// widths,and resume updating. Updating is disabled as long as
|
||||
// columnResizing is true
|
||||
this.getTableHeader().addMouseListener(new MouseAdapter() {
|
||||
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
columnResizing = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent e) {
|
||||
columnResizing = false;
|
||||
for (int i = 0; i < ((JTableHeader) e.getSource())
|
||||
.getColumnModel().getColumnCount(); i++) {
|
||||
columnWidths[i] = ((JTableHeader) e.getSource())
|
||||
.getColumnModel().getColumn(i).getWidth();
|
||||
// System.out.println("nw " + columnWidths[i]);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Updates table contents with new data
|
||||
* @param tableModel - TableModel
|
||||
* @return boolean - If table data was updated
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
synchronized public boolean updateTable(final TableModel tableModel) {
|
||||
|
||||
// If problems list is not visible, no need to update
|
||||
if (!this.isVisible()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SwingWorker worker = new SwingWorker() {
|
||||
|
||||
protected Object doInBackground() throws Exception {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void done() {
|
||||
|
||||
try {
|
||||
setModel(tableModel);
|
||||
|
||||
// Set column widths to user defined widths
|
||||
for (int i = 0; i < getColumnModel().getColumnCount(); i++) {
|
||||
getColumnModel().getColumn(i).setPreferredWidth(
|
||||
columnWidths[i]);
|
||||
}
|
||||
getTableHeader().setReorderingAllowed(false);
|
||||
validate();
|
||||
repaint();
|
||||
} catch (Exception e) {
|
||||
System.out.println("Exception at XQErrorTable.updateTable " + e);
|
||||
// e.printStackTrace();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
if (!columnResizing) {
|
||||
worker.execute();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println("ErrorTable updateTable Worker's slacking."
|
||||
+ e.getMessage());
|
||||
// e.printStackTrace();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,245 +0,0 @@
|
||||
/*
|
||||
Part of the XQMode project - https://github.com/Manindra29/XQMode
|
||||
|
||||
Under Google Summer of Code 2012 -
|
||||
http://www.google-melange.com/gsoc/homepage/google/gsoc2012
|
||||
|
||||
Copyright (C) 2012 Manindra Moharana
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2
|
||||
as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
package processing.mode.experimental;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.core.JavaCore;
|
||||
import org.eclipse.jdt.core.dom.AST;
|
||||
import org.eclipse.jdt.core.dom.ASTParser;
|
||||
import org.eclipse.jdt.core.dom.ASTVisitor;
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.jdt.core.dom.MethodDeclaration;
|
||||
import org.eclipse.jdt.core.dom.Modifier;
|
||||
import org.eclipse.jdt.core.dom.NumberLiteral;
|
||||
import org.eclipse.jdt.core.dom.SimpleType;
|
||||
import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
|
||||
import org.eclipse.jface.text.BadLocationException;
|
||||
import org.eclipse.jface.text.Document;
|
||||
import org.eclipse.text.edits.MalformedTreeException;
|
||||
import org.eclipse.text.edits.TextEdit;
|
||||
|
||||
import processing.mode.java.preproc.PdePreprocessor;
|
||||
|
||||
/**
|
||||
* My implementation of P5 preprocessor. Uses Eclipse JDT features instead of
|
||||
* ANTLR. Performance gains mostly and full control over debug output. But needs
|
||||
* lots and lots of testing. There will always an option to switch back to PDE
|
||||
* preproc.
|
||||
*
|
||||
* @author Manindra Moharana <me@mkmoharana.com>
|
||||
*
|
||||
*/
|
||||
public class XQPreprocessor {
|
||||
|
||||
private ASTRewrite rewrite = null;
|
||||
private ArrayList<String> imports;
|
||||
private ArrayList<ImportStatement> extraImports;
|
||||
|
||||
private String[] coreImports, defaultImports;
|
||||
|
||||
public XQPreprocessor() {
|
||||
PdePreprocessor p = new PdePreprocessor(null);
|
||||
defaultImports = p.getDefaultImports();
|
||||
coreImports = p.getCoreImports();
|
||||
}
|
||||
|
||||
/**
|
||||
* The main method that performs preprocessing. Converts code into compilable java.
|
||||
* @param source - String
|
||||
* @param programImports - List of import statements
|
||||
* @return String - Compile ready java code
|
||||
*/
|
||||
public String doYourThing(String source,
|
||||
ArrayList<ImportStatement> programImports) {
|
||||
this.extraImports = programImports;
|
||||
//source = prepareImports() + source;
|
||||
Document doc = new Document(source);
|
||||
|
||||
ASTParser parser = ASTParser.newParser(AST.JLS4);
|
||||
parser.setSource(doc.get().toCharArray());
|
||||
parser.setKind(ASTParser.K_COMPILATION_UNIT);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, String> options = JavaCore.getOptions();
|
||||
|
||||
// Ben has decided to move on to 1.6. Yay!
|
||||
JavaCore.setComplianceOptions(JavaCore.VERSION_1_6, options);
|
||||
options.put(JavaCore.COMPILER_SOURCE, JavaCore.VERSION_1_6);
|
||||
parser.setCompilerOptions(options);
|
||||
CompilationUnit cu = (CompilationUnit) parser.createAST(null);
|
||||
cu.recordModifications();
|
||||
rewrite = ASTRewrite.create(cu.getAST());
|
||||
cu.accept(new XQASTVisitor());
|
||||
|
||||
TextEdit edits = cu.rewrite(doc, null);
|
||||
try {
|
||||
edits.apply(doc);
|
||||
} catch (MalformedTreeException e) {
|
||||
e.printStackTrace();
|
||||
} catch (BadLocationException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
// System.out.println("------------XQPreProc-----------------");
|
||||
// System.out.println(doc.get());
|
||||
// System.out.println("------------XQPreProc End-----------------");
|
||||
|
||||
// Calculate main class offset
|
||||
int position = doc.get().indexOf("{") + 1;
|
||||
int lines = 0;
|
||||
for (int i = 0; i < position; i++) {
|
||||
if (doc.get().charAt(i) == '\n') {
|
||||
lines++;
|
||||
}
|
||||
}
|
||||
lines += 2;
|
||||
// System.out.println("Lines: " + lines);
|
||||
|
||||
return doc.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all import statements as lines of code
|
||||
*
|
||||
* @return String - All import statements combined. Each import in a separate line.
|
||||
*/
|
||||
public String prepareImports() {
|
||||
imports = new ArrayList<String>();
|
||||
for (int i = 0; i < extraImports.size(); i++) {
|
||||
imports.add(new String(extraImports.get(i).importName));
|
||||
}
|
||||
imports.add(new String("// Default Imports"));
|
||||
for (int i = 0; i < coreImports.length; i++) {
|
||||
imports.add(new String("import " + coreImports[i] + ";"));
|
||||
}
|
||||
for (int i = 0; i < defaultImports.length; i++) {
|
||||
imports.add(new String("import " + defaultImports[i] + ";"));
|
||||
}
|
||||
String totalImports = "";
|
||||
for (int i = 0; i < imports.size(); i++) {
|
||||
totalImports += imports.get(i) + "\n";
|
||||
}
|
||||
totalImports += "\n";
|
||||
return totalImports;
|
||||
}
|
||||
|
||||
public String prepareImports(ArrayList<ImportStatement> programImports) {
|
||||
this.extraImports = programImports;
|
||||
return prepareImports();
|
||||
}
|
||||
|
||||
/**
|
||||
* Visitor implementation that does all the substitution dirty work. <br>
|
||||
* <LI>Any function not specified as being protected or private will be made
|
||||
* 'public'. This means that <TT>void setup()</TT> becomes
|
||||
* <TT>public void setup()</TT>.
|
||||
*
|
||||
* <LI>Converts doubles into floats, i.e. 12.3 becomes 12.3f so that people
|
||||
* don't have to add f after their numbers all the time since it's confusing
|
||||
* for beginners. Also, most functions of p5 core deal with floats only.
|
||||
*
|
||||
* @author Manindra Moharana
|
||||
*
|
||||
*/
|
||||
private class XQASTVisitor extends ASTVisitor {
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public boolean visit(MethodDeclaration node) {
|
||||
if (node.getReturnType2() != null) {
|
||||
// if return type is color, make it int
|
||||
// if (node.getReturnType2().toString().equals("color")) {
|
||||
// System.err.println("color type detected!");
|
||||
// node.setReturnType2(rewrite.getAST().newPrimitiveType(
|
||||
// PrimitiveType.INT));
|
||||
// }
|
||||
|
||||
// The return type is not void, no need to make it public
|
||||
// if (!node.getReturnType2().toString().equals("void"))
|
||||
// return true;
|
||||
}
|
||||
|
||||
// Simple method, make it public
|
||||
if (node.modifiers().size() == 0 && !node.isConstructor()) {
|
||||
// rewrite.set(node, node.getModifiersProperty(),
|
||||
// Modifier.PUBLIC,
|
||||
// null);
|
||||
// rewrite.getListRewrite(node,
|
||||
// node.getModifiersProperty()).insertLast(Modifier., null)
|
||||
List newMod = rewrite.getAST().newModifiers(Modifier.PUBLIC);
|
||||
node.modifiers().add(newMod.get(0));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean visit(NumberLiteral node) {
|
||||
if (!node.getToken().endsWith("f")
|
||||
&& !node.getToken().endsWith("d")) {
|
||||
for (int i = 0; i < node.getToken().length(); i++) {
|
||||
if (node.getToken().charAt(i) == '.') {
|
||||
|
||||
String s = node.getToken() + "f";
|
||||
node.setToken(s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// public boolean visit(FieldDeclaration node) {
|
||||
// if (node.getType().toString().equals("color")){
|
||||
// System.err.println("color type detected!");
|
||||
// node.setType(rewrite.getAST().newPrimitiveType(
|
||||
// PrimitiveType.INT));
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// public boolean visit(VariableDeclarationStatement node) {
|
||||
// if (node.getType().toString().equals("color")){
|
||||
// System.err.println("color type detected!");
|
||||
// node.setType(rewrite.getAST().newPrimitiveType(
|
||||
// PrimitiveType.INT));
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
|
||||
/**
|
||||
* This is added just for debugging purposes - to make sure that all
|
||||
* instances of color type have been substituded as in by the regex
|
||||
* search in ErrorCheckerService.preprocessCode().
|
||||
*/
|
||||
public boolean visit(SimpleType node) {
|
||||
if (node.toString().equals("color")) {
|
||||
System.err
|
||||
.println("color type detected! \nThis shouldn't be happening! Please report this as an issue.");
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
# DEBUGGER
|
||||
|
||||
# breakpointed line background color
|
||||
breakpoint.bgcolor = #f0f0f0
|
||||
# marker for breakpointed lines in left hand gutter (2 ascii characters)
|
||||
breakpoint.marker = <>
|
||||
breakpoint.marker.color = #4a545e
|
||||
|
||||
# current line background color
|
||||
currentline.bgcolor = #ffff96
|
||||
# marker for the current line in left hand gutter (2 ascii characters)
|
||||
currentline.marker = ->
|
||||
currentline.marker.color = #e27500
|
||||
|
||||
# left hand gutter background color
|
||||
gutter.bgcolor = #fcfcfc
|
||||
# color of vertical separation line
|
||||
gutter.linecolor = #e9e9e9
|
||||
# space (in px) added to left and right of gutter markers
|
||||
gutter.padding = 3
|
||||
|
||||
|
||||
# XQMODE
|
||||
|
||||
# underline colors
|
||||
editor.errorcolor = #ed2630
|
||||
editor.warningcolor = #ffc30e
|
||||
editor.errormarkercolor = #ed2630
|
||||
editor.warningmarkercolor = #ffc30e
|
||||
|
||||
# ERROR BAR - error bar on the right that shows the markers
|
||||
errorbar.errorcolor = #ed2630
|
||||
errorbar.warningcolor = #ffc30e
|
||||
errorbar.backgroundcolor = #2c343d
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 5.0 KiB |
Reference in New Issue
Block a user