Skip to content

Commit c8015e4

Browse files
committed
Improved (the by-default-disabled) internal viewer - fixed selection, selecting opened element
1 parent 85f9165 commit c8015e4

File tree

5 files changed

+90
-154
lines changed

5 files changed

+90
-154
lines changed

plugins/sources/src/org/graalvm/visualvm/sources/SourceHandle.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ public static enum Feature {
9494

9595
public abstract int getOffset();
9696

97+
public int getEndOffset() { return getOffset(); }
98+
9799

98100
public abstract String getText();
99101

plugins/sources/src/org/graalvm/visualvm/sources/java/JavaSourceHandle.java

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
*/
2525
package org.graalvm.visualvm.sources.java;
2626

27+
import java.util.regex.Matcher;
28+
import java.util.regex.Pattern;
2729
import org.graalvm.visualvm.sources.SourceHandle;
2830
import org.graalvm.visualvm.sources.SourceHandleUtils;
2931
import org.graalvm.visualvm.sources.SourcePathHandle;
@@ -44,6 +46,7 @@ final class JavaSourceHandle extends SourceHandle {
4446
private int line;
4547
private int column;
4648
private int offset;
49+
private int endOffset;
4750

4851
private final SourcePathHandle pathHandle;
4952

@@ -56,6 +59,7 @@ final class JavaSourceHandle extends SourceHandle {
5659
this.line = line;
5760

5861
this.offset = -1;
62+
this.endOffset = -1;
5963
this.column = -1;
6064

6165
this.pathHandle = pathHandle;
@@ -109,15 +113,30 @@ public int getOffset() {
109113
if (offset == -1) {
110114
if (methodName == null || methodName.isEmpty() || methodName.startsWith("*")) { // NOI18N
111115
offset = JavaSourceUtils.classDefinitionOffset(getText(), className, false);
112-
// System.err.println(JavaUtils.maskNonClass(getText(), offset));
113116
} else {
114117
offset = JavaSourceUtils.methodDefinitionOffset(getText(), className, methodName, methodSignature, false);
115118
}
116119
if (offset == -1) offset = 0;
117-
// text = JavaUtils.maskNonClass(JavaUtils.maskNonCode(text), offset);
118120
}
119121
return offset;
120122
}
123+
124+
@Override
125+
public int getEndOffset() {
126+
if (endOffset == -1) {
127+
int _offset = getOffset();
128+
String _text = getText();
129+
130+
if (_text.charAt(_offset) == '{') { // NOI18N
131+
endOffset = _offset + 1;
132+
} else {
133+
Pattern pattern = Pattern.compile(JavaSourceUtils.FULLY_QUALIFIED_IDENTIFIER_REGEX);
134+
Matcher matcher = pattern.matcher(_text);
135+
endOffset = _offset + (matcher.find(_offset) ? matcher.group().length() : 0);
136+
}
137+
}
138+
return endOffset;
139+
}
121140

122141

123142
@Override

plugins/sources/src/org/graalvm/visualvm/sources/java/JavaSourceUtils.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ final class JavaSourceUtils {
4141
private static final String LAMBDA_CLASS_PREFIX = "$Lambda$"; // NOI18N
4242
static final String LAMBDA_CLASS_PREFIX_MASK = "-Lambda-"; // NOI18N
4343

44-
private static final String IDENTIFIER_REGEX = "\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*"; // NOI18N
45-
private static final String FULLY_QUALIFIED_IDENTIFIER_REGEX = "(" + IDENTIFIER_REGEX + "\\.)*" + IDENTIFIER_REGEX; // NOI18N
44+
static final String IDENTIFIER_REGEX = "\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*"; // NOI18N
45+
static final String FULLY_QUALIFIED_IDENTIFIER_REGEX = "(" + IDENTIFIER_REGEX + "\\.)*" + IDENTIFIER_REGEX; // NOI18N
4646
private static final String THROWS_REGEX = "throws\\s+(" + FULLY_QUALIFIED_IDENTIFIER_REGEX + "\\s*,\\s*)*" + FULLY_QUALIFIED_IDENTIFIER_REGEX; // NOI18N
4747

4848

plugins/sources/src/org/graalvm/visualvm/sources/viewer/internal/InternalSourceViewerComponent.java

Lines changed: 58 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@
2929
import java.awt.Component;
3030
import java.awt.Dimension;
3131
import java.awt.Graphics;
32-
import java.awt.Insets;
32+
import java.awt.Graphics2D;
3333
import java.awt.Rectangle;
34+
import java.awt.Shape;
3435
import java.awt.event.MouseAdapter;
3536
import java.awt.event.MouseEvent;
3637
import java.beans.PropertyChangeEvent;
@@ -42,16 +43,17 @@
4243
import javax.swing.JTable;
4344
import javax.swing.JTextArea;
4445
import javax.swing.JViewport;
46+
import javax.swing.SwingUtilities;
4547
import javax.swing.event.CaretEvent;
4648
import javax.swing.event.CaretListener;
47-
import javax.swing.plaf.TextUI;
4849
import javax.swing.table.AbstractTableModel;
4950
import javax.swing.table.DefaultTableCellRenderer;
5051
import javax.swing.table.TableModel;
5152
import javax.swing.text.BadLocationException;
5253
import javax.swing.text.DefaultHighlighter;
53-
import javax.swing.text.Highlighter;
5454
import javax.swing.text.JTextComponent;
55+
import javax.swing.text.View;
56+
import org.openide.util.Exceptions;
5557

5658
/**
5759
*
@@ -67,7 +69,7 @@ final class InternalSourceViewerComponent extends JPanel implements PropertyChan
6769
private final JPanel lineNumbersPanel;
6870

6971

70-
public InternalSourceViewerComponent(String text, int offset, InternalSourceAppearance appearance) {
72+
public InternalSourceViewerComponent(String text, int offset, int endOffset, InternalSourceAppearance appearance) {
7173
super(new BorderLayout());
7274

7375
sourceArea = new SourceArea();
@@ -77,7 +79,7 @@ public InternalSourceViewerComponent(String text, int offset, InternalSourceAppe
7779
propertyChange(null);
7880

7981
sourceArea.setText(text);
80-
sourceArea.setOffset(offset);
82+
setOffset(offset, endOffset);
8183

8284
lineNumbersPanel = new JPanel(new BorderLayout());
8385
lineNumbersPanel.setBorder(BorderFactory.createEmptyBorder(0, 15, 0, 10));
@@ -109,8 +111,12 @@ public void propertyChange(PropertyChangeEvent evt) {
109111
}
110112

111113

112-
void setOffset(int offset) {
114+
void setOffset(final int offset, final int endOffset) {
113115
sourceArea.setOffset(offset);
116+
117+
SwingUtilities.invokeLater(new Runnable() {
118+
public void run() { sourceArea.select(offset, endOffset); }
119+
});
114120
}
115121

116122

@@ -129,13 +135,17 @@ private static class SourceArea extends JTextArea implements CaretListener {
129135

130136
private int pendingOffset = -1;
131137

138+
private Object rowHighlight;
139+
private final LineHighlightPainter highlightPainter;
140+
141+
132142
SourceArea() {
133143
super();
134144

135145
setEditable(false);
136146
setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 5));
137147

138-
setHighlighter(new LineHighlighter());
148+
highlightPainter = new LineHighlightPainter();
139149
addCaretListener(this);
140150

141151
MouseAdapter adapter = new MouseAdapter() {
@@ -185,6 +195,11 @@ public void validate() {
185195
pendingOffset = -1;
186196
}
187197
}
198+
199+
public void requestFocus() {
200+
super.requestFocus();
201+
setHighlight(getCaretPosition());
202+
}
188203

189204

190205
@Override
@@ -193,19 +208,24 @@ public void caretUpdate(CaretEvent e) {
193208
}
194209

195210

196-
public void setHighlight(int dot) {
197-
getHighlighter().removeAllHighlights();
198-
int currentLine = getLineFromOffset(this, dot);
199-
int startPos = getLineStartOffsetForLine(this, currentLine);
200-
int endOffset = getLineEndOffsetForLine(this, currentLine);
211+
public void setHighlight(final int dot) {
212+
SwingUtilities.invokeLater(new Runnable() {
213+
public void run() {
214+
if (rowHighlight != null) getHighlighter().removeHighlight(rowHighlight);
215+
216+
int currentLine = getLineFromOffset(SourceArea.this, dot);
217+
int startOffset = getLineStartOffsetForLine(SourceArea.this, currentLine);
218+
int endOffset = getLineEndOffsetForLine(SourceArea.this, currentLine);
219+
220+
try {
221+
rowHighlight = getHighlighter().addHighlight(startOffset, endOffset, highlightPainter);
222+
} catch (BadLocationException ex) {
223+
Exceptions.printStackTrace(ex);
224+
}
201225

202-
try {
203-
getHighlighter().addHighlight(startPos, endOffset, new DefaultHighlighter.DefaultHighlightPainter(new Color(233, 239, 248)));
204-
// getHighlighter().addHighlight(startPos, endOffset, new CustomHighlightPainter());
205-
} catch (Exception ex) {
206-
ex.printStackTrace();
207-
}
208-
repaint();
226+
repaint();
227+
}
228+
});
209229
}
210230

211231
public int getLineFromOffset(JTextComponent component, int offset) {
@@ -220,136 +240,31 @@ public int getLineEndOffsetForLine(JTextComponent component, int line) {
220240
return component.getDocument().getDefaultRootElement().getElement(line).getEndOffset();
221241
}
222242

223-
static class LineHighlighter extends DefaultHighlighter {
224-
private JTextComponent component;
225-
226-
@Override
227-
public final void install(final JTextComponent c) {
228-
super.install(c);
229-
this.component = c;
230-
}
231-
232-
@Override
233-
public final void deinstall(final JTextComponent c) {
234-
super.deinstall(c);
235-
this.component = null;
243+
244+
static final class LineHighlightPainter extends DefaultHighlighter.DefaultHighlightPainter {
245+
246+
LineHighlightPainter() {
247+
super(new Color(233, 239, 248));
236248
}
237-
238-
@Override
239-
public final void paint(final Graphics g) {
240-
final Highlighter.Highlight[] highlights = getHighlights();
241-
final int len = highlights.length;
242-
for (int i = 0; i < len; i++) {
243-
Highlighter.Highlight info = highlights[i];
244-
if (info.getClass().getName().contains("LayeredHighlightInfo")) { // NOI18N
245-
246-
final Rectangle a = this.component.getBounds();
247-
final Insets insets = this.component.getInsets();
248-
a.x = insets.left;
249-
a.y = insets.top;
250-
251-
a.height -= insets.top + insets.bottom;
252-
final Highlighter.HighlightPainter p = info.getPainter();
253-
p.paint(g, info.getStartOffset(), info.getEndOffset(), a, this.component);
254-
255-
Rectangle alloc = a;
256-
try {
257-
TextUI mapper = this.component.getUI();
258-
Rectangle p0 = mapper.modelToView(this.component, this.component.getSelectionStart());
259-
Rectangle p1 = mapper.modelToView(this.component, this.component.getSelectionEnd());
260-
261-
g.setColor(this.component.getSelectionColor());
262-
if (p0.y == p1.y) {
263-
Rectangle r = p0.union(p1);
264-
g.fillRect(r.x, r.y, r.width, r.height);
265-
} else {
266-
int p0ToMarginWidth = alloc.x + alloc.width - p0.x;
267-
g.fillRect(p0.x, p0.y, p0ToMarginWidth, p0.height);
268-
if ((p0.y + p0.height) != p1.y) g.fillRect(alloc.x, p0.y + p0.height, alloc.width, p1.y - (p0.y + p0.height));
269-
g.fillRect(alloc.x, p1.y, (p1.x - alloc.x), p1.height);
270-
}
271-
} catch (BadLocationException e) {
272-
}
273-
}
249+
250+
public Shape paintLayer(Graphics g, int offs0, int offs1,
251+
Shape bounds, JTextComponent c, View view) {
252+
try {
253+
Rectangle r = c.modelToView(offs0);
254+
r.x = 0;
255+
r.width = c.getWidth();
256+
257+
g.setColor(getColor());
258+
((Graphics2D)g).fill(r);
259+
260+
return r;
261+
} catch (BadLocationException ex) {
262+
return null;
274263
}
275264
}
276265

277-
@Override
278-
public void removeAllHighlights() {
279-
if (component != null) component.repaint(0, 0, component.getWidth(), component.getHeight());
280-
super.removeAllHighlights();
281-
}
282266
}
283267

284-
// static final class CustomHighlightPainter extends DefaultHighlighter.DefaultHighlightPainter {
285-
//
286-
// CustomHighlightPainter() {
287-
// super(Color.ORANGE);
288-
//// super(new Color(233, 239, 248));
289-
// }
290-
//
291-
// public void paint(Graphics g, int offs0, int offs1,
292-
// Shape bounds, JTextComponent c) {
293-
//
294-
// int selStart = c.getSelectionStart();
295-
// int selEnd = c.getSelectionEnd();
296-
//
297-
// // No selection or selection fully outside of the highlight
298-
// if (selEnd - selStart == 0 || offs0 >= selEnd || offs1 <= selStart) super.paint(g, offs0, offs1, bounds, c);
299-
//
300-
// // Selection fully covers the highlight
301-
// if (offs0 >= selStart && offs1 <= selEnd) return;
302-
//
303-
// // Selection partially covers the highlight
304-
// if (offs0 < selStart || offs1 > selEnd) {
305-
// // Selection ends inside of the highlight
306-
// if (offs0 >= selStart) super.paint(g, selEnd, offs1, bounds, c);
307-
// // Selection starts inside of the highlight
308-
// else if (offs1 <= selEnd) super.paint(g, offs0, selStart, bounds, c);
309-
//
310-
// // Selection fully inside of the highlight
311-
// super.paint(g, offs0, selStart, bounds, c);
312-
// super.paint(g, selEnd, offs1, bounds, c);
313-
// }
314-
//
315-
//
316-
// Rectangle alloc = bounds.getBounds();
317-
// try {
318-
// // --- determine locations ---
319-
// TextUI mapper = c.getUI();
320-
// Rectangle p0 = mapper.modelToView(c, offs0);
321-
// Rectangle p1 = mapper.modelToView(c, offs1);
322-
//
323-
// // --- render ---
324-
// Color color = getColor();
325-
//
326-
// if (color == null) {
327-
// g.setColor(c.getSelectionColor());
328-
// }
329-
// else {
330-
// g.setColor(color);
331-
// }
332-
// if (p0.y == p1.y) {
333-
// // same line, render a rectangle
334-
// Rectangle r = p0.union(p1);
335-
// g.fillRect(r.x, r.y, r.width, r.height);
336-
// } else {
337-
// // different lines
338-
// int p0ToMarginWidth = alloc.x + alloc.width - p0.x;
339-
// g.fillRect(p0.x, p0.y, p0ToMarginWidth, p0.height);
340-
// if ((p0.y + p0.height) != p1.y) {
341-
// g.fillRect(alloc.x, p0.y + p0.height, alloc.width,
342-
// p1.y - (p0.y + p0.height));
343-
// }
344-
// g.fillRect(alloc.x, p1.y, (p1.x - alloc.x), p1.height);
345-
// }
346-
// } catch (BadLocationException e) {
347-
// // can't render
348-
// }
349-
// }
350-
//
351-
// }
352-
353268
}
354269

355270
private static class LineNumbers extends JTable {

0 commit comments

Comments
 (0)