1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
|
package cuchaz.enigma.gui.util;
import java.awt.*;
import java.awt.datatransfer.StringSelection;
import java.awt.event.*;
import java.awt.font.TextAttribute;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.function.Consumer;
import javax.swing.*;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import com.formdev.flatlaf.extras.FlatSVGIcon;
import com.google.common.collect.Lists;
import cuchaz.enigma.analysis.index.EntryIndex;
import cuchaz.enigma.gui.Gui;
import cuchaz.enigma.translation.representation.AccessFlags;
import cuchaz.enigma.translation.representation.entry.ClassEntry;
import cuchaz.enigma.translation.representation.entry.MethodEntry;
import cuchaz.enigma.utils.Os;
public class GuiUtil {
public static final Icon CLASS_ICON = loadIcon("class");
public static final Icon INTERFACE_ICON = loadIcon("interface");
public static final Icon ENUM_ICON = loadIcon("enum");
public static final Icon ANNOTATION_ICON = loadIcon("annotation");
public static final Icon RECORD_ICON = loadIcon("record");
public static final Icon METHOD_ICON = loadIcon("method");
public static final Icon FIELD_ICON = loadIcon("field");
public static final Icon CONSTRUCTOR_ICON = loadIcon("constructor");
public static void openUrl(String url) {
try {
switch (Os.getOs()) {
case LINUX:
new ProcessBuilder("/usr/bin/env", "xdg-open", url).start();
break;
default:
if (Desktop.isDesktopSupported()) {
Desktop desktop = Desktop.getDesktop();
desktop.browse(new URI(url));
}
}
} catch (IOException ex) {
throw new RuntimeException(ex);
} catch (URISyntaxException ex) {
throw new IllegalArgumentException(ex);
}
}
public static JLabel unboldLabel(JLabel label) {
Font font = label.getFont();
label.setFont(font.deriveFont(font.getStyle() & ~Font.BOLD));
return label;
}
/**
* Puts the provided {@code text} in the system clipboard.
*/
public static void copyToClipboard(String text) {
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(text), null);
}
public static void showPopup(JComponent component, String text, int x, int y) {
// from https://stackoverflow.com/questions/39955015/java-swing-show-tooltip-as-a-message-dialog
JToolTip tooltip = new JToolTip();
tooltip.setTipText(text);
Popup p = PopupFactory.getSharedInstance().getPopup(component, tooltip, x + 10, y);
p.show();
Timer t = new Timer(1000, e -> p.hide());
t.setRepeats(false);
t.start();
}
public static void showToolTipNow(JComponent component) {
// HACKHACK: trick the tooltip manager into showing the tooltip right now
ToolTipManager manager = ToolTipManager.sharedInstance();
int oldDelay = manager.getInitialDelay();
manager.setInitialDelay(0);
manager.mouseMoved(new MouseEvent(component, MouseEvent.MOUSE_MOVED, System.currentTimeMillis(), 0, 0, 0, 0, false));
manager.setInitialDelay(oldDelay);
}
public static JLabel createLink(String text, Runnable action) {
JLabel link = new JLabel(text);
link.setForeground(Color.BLUE.darker());
link.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
@SuppressWarnings("unchecked")
Map<TextAttribute, Object> attributes = (Map<TextAttribute, Object>) link.getFont().getAttributes();
attributes.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
link.setFont(link.getFont().deriveFont(attributes));
link.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
action.run();
}
});
return link;
}
public static Icon loadIcon(String name) {
String path = "icons/" + name + ".svg";
// Do an eager check for a missing icon since FlatSVGIcon does it later at render time
if (GuiUtil.class.getResource('/' + path) == null) {
throw new NoSuchElementException("Missing icon: '" + name + "' at " + path);
}
// Note: the width and height are scaled automatically because the FlatLaf UI scale
// is set in LookAndFeel.setGlobalLAF()
return new FlatSVGIcon(path, 16, 16, GuiUtil.class.getClassLoader());
}
public static Icon getClassIcon(Gui gui, ClassEntry entry) {
EntryIndex entryIndex = gui.getController().project.getJarIndex().getEntryIndex();
AccessFlags access = entryIndex.getClassAccess(entry);
if (access != null) {
if (access.isAnnotation()) {
return ANNOTATION_ICON;
} else if (access.isInterface()) {
return INTERFACE_ICON;
} else if (access.isEnum()) {
return ENUM_ICON;
} else if (entryIndex.getDefinition(entry).isRecord()) {
return RECORD_ICON;
}
}
return CLASS_ICON;
}
public static Icon getMethodIcon(MethodEntry entry) {
if (entry.isConstructor()) {
return CONSTRUCTOR_ICON;
}
return METHOD_ICON;
}
public static TreePath getPathToRoot(TreeNode node) {
List<TreeNode> nodes = Lists.newArrayList();
TreeNode n = node;
do {
nodes.add(n);
n = n.getParent();
} while (n != null);
Collections.reverse(nodes);
return new TreePath(nodes.toArray());
}
public static MouseListener onMouseClick(Consumer<MouseEvent> op) {
return new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
op.accept(e);
}
};
}
public static MouseListener onMousePress(Consumer<MouseEvent> op) {
return new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
op.accept(e);
}
};
}
public static WindowListener onWindowClose(Consumer<WindowEvent> op) {
return new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
op.accept(e);
}
};
}
}
|