Moved the search panel to its own panel.
- Fixes search panel glitch - Fixes markers mismatching with scrollbar thumb.
This commit is contained in:
parent
850da2dc4f
commit
a24c4c0fb6
|
@ -48,18 +48,21 @@ import java.util.Map;
|
|||
* Created by Bl3nd.
|
||||
* Date: 8/26/2024
|
||||
*/
|
||||
public class MyErrorStripe extends JPanel {
|
||||
public class MyErrorStripe extends JPanel
|
||||
{
|
||||
private final RSyntaxTextArea textArea;
|
||||
private final transient Listener listener;
|
||||
|
||||
public MyErrorStripe(RSyntaxTextArea textArea) {
|
||||
public MyErrorStripe(RSyntaxTextArea textArea)
|
||||
{
|
||||
this.textArea = textArea;
|
||||
setLayout(null);
|
||||
listener = new Listener();
|
||||
addMouseListener(listener);
|
||||
}
|
||||
|
||||
private int lineToY(int line, Rectangle r) {
|
||||
private int lineToY(int line, Rectangle r)
|
||||
{
|
||||
if (r == null)
|
||||
r = new Rectangle();
|
||||
|
||||
|
@ -71,13 +74,15 @@ public class MyErrorStripe extends JPanel {
|
|||
return Math.round((h - 1) * line / Math.max(lineCount, linesPerVisibleRect));
|
||||
}
|
||||
|
||||
private int yToLine(int y) {
|
||||
private int yToLine(int y)
|
||||
{
|
||||
int line = -1;
|
||||
int h = textArea.getVisibleRect().height;
|
||||
int lineHeight = textArea.getLineHeight();
|
||||
int linesPerVisibleRect = h / lineHeight;
|
||||
int lineCount = textArea.getLineCount();
|
||||
if (y < h) {
|
||||
if (y < h)
|
||||
{
|
||||
float at = y / (float) h;
|
||||
line = Math.round((Math.max(lineCount, linesPerVisibleRect) - 1) * at);
|
||||
}
|
||||
|
@ -85,7 +90,8 @@ public class MyErrorStripe extends JPanel {
|
|||
return line;
|
||||
}
|
||||
|
||||
private void paintParserNoticeMarker(Graphics2D g, ParserNotice notice, int width, int height) {
|
||||
private void paintParserNoticeMarker(Graphics2D g, ParserNotice notice, int width, int height)
|
||||
{
|
||||
Color borderColor = notice.getColor();
|
||||
if (borderColor == null)
|
||||
borderColor = Color.BLACK;
|
||||
|
@ -98,7 +104,8 @@ public class MyErrorStripe extends JPanel {
|
|||
g.drawRect(0, 0, width - 1, height - 1);
|
||||
}
|
||||
|
||||
public void refreshMarkers() {
|
||||
public void refreshMarkers()
|
||||
{
|
||||
removeAll();
|
||||
Map<Integer, Marker> markerMap = new HashMap<>();
|
||||
List<DocumentRange> occurrences = textArea.getMarkedOccurrences();
|
||||
|
@ -107,24 +114,30 @@ public class MyErrorStripe extends JPanel {
|
|||
repaint();
|
||||
}
|
||||
|
||||
private void addMarkersForRanges(List<DocumentRange> occurrences, Map<Integer, Marker> markerMap, Color color) {
|
||||
for (DocumentRange range : occurrences) {
|
||||
private void addMarkersForRanges(List<DocumentRange> occurrences, Map<Integer, Marker> markerMap, Color color)
|
||||
{
|
||||
for (DocumentRange range : occurrences)
|
||||
{
|
||||
int line;
|
||||
try {
|
||||
try
|
||||
{
|
||||
line = textArea.getLineOfOffset(range.getStartOffset());
|
||||
} catch (BadLocationException e) {
|
||||
} catch (BadLocationException e)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ParserNotice notice = new MarkedOccurrenceNotice(range, color);
|
||||
Integer key = line;
|
||||
Marker m = markerMap.get(key);
|
||||
if (m == null) {
|
||||
if (m == null)
|
||||
{
|
||||
m = new Marker(notice);
|
||||
m.addMouseListener(listener);
|
||||
markerMap.put(key, m);
|
||||
add(m);
|
||||
} else {
|
||||
} else
|
||||
{
|
||||
if (!m.containsMarkedOccurrence())
|
||||
m.addNotice(notice);
|
||||
}
|
||||
|
@ -132,179 +145,216 @@ public class MyErrorStripe extends JPanel {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void updateUI() {
|
||||
public void updateUI()
|
||||
{
|
||||
super.updateUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintComponent(Graphics g) {
|
||||
protected void paintComponent(Graphics g)
|
||||
{
|
||||
super.paintComponent(g);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintChildren(Graphics g) {
|
||||
protected void paintChildren(Graphics g)
|
||||
{
|
||||
super.paintChildren(g);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize() {
|
||||
public Dimension getPreferredSize()
|
||||
{
|
||||
return new Dimension(14, textArea.getPreferredScrollableViewportSize().height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doLayout() {
|
||||
for (int i = 0; i < getComponentCount(); i++) {
|
||||
public void doLayout()
|
||||
{
|
||||
for (int i = 0; i < getComponentCount(); i++)
|
||||
{
|
||||
Marker m = (Marker) getComponent(i);
|
||||
m.updateLocation();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNotify() {
|
||||
public void addNotify()
|
||||
{
|
||||
super.addNotify();
|
||||
refreshMarkers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNotify() {
|
||||
public void removeNotify()
|
||||
{
|
||||
super.removeNotify();
|
||||
}
|
||||
|
||||
private class Listener extends MouseAdapter {
|
||||
private class Listener extends MouseAdapter
|
||||
{
|
||||
private final Rectangle r = new Rectangle();
|
||||
|
||||
@Override
|
||||
public void mouseClicked(@NotNull MouseEvent e) {
|
||||
public void mouseClicked(@NotNull MouseEvent e)
|
||||
{
|
||||
Component source = (Component) e.getSource();
|
||||
if (source instanceof MyErrorStripe.Marker) {
|
||||
if (source instanceof MyErrorStripe.Marker)
|
||||
{
|
||||
Marker m = (Marker) source;
|
||||
m.mouseClicked(e);
|
||||
return;
|
||||
}
|
||||
|
||||
int line = yToLine(e.getY());
|
||||
if (line > -1) {
|
||||
try {
|
||||
if (line > -1)
|
||||
{
|
||||
try
|
||||
{
|
||||
int offset = textArea.getLineOfOffset(line);
|
||||
textArea.setCaretPosition(offset);
|
||||
RSyntaxUtilities.selectAndPossiblyCenter(textArea, new DocumentRange(offset, offset), false);
|
||||
} catch (BadLocationException exception) {
|
||||
} catch (BadLocationException exception)
|
||||
{
|
||||
UIManager.getLookAndFeel().provideErrorFeedback(textArea);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class MarkedOccurrenceNotice implements ParserNotice {
|
||||
private class MarkedOccurrenceNotice implements ParserNotice
|
||||
{
|
||||
private final DocumentRange range;
|
||||
private final Color color;
|
||||
|
||||
MarkedOccurrenceNotice(DocumentRange range, Color color) {
|
||||
MarkedOccurrenceNotice(DocumentRange range, Color color)
|
||||
{
|
||||
this.range = range;
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsPosition(int pos) {
|
||||
public boolean containsPosition(int pos)
|
||||
{
|
||||
return pos >= range.getStartOffset() && pos < range.getEndOffset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getColor() {
|
||||
public Color getColor()
|
||||
{
|
||||
return color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
public int getLength()
|
||||
{
|
||||
return range.getEndOffset() - range.getStartOffset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Level getLevel() {
|
||||
public Level getLevel()
|
||||
{
|
||||
return Level.INFO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLine() {
|
||||
try {
|
||||
public int getLine()
|
||||
{
|
||||
try
|
||||
{
|
||||
return textArea.getLineOfOffset(range.getStartOffset()) + 1;
|
||||
} catch (BadLocationException e) {
|
||||
} catch (BadLocationException e)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getKnowsOffsetAndLength() {
|
||||
return false;
|
||||
public boolean getKnowsOffsetAndLength()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
@Override
|
||||
public @NotNull String getMessage() {
|
||||
public @NotNull String getMessage()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOffset() {
|
||||
public int getOffset()
|
||||
{
|
||||
return range.getStartOffset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parser getParser() {
|
||||
public Parser getParser()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getShowInEditor() {
|
||||
public boolean getShowInEditor()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getToolTipText() {
|
||||
public String getToolTipText()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@NotNull ParserNotice o) {
|
||||
public int compareTo(@NotNull ParserNotice o)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
public int hashCode()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static final int MARKER_HEIGHT = 3;
|
||||
|
||||
private class Marker extends JComponent {
|
||||
private class Marker extends JComponent
|
||||
{
|
||||
private final java.util.List<ParserNotice> notices;
|
||||
|
||||
Marker(ParserNotice notice) {
|
||||
Marker(ParserNotice notice)
|
||||
{
|
||||
notices = new ArrayList<>();
|
||||
addNotice(notice);
|
||||
setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
|
||||
setSize(getPreferredSize());
|
||||
}
|
||||
|
||||
private void addNotice(ParserNotice notice) {
|
||||
private void addNotice(ParserNotice notice)
|
||||
{
|
||||
notices.add(notice);
|
||||
}
|
||||
|
||||
@Contract(value = " -> new", pure = true)
|
||||
@Override
|
||||
public @NotNull Dimension getPreferredSize() {
|
||||
public @NotNull Dimension getPreferredSize()
|
||||
{
|
||||
return new Dimension(12, MARKER_HEIGHT);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintComponent(Graphics g) {
|
||||
protected void paintComponent(Graphics g)
|
||||
{
|
||||
final ParserNotice notice = getHighestPriorityNotice();
|
||||
if (notice != null)
|
||||
paintParserNoticeMarker((Graphics2D) g, notice, getWidth(), getHeight());
|
||||
}
|
||||
|
||||
protected void mouseClicked(MouseEvent e) {
|
||||
protected void mouseClicked(MouseEvent e)
|
||||
{
|
||||
ParserNotice pn = notices.get(0);
|
||||
int offs = pn.getOffset();
|
||||
int len = pn.getLength();
|
||||
|
@ -312,9 +362,11 @@ public class MyErrorStripe extends JPanel {
|
|||
{
|
||||
DocumentRange range = new DocumentRange(offs, offs + len);
|
||||
RSyntaxUtilities.selectAndPossiblyCenter(textArea, range, true);
|
||||
} else {
|
||||
} else
|
||||
{
|
||||
int line = pn.getLine();
|
||||
try {
|
||||
try
|
||||
{
|
||||
offs = textArea.getLineStartOffset(line);
|
||||
textArea.getFoldManager().ensureOffsetNotInClosedFold(offs);
|
||||
textArea.setCaretPosition(offs);
|
||||
|
@ -325,10 +377,13 @@ public class MyErrorStripe extends JPanel {
|
|||
}
|
||||
}
|
||||
|
||||
public boolean containsMarkedOccurrence() {
|
||||
public boolean containsMarkedOccurrence()
|
||||
{
|
||||
boolean result = false;
|
||||
for (ParserNotice notice : notices) {
|
||||
if (notice instanceof MarkedOccurrenceNotice) {
|
||||
for (ParserNotice notice : notices)
|
||||
{
|
||||
if (notice instanceof MarkedOccurrenceNotice)
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
@ -337,11 +392,14 @@ public class MyErrorStripe extends JPanel {
|
|||
return result;
|
||||
}
|
||||
|
||||
public ParserNotice getHighestPriorityNotice() {
|
||||
public ParserNotice getHighestPriorityNotice()
|
||||
{
|
||||
ParserNotice selectedNotice = null;
|
||||
int lowestLevel = Integer.MAX_VALUE;
|
||||
for (ParserNotice notice : notices) {
|
||||
if (notice.getLevel().getNumericValue() < lowestLevel) {
|
||||
for (ParserNotice notice : notices)
|
||||
{
|
||||
if (notice.getLevel().getNumericValue() < lowestLevel)
|
||||
{
|
||||
lowestLevel = notice.getLevel().getNumericValue();
|
||||
selectedNotice = notice;
|
||||
}
|
||||
|
@ -350,7 +408,8 @@ public class MyErrorStripe extends JPanel {
|
|||
return selectedNotice;
|
||||
}
|
||||
|
||||
public void updateLocation() {
|
||||
public void updateLocation()
|
||||
{
|
||||
int line = notices.get(0).getLine();
|
||||
int y = lineToY(line - 1, null);
|
||||
setLocation(2, y);
|
||||
|
|
|
@ -18,197 +18,171 @@
|
|||
|
||||
package the.bytecode.club.bytecodeviewer.gui.components;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseWheelEvent;
|
||||
import java.awt.event.MouseWheelListener;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.text.BadLocationException;
|
||||
|
||||
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
|
||||
import org.fife.ui.rtextarea.RTextScrollPane;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
import the.bytecode.club.bytecodeviewer.Configuration;
|
||||
import the.bytecode.club.bytecodeviewer.GlobalHotKeys;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.listeners.PressKeyListener;
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.listeners.ReleaseKeyListener;
|
||||
import the.bytecode.club.bytecodeviewer.gui.theme.LAFTheme;
|
||||
import the.bytecode.club.bytecodeviewer.resources.IconResources;
|
||||
import the.bytecode.club.bytecodeviewer.translation.TranslatedComponents;
|
||||
import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJCheckBox;
|
||||
import the.bytecode.club.bytecodeviewer.util.JTextAreaUtils;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.text.BadLocationException;
|
||||
import java.awt.*;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseWheelEvent;
|
||||
|
||||
/**
|
||||
* Searching on an RSyntaxTextArea using swing highlighting
|
||||
*
|
||||
* @author Konloch
|
||||
* @since 6/25/2021
|
||||
*/
|
||||
public class SearchableRSyntaxTextArea extends RSyntaxTextArea {
|
||||
public class SearchableRSyntaxTextArea extends RSyntaxTextArea
|
||||
{
|
||||
|
||||
private RTextScrollPane scrollPane = new RTextScrollPane(this);
|
||||
private final JPanel searchPanel = new JPanel(new BorderLayout());
|
||||
private final JTextField searchInput = new JTextField();
|
||||
private final JCheckBox caseSensitiveSearch = new TranslatedJCheckBox("Match case", TranslatedComponents.MATCH_CASE);
|
||||
private final JLabel titleHeader = new JLabel("");
|
||||
private final Color darkScrollBackground = new Color(0x3c3f41);
|
||||
private final Color darkScrollForeground = new Color(0x575859);
|
||||
private final Color blackScrollBackground = new Color(0x232323);
|
||||
private final Color blackScrollForeground = new Color(0x575859);
|
||||
private Runnable onCtrlS;
|
||||
private RTextScrollPane scrollPane = new RTextScrollPane(this);
|
||||
private final TextAreaSearchPanel textAreaSearchPanel;
|
||||
private final Color darkScrollBackground = new Color(0x3c3f41);
|
||||
private final Color darkScrollForeground = new Color(0x575859);
|
||||
private final Color blackScrollBackground = new Color(0x232323);
|
||||
private final Color blackScrollForeground = new Color(0x575859);
|
||||
private Runnable onCtrlS;
|
||||
|
||||
public SearchableRSyntaxTextArea() {
|
||||
if (Configuration.lafTheme == LAFTheme.HIGH_CONTRAST_DARK) {
|
||||
//this fixes the white border on the jScrollBar panes
|
||||
scrollPane.getHorizontalScrollBar().setBackground(blackScrollBackground);
|
||||
scrollPane.getHorizontalScrollBar().setForeground(blackScrollForeground);
|
||||
scrollPane.getVerticalScrollBar().setBackground(blackScrollBackground);
|
||||
scrollPane.getVerticalScrollBar().setForeground(blackScrollForeground);
|
||||
} else if (Configuration.lafTheme.isDark()) {
|
||||
//this fixes the white border on the jScrollBar panes
|
||||
scrollPane.getHorizontalScrollBar().setBackground(darkScrollBackground);
|
||||
scrollPane.getHorizontalScrollBar().setForeground(darkScrollForeground);
|
||||
scrollPane.getVerticalScrollBar().setBackground(darkScrollBackground);
|
||||
scrollPane.getVerticalScrollBar().setForeground(darkScrollForeground);
|
||||
}
|
||||
public SearchableRSyntaxTextArea()
|
||||
{
|
||||
if (Configuration.lafTheme == LAFTheme.HIGH_CONTRAST_DARK)
|
||||
{
|
||||
//this fixes the white border on the jScrollBar panes
|
||||
scrollPane.getHorizontalScrollBar().setBackground(blackScrollBackground);
|
||||
scrollPane.getHorizontalScrollBar().setForeground(blackScrollForeground);
|
||||
scrollPane.getVerticalScrollBar().setBackground(blackScrollBackground);
|
||||
scrollPane.getVerticalScrollBar().setForeground(blackScrollForeground);
|
||||
} else if (Configuration.lafTheme.isDark())
|
||||
{
|
||||
//this fixes the white border on the jScrollBar panes
|
||||
scrollPane.getHorizontalScrollBar().setBackground(darkScrollBackground);
|
||||
scrollPane.getHorizontalScrollBar().setForeground(darkScrollForeground);
|
||||
scrollPane.getVerticalScrollBar().setBackground(darkScrollBackground);
|
||||
scrollPane.getVerticalScrollBar().setForeground(darkScrollForeground);
|
||||
}
|
||||
|
||||
setAntiAliasingEnabled(true);
|
||||
this.textAreaSearchPanel = new TextAreaSearchPanel(this);
|
||||
|
||||
scrollPane.setColumnHeaderView(searchPanel);
|
||||
setAntiAliasingEnabled(true);
|
||||
|
||||
JButton searchNext = new JButton();
|
||||
JButton searchPrev = new JButton();
|
||||
JPanel buttonPane = new JPanel(new BorderLayout());
|
||||
buttonPane.add(searchNext, BorderLayout.WEST);
|
||||
buttonPane.add(searchPrev, BorderLayout.EAST);
|
||||
searchNext.setIcon(IconResources.nextIcon);
|
||||
searchPrev.setIcon(IconResources.prevIcon);
|
||||
searchPanel.add(buttonPane, BorderLayout.WEST);
|
||||
searchPanel.add(searchInput, BorderLayout.CENTER);
|
||||
searchPanel.add(caseSensitiveSearch, BorderLayout.EAST);
|
||||
addKeyListener(new PressKeyListener(keyEvent ->
|
||||
{
|
||||
if ((keyEvent.getKeyCode() == KeyEvent.VK_F) && ((keyEvent.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0))
|
||||
this.textAreaSearchPanel.getSearchInput().requestFocusInWindow();
|
||||
|
||||
searchNext.addActionListener(arg0 -> search(searchInput.getText(), true, caseSensitiveSearch.isSelected()));
|
||||
searchPrev.addActionListener(arg0 -> search(searchInput.getText(), false, caseSensitiveSearch.isSelected()));
|
||||
if (onCtrlS != null && (keyEvent.getKeyCode() == KeyEvent.VK_S) && ((keyEvent.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0))
|
||||
{
|
||||
onCtrlS.run();
|
||||
return;
|
||||
}
|
||||
|
||||
searchInput.addKeyListener(new ReleaseKeyListener(keyEvent ->
|
||||
{
|
||||
if (keyEvent.getKeyCode() == KeyEvent.VK_ENTER)
|
||||
search(searchInput.getText(), true, caseSensitiveSearch.isSelected());
|
||||
}));
|
||||
GlobalHotKeys.keyPressed(keyEvent);
|
||||
}));
|
||||
|
||||
addKeyListener(new PressKeyListener(keyEvent ->
|
||||
{
|
||||
if ((keyEvent.getKeyCode() == KeyEvent.VK_F) && ((keyEvent.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0))
|
||||
searchInput.requestFocus();
|
||||
final Font newFont = getFont().deriveFont((float) BytecodeViewer.viewer.getFontSize());
|
||||
|
||||
if (onCtrlS != null && (keyEvent.getKeyCode() == KeyEvent.VK_S) && ((keyEvent.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0)) {
|
||||
onCtrlS.run();
|
||||
return;
|
||||
}
|
||||
//set number-bar font
|
||||
setFont(newFont);
|
||||
|
||||
GlobalHotKeys.keyPressed(keyEvent);
|
||||
}));
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
//attach CTRL + Mouse Wheel Zoom
|
||||
attachCtrlMouseWheelZoom();
|
||||
|
||||
final Font newFont = getFont().deriveFont((float) BytecodeViewer.viewer.getFontSize());
|
||||
//set text font
|
||||
setFont(newFont);
|
||||
});
|
||||
|
||||
//set number-bar font
|
||||
setFont(newFont);
|
||||
}
|
||||
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
//attach CTRL + Mouse Wheel Zoom
|
||||
attachCtrlMouseWheelZoom();
|
||||
public void search(String search, boolean forwardSearchDirection, boolean caseSensitiveSearch)
|
||||
{
|
||||
JTextAreaUtils.search(this, search, forwardSearchDirection, caseSensitiveSearch);
|
||||
}
|
||||
|
||||
//set text font
|
||||
setFont(newFont);
|
||||
});
|
||||
public void highlight(String pattern, boolean caseSensitiveSearch)
|
||||
{
|
||||
JTextAreaUtils.highlight(this, pattern, caseSensitiveSearch);
|
||||
}
|
||||
|
||||
}
|
||||
public void attachCtrlMouseWheelZoom()
|
||||
{
|
||||
scrollPane.addMouseWheelListener(e -> {
|
||||
if (getText().isEmpty()) return;
|
||||
if ((e.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) != 0)
|
||||
{
|
||||
Font font = getFont();
|
||||
int size = font.getSize();
|
||||
if (e.getWheelRotation() > 0)
|
||||
setFont(new Font(font.getName(), font.getStyle(), --size >= 2 ? --size : 2));
|
||||
else
|
||||
setFont(new Font(font.getName(), font.getStyle(), ++size));
|
||||
|
||||
public void search(String search, boolean forwardSearchDirection, boolean caseSensitiveSearch) {
|
||||
JTextAreaUtils.search(this, search, forwardSearchDirection, caseSensitiveSearch);
|
||||
}
|
||||
e.consume();
|
||||
}
|
||||
});
|
||||
|
||||
public void highlight(String pattern, boolean caseSensitiveSearch) {
|
||||
JTextAreaUtils.highlight(this, pattern, caseSensitiveSearch);
|
||||
}
|
||||
scrollPane = new RTextScrollPane()
|
||||
{
|
||||
@Override
|
||||
protected void processMouseWheelEvent(MouseWheelEvent event)
|
||||
{
|
||||
if (!isWheelScrollingEnabled())
|
||||
{
|
||||
if (getParent() != null)
|
||||
{
|
||||
getParent().dispatchEvent(SwingUtilities.convertMouseEvent(this, event, getParent()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public void attachCtrlMouseWheelZoom() {
|
||||
scrollPane.addMouseWheelListener(e -> {
|
||||
if (getText().isEmpty()) return;
|
||||
if ((e.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) != 0) {
|
||||
Font font = getFont();
|
||||
int size = font.getSize();
|
||||
if (e.getWheelRotation() > 0)
|
||||
setFont(new Font(font.getName(), font.getStyle(), --size >= 2 ? --size : 2));
|
||||
else
|
||||
setFont(new Font(font.getName(), font.getStyle(), ++size));
|
||||
super.processMouseWheelEvent(event);
|
||||
}
|
||||
};
|
||||
|
||||
e.consume();
|
||||
}
|
||||
});
|
||||
scrollPane.setWheelScrollingEnabled(false);
|
||||
}
|
||||
|
||||
scrollPane = new RTextScrollPane() {
|
||||
@Override
|
||||
protected void processMouseWheelEvent(MouseWheelEvent event) {
|
||||
if (!isWheelScrollingEnabled()) {
|
||||
if (getParent() != null) {
|
||||
getParent().dispatchEvent(SwingUtilities.convertMouseEvent(this, event, getParent()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
public String getLineText(int line)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (line < getLineCount())
|
||||
{
|
||||
int start = getLineStartOffset(line);
|
||||
int end = getLineEndOffset(line);
|
||||
return getText(start, end - start).trim();
|
||||
}
|
||||
} catch (BadLocationException ignored)
|
||||
{
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
super.processMouseWheelEvent(event);
|
||||
}
|
||||
};
|
||||
public void setOnCtrlS(Runnable onCtrlS)
|
||||
{
|
||||
this.onCtrlS = onCtrlS;
|
||||
}
|
||||
|
||||
scrollPane.setWheelScrollingEnabled(false);
|
||||
}
|
||||
public RTextScrollPane getScrollPane()
|
||||
{
|
||||
return scrollPane;
|
||||
}
|
||||
|
||||
public String getLineText(int line) {
|
||||
try {
|
||||
if (line < getLineCount()) {
|
||||
int start = getLineStartOffset(line);
|
||||
int end = getLineEndOffset(line);
|
||||
return getText(start, end - start).trim();
|
||||
}
|
||||
} catch (BadLocationException ignored) {
|
||||
}
|
||||
return "";
|
||||
}
|
||||
public TextAreaSearchPanel getTextAreaSearchPanel()
|
||||
{
|
||||
return textAreaSearchPanel;
|
||||
}
|
||||
|
||||
public void setOnCtrlS(Runnable onCtrlS) {
|
||||
this.onCtrlS = onCtrlS;
|
||||
}
|
||||
|
||||
public RTextScrollPane getScrollPane() {
|
||||
return scrollPane;
|
||||
}
|
||||
|
||||
public JPanel getSearchPanel() {
|
||||
return searchPanel;
|
||||
}
|
||||
|
||||
public JTextField getSearchInput() {
|
||||
return searchInput;
|
||||
}
|
||||
|
||||
public JCheckBox getCaseSensitiveSearch() {
|
||||
return caseSensitiveSearch;
|
||||
}
|
||||
|
||||
public JLabel getTitleHeader() {
|
||||
return titleHeader;
|
||||
}
|
||||
|
||||
public Runnable getOnCtrlS() {
|
||||
return onCtrlS;
|
||||
}
|
||||
public Runnable getOnCtrlS()
|
||||
{
|
||||
return onCtrlS;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
/***************************************************************************
|
||||
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
|
||||
* Copyright (C) 2014 Konloch - Konloch.com / BytecodeViewer.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 3 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, see <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
package the.bytecode.club.bytecodeviewer.gui.components;
|
||||
|
||||
import the.bytecode.club.bytecodeviewer.gui.components.listeners.ReleaseKeyListener;
|
||||
import the.bytecode.club.bytecodeviewer.resources.IconResources;
|
||||
import the.bytecode.club.bytecodeviewer.translation.TranslatedComponents;
|
||||
import the.bytecode.club.bytecodeviewer.translation.components.TranslatedJCheckBox;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.KeyEvent;
|
||||
|
||||
/**
|
||||
* This panel represents the decompiler name and search box on the top of every {@link the.bytecode.club.bytecodeviewer.gui.resourceviewer.BytecodeViewPanel}
|
||||
* <p>
|
||||
* Created by Bl3nd.
|
||||
* Date: 9/6/2024
|
||||
*/
|
||||
public class TextAreaSearchPanel extends JPanel
|
||||
{
|
||||
private final JCheckBox caseSensitiveSearch = new TranslatedJCheckBox("Match case", TranslatedComponents.MATCH_CASE);
|
||||
private final JLabel titleHeader = new JLabel("");
|
||||
private final JTextField searchInput = new JTextField();
|
||||
private final JTextArea textArea;
|
||||
|
||||
public TextAreaSearchPanel(JTextArea textArea)
|
||||
{
|
||||
super(new BorderLayout());
|
||||
this.textArea = textArea;
|
||||
setup();
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
private void setup()
|
||||
{
|
||||
this.add(titleHeader, BorderLayout.NORTH);
|
||||
|
||||
JPanel searchPanel = new JPanel();
|
||||
searchPanel.setLayout(new BoxLayout(searchPanel, BoxLayout.X_AXIS));
|
||||
|
||||
JButton searchNext = new JButton(IconResources.nextIcon);
|
||||
searchPanel.add(searchNext);
|
||||
searchNext.addActionListener(arg0 -> ((SearchableRSyntaxTextArea) textArea).search(searchInput.getText(), true, caseSensitiveSearch.isSelected()));
|
||||
|
||||
JButton searchPrev = new JButton(IconResources.prevIcon);
|
||||
searchPanel.add(searchPrev);
|
||||
searchPrev.addActionListener(arg0 -> ((SearchableRSyntaxTextArea) textArea).search(searchInput.getText(), false, caseSensitiveSearch.isSelected()));
|
||||
|
||||
searchPanel.add(searchInput);
|
||||
searchInput.addKeyListener(new ReleaseKeyListener(keyEvent ->
|
||||
{
|
||||
if (keyEvent.getKeyCode() == KeyEvent.VK_ENTER)
|
||||
((SearchableRSyntaxTextArea) textArea).search(searchInput.getText(), true, caseSensitiveSearch.isSelected());
|
||||
}));
|
||||
|
||||
searchPanel.add(caseSensitiveSearch);
|
||||
|
||||
// This is needed to add more room to the right of the sensitive search check box
|
||||
searchPanel.add(Box.createHorizontalStrut(2));
|
||||
|
||||
this.add(searchPanel, BorderLayout.SOUTH);
|
||||
}
|
||||
|
||||
public JLabel getTitleHeader()
|
||||
{
|
||||
return titleHeader;
|
||||
}
|
||||
|
||||
public JTextField getSearchInput()
|
||||
{
|
||||
return searchInput;
|
||||
}
|
||||
}
|
|
@ -394,8 +394,8 @@ public class BytecodeViewPanelUpdater implements Runnable
|
|||
updateUpdaterTextArea = new SearchableRSyntaxTextArea();
|
||||
|
||||
Configuration.rstaTheme.apply(updateUpdaterTextArea);
|
||||
bytecodeViewPanel.add(updateUpdaterTextArea.getTextAreaSearchPanel(), BorderLayout.NORTH);
|
||||
bytecodeViewPanel.add(updateUpdaterTextArea.getScrollPane());
|
||||
bytecodeViewPanel.add(updateUpdaterTextArea.getTitleHeader(), BorderLayout.NORTH);
|
||||
|
||||
bytecodeViewPanel.textArea = updateUpdaterTextArea;
|
||||
|
||||
|
@ -424,12 +424,14 @@ public class BytecodeViewPanelUpdater implements Runnable
|
|||
bytecodeViewPanel.compiler = Compiler.KRAKATAU_ASSEMBLER;
|
||||
|
||||
String editable = isPanelEditable ? " - " + EDITABLE : "";
|
||||
bytecodeViewPanel.textArea.getTitleHeader().setText(decompiler.getDecompilerName() + editable);
|
||||
bytecodeViewPanel.textArea.getTextAreaSearchPanel().getTitleHeader().setText(decompiler.getDecompilerName() + editable);
|
||||
|
||||
// TODO: Whenever you click on a mark, both text areas get scrolled. Also, the error strip isn't laid out correctly.
|
||||
MyErrorStripe errorStripe = new MyErrorStripe(bytecodeViewPanel.textArea);
|
||||
bytecodeViewPanel.add(errorStripe, BorderLayout.LINE_END);
|
||||
|
||||
bytecodeViewPanel.revalidate();
|
||||
bytecodeViewPanel.repaint();
|
||||
|
||||
bytecodeViewPanel.textArea.addCaretListener(e -> {
|
||||
if (bytecodeViewPanel.textArea.isFocusOwner())
|
||||
{
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user