fix(gui): improve colors in usage tree, some UI fixes (PR #2506)
* fix(gui): refactor code in UsageDialogPlus * fix(gui): added padding between buttons in package exclusion dialog & fixed crash * fix(gui): added padding between buttons in settings dialog * fix: fix javadoc * fix: fix javadoc * fix: fix javadoc
This commit is contained in:
@@ -186,6 +186,7 @@ public class JadxSettingsWindow extends JDialog {
|
||||
buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS));
|
||||
buttonPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
|
||||
buttonPane.add(resetBtn);
|
||||
buttonPane.add(Box.createRigidArea(new Dimension(10, 0)));
|
||||
buttonPane.add(copyBtn);
|
||||
buttonPane.add(Box.createHorizontalGlue());
|
||||
buttonPane.add(saveBtn);
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
package jadx.gui.ui.cellrenders;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JTree;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.DefaultTreeCellRenderer;
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
import jadx.gui.treemodel.JNode;
|
||||
import jadx.gui.utils.UiUtils;
|
||||
|
||||
public class PathHighlightTreeCellRenderer extends DefaultTreeCellRenderer {
|
||||
|
||||
private final boolean isDarkTheme;
|
||||
|
||||
public PathHighlightTreeCellRenderer() {
|
||||
super();
|
||||
Color themeBackground = UIManager.getColor("Panel.background");
|
||||
isDarkTheme = UiUtils.isDarkTheme(themeBackground);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected,
|
||||
boolean expanded, boolean leaf, int row, boolean hasFocus) {
|
||||
|
||||
Component comp = super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
|
||||
|
||||
DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
|
||||
Object userObject = node.getUserObject();
|
||||
|
||||
// Calculate the node level
|
||||
int level = node.getLevel();
|
||||
// Set different colors according to the level
|
||||
float hue = (level * 0.1f) % 1.0f; // Hue cycle
|
||||
Color levelColor = Color.getHSBColor(hue, 0.1f, 0.95f);
|
||||
|
||||
// Check if it is on the selected path
|
||||
boolean onSelectionPath = false;
|
||||
TreePath selectionPath = tree.getSelectionPath();
|
||||
if (selectionPath != null) {
|
||||
// Check if the current node is on the selected path (whether it is part of the selected path)
|
||||
Object[] selectedPathNodes = selectionPath.getPath();
|
||||
for (Object pathNode : selectedPathNodes) {
|
||||
if (pathNode == node) {
|
||||
onSelectionPath = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (onSelectionPath && !selected) {
|
||||
// If it is on the selected path but not the selected node, use a special foreground
|
||||
setForeground(isDarkTheme ? Color.decode("#70AEFF") : Color.decode("#0033B3"));
|
||||
} else if (!selected) {
|
||||
// Only apply the background color when it is not selected
|
||||
setBackground(levelColor);
|
||||
// Normal border
|
||||
setBorder(BorderFactory.createEmptyBorder(2, level * 2 + 1, 2, 1));
|
||||
} else {
|
||||
// The selected node also adds a border
|
||||
setBorder(BorderFactory.createEmptyBorder(2, level * 2 + 1, 2, 1));
|
||||
}
|
||||
|
||||
if (userObject instanceof JNode) {
|
||||
JNode jNode = (JNode) userObject;
|
||||
setText(jNode.makeLongString());
|
||||
setIcon(jNode.getIcon());
|
||||
setToolTipText(jNode.getTooltip());
|
||||
}
|
||||
return comp;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
package jadx.gui.ui.dialog;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.Label;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.ArrayList;
|
||||
@@ -17,6 +16,7 @@ import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
@@ -61,12 +61,12 @@ public class ExcludePkgDialog extends JDialog {
|
||||
tree.setModel(treeModel);
|
||||
tree.setCellRenderer(new PkgListCellRenderer());
|
||||
JScrollPane listPanel = new JScrollPane(tree);
|
||||
listPanel.setBorder(BorderFactory.createLineBorder(Color.black));
|
||||
listPanel.setBorder(BorderFactory.createEmptyBorder());
|
||||
tree.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
TreePath path = tree.getPathForLocation(e.getX(), e.getY());
|
||||
if (path != null) {
|
||||
if (path != null && path.getLastPathComponent() instanceof PkgNode) {
|
||||
PkgNode node = (PkgNode) path.getLastPathComponent();
|
||||
node.toggle();
|
||||
repaint();
|
||||
@@ -75,18 +75,18 @@ public class ExcludePkgDialog extends JDialog {
|
||||
});
|
||||
|
||||
JPanel actionPanel = new JPanel();
|
||||
BoxLayout boxLayout = new BoxLayout(actionPanel, BoxLayout.LINE_AXIS);
|
||||
actionPanel.setLayout(boxLayout);
|
||||
actionPanel.add(new Label(" "));
|
||||
JButton btnOk = new JButton(NLS.str("exclude_dialog.ok"));
|
||||
actionPanel.setLayout(new BoxLayout(actionPanel, BoxLayout.LINE_AXIS));
|
||||
JButton btnOk = new JButton(NLS.str("common_dialog.ok"));
|
||||
JButton btnAll = new JButton(NLS.str("exclude_dialog.select_all"));
|
||||
JButton btnInvert = new JButton(NLS.str("exclude_dialog.invert"));
|
||||
JButton btnDeselect = new JButton(NLS.str("exclude_dialog.deselect"));
|
||||
actionPanel.add(btnDeselect);
|
||||
actionPanel.add(Box.createRigidArea(new Dimension(10, 0)));
|
||||
actionPanel.add(btnInvert);
|
||||
actionPanel.add(Box.createRigidArea(new Dimension(10, 0)));
|
||||
actionPanel.add(btnAll);
|
||||
actionPanel.add(new Label(" "));
|
||||
actionPanel.add(btnOk);
|
||||
actionPanel.add(Box.createHorizontalGlue());
|
||||
actionPanel.add(btnOk, BorderLayout.PAGE_END);
|
||||
|
||||
JPanel mainPane = new JPanel(new BorderLayout(5, 5));
|
||||
mainPane.add(listPanel, BorderLayout.CENTER);
|
||||
|
||||
@@ -5,8 +5,6 @@ import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.FlowLayout;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.ArrayList;
|
||||
@@ -19,7 +17,6 @@ import java.util.Map;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JLabel;
|
||||
@@ -33,16 +30,12 @@ import javax.swing.SwingUtilities;
|
||||
import javax.swing.WindowConstants;
|
||||
import javax.swing.event.TreeExpansionEvent;
|
||||
import javax.swing.event.TreeExpansionListener;
|
||||
import javax.swing.event.TreeSelectionEvent;
|
||||
import javax.swing.event.TreeSelectionListener;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.DefaultTreeCellRenderer;
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
import javax.swing.tree.TreeNode;
|
||||
import javax.swing.tree.TreePath;
|
||||
import javax.swing.tree.TreeSelectionModel;
|
||||
|
||||
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
@@ -63,8 +56,9 @@ import jadx.gui.treemodel.JField;
|
||||
import jadx.gui.treemodel.JMethod;
|
||||
import jadx.gui.treemodel.JNode;
|
||||
import jadx.gui.ui.MainWindow;
|
||||
import jadx.gui.ui.codearea.AbstractCodeArea;
|
||||
import jadx.gui.ui.cellrenders.PathHighlightTreeCellRenderer;
|
||||
import jadx.gui.ui.panel.ProgressPanel;
|
||||
import jadx.gui.ui.panel.SimpleCodePanel;
|
||||
import jadx.gui.utils.JNodeCache;
|
||||
import jadx.gui.utils.NLS;
|
||||
import jadx.gui.utils.UiUtils;
|
||||
@@ -74,14 +68,14 @@ public class UsageDialogPlus extends CommonSearchDialog {
|
||||
|
||||
private final JPanel mainPanel;
|
||||
private final JSplitPane splitPane;
|
||||
private final CodePanel codePanel;
|
||||
private final SimpleCodePanel simpleCodePanel;
|
||||
private final JTree usageTree;
|
||||
private final DefaultTreeModel treeModel;
|
||||
private final DefaultMutableTreeNode rootNode;
|
||||
private final ProgressPanel localProgressPanel;
|
||||
private final JLabel resultsInfoLabel;
|
||||
private final JLabel progressInfoLabel;
|
||||
private JNode initialNode;
|
||||
private final JNode initialNode;
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(UsageDialogPlus.class);
|
||||
|
||||
@@ -116,15 +110,15 @@ public class UsageDialogPlus extends CommonSearchDialog {
|
||||
warnLabel.setVisible(false);
|
||||
|
||||
// Initialize result and progress info labels
|
||||
resultsInfoLabel = new JLabel("");
|
||||
progressInfoLabel = new JLabel("");
|
||||
resultsInfoLabel = new JLabel();
|
||||
progressInfoLabel = new JLabel();
|
||||
localProgressPanel = new ProgressPanel(mainWindow, false);
|
||||
|
||||
mainPanel = new JPanel();
|
||||
mainPanel.setLayout(new BorderLayout());
|
||||
|
||||
// Create the code panel
|
||||
codePanel = new CodePanel(mainWindow);
|
||||
simpleCodePanel = new SimpleCodePanel(mainWindow);
|
||||
|
||||
// Create the tree
|
||||
rootNode = new DefaultMutableTreeNode(node);
|
||||
@@ -136,31 +130,29 @@ public class UsageDialogPlus extends CommonSearchDialog {
|
||||
usageTree.putClientProperty("JTree.lineStyle", "Horizontal");
|
||||
usageTree.setRowHeight(22);
|
||||
usageTree.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
|
||||
usageTree.setFont(mainWindow.getSettings().getFont());
|
||||
|
||||
// Use a custom renderer instead of a custom UI
|
||||
usageTree.setCellRenderer(new PathHighlightTreeCellRenderer());
|
||||
|
||||
// Add tree listeners
|
||||
usageTree.addTreeSelectionListener(new TreeSelectionListener() {
|
||||
@Override
|
||||
public void valueChanged(TreeSelectionEvent e) {
|
||||
DefaultMutableTreeNode node = (DefaultMutableTreeNode) usageTree.getLastSelectedPathComponent();
|
||||
if (node == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object nodeInfo = node.getUserObject();
|
||||
if (nodeInfo instanceof CodeNode) {
|
||||
CodeNode codeNode = (CodeNode) nodeInfo;
|
||||
codePanel.showCode(codeNode, codeNode.makeDescString());
|
||||
} else if (nodeInfo instanceof JNode) {
|
||||
JNode jNode = (JNode) nodeInfo;
|
||||
codePanel.showCode(jNode, jNode.makeDescString());
|
||||
}
|
||||
|
||||
// Update the result information to display the number of child nodes of the currently selected node
|
||||
updateResultsInfo(node);
|
||||
usageTree.addTreeSelectionListener(e -> {
|
||||
DefaultMutableTreeNode node1 = (DefaultMutableTreeNode) usageTree.getLastSelectedPathComponent();
|
||||
if (node1 == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object nodeInfo = node1.getUserObject();
|
||||
if (nodeInfo instanceof CodeNode) {
|
||||
CodeNode codeNode = (CodeNode) nodeInfo;
|
||||
simpleCodePanel.showCode(codeNode, codeNode.makeDescString());
|
||||
} else if (nodeInfo instanceof JNode) {
|
||||
JNode jNode = (JNode) nodeInfo;
|
||||
simpleCodePanel.showCode(jNode, jNode.makeDescString());
|
||||
}
|
||||
|
||||
// Update the result information to display the number of child nodes of the currently selected node
|
||||
updateResultsInfo(node1);
|
||||
});
|
||||
|
||||
usageTree.addTreeExpansionListener(new TreeExpansionListener() {
|
||||
@@ -206,7 +198,7 @@ public class UsageDialogPlus extends CommonSearchDialog {
|
||||
usageTree.setSelectionPath(path);
|
||||
|
||||
// Handle the right-click menu
|
||||
if (e.getButton() == MouseEvent.BUTTON3) {
|
||||
if (SwingUtilities.isRightMouseButton(e)) {
|
||||
DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) path.getLastPathComponent();
|
||||
Object userObject = selectedNode.getUserObject();
|
||||
|
||||
@@ -218,7 +210,7 @@ public class UsageDialogPlus extends CommonSearchDialog {
|
||||
}
|
||||
|
||||
// Handle left-click single/double click
|
||||
if (e.getButton() == MouseEvent.BUTTON1) {
|
||||
if (SwingUtilities.isLeftMouseButton(e)) {
|
||||
long clickTime = System.currentTimeMillis();
|
||||
// Double-click interval
|
||||
long doubleClickInterval = 300;
|
||||
@@ -299,7 +291,7 @@ public class UsageDialogPlus extends CommonSearchDialog {
|
||||
leftPanel.add(statusPanel, BorderLayout.SOUTH);
|
||||
|
||||
splitPane.setLeftComponent(leftPanel);
|
||||
splitPane.setRightComponent(codePanel);
|
||||
splitPane.setRightComponent(simpleCodePanel);
|
||||
|
||||
mainPanel.add(splitPane, BorderLayout.CENTER);
|
||||
|
||||
@@ -547,14 +539,10 @@ public class UsageDialogPlus extends CommonSearchDialog {
|
||||
});
|
||||
|
||||
JMenuItem jumpToItem = new JMenuItem(NLS.str("usage_dialog_plus.jump_to"));
|
||||
jumpToItem.addActionListener(evt -> {
|
||||
openItem(node);
|
||||
});
|
||||
jumpToItem.addActionListener(evt -> openItem(node));
|
||||
|
||||
JMenuItem copyPathItem = new JMenuItem(NLS.str("usage_dialog_plus.copy_path"));
|
||||
copyPathItem.addActionListener(evt -> {
|
||||
copyUsagePath(path);
|
||||
});
|
||||
copyPathItem.addActionListener(evt -> copyUsagePath(path));
|
||||
|
||||
popup.add(expandItem);
|
||||
popup.addSeparator();
|
||||
@@ -597,274 +585,6 @@ public class UsageDialogPlus extends CommonSearchDialog {
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the PathHighlightTreeUI class, use the enhanced CellRenderer instead
|
||||
private class PathHighlightTreeCellRenderer extends DefaultTreeCellRenderer {
|
||||
private static final int INDENT_PER_LEVEL = 18; // Each level of indentation in pixels
|
||||
private final Color selectedPathColor = new Color(220, 240, 255); // Light blue background
|
||||
private final Color selectedPathTextColor = new Color(0, 0, 150); // Dark blue text
|
||||
|
||||
@Override
|
||||
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected,
|
||||
boolean expanded, boolean leaf, int row, boolean hasFocus) {
|
||||
|
||||
Component comp = super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
|
||||
|
||||
DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
|
||||
Object userObject = node.getUserObject();
|
||||
|
||||
// Calculate the node level
|
||||
int level = node.getLevel();
|
||||
// Set different colors according to the level
|
||||
float hue = (level * 0.1f) % 1.0f; // Hue cycle
|
||||
Color levelColor = Color.getHSBColor(hue, 0.1f, 0.95f);
|
||||
|
||||
// Check if it is on the selected path
|
||||
boolean onSelectionPath = false;
|
||||
TreePath selectionPath = tree.getSelectionPath();
|
||||
if (selectionPath != null) {
|
||||
// Check if the current node is on the selected path (whether it is part of the selected path)
|
||||
Object[] selectedPathNodes = selectionPath.getPath();
|
||||
for (Object pathNode : selectedPathNodes) {
|
||||
if (pathNode == node) {
|
||||
onSelectionPath = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (onSelectionPath && !selected) {
|
||||
// If it is on the selected path but not the selected node, use a special background
|
||||
setBackground(selectedPathColor);
|
||||
setForeground(selectedPathTextColor);
|
||||
|
||||
// Set the highlighted border
|
||||
setBorder(BorderFactory.createCompoundBorder(
|
||||
BorderFactory.createLineBorder(selectedPathTextColor, 1),
|
||||
BorderFactory.createEmptyBorder(1, level * 2, 1, 1)));
|
||||
} else if (!selected) {
|
||||
// Only apply the background color when it is not selected
|
||||
setBackground(levelColor);
|
||||
// Normal border
|
||||
setBorder(BorderFactory.createEmptyBorder(2, level * 2 + 1, 2, 1));
|
||||
} else {
|
||||
// The selected node also adds a border
|
||||
setBorder(BorderFactory.createEmptyBorder(2, level * 2 + 1, 2, 1));
|
||||
}
|
||||
|
||||
if (userObject instanceof JNode) {
|
||||
JNode jNode = (JNode) userObject;
|
||||
setText(jNode.makeLongString());
|
||||
setIcon(jNode.getIcon());
|
||||
setToolTipText(jNode.getTooltip());
|
||||
} else if (userObject instanceof CodeNode) {
|
||||
CodeNode codeNode = (CodeNode) userObject;
|
||||
setText(codeNode.makeLongString());
|
||||
setIcon(codeNode.getIcon());
|
||||
setToolTipText(codeNode.getTooltip());
|
||||
}
|
||||
|
||||
return comp;
|
||||
}
|
||||
|
||||
// Add custom icons to enhance visual distinction
|
||||
@Override
|
||||
public Icon getLeafIcon() {
|
||||
return super.getLeafIcon();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getOpenIcon() {
|
||||
return super.getOpenIcon();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getClosedIcon() {
|
||||
return super.getClosedIcon();
|
||||
}
|
||||
}
|
||||
|
||||
// The code panel class is used to display the code of the selected node.
|
||||
private class CodePanel extends JPanel {
|
||||
private final RSyntaxTextArea codeArea;
|
||||
private final JLabel titleLabel;
|
||||
|
||||
public CodePanel(MainWindow mainWindow) {
|
||||
setLayout(new BorderLayout(5, 5));
|
||||
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
|
||||
|
||||
// Set the minimum size to ensure the panel is not completely minimized
|
||||
setMinimumSize(new Dimension(300, 400));
|
||||
setPreferredSize(new Dimension(800, 600));
|
||||
|
||||
// The title label
|
||||
titleLabel = new JLabel(NLS.str("usage_dialog_plus.code_view"));
|
||||
titleLabel.setFont(codeFont);
|
||||
titleLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 10, 5));
|
||||
|
||||
// The code area
|
||||
codeArea = AbstractCodeArea.getDefaultArea(mainWindow);
|
||||
codeArea.setEditable(false);
|
||||
codeArea.setText("// " + NLS.str("usage_dialog_plus.select_node"));
|
||||
|
||||
JScrollPane scrollPane = new JScrollPane(codeArea);
|
||||
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
|
||||
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
|
||||
|
||||
add(titleLabel, BorderLayout.NORTH);
|
||||
add(scrollPane, BorderLayout.CENTER);
|
||||
}
|
||||
|
||||
public void showCode(JNode node, String codeLine) {
|
||||
if (node != null) {
|
||||
titleLabel.setText(NLS.str("usage_dialog_plus.code_for") + " " + node.makeLongString());
|
||||
codeArea.setSyntaxEditingStyle(node.getSyntaxName());
|
||||
|
||||
// Get the complete code
|
||||
String contextCode = getContextCode(node, codeLine);
|
||||
codeArea.setText(contextCode);
|
||||
|
||||
// Highlight the key line and scroll to that position
|
||||
scrollToCodeLine(codeArea, codeLine);
|
||||
|
||||
// If it is a CodeNode, we can get a more precise position
|
||||
if (node instanceof CodeNode) {
|
||||
CodeNode codeNode = (CodeNode) node;
|
||||
int pos = codeNode.getPos();
|
||||
if (pos > 0) {
|
||||
// Try to use the position information to more accurately locate
|
||||
try {
|
||||
String text = codeArea.getText();
|
||||
int lineNum = 0;
|
||||
int curPos = 0;
|
||||
// Calculate the line number corresponding to the position
|
||||
for (int i = 0; i < text.length() && curPos <= pos; i++) {
|
||||
if (text.charAt(i) == '\n') {
|
||||
lineNum++;
|
||||
}
|
||||
curPos++;
|
||||
}
|
||||
|
||||
if (lineNum > 0) {
|
||||
// Scroll to the calculated line number
|
||||
int finalLineNum = lineNum;
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
try {
|
||||
Rectangle lineRect = codeArea
|
||||
.modelToView(codeArea.getLineStartOffset(finalLineNum));
|
||||
if (lineRect != null) {
|
||||
JScrollPane scrollPane = (JScrollPane) codeArea.getParent().getParent();
|
||||
Rectangle viewRect = scrollPane.getViewport().getViewRect();
|
||||
int y = lineRect.y - (viewRect.height - lineRect.height) / 2;
|
||||
if (y < 0) {
|
||||
y = 0;
|
||||
}
|
||||
scrollPane.getViewport().setViewPosition(new Point(0, y));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Fall back to using string matching
|
||||
scrollToCodeLine(codeArea, codeLine);
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Fall back to using string matching
|
||||
scrollToCodeLine(codeArea, codeLine);
|
||||
}
|
||||
} else {
|
||||
// If there is no position information, use string matching
|
||||
scrollToCodeLine(codeArea, codeLine);
|
||||
}
|
||||
} else {
|
||||
// Not a CodeNode, use string matching
|
||||
scrollToCodeLine(codeArea, codeLine);
|
||||
}
|
||||
} else {
|
||||
titleLabel.setText(NLS.str("usage_dialog_plus.code_view"));
|
||||
codeArea.setText("// " + NLS.str("usage_dialog_plus.select_node"));
|
||||
}
|
||||
}
|
||||
|
||||
private String getContextCode(JNode node, String codeLine) {
|
||||
// Always try to get the complete code
|
||||
if (node instanceof CodeNode) {
|
||||
CodeNode codeNode = (CodeNode) node;
|
||||
JNode usageJNode = codeNode.getJParent();
|
||||
if (usageJNode != null) {
|
||||
// Try to get the complete code of the method or class
|
||||
String fullCode = getFullNodeCode(usageJNode);
|
||||
if (fullCode != null && !fullCode.isEmpty()) {
|
||||
return fullCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If you cannot get more context, at least add some empty lines and comments
|
||||
return "// Unable to get complete context, only display related lines\n\n" + codeLine;
|
||||
}
|
||||
|
||||
private String getFullNodeCode(JNode node) {
|
||||
if (node != null) {
|
||||
// Get the code information of the node
|
||||
ICodeInfo codeInfo = node.getCodeInfo();
|
||||
if (codeInfo != null && !codeInfo.equals(ICodeInfo.EMPTY)) {
|
||||
return codeInfo.getCodeStr();
|
||||
}
|
||||
|
||||
// If it is a class node, try to get the class code
|
||||
if (node instanceof JClass) {
|
||||
JClass jClass = (JClass) node;
|
||||
return jClass.getCodeInfo().getCodeStr();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void scrollToCodeLine(RSyntaxTextArea textArea, String lineToHighlight) {
|
||||
// Try to find and highlight a specific line in the code and scroll to that position
|
||||
try {
|
||||
String fullText = textArea.getText();
|
||||
int lineIndex = fullText.indexOf(lineToHighlight);
|
||||
if (lineIndex >= 0) {
|
||||
// Ensure the text area has updated the layout
|
||||
textArea.revalidate();
|
||||
|
||||
// Highlight the code line
|
||||
textArea.setCaretPosition(lineIndex);
|
||||
int endIndex = lineIndex + lineToHighlight.length();
|
||||
textArea.select(lineIndex, endIndex);
|
||||
textArea.getCaret().setSelectionVisible(true);
|
||||
|
||||
// Use SwingUtilities.invokeLater to ensure the scroll is executed after the UI is updated
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
try {
|
||||
// Get the line number
|
||||
int lineNum = textArea.getLineOfOffset(lineIndex);
|
||||
// Ensure the line is centered in the view
|
||||
Rectangle lineRect = textArea.modelToView(textArea.getLineStartOffset(lineNum));
|
||||
if (lineRect != null) {
|
||||
// Calculate the center point of the view
|
||||
JScrollPane scrollPane = (JScrollPane) textArea.getParent().getParent();
|
||||
Rectangle viewRect = scrollPane.getViewport().getViewRect();
|
||||
int y = lineRect.y - (viewRect.height - lineRect.height) / 2;
|
||||
if (y < 0) {
|
||||
y = 0;
|
||||
}
|
||||
// Scroll to the calculated position
|
||||
scrollPane.getViewport().setViewPosition(new Point(0, y));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.debug("Error scrolling to line: {}", e.getMessage());
|
||||
}
|
||||
});
|
||||
} else {
|
||||
LOG.debug("Could not find line to highlight: {}", lineToHighlight);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.debug("Error highlighting line: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected JPanel initButtonsPanel() {
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
package jadx.gui.ui.panel;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
|
||||
import org.fife.ui.rtextarea.RTextScrollPane;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.api.ICodeInfo;
|
||||
import jadx.gui.settings.JadxSettings;
|
||||
import jadx.gui.settings.LineNumbersMode;
|
||||
import jadx.gui.treemodel.CodeNode;
|
||||
import jadx.gui.treemodel.JClass;
|
||||
import jadx.gui.treemodel.JNode;
|
||||
import jadx.gui.ui.MainWindow;
|
||||
import jadx.gui.ui.codearea.AbstractCodeArea;
|
||||
import jadx.gui.utils.NLS;
|
||||
|
||||
// The code panel class is used to display the code of the selected node.
|
||||
public class SimpleCodePanel extends JPanel {
|
||||
private static final long serialVersionUID = -4073178549744330905L;
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SimpleCodePanel.class);
|
||||
|
||||
private final RSyntaxTextArea codeArea;
|
||||
private final RTextScrollPane codeScrollPane;
|
||||
private final JLabel titleLabel;
|
||||
|
||||
public SimpleCodePanel(MainWindow mainWindow) {
|
||||
JadxSettings settings = mainWindow.getSettings();
|
||||
|
||||
setLayout(new BorderLayout(5, 5));
|
||||
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
|
||||
|
||||
// Set the minimum size to ensure the panel is not completely minimized
|
||||
setMinimumSize(new Dimension(300, 400));
|
||||
setPreferredSize(new Dimension(800, 600));
|
||||
|
||||
// The title label
|
||||
titleLabel = new JLabel(NLS.str("usage_dialog_plus.code_view"));
|
||||
titleLabel.setFont(settings.getFont());
|
||||
titleLabel.setBorder(BorderFactory.createEmptyBorder(5, 5, 10, 5));
|
||||
|
||||
// The code area
|
||||
codeArea = AbstractCodeArea.getDefaultArea(mainWindow);
|
||||
codeArea.setText("// " + NLS.str("usage_dialog_plus.select_node"));
|
||||
|
||||
codeScrollPane = new RTextScrollPane(codeArea);
|
||||
codeScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
|
||||
codeScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
|
||||
|
||||
add(titleLabel, BorderLayout.NORTH);
|
||||
add(codeScrollPane, BorderLayout.CENTER);
|
||||
|
||||
applySettings(settings);
|
||||
}
|
||||
|
||||
private void applySettings(JadxSettings settings) {
|
||||
codeScrollPane.setLineNumbersEnabled(settings.getLineNumbersMode() != LineNumbersMode.DISABLE);
|
||||
codeScrollPane.getGutter().setLineNumberFont(settings.getFont());
|
||||
codeArea.setFont(settings.getFont());
|
||||
}
|
||||
|
||||
public void showCode(JNode node, String codeLine) {
|
||||
if (node != null) {
|
||||
titleLabel.setText(NLS.str("usage_dialog_plus.code_for", node.makeLongString()));
|
||||
codeArea.setSyntaxEditingStyle(node.getSyntaxName());
|
||||
|
||||
// Get the complete code
|
||||
String contextCode = getContextCode(node, codeLine);
|
||||
codeArea.setText(contextCode);
|
||||
|
||||
// Highlight the key line and scroll to that position
|
||||
scrollToCodeLine(codeArea, codeLine);
|
||||
|
||||
// If it is a CodeNode, we can get a more precise position
|
||||
if (node instanceof CodeNode) {
|
||||
CodeNode codeNode = (CodeNode) node;
|
||||
int pos = codeNode.getPos();
|
||||
if (pos > 0) {
|
||||
// Try to use the position information to more accurately locate
|
||||
try {
|
||||
String text = codeArea.getText();
|
||||
int lineNum = 0;
|
||||
int curPos = 0;
|
||||
// Calculate the line number corresponding to the position
|
||||
for (int i = 0; i < text.length() && curPos <= pos; i++) {
|
||||
if (text.charAt(i) == '\n') {
|
||||
lineNum++;
|
||||
}
|
||||
curPos++;
|
||||
}
|
||||
|
||||
if (lineNum > 0) {
|
||||
// Scroll to the calculated line number
|
||||
int finalLineNum = lineNum;
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
try {
|
||||
Rectangle2D lineRect = codeArea
|
||||
.modelToView2D(codeArea.getLineStartOffset(finalLineNum));
|
||||
if (lineRect != null) {
|
||||
JScrollPane scrollPane = (JScrollPane) codeArea.getParent().getParent();
|
||||
Rectangle viewRect = scrollPane.getViewport().getViewRect();
|
||||
int y = (int) (lineRect.getY() - (viewRect.height - lineRect.getHeight()) / 2);
|
||||
if (y < 0) {
|
||||
y = 0;
|
||||
}
|
||||
scrollPane.getViewport().setViewPosition(new Point(0, y));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Fall back to using string matching
|
||||
scrollToCodeLine(codeArea, codeLine);
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Fall back to using string matching
|
||||
scrollToCodeLine(codeArea, codeLine);
|
||||
}
|
||||
} else {
|
||||
// If there is no position information, use string matching
|
||||
scrollToCodeLine(codeArea, codeLine);
|
||||
}
|
||||
} else {
|
||||
// Not a CodeNode, use string matching
|
||||
scrollToCodeLine(codeArea, codeLine);
|
||||
}
|
||||
} else {
|
||||
titleLabel.setText(NLS.str("usage_dialog_plus.code_view"));
|
||||
codeArea.setText("// " + NLS.str("usage_dialog_plus.select_node"));
|
||||
}
|
||||
}
|
||||
|
||||
private String getContextCode(JNode node, String codeLine) {
|
||||
// Always try to get the complete code
|
||||
if (node instanceof CodeNode) {
|
||||
CodeNode codeNode = (CodeNode) node;
|
||||
JNode usageJNode = codeNode.getJParent();
|
||||
if (usageJNode != null) {
|
||||
// Try to get the complete code of the method or class
|
||||
String fullCode = getFullNodeCode(usageJNode);
|
||||
if (fullCode != null && !fullCode.isEmpty()) {
|
||||
return fullCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If you cannot get more context, at least add some empty lines and comments
|
||||
return "// Unable to get complete context, only display related lines\n\n" + codeLine;
|
||||
}
|
||||
|
||||
private String getFullNodeCode(JNode node) {
|
||||
if (node != null) {
|
||||
// Get the code information of the node
|
||||
ICodeInfo codeInfo = node.getCodeInfo();
|
||||
if (codeInfo != null && !codeInfo.equals(ICodeInfo.EMPTY)) {
|
||||
return codeInfo.getCodeStr();
|
||||
}
|
||||
|
||||
// If it is a class node, try to get the class code
|
||||
if (node instanceof JClass) {
|
||||
JClass jClass = (JClass) node;
|
||||
return jClass.getCodeInfo().getCodeStr();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void scrollToCodeLine(RSyntaxTextArea textArea, String lineToHighlight) {
|
||||
// Try to find and highlight a specific line in the code and scroll to that position
|
||||
try {
|
||||
String fullText = textArea.getText();
|
||||
int lineIndex = fullText.indexOf(lineToHighlight);
|
||||
if (lineIndex >= 0) {
|
||||
// Ensure the text area has updated the layout
|
||||
textArea.revalidate();
|
||||
|
||||
// Highlight the code line
|
||||
textArea.setCaretPosition(lineIndex);
|
||||
int endIndex = lineIndex + lineToHighlight.length();
|
||||
textArea.select(lineIndex, endIndex);
|
||||
textArea.getCaret().setSelectionVisible(true);
|
||||
|
||||
// Use SwingUtilities.invokeLater to ensure the scroll is executed after the UI is updated
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
try {
|
||||
// Get the line number
|
||||
int lineNum = textArea.getLineOfOffset(lineIndex);
|
||||
// Ensure the line is centered in the view
|
||||
Rectangle2D lineRect = textArea.modelToView2D(textArea.getLineStartOffset(lineNum));
|
||||
if (lineRect != null) {
|
||||
// Calculate the center point of the view
|
||||
JScrollPane scrollPane = (JScrollPane) textArea.getParent().getParent();
|
||||
Rectangle viewRect = scrollPane.getViewport().getViewRect();
|
||||
int y = (int) (lineRect.getY() - (viewRect.height - lineRect.getHeight()) / 2);
|
||||
if (y < 0) {
|
||||
y = 0;
|
||||
}
|
||||
// Scroll to the calculated position
|
||||
scrollPane.getViewport().setViewPosition(new Point(0, y));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.debug("Error scrolling to line: {}", e.getMessage());
|
||||
}
|
||||
});
|
||||
} else {
|
||||
LOG.debug("Could not find line to highlight: {}", lineToHighlight);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.debug("Error highlighting line: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -463,6 +463,52 @@ public class UiUtils {
|
||||
return brightness < 0.5;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the brightness of a given {@code Color} object without altering its hue or saturation.
|
||||
*
|
||||
* <p>
|
||||
* This method converts the input RGB color to the HSB (Hue, Saturation, Brightness) color model,
|
||||
* multiplies its brightness component by the specified {@code factor}, and then converts it back
|
||||
* to a new RGB {@code Color} object.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The new brightness value is capped at {@code 1.0f} (maximum HSB brightness) to prevent
|
||||
* colors from becoming invalid or exceeding full brightness.
|
||||
* </p>
|
||||
*
|
||||
* How to use:
|
||||
* <ul>
|
||||
* <li>To make a color **brighter**: Use a {@code factor} greater than {@code 1.0f} (e.g.,
|
||||
* {@code 1.2f}, {@code 1.5f}).</li>
|
||||
* <li>To make a color **darker**: Use a {@code factor} less than {@code 1.0f} (e.g., {@code 0.8f},
|
||||
* {@code 0.5f}).</li>
|
||||
* <li>To keep the brightness **unchanged**: Use a {@code factor} of {@code 1.0f}.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <pre>{@code
|
||||
* // Example usage:
|
||||
* Color originalColor = Color.BLUE;
|
||||
*
|
||||
* // Make the blue color 50% brighter (factor 1.5)
|
||||
* Color brighterBlue = adjustBrightness(originalColor, 1.5f);
|
||||
*
|
||||
* // Make the blue color 30% darker (factor 0.7)
|
||||
* Color darkerBlue = adjustBrightness(originalColor, 0.7f);
|
||||
*
|
||||
* // Get the brightest possible version of the color (will cap at 1.0 brightness)
|
||||
* Color maxBrightnessBlue = adjustBrightness(originalColor, 10.0f);
|
||||
*
|
||||
* // Get a very dark, almost black version
|
||||
* Color veryDarkBlue = adjustBrightness(originalColor, 0.1f);
|
||||
* }</pre>
|
||||
*
|
||||
* @param color The original {@code Color} object whose brightness needs to be adjusted.
|
||||
* @param factor The multiplier for the brightness.
|
||||
* @return A new {@code Color} object with the adjusted brightness.
|
||||
* @see java.awt.Color#RGBtoHSB(int, int, int, float[])
|
||||
* @see java.awt.Color#getHSBColor(float, float, float)
|
||||
*/
|
||||
public static Color adjustBrightness(Color color, float factor) {
|
||||
float[] hsb = Color.RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue(), null);
|
||||
hsb[2] = Math.min(1.0f, hsb[2] * factor); // Adjust brightness
|
||||
|
||||
@@ -188,10 +188,10 @@ usage_dialog.label=Verwendungen von:
|
||||
usage_dialog_plus.jump_to=Zur aktuellen Position springen
|
||||
usage_dialog_plus.copy_path=Verwendungspfad kopieren
|
||||
usage_dialog_plus.search_complete=Suche abgeschlossen
|
||||
#usage_dialog_plus.code_view=code view
|
||||
#usage_dialog_plus.select_node=select node
|
||||
#usage_dialog_plus.code_for=code for
|
||||
#usage_dialog_plus.expand_usages=expand data
|
||||
#usage_dialog_plus.code_view=Code View
|
||||
#usage_dialog_plus.select_node=Select Node
|
||||
#usage_dialog_plus.code_for=Code for %s
|
||||
#usage_dialog_plus.expand_usages=Expand Data
|
||||
|
||||
comment_dialog.title.add=Code-Kommentar hinzufügen
|
||||
comment_dialog.title.update=Code-Kommentar aktualisieren
|
||||
@@ -393,7 +393,6 @@ script.log=Protokoll anzeigen
|
||||
#encoding_dialog.message=Select encoding:
|
||||
|
||||
exclude_dialog.title=Paketauswahl
|
||||
exclude_dialog.ok=OK
|
||||
exclude_dialog.select_all=Alles auswählen
|
||||
exclude_dialog.deselect=Abwählen
|
||||
exclude_dialog.invert=Invertieren
|
||||
|
||||
@@ -136,7 +136,7 @@ message.unable_preview_font=Unable preview font
|
||||
|
||||
heapUsage.text=JADX memory usage: %.2f GB of %.2f GB
|
||||
|
||||
common_dialog.ok=Ok
|
||||
common_dialog.ok=OK
|
||||
common_dialog.cancel=Cancel
|
||||
common_dialog.add=Add
|
||||
common_dialog.update=Update
|
||||
@@ -179,7 +179,7 @@ search_dialog.keep_open=Keep open
|
||||
search_dialog.tip_searching=Searching
|
||||
search_dialog.limit_package=Limit to package:
|
||||
search_dialog.package_not_found=No matching package found
|
||||
search_dialog.copy=copy all
|
||||
search_dialog.copy=Copy All
|
||||
|
||||
usage_dialog.title=Usage search
|
||||
usage_dialog.label=Usage for:
|
||||
@@ -188,10 +188,10 @@ usage_dialog_plus.title=Usage tree search
|
||||
usage_dialog_plus.jump_to=Jump to current location
|
||||
usage_dialog_plus.copy_path=Copy usage tree path
|
||||
usage_dialog_plus.search_complete=Search completed
|
||||
usage_dialog_plus.code_view=code view
|
||||
usage_dialog_plus.select_node=select node
|
||||
usage_dialog_plus.code_for=code for
|
||||
usage_dialog_plus.expand_usages=expand data
|
||||
usage_dialog_plus.code_view=Code View
|
||||
usage_dialog_plus.select_node=Select Node
|
||||
usage_dialog_plus.code_for=Code for %s
|
||||
usage_dialog_plus.expand_usages=Expand Data
|
||||
|
||||
comment_dialog.title.add=Add code comment
|
||||
comment_dialog.title.update=Update code comment
|
||||
@@ -393,7 +393,6 @@ encoding_dialog.title=Encoding
|
||||
encoding_dialog.message=Select encoding:
|
||||
|
||||
exclude_dialog.title=Package Selector
|
||||
exclude_dialog.ok=OK
|
||||
exclude_dialog.select_all=Select all
|
||||
exclude_dialog.deselect=Deselect
|
||||
exclude_dialog.invert=Invert
|
||||
|
||||
@@ -136,7 +136,7 @@ nav.forward=Adelante
|
||||
|
||||
#heapUsage.text=JADX memory usage: %.2f GB of %.2f GB
|
||||
|
||||
#common_dialog.ok=Ok
|
||||
#common_dialog.ok=OK
|
||||
#common_dialog.cancel=Cancel
|
||||
#common_dialog.add=Add
|
||||
#common_dialog.update=Update
|
||||
@@ -188,10 +188,10 @@ usage_dialog.label=Usage for:
|
||||
#usage_dialog_plus.jump_to=Jump to current location
|
||||
#usage_dialog_plus.copy_path=Copy usage tree path
|
||||
#usage_dialog_plus.search_complete=Search completed
|
||||
#usage_dialog_plus.code_view=code view
|
||||
#usage_dialog_plus.select_node=select node
|
||||
#usage_dialog_plus.code_for=code for
|
||||
#usage_dialog_plus.expand_usages=expand data
|
||||
#usage_dialog_plus.code_view=Code View
|
||||
#usage_dialog_plus.select_node=Select Node
|
||||
#usage_dialog_plus.code_for=Code for %s
|
||||
#usage_dialog_plus.expand_usages=Expand Data
|
||||
|
||||
#comment_dialog.title.add=Add code comment
|
||||
#comment_dialog.title.update=Update code comment
|
||||
@@ -393,7 +393,6 @@ popup.rename=Renombrar
|
||||
#encoding_dialog.message=Select encoding:
|
||||
|
||||
#exclude_dialog.title=Package Selector
|
||||
#exclude_dialog.ok=OK
|
||||
#exclude_dialog.select_all=Select all
|
||||
#exclude_dialog.deselect=Deselect
|
||||
#exclude_dialog.invert=Invert
|
||||
|
||||
@@ -188,10 +188,10 @@ usage_dialog.label=Penggunaan untuk:
|
||||
#usage_dialog_plus.jump_to=Jump to current location
|
||||
#usage_dialog_plus.copy_path=Copy usage tree path
|
||||
#usage_dialog_plus.search_complete=Search completed
|
||||
#usage_dialog_plus.code_view=code view
|
||||
#usage_dialog_plus.select_node=select node
|
||||
#usage_dialog_plus.code_for=code for
|
||||
#usage_dialog_plus.expand_usages=expand data
|
||||
#usage_dialog_plus.code_view=Code View
|
||||
#usage_dialog_plus.select_node=Select Node
|
||||
#usage_dialog_plus.code_for=Code for %s
|
||||
#usage_dialog_plus.expand_usages=Expand Data
|
||||
|
||||
comment_dialog.title.add=Tambahkan komentar kode
|
||||
comment_dialog.title.update=Perbarui komentar kode
|
||||
@@ -393,7 +393,6 @@ script.log=Tampilkan log
|
||||
#encoding_dialog.message=Select encoding:
|
||||
|
||||
exclude_dialog.title=Selektor Paket
|
||||
exclude_dialog.ok=OK
|
||||
exclude_dialog.select_all=Pilih semua
|
||||
exclude_dialog.deselect=Batal pilih
|
||||
exclude_dialog.invert=Balik pilihan
|
||||
|
||||
@@ -188,10 +188,10 @@ usage_dialog.label=다음의 사용 검색 결과:
|
||||
#usage_dialog_plus.jump_to=Jump to current location
|
||||
#usage_dialog_plus.copy_path=Copy usage tree path
|
||||
#usage_dialog_plus.search_complete=Search completed
|
||||
#usage_dialog_plus.code_view=code view
|
||||
#usage_dialog_plus.select_node=select node
|
||||
#usage_dialog_plus.code_for=code for
|
||||
#usage_dialog_plus.expand_usages=expand data
|
||||
#usage_dialog_plus.code_view=Code View
|
||||
#usage_dialog_plus.select_node=Select Node
|
||||
#usage_dialog_plus.code_for=Code for %s
|
||||
#usage_dialog_plus.expand_usages=Expand Data
|
||||
|
||||
comment_dialog.title.add=주석 추가
|
||||
comment_dialog.title.update=주석 업데이트
|
||||
@@ -393,7 +393,6 @@ popup.search_global="%s" 전역 검색
|
||||
#encoding_dialog.message=Select encoding:
|
||||
|
||||
exclude_dialog.title=패키지 선택기
|
||||
exclude_dialog.ok=확인
|
||||
exclude_dialog.select_all=모두 선택
|
||||
exclude_dialog.deselect=선택 해제
|
||||
exclude_dialog.invert=반전
|
||||
|
||||
@@ -188,10 +188,10 @@ usage_dialog.label=Usado por:
|
||||
#usage_dialog_plus.jump_to=Jump to current location
|
||||
#usage_dialog_plus.copy_path=Copy usage tree path
|
||||
#usage_dialog_plus.search_complete=Search completed
|
||||
#usage_dialog_plus.code_view=code view
|
||||
#usage_dialog_plus.select_node=select node
|
||||
#usage_dialog_plus.code_for=code for
|
||||
#usage_dialog_plus.expand_usages=expand data
|
||||
#usage_dialog_plus.code_view=Code View
|
||||
#usage_dialog_plus.select_node=Select Node
|
||||
#usage_dialog_plus.code_for=Code for %s
|
||||
#usage_dialog_plus.expand_usages=Expand Data
|
||||
|
||||
comment_dialog.title.add=Adicionar comentário ao código
|
||||
comment_dialog.title.update=Atualizar comentário do código
|
||||
@@ -393,7 +393,6 @@ popup.search_global=Busca global "%s"
|
||||
#encoding_dialog.message=Select encoding:
|
||||
|
||||
exclude_dialog.title=Selecionar pacote
|
||||
exclude_dialog.ok=OK
|
||||
exclude_dialog.select_all=Selecionar tudo
|
||||
exclude_dialog.deselect=Remover seleção
|
||||
exclude_dialog.invert=Inverter
|
||||
|
||||
@@ -188,10 +188,10 @@ usage_dialog.label=Использования:
|
||||
#usage_dialog_plus.jump_to=Jump to current location
|
||||
#usage_dialog_plus.copy_path=Copy usage tree path
|
||||
#usage_dialog_plus.search_complete=Search completed
|
||||
#usage_dialog_plus.code_view=code view
|
||||
#usage_dialog_plus.select_node=select node
|
||||
#usage_dialog_plus.code_for=code for
|
||||
#usage_dialog_plus.expand_usages=expand data
|
||||
#usage_dialog_plus.code_view=Code View
|
||||
#usage_dialog_plus.select_node=Select Node
|
||||
#usage_dialog_plus.code_for=Code for %s
|
||||
#usage_dialog_plus.expand_usages=Expand Data
|
||||
|
||||
comment_dialog.title.add=Добавить комментарий
|
||||
comment_dialog.title.update=Обновить
|
||||
@@ -393,7 +393,6 @@ script.log=Показать лог
|
||||
#encoding_dialog.message=Select encoding:
|
||||
|
||||
exclude_dialog.title=Выбор пакетов
|
||||
exclude_dialog.ok=OK
|
||||
exclude_dialog.select_all=Выбрать все
|
||||
exclude_dialog.deselect=Убрать
|
||||
exclude_dialog.invert=Инвертировать
|
||||
|
||||
@@ -190,7 +190,7 @@ usage_dialog_plus.copy_path=复制用例路径
|
||||
usage_dialog_plus.search_complete=搜索完成
|
||||
usage_dialog_plus.code_view=代码预览
|
||||
usage_dialog_plus.select_node=选择节点
|
||||
usage_dialog_plus.code_for=代码信息
|
||||
usage_dialog_plus.code_for=代码信息 %s
|
||||
usage_dialog_plus.expand_usages=展开数据
|
||||
|
||||
comment_dialog.title.add=添加代码注释
|
||||
@@ -393,7 +393,6 @@ script.log=显示日志
|
||||
#encoding_dialog.message=Select encoding:
|
||||
|
||||
exclude_dialog.title=选择要排除的包
|
||||
exclude_dialog.ok=确定
|
||||
exclude_dialog.select_all=全选
|
||||
exclude_dialog.deselect=取消选择
|
||||
exclude_dialog.invert=反选
|
||||
|
||||
@@ -190,7 +190,7 @@ usage_dialog_plus.copy_path=複製使用情況路徑
|
||||
usage_dialog_plus.search_complete=搜尋完成
|
||||
usage_dialog_plus.code_view=程式碼預覽
|
||||
usage_dialog_plus.select_node=選擇節點
|
||||
usage_dialog_plus.code_for=程式碼資訊
|
||||
usage_dialog_plus.code_for=程式碼資訊 %s
|
||||
usage_dialog_plus.expand_usages=展開資料
|
||||
|
||||
comment_dialog.title.add=新增程式碼註解
|
||||
@@ -393,7 +393,6 @@ script.log=顯示記錄檔
|
||||
#encoding_dialog.message=Select encoding:
|
||||
|
||||
exclude_dialog.title=套件選擇
|
||||
exclude_dialog.ok=OK
|
||||
exclude_dialog.select_all=全選
|
||||
exclude_dialog.deselect=取消選取
|
||||
exclude_dialog.invert=反轉選取
|
||||
|
||||
Reference in New Issue
Block a user