1+ package processing .mode .java .pdex ;
2+
3+ import java .awt .EventQueue ;
4+ import java .awt .event .InputEvent ;
5+ import java .awt .event .KeyAdapter ;
6+ import java .awt .event .KeyEvent ;
7+ import java .awt .event .MouseAdapter ;
8+ import java .awt .event .MouseEvent ;
9+ import java .awt .event .MouseWheelEvent ;
10+ import java .util .function .Predicate ;
11+
12+ import javax .swing .JMenuItem ;
13+
14+ import org .eclipse .jdt .core .dom .ASTNode ;
15+ import org .eclipse .jdt .core .dom .IBinding ;
16+ import org .eclipse .jdt .core .dom .MethodDeclaration ;
17+ import org .eclipse .jdt .core .dom .SimpleName ;
18+ import org .eclipse .jdt .core .dom .TypeDeclaration ;
19+ import org .eclipse .jdt .core .dom .VariableDeclaration ;
20+
21+ import processing .app .Language ;
22+ import processing .app .Messages ;
23+ import processing .app .Platform ;
24+ import processing .mode .java .JavaEditor ;
25+ import processing .mode .java .JavaMode ;
26+ import processing .mode .java .pdex .PreprocessedSketch .SketchInterval ;
27+
28+ import static processing .mode .java .pdex .ASTUtils .getSimpleNameAt ;
29+ import static processing .mode .java .pdex .ASTUtils .resolveBinding ;
30+
31+
32+ class InspectMode {
33+ final JavaEditor editor ;
34+ final PreprocessingService pps ;
35+ final ShowUsage usage ;
36+
37+ boolean inspectModeEnabled ;
38+
39+ boolean isMouse1Down ;
40+ boolean isMouse2Down ;
41+ boolean isHotkeyDown ;
42+
43+ Predicate <MouseEvent > mouseEventHotkeyTest = Platform .isMacOS () ?
44+ InputEvent ::isMetaDown : InputEvent ::isControlDown ;
45+ Predicate <KeyEvent > keyEventHotkeyTest = Platform .isMacOS () ?
46+ e -> e .getKeyCode () == KeyEvent .VK_META :
47+ e -> e .getKeyCode () == KeyEvent .VK_CONTROL ;
48+
49+
50+ InspectMode (JavaEditor editor , PreprocessingService pps , ShowUsage usage ) {
51+ this .editor = editor ;
52+ this .pps = pps ;
53+ this .usage = usage ;
54+
55+ // Add listeners
56+
57+ JMenuItem showUsageItem = new JMenuItem (Language .text ("editor.popup.jump_to_declaration" ));
58+ showUsageItem .addActionListener (e -> handleInspect ());
59+ editor .getTextArea ().getRightClickPopup ().add (showUsageItem );
60+
61+ editor .getJavaTextArea ().getPainter ().addMouseListener (new MouseAdapter () {
62+ @ Override
63+ public void mousePressed (MouseEvent e ) {
64+ isMouse1Down = isMouse1Down || (e .getButton () == MouseEvent .BUTTON1 );
65+ isMouse2Down = isMouse2Down || (e .getButton () == MouseEvent .BUTTON2 );
66+ }
67+
68+ @ Override
69+ public void mouseReleased (MouseEvent e ) {
70+ boolean releasingMouse1 = e .getButton () == MouseEvent .BUTTON1 ;
71+ boolean releasingMouse2 = e .getButton () == MouseEvent .BUTTON2 ;
72+ if (JavaMode .inspectModeHotkeyEnabled && inspectModeEnabled &&
73+ isMouse1Down && releasingMouse1 ) {
74+ handleInspect (e );
75+ } else if (!inspectModeEnabled && isMouse2Down && releasingMouse2 ) {
76+ handleInspect (e );
77+ }
78+ isMouse1Down = isMouse1Down && !releasingMouse1 ;
79+ isMouse2Down = isMouse2Down && !releasingMouse2 ;
80+ }
81+ });
82+
83+ editor .getJavaTextArea ().getPainter ().addMouseMotionListener (new MouseAdapter () {
84+ @ Override
85+ public void mouseDragged (MouseEvent e ) {
86+ if (editor .isSelectionActive ()) {
87+ // Mouse was dragged too much, disable
88+ inspectModeEnabled = false ;
89+ // Cancel possible mouse 2 press
90+ isMouse2Down = false ;
91+ }
92+ }
93+
94+ @ Override
95+ public void mouseMoved (MouseEvent e ) {
96+ isMouse1Down = false ;
97+ isMouse2Down = false ;
98+ isHotkeyDown = mouseEventHotkeyTest .test (e );
99+ inspectModeEnabled = isHotkeyDown ;
100+ }
101+ });
102+
103+ editor .getJavaTextArea ().addMouseWheelListener (new MouseAdapter () {
104+ @ Override
105+ public void mouseWheelMoved (MouseWheelEvent e ) {
106+ // Editor was scrolled while mouse 1 was pressed, disable
107+ if (isMouse1Down ) inspectModeEnabled = false ;
108+ }
109+ });
110+
111+ editor .getJavaTextArea ().addKeyListener (new KeyAdapter () {
112+ @ Override
113+ public void keyPressed (KeyEvent e ) {
114+ isHotkeyDown = isHotkeyDown || keyEventHotkeyTest .test (e );
115+ // Enable if hotkey was just pressed and mouse 1 is not down
116+ inspectModeEnabled = inspectModeEnabled || (!isMouse1Down && isHotkeyDown );
117+ }
118+
119+ @ Override
120+ public void keyReleased (KeyEvent e ) {
121+ isHotkeyDown = isHotkeyDown && !keyEventHotkeyTest .test (e );
122+ // Disable if hotkey was just released
123+ inspectModeEnabled = inspectModeEnabled && isHotkeyDown ;
124+ }
125+ });
126+ }
127+
128+
129+ void handleInspect () {
130+ int off = editor .getSelectionStart ();
131+ int tabIndex = editor .getSketch ().getCurrentCodeIndex ();
132+
133+ pps .whenDoneBlocking (ps -> handleInspect (ps , tabIndex , off ));
134+ }
135+
136+
137+ // Thread: EDT
138+ void handleInspect (MouseEvent evt ) {
139+ int off = editor .getJavaTextArea ().xyToOffset (evt .getX (), evt .getY ());
140+ if (off < 0 ) return ;
141+ int tabIndex = editor .getSketch ().getCurrentCodeIndex ();
142+
143+ pps .whenDoneBlocking (ps -> handleInspect (ps , tabIndex , off ));
144+ }
145+
146+
147+ // Thread: worker
148+ private void handleInspect (PreprocessedSketch ps , int tabIndex , int offset ) {
149+ ASTNode root = ps .compilationUnit ;
150+ int javaOffset = ps .tabOffsetToJavaOffset (tabIndex , offset );
151+
152+ SimpleName simpleName = getSimpleNameAt (root , javaOffset , javaOffset );
153+
154+ if (simpleName == null ) {
155+ Messages .log ("no simple name found at click location" );
156+ return ;
157+ }
158+
159+ IBinding binding = resolveBinding (simpleName );
160+ if (binding == null ) {
161+ Messages .log ("binding not resolved" );
162+ return ;
163+ }
164+
165+ String key = binding .getKey ();
166+ ASTNode decl = ps .compilationUnit .findDeclaringNode (key );
167+ if (decl == null ) {
168+ Messages .log ("decl not found, showing usage instead" );
169+ usage .findUsageAndUpdateTree (ps , binding );
170+ return ;
171+ }
172+
173+ SimpleName declName = null ;
174+ switch (binding .getKind ()) {
175+ case IBinding .TYPE : declName = ((TypeDeclaration ) decl ).getName (); break ;
176+ case IBinding .METHOD : declName = ((MethodDeclaration ) decl ).getName (); break ;
177+ case IBinding .VARIABLE : declName = ((VariableDeclaration ) decl ).getName (); break ;
178+ }
179+ if (declName == null ) {
180+ Messages .log ("decl name not found " + decl );
181+ return ;
182+ }
183+
184+ if (declName .equals (simpleName )) {
185+ usage .findUsageAndUpdateTree (ps , binding );
186+ } else {
187+ Messages .log ("found declaration, offset " + decl .getStartPosition () + ", name: " + declName );
188+ SketchInterval si = ps .mapJavaToSketch (declName );
189+ if (!ps .inRange (si )) return ;
190+ EventQueue .invokeLater (() -> {
191+ editor .highlight (si .tabIndex , si .startTabOffset , si .stopTabOffset );
192+ });
193+ }
194+ }
195+
196+
197+ void dispose () {
198+ // Nothing to do
199+ }
200+ }
0 commit comments