1
2
3
4
5
6
7
8
9
10
11 package com.jsql.view.swing.tab;
12
13 import com.formdev.flatlaf.extras.FlatSVGIcon;
14 import com.jsql.model.bean.database.AbstractElementDatabase;
15 import com.jsql.util.I18nUtil;
16 import com.jsql.util.LogLevelUtil;
17 import com.jsql.util.StringUtil;
18 import com.jsql.util.reverse.ModelReverse;
19 import com.jsql.view.swing.action.ActionCloseTabResult;
20 import com.jsql.view.swing.action.HotkeyUtil;
21 import com.jsql.view.swing.popupmenu.JPopupMenuText;
22 import com.jsql.view.swing.tab.dnd.DnDTabbedPane;
23 import com.jsql.view.swing.tab.dnd.TabTransferHandler;
24 import com.jsql.view.swing.table.PanelTable;
25 import com.jsql.view.swing.terminal.AbstractExploit;
26 import com.jsql.view.swing.terminal.ExploitReverseShell;
27 import com.jsql.view.swing.text.JPopupTextArea;
28 import com.jsql.view.swing.text.JTextFieldPlaceholder;
29 import com.jsql.view.swing.util.*;
30 import org.apache.commons.lang3.StringUtils;
31 import org.apache.logging.log4j.LogManager;
32 import org.apache.logging.log4j.Logger;
33 import org.jsoup.Jsoup;
34 import org.jsoup.safety.Safelist;
35
36 import javax.swing.*;
37 import javax.swing.event.HyperlinkEvent;
38 import javax.swing.text.DefaultEditorKit;
39 import java.awt.*;
40 import java.awt.datatransfer.StringSelection;
41 import java.awt.event.*;
42 import java.io.IOException;
43 import java.net.MalformedURLException;
44 import java.net.URISyntaxException;
45 import java.util.Arrays;
46 import java.util.EmptyStackException;
47 import java.util.List;
48 import java.util.UUID;
49 import java.util.function.BiConsumer;
50 import java.util.function.IntConsumer;
51
52
53
54
55 public class TabResults extends DnDTabbedPane {
56
57 private static final Logger LOGGER = LogManager.getRootLogger();
58
59 public static final String TAB_EXPLOIT_FAILURE_INCORRECT_URL = "Tab exploit failure: incorrect URL";
60 public static final String UDF_SHELL = "UDF shell";
61 public static final String SQL_SHELL = "SQL shell";
62 public static final String REVERSE_SHELL = "Reverse shell";
63 public static final String WEB_SHELL = "webShell";
64 public static final String TAB_RESULTS = "tabResults";
65
66
67
68
69 public TabResults() {
70 this.setName(TabResults.TAB_RESULTS);
71 this.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
72 this.setTransferHandler(new TabTransferHandler());
73 this.putClientProperty("JTabbedPane.tabClosable", true);
74 this.putClientProperty("JTabbedPane.tabCloseCallback", (IntConsumer) ActionCloseTabResult::perform);
75 UIManager.put("TabbedPane.closeHoverForeground", LogLevelUtil.COLOR_RED);
76 HotkeyUtil.addShortcut(this);
77 this.addMouseWheelListener(new TabbedPaneMouseWheelListener());
78 MediatorHelper.register(this);
79 }
80
81 public void addFileTab(String label, String content, String path) {
82 MediatorHelper.frame().getSplitNS().invokeLaterWithSplitOrientation(() -> {
83 JTextArea fileText = new JPopupTextArea().getProxy();
84 fileText.setText(content);
85 fileText.setFont(new Font(UiUtil.FONT_NAME_MONO_NON_ASIAN, Font.PLAIN, 14));
86 fileText.setCaretPosition(0);
87 this.addTextTab(label, path, fileText, UiUtil.DOWNLOAD.getIcon());
88 MediatorHelper.tabManagersCards().addToLists(path, label);
89 });
90 }
91
92 public void addAdminTab(String urlSuccess) {
93 MediatorHelper.frame().getSplitNS().invokeLaterWithSplitOrientation(() -> {
94 String htmlSource = StringUtils.EMPTY;
95
96
97
98
99 try {
100
101
102
103 htmlSource = Jsoup.clean(
104 Jsoup.connect(urlSuccess)
105
106 .ignoreContentType(true)
107
108 .ignoreHttpErrors(true)
109 .get()
110 .html()
111 .replaceAll("<img[^>]*>", StringUtils.EMPTY)
112 .replaceAll("<input[^>]*type=\"?hidden\"?[^>]*>", StringUtils.EMPTY)
113 .replaceAll("<input[^>]*type=\"?(submit|button)\"?[^>]*>", "<div style=\"background-color:#eeeeee;text-align:center;border:1px solid black;width:100px;\">button</div>")
114 .replaceAll("<input[^>]*>", "<div style=\"text-align:center;border:1px solid black;width:100px;\">input</div>"),
115 Safelist.relaxed()
116 .addTags("center", "div", "span")
117 .addAttributes(":all", "style")
118 );
119 } catch (IOException e) {
120 LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Failure opening page: {}", e.getMessage());
121 } catch (ExceptionInInitializerError | NoClassDefFoundError e) {
122 LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
123 }
124
125 final var browser = new JTextPane();
126 browser.setContentType("text/html");
127 browser.setEditable(false);
128 browser.setCaretPosition(0);
129
130
131
132 try {
133 browser.setText(htmlSource);
134 } catch (IndexOutOfBoundsException | EmptyStackException e) {
135 LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
136 }
137
138 JMenuItem itemCopyUrl = new JMenuItem(I18nUtil.valueByKey("CONTEXT_MENU_COPY_PAGE_URL"));
139 I18nViewUtil.addComponentForKey("CONTEXT_MENU_COPY_PAGE_URL", itemCopyUrl);
140
141 JMenuItem itemCopy = new JMenuItem();
142 itemCopy.setAction(browser.getActionMap().get(DefaultEditorKit.copyAction));
143 itemCopy.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_DOWN_MASK));
144 itemCopy.setMnemonic('C');
145 itemCopy.setText(I18nUtil.valueByKey("CONTEXT_MENU_COPY"));
146 I18nViewUtil.addComponentForKey("CONTEXT_MENU_COPY", itemCopy);
147
148 JMenuItem itemSelectAll = new JMenuItem();
149 itemSelectAll.setAction(browser.getActionMap().get(DefaultEditorKit.selectAllAction));
150 itemSelectAll.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, InputEvent.CTRL_DOWN_MASK));
151 itemSelectAll.setText(I18nUtil.valueByKey("CONTEXT_MENU_SELECT_ALL"));
152 I18nViewUtil.addComponentForKey("CONTEXT_MENU_SELECT_ALL", itemSelectAll);
153 itemSelectAll.setMnemonic('A');
154
155 final var menu = new JPopupMenu();
156 menu.add(itemCopyUrl);
157 menu.add(new JSeparator());
158 menu.add(itemCopy);
159 menu.add(itemSelectAll);
160 menu.applyComponentOrientation(ComponentOrientation.getOrientation(I18nUtil.getCurrentLocale()));
161
162 itemCopyUrl.addActionListener(actionEvent -> {
163 var stringSelection = new StringSelection(urlSuccess);
164 var clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
165 clipboard.setContents(stringSelection, null);
166 });
167
168 itemSelectAll.addActionListener(actionEvent -> browser.selectAll());
169
170 browser.addFocusListener(new FocusAdapter() {
171 @Override
172 public void focusGained(FocusEvent focusEvent) {
173 browser.getCaret().setVisible(true);
174 browser.getCaret().setSelectionVisible(true);
175 }
176 });
177 browser.addMouseListener(new BrowserMouseAdapter(browser, menu));
178
179 final var scroller = new JScrollPane(browser);
180 MediatorHelper.tabResults().addTab(urlSuccess.replaceAll(".*/", StringUtils.EMPTY) + StringUtils.SPACE, scroller);
181 try {
182 MediatorHelper.tabResults().setSelectedComponent(scroller);
183 } catch (ArrayIndexOutOfBoundsException e) {
184 LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
185 }
186 MediatorHelper.tabResults().setToolTipTextAt(
187 MediatorHelper.tabResults().indexOfComponent(scroller),
188 String.format("<html>%s</html>", urlSuccess)
189 );
190
191
192 var header = new TabHeader(
193 urlSuccess.replaceAll(".*/", StringUtils.EMPTY),
194 UiUtil.ADMIN.getIcon()
195 );
196 MediatorHelper.tabResults().setTabComponentAt(MediatorHelper.tabResults().indexOfComponent(scroller), header);
197 browser.setCaretPosition(0);
198
199 MediatorHelper.tabResults().updateUI();
200 });
201 }
202
203 public void addReportTab(String content) {
204 MediatorHelper.frame().getSplitNS().invokeLaterWithSplitOrientation(() -> {
205 JEditorPane editorPane = new JEditorPane();
206 editorPane.setContentType("text/html");
207 editorPane.setText("<html><span style=\"white-space: nowrap; font-family:'"+ UiUtil.FONT_NAME_MONO_NON_ASIAN +"'\">" + content + "</span></html>");
208 editorPane.setFont(UIManager.getFont("TextArea.font"));
209 editorPane.setDragEnabled(true);
210 editorPane.setEditable(false);
211 editorPane.setCaretPosition(0);
212 editorPane.getCaret().setBlinkRate(0);
213 editorPane.setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
214 editorPane.setComponentPopupMenu(new JPopupMenuText(editorPane));
215 editorPane.addHyperlinkListener(linkEvent -> {
216 if (HyperlinkEvent.EventType.ACTIVATED.equals(linkEvent.getEventType())) {
217 try {
218 Desktop.getDesktop().browse(linkEvent.getURL().toURI());
219 } catch (IOException | URISyntaxException | UnsupportedOperationException e) {
220 LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Failing to browse Url", e);
221 }
222 }
223 });
224 editorPane.addFocusListener(new FocusAdapter() {
225 @Override
226 public void focusGained(FocusEvent focusEvent) {
227 editorPane.getCaret().setVisible(true);
228 editorPane.getCaret().setSelectionVisible(true);
229 editorPane.getCaret().setBlinkRate(0);
230 }
231 });
232 UiUtil.init(editorPane);
233
234 this.addTextTab("Vulnerability report", "Analysis report with all payloads detected", editorPane, UiUtil.APP_ICON.getIcon());
235 });
236 }
237
238 public void addTextTab(String label, String toolTipText, JComponent componentText, FlatSVGIcon icon) {
239 var scroller = new JScrollPane(componentText);
240 this.addTab(label + StringUtils.SPACE, scroller);
241 this.setSelectedComponent(scroller);
242 this.setToolTipTextAt(this.indexOfComponent(scroller), toolTipText);
243 var header = new TabHeader(label, icon);
244 this.setTabComponentAt(this.indexOfComponent(scroller), header);
245
246 this.updateUI();
247 }
248
249 public void addTabExploitWeb(String url) {
250 MediatorHelper.frame().getSplitNS().invokeLaterWithSplitOrientation(() -> {
251 try {
252 var terminalID = UUID.randomUUID();
253 var terminal = new AbstractExploit(terminalID, url, "web") {
254 @Override
255 public void action(String command, UUID terminalID, String urlShell, String... arg) {
256 MediatorHelper.model().getResourceAccess().runWebShell(command, terminalID, urlShell);
257 }
258 };
259 terminal.setName(TabResults.WEB_SHELL);
260 MediatorHelper.frame().getMapUuidShell().put(terminalID, terminal);
261
262 JPanel panelTerminalWithReverse = this.getTerminalWithMenu(terminal);
263 this.addTab("Web shell", panelTerminalWithReverse);
264 this.setSelectedComponent(panelTerminalWithReverse);
265
266 var header = new TabHeader("Web shell", UiUtil.TERMINAL.getIcon());
267 this.setTabComponentAt(this.indexOfComponent(panelTerminalWithReverse), header);
268 terminal.requestFocusInWindow();
269
270 this.updateUI();
271 } catch (MalformedURLException | URISyntaxException e) {
272 LOGGER.log(LogLevelUtil.CONSOLE_ERROR, TabResults.TAB_EXPLOIT_FAILURE_INCORRECT_URL, e);
273 }
274 });
275 }
276
277 public void addTabExploitReverseShell(String port) {
278 MediatorHelper.frame().getSplitNS().invokeLaterWithSplitOrientation(() -> {
279 try {
280 var terminalID = UUID.randomUUID();
281 var terminal = new ExploitReverseShell(terminalID, port);
282 MediatorHelper.frame().getMapUuidShell().put(terminalID, terminal);
283
284 JScrollPane scroller = new JScrollPane(terminal);
285 this.addTab(TabResults.REVERSE_SHELL, scroller);
286 this.setSelectedComponent(scroller);
287
288 var header = new TabHeader(TabResults.REVERSE_SHELL, UiUtil.TERMINAL.getIcon());
289 this.setTabComponentAt(this.indexOfComponent(scroller), header);
290 terminal.requestFocusInWindow();
291
292 this.updateUI();
293 } catch (URISyntaxException | IOException e) {
294 LOGGER.log(LogLevelUtil.CONSOLE_ERROR, TabResults.TAB_EXPLOIT_FAILURE_INCORRECT_URL, e);
295 }
296 });
297 }
298
299 public void addTabExploitUdf(BiConsumer<String, UUID> biConsumerRunCmd) {
300 MediatorHelper.frame().getSplitNS().invokeLaterWithSplitOrientation(() -> {
301 try {
302 var terminalID = UUID.randomUUID();
303 var terminal = new AbstractExploit(terminalID, null, "udf") {
304 @Override
305 public void action(String command, UUID terminalID, String urlShell, String... arg) {
306 biConsumerRunCmd.accept(command, terminalID);
307 }
308 };
309 MediatorHelper.frame().getMapUuidShell().put(terminalID, terminal);
310
311 JPanel panelTerminalWithReverse = this.getTerminalWithMenu(terminal);
312 this.addTab(TabResults.UDF_SHELL, panelTerminalWithReverse);
313 this.setSelectedComponent(panelTerminalWithReverse);
314
315 var header = new TabHeader(TabResults.UDF_SHELL, UiUtil.TERMINAL.getIcon());
316 this.setTabComponentAt(this.indexOfComponent(panelTerminalWithReverse), header);
317 terminal.requestFocusInWindow();
318
319 this.updateUI();
320 } catch (MalformedURLException | URISyntaxException e) {
321 LOGGER.log(LogLevelUtil.CONSOLE_ERROR, TabResults.TAB_EXPLOIT_FAILURE_INCORRECT_URL, e);
322 }
323 });
324 }
325
326 public void addTabExploitSql(String url, String user, String pass) {
327 MediatorHelper.frame().getSplitNS().invokeLaterWithSplitOrientation(() -> {
328 try {
329 var terminalID = UUID.randomUUID();
330 var terminal = new AbstractExploit(terminalID, url, "sql") {
331 @Override
332 public void action(String cmd, UUID terminalID, String wbhPath, String... arg) {
333 MediatorHelper.model().getResourceAccess().runSqlShell(cmd, terminalID, wbhPath, arg[0], arg[1]);
334 }
335 };
336 terminal.setLoginPassword(new String[]{ user, pass });
337 MediatorHelper.frame().getMapUuidShell().put(terminalID, terminal);
338
339 JScrollPane scroller = new JScrollPane(terminal);
340 this.addTab(TabResults.SQL_SHELL, scroller);
341 this.setSelectedComponent(scroller);
342
343 var header = new TabHeader(TabResults.SQL_SHELL, UiUtil.TERMINAL.getIcon());
344 this.setTabComponentAt(this.indexOfComponent(scroller), header);
345 terminal.requestFocusInWindow();
346
347 this.updateUI();
348 } catch (MalformedURLException | URISyntaxException e) {
349 LOGGER.log(LogLevelUtil.CONSOLE_ERROR, TabResults.TAB_EXPLOIT_FAILURE_INCORRECT_URL, e);
350 }
351 });
352 }
353
354 public void addTabValues(String[][] data, String[] columnNames, AbstractElementDatabase table) {
355 var panelTable = new PanelTable(data, columnNames);
356
357 this.addTab(StringUtil.detectUtf8(table.toString()), panelTable);
358 panelTable.setComponentOrientation(ComponentOrientation.getOrientation(I18nUtil.getCurrentLocale()));
359
360 this.setSelectedComponent(panelTable);
361
362 var header = new TabHeader(UiStringUtil.detectUtf8Html(table.toString()), UiUtil.TABLE_BOLD.getIcon());
363 this.setTabComponentAt(this.indexOfComponent(panelTable), header);
364
365 this.updateUI();
366 }
367
368 private JPanel getTerminalWithMenu(AbstractExploit terminal) {
369 JPanel panelTerminalWithReverse = new JPanel() {
370 @Override
371 public boolean isOptimizedDrawingEnabled() {
372 return false;
373 }
374 };
375 OverlayLayout overlay = new OverlayLayout(panelTerminalWithReverse);
376 panelTerminalWithReverse.setLayout(overlay);
377
378 var panelReverseMargin = new JPanel();
379 panelReverseMargin.setLayout(new BoxLayout(panelReverseMargin, BoxLayout.LINE_AXIS));
380 panelReverseMargin.setOpaque(false);
381 panelReverseMargin.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 15));
382
383 var menuReverse = new JLabel(TabResults.REVERSE_SHELL, UiUtil.ARROW_DOWN.getIcon(), SwingConstants.LEFT);
384 menuReverse.setName(TabResults.REVERSE_SHELL);
385 menuReverse.addMouseListener(new MouseAdapter() {
386 @Override
387 public void mousePressed(MouseEvent e) {
388 var popupMenu = TabResults.this.showMenu(terminal);
389 popupMenu.updateUI();
390 popupMenu.show(e.getComponent(), e.getComponent().getX(),5 + e.getComponent().getY() + e.getComponent().getHeight());
391 popupMenu.setLocation(e.getComponent().getLocationOnScreen().x,5 + e.getComponent().getLocationOnScreen().y + e.getComponent().getHeight());
392 }
393 });
394 menuReverse.setMaximumSize(menuReverse.getPreferredSize());
395 JScrollPane scrollerTerminal = new JScrollPane(terminal);
396 scrollerTerminal.setAlignmentX(1f);
397 scrollerTerminal.setAlignmentY(0f);
398 panelReverseMargin.setAlignmentX(1f);
399 panelReverseMargin.setAlignmentY(0f);
400 panelReverseMargin.add(menuReverse);
401 panelTerminalWithReverse.add(panelReverseMargin);
402 panelTerminalWithReverse.add(scrollerTerminal);
403
404 return panelTerminalWithReverse;
405 }
406
407 private JPopupMenu showMenu(AbstractExploit terminal) {
408 JPopupMenu menuReverse = new JPopupMenu();
409
410 var menuListen = new JMenu("Listen");
411 menuListen.setComponentOrientation(
412 ComponentOrientation.RIGHT_TO_LEFT.equals(ComponentOrientation.getOrientation(I18nUtil.getCurrentLocale()))
413 ? ComponentOrientation.LEFT_TO_RIGHT
414 : ComponentOrientation.RIGHT_TO_LEFT
415 );
416 var panelPublicAddress = new JPanel(new BorderLayout());
417 panelPublicAddress.add(new JLabel("<html><b>Your public address (listener) :</b></html>"));
418 menuListen.add(panelPublicAddress);
419 menuListen.add(new JSeparator());
420 var address = new JTextFieldPlaceholder("Local IP/domain", "10.0.2.2");
421 menuListen.add(address);
422 var port = new JTextFieldPlaceholder("Local port", "4444");
423 menuListen.add(port);
424
425 var panelServerConnection = new JPanel(new BorderLayout());
426 panelServerConnection.add(new JLabel("<html><b>Server method (connector) :</b></html>"));
427 menuListen.add(panelServerConnection);
428 menuListen.add(new JSeparator());
429 var buttonGroup = new ButtonGroup();
430 List<ModelReverse> commandsReverse = MediatorHelper.model().getMediatorUtils().preferencesUtil().getCommandsReverse();
431 commandsReverse.forEach(modelReverse -> {
432 var radio = new RadioItemNonClosing(modelReverse.getName());
433 radio.setActionCommand(modelReverse.getName());
434 radio.setSelected("bash".equals(modelReverse.getName()));
435 buttonGroup.add(radio);
436 menuListen.add(radio);
437 });
438
439 Runnable runnableReverse = () -> {
440 try {
441 Thread.sleep(2500);
442 MediatorHelper.model().getMediatorUtils().preferencesUtil().getCommandsReverse().stream()
443 .filter(modelReverse -> modelReverse.getName().equals(buttonGroup.getSelection().getActionCommand()))
444 .findFirst()
445 .ifPresent(modelReverse -> MediatorHelper.model().getResourceAccess().runWebShell(
446 String.format(modelReverse.getCommand(), address.getText(), port.getText()),
447 null,
448 terminal.getUrlShell(),
449 true
450 ));
451 } catch (InterruptedException e) {
452 LOGGER.log(LogLevelUtil.IGNORE, e, e);
453 Thread.currentThread().interrupt();
454 }
455 };
456
457 var panelOpenIn = new JPanel(new BorderLayout());
458 panelOpenIn.add(new JLabel("<html><b>Open In :</b></html>"));
459 menuListen.add(panelOpenIn);
460 menuListen.add(new JSeparator());
461
462 var menuBuiltInShell = new RadioItemNonClosing("Built-in shell", true);
463 var menuExternalShell = new RadioItemNonClosing("External listening shell");
464 var buttonTypeShell = new ButtonGroup();
465 buttonTypeShell.add(menuBuiltInShell);
466 buttonTypeShell.add(menuExternalShell);
467 menuListen.add(menuBuiltInShell);
468 menuListen.add(menuExternalShell);
469 menuListen.add(new JSeparator());
470 var panelCreate = new JPanel(new BorderLayout());
471 panelCreate.add(new JButton(new AbstractAction("Create reverse shell") {
472 @Override
473 public void actionPerformed(ActionEvent e) {
474 if (menuBuiltInShell.isSelected()) {
475 MediatorHelper.tabResults().addTabExploitReverseShell(port.getText());
476 }
477 new Thread(runnableReverse).start();
478 menuReverse.setVisible(false);
479 }
480 }));
481 menuListen.add(panelCreate);
482
483 var menuConnect = new JMenu("Connect");
484 menuConnect.setComponentOrientation(
485 ComponentOrientation.RIGHT_TO_LEFT.equals(ComponentOrientation.getOrientation(I18nUtil.getCurrentLocale()))
486 ? ComponentOrientation.LEFT_TO_RIGHT
487 : ComponentOrientation.RIGHT_TO_LEFT
488 );
489 var panelServerPublicAddress = new JPanel(new BorderLayout());
490 panelServerPublicAddress.add(new JLabel("<html><b>Server public address (listener) :</b></html>"));
491 menuConnect.add(panelServerPublicAddress);
492 menuConnect.add(new JSeparator());
493 menuConnect.add(new JTextFieldPlaceholder("Target IP/domain"));
494 menuConnect.add(new JTextFieldPlaceholder("Target port"));
495 menuConnect.add(new JSeparator());
496
497 var panelServerListeningConnection = new JPanel(new BorderLayout());
498 panelServerListeningConnection.add(new JLabel("<html><b>Server listening method :</b></html>"));
499 menuConnect.add(panelServerListeningConnection);
500 var buttonGroupListening = new ButtonGroup();
501 List.of("netcat").forEach(method -> {
502 var radio = new JRadioButtonMenuItem(method) {
503 @Override
504 protected void processMouseEvent(MouseEvent evt) {
505 if (evt.getID() == MouseEvent.MOUSE_RELEASED && this.contains(evt.getPoint())) {
506 this.doClick();
507 this.setArmed(true);
508 } else {
509 super.processMouseEvent(evt);
510 }
511 }
512 };
513 radio.setSelected("netcat".equals(method));
514 buttonGroupListening.add(radio);
515 menuConnect.add(radio);
516 });
517 menuConnect.add(new JSeparator());
518 menuConnect.add(new JMenuItem("Create"));
519
520 menuReverse.add(menuListen);
521 menuReverse.add(menuConnect);
522 return menuReverse;
523 }
524
525 private static class BrowserMouseAdapter extends MouseAdapter {
526 private final JTextPane browser;
527 private final JPopupMenu menu;
528
529 public BrowserMouseAdapter(JTextPane browser, JPopupMenu menu) {
530 this.browser = browser;
531 this.menu = menu;
532 }
533
534 @Override
535 public void mousePressed(MouseEvent evt) {
536 this.browser.requestFocusInWindow();
537 if (evt.isPopupTrigger()) {
538 this.menu.show(evt.getComponent(), evt.getX(), evt.getY());
539 }
540 }
541
542 @Override
543 public void mouseReleased(MouseEvent evt) {
544 if (evt.isPopupTrigger()) {
545 Arrays.stream(this.menu.getComponents()).map(a -> (JComponent) a).forEach(JComponent::updateUI);
546 this.menu.updateUI();
547
548 try {
549 this.menu.show(evt.getComponent(), evt.getX(), evt.getY());
550 } catch (IllegalComponentStateException e) {
551 LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
552 }
553 this.menu.setLocation(
554 ComponentOrientation.RIGHT_TO_LEFT.equals(ComponentOrientation.getOrientation(I18nUtil.getCurrentLocale()))
555 ? evt.getXOnScreen() - this.menu.getWidth()
556 : evt.getXOnScreen(),
557 evt.getYOnScreen()
558 );
559 }
560 }
561 }
562 }