diff options
| author | 2020-05-03 21:06:38 +0100 | |
|---|---|---|
| committer | 2020-05-03 21:06:38 +0100 | |
| commit | 854f4d49407e45d67dd5754afd21a7e59970ca5b (patch) | |
| tree | 582e3245786f9723b5895b0c8d41087b0e6bb416 /src/main/java/cuchaz/enigma/gui/Gui.java | |
| parent | Rewrite search dialog (#233) (diff) | |
| download | enigma-fork-854f4d49407e45d67dd5754afd21a7e59970ca5b.tar.gz enigma-fork-854f4d49407e45d67dd5754afd21a7e59970ca5b.tar.xz enigma-fork-854f4d49407e45d67dd5754afd21a7e59970ca5b.zip | |
Multiplayer support (#221)
* First pass on multiplayer
* Apply review suggestions
* Dedicated Enigma server
* Don't jump to references when other users do stuff
* Better UI + translations
* french translation
* Apply review suggestions
* Document the protocol
* Fix most issues with scrolling.
* Apply review suggestions
* Fix zip hash issues + add a bit more logging
* Optimize zip hash
* Fix a couple of login bugs
* Add message log and user list
* Make Message an abstract class
* Make status bar work, add chat box
* Hide message log/users list when not connected
* Fix status bar not resetting entirely
* Run stop server task on server thread to prevent multithreading race conditions
* Add c2s message to packet id list
* Fix message scroll bar not scrolling to the end
* Formatting
* User list size -> ushort
* Combine contains and remove check
* Check removal before sending packet
* Add password to login packet
* Fix the GUI closing the rename text field when someone else renames something
* Update fr_fr.json
* oups
* Make connection/server create dialogs not useless if it fails once
* Refactor UI state updating
* Fix imports
* Fix Collab menu
* Fix NPE when rename not allowed
* Make the log file a configurable option
* Don't use modified UTF
* Update fr_fr.json
* Bump version to 0.15.4
* Apparently I can't spell neither words nor semantic versions
Co-authored-by: Yanis48 <doublecraft.official@gmail.com>
Co-authored-by: 2xsaiko <git@dblsaiko.net>
Diffstat (limited to 'src/main/java/cuchaz/enigma/gui/Gui.java')
| -rw-r--r-- | src/main/java/cuchaz/enigma/gui/Gui.java | 193 |
1 files changed, 164 insertions, 29 deletions
diff --git a/src/main/java/cuchaz/enigma/gui/Gui.java b/src/main/java/cuchaz/enigma/gui/Gui.java index 3412cd5..3adabae 100644 --- a/src/main/java/cuchaz/enigma/gui/Gui.java +++ b/src/main/java/cuchaz/enigma/gui/Gui.java | |||
| @@ -34,6 +34,7 @@ import cuchaz.enigma.config.Themes; | |||
| 34 | import cuchaz.enigma.gui.dialog.CrashDialog; | 34 | import cuchaz.enigma.gui.dialog.CrashDialog; |
| 35 | import cuchaz.enigma.gui.dialog.JavadocDialog; | 35 | import cuchaz.enigma.gui.dialog.JavadocDialog; |
| 36 | import cuchaz.enigma.gui.dialog.SearchDialog; | 36 | import cuchaz.enigma.gui.dialog.SearchDialog; |
| 37 | import cuchaz.enigma.gui.elements.CollapsibleTabbedPane; | ||
| 37 | import cuchaz.enigma.gui.elements.MenuBar; | 38 | import cuchaz.enigma.gui.elements.MenuBar; |
| 38 | import cuchaz.enigma.gui.elements.PopupMenuBar; | 39 | import cuchaz.enigma.gui.elements.PopupMenuBar; |
| 39 | import cuchaz.enigma.gui.filechooser.FileChooserAny; | 40 | import cuchaz.enigma.gui.filechooser.FileChooserAny; |
| @@ -46,10 +47,12 @@ import cuchaz.enigma.gui.panels.PanelEditor; | |||
| 46 | import cuchaz.enigma.gui.panels.PanelIdentifier; | 47 | import cuchaz.enigma.gui.panels.PanelIdentifier; |
| 47 | import cuchaz.enigma.gui.panels.PanelObf; | 48 | import cuchaz.enigma.gui.panels.PanelObf; |
| 48 | import cuchaz.enigma.gui.util.History; | 49 | import cuchaz.enigma.gui.util.History; |
| 50 | import cuchaz.enigma.network.packet.*; | ||
| 49 | import cuchaz.enigma.throwables.IllegalNameException; | 51 | import cuchaz.enigma.throwables.IllegalNameException; |
| 50 | import cuchaz.enigma.translation.mapping.*; | 52 | import cuchaz.enigma.translation.mapping.*; |
| 51 | import cuchaz.enigma.translation.representation.entry.*; | 53 | import cuchaz.enigma.translation.representation.entry.*; |
| 52 | import cuchaz.enigma.utils.I18n; | 54 | import cuchaz.enigma.utils.I18n; |
| 55 | import cuchaz.enigma.utils.Message; | ||
| 53 | import cuchaz.enigma.gui.util.ScaleUtil; | 56 | import cuchaz.enigma.gui.util.ScaleUtil; |
| 54 | import cuchaz.enigma.utils.Utils; | 57 | import cuchaz.enigma.utils.Utils; |
| 55 | import de.sciss.syntaxpane.DefaultSyntaxKit; | 58 | import de.sciss.syntaxpane.DefaultSyntaxKit; |
| @@ -63,8 +66,11 @@ public class Gui { | |||
| 63 | private final MenuBar menuBar; | 66 | private final MenuBar menuBar; |
| 64 | // state | 67 | // state |
| 65 | public History<EntryReference<Entry<?>, Entry<?>>> referenceHistory; | 68 | public History<EntryReference<Entry<?>, Entry<?>>> referenceHistory; |
| 69 | public EntryReference<Entry<?>, Entry<?>> renamingReference; | ||
| 66 | public EntryReference<Entry<?>, Entry<?>> cursorReference; | 70 | public EntryReference<Entry<?>, Entry<?>> cursorReference; |
| 67 | private boolean shouldNavigateOnClick; | 71 | private boolean shouldNavigateOnClick; |
| 72 | private ConnectionState connectionState; | ||
| 73 | private boolean isJarOpen; | ||
| 68 | 74 | ||
| 69 | public FileDialog jarFileChooser; | 75 | public FileDialog jarFileChooser; |
| 70 | public FileDialog tinyMappingsFileChooser; | 76 | public FileDialog tinyMappingsFileChooser; |
| @@ -76,6 +82,7 @@ public class Gui { | |||
| 76 | private JFrame frame; | 82 | private JFrame frame; |
| 77 | public Config.LookAndFeel editorFeel; | 83 | public Config.LookAndFeel editorFeel; |
| 78 | public PanelEditor editor; | 84 | public PanelEditor editor; |
| 85 | public JScrollPane sourceScroller; | ||
| 79 | private JPanel classesPanel; | 86 | private JPanel classesPanel; |
| 80 | private JSplitPane splitClasses; | 87 | private JSplitPane splitClasses; |
| 81 | private PanelIdentifier infoPanel; | 88 | private PanelIdentifier infoPanel; |
| @@ -87,6 +94,20 @@ public class Gui { | |||
| 87 | private JList<Token> tokens; | 94 | private JList<Token> tokens; |
| 88 | private JTabbedPane tabs; | 95 | private JTabbedPane tabs; |
| 89 | 96 | ||
| 97 | private JSplitPane splitRight; | ||
| 98 | private JSplitPane logSplit; | ||
| 99 | private CollapsibleTabbedPane logTabs; | ||
| 100 | private JList<String> users; | ||
| 101 | private DefaultListModel<String> userModel; | ||
| 102 | private JScrollPane messageScrollPane; | ||
| 103 | private JList<Message> messages; | ||
| 104 | private DefaultListModel<Message> messageModel; | ||
| 105 | private JTextField chatBox; | ||
| 106 | |||
| 107 | private JPanel statusBar; | ||
| 108 | private JLabel connectionStatusLabel; | ||
| 109 | private JLabel statusLabel; | ||
| 110 | |||
| 90 | public JTextField renameTextField; | 111 | public JTextField renameTextField; |
| 91 | public JTextArea javadocTextArea; | 112 | public JTextArea javadocTextArea; |
| 92 | 113 | ||
| @@ -150,7 +171,7 @@ public class Gui { | |||
| 150 | // init editor | 171 | // init editor |
| 151 | selectionHighlightPainter = new SelectionHighlightPainter(); | 172 | selectionHighlightPainter = new SelectionHighlightPainter(); |
| 152 | this.editor = new PanelEditor(this); | 173 | this.editor = new PanelEditor(this); |
| 153 | JScrollPane sourceScroller = new JScrollPane(this.editor); | 174 | this.sourceScroller = new JScrollPane(this.editor); |
| 154 | this.editor.setContentType("text/enigma-sources"); | 175 | this.editor.setContentType("text/enigma-sources"); |
| 155 | this.editor.setBackground(new Color(Config.getInstance().editorBackground)); | 176 | this.editor.setBackground(new Color(Config.getInstance().editorBackground)); |
| 156 | DefaultSyntaxKit kit = (DefaultSyntaxKit) this.editor.getEditorKit(); | 177 | DefaultSyntaxKit kit = (DefaultSyntaxKit) this.editor.getEditorKit(); |
| @@ -283,7 +304,34 @@ public class Gui { | |||
| 283 | tabs.addTab(I18n.translate("info_panel.tree.inheritance"), inheritancePanel); | 304 | tabs.addTab(I18n.translate("info_panel.tree.inheritance"), inheritancePanel); |
| 284 | tabs.addTab(I18n.translate("info_panel.tree.implementations"), implementationsPanel); | 305 | tabs.addTab(I18n.translate("info_panel.tree.implementations"), implementationsPanel); |
| 285 | tabs.addTab(I18n.translate("info_panel.tree.calls"), callPanel); | 306 | tabs.addTab(I18n.translate("info_panel.tree.calls"), callPanel); |
| 286 | JSplitPane splitRight = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, centerPanel, tabs); | 307 | logTabs = new CollapsibleTabbedPane(JTabbedPane.BOTTOM); |
| 308 | userModel = new DefaultListModel<>(); | ||
| 309 | users = new JList<>(userModel); | ||
| 310 | messageModel = new DefaultListModel<>(); | ||
| 311 | messages = new JList<>(messageModel); | ||
| 312 | messages.setCellRenderer(new MessageListCellRenderer()); | ||
| 313 | JPanel messagePanel = new JPanel(new BorderLayout()); | ||
| 314 | messageScrollPane = new JScrollPane(this.messages); | ||
| 315 | messagePanel.add(messageScrollPane, BorderLayout.CENTER); | ||
| 316 | JPanel chatPanel = new JPanel(new BorderLayout()); | ||
| 317 | chatBox = new JTextField(); | ||
| 318 | AbstractAction sendListener = new AbstractAction("Send") { | ||
| 319 | @Override | ||
| 320 | public void actionPerformed(ActionEvent e) { | ||
| 321 | sendMessage(); | ||
| 322 | } | ||
| 323 | }; | ||
| 324 | chatBox.addActionListener(sendListener); | ||
| 325 | JButton chatSendButton = new JButton(sendListener); | ||
| 326 | chatPanel.add(chatBox, BorderLayout.CENTER); | ||
| 327 | chatPanel.add(chatSendButton, BorderLayout.EAST); | ||
| 328 | messagePanel.add(chatPanel, BorderLayout.SOUTH); | ||
| 329 | logTabs.addTab(I18n.translate("log_panel.users"), new JScrollPane(this.users)); | ||
| 330 | logTabs.addTab(I18n.translate("log_panel.messages"), messagePanel); | ||
| 331 | logSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true, tabs, logTabs); | ||
| 332 | logSplit.setResizeWeight(0.5); | ||
| 333 | logSplit.resetToPreferredSizes(); | ||
| 334 | splitRight = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, centerPanel, this.logSplit); | ||
| 287 | splitRight.setResizeWeight(1); // let the left side take all the slack | 335 | splitRight.setResizeWeight(1); // let the left side take all the slack |
| 288 | splitRight.resetToPreferredSizes(); | 336 | splitRight.resetToPreferredSizes(); |
| 289 | JSplitPane splitCenter = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, this.classesPanel, splitRight); | 337 | JSplitPane splitCenter = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, this.classesPanel, splitRight); |
| @@ -294,7 +342,17 @@ public class Gui { | |||
| 294 | this.menuBar = new MenuBar(this); | 342 | this.menuBar = new MenuBar(this); |
| 295 | this.frame.setJMenuBar(this.menuBar); | 343 | this.frame.setJMenuBar(this.menuBar); |
| 296 | 344 | ||
| 345 | // init status bar | ||
| 346 | statusBar = new JPanel(new BorderLayout()); | ||
| 347 | statusBar.setBorder(BorderFactory.createLoweredBevelBorder()); | ||
| 348 | connectionStatusLabel = new JLabel(); | ||
| 349 | statusLabel = new JLabel(); | ||
| 350 | statusBar.add(statusLabel, BorderLayout.CENTER); | ||
| 351 | statusBar.add(connectionStatusLabel, BorderLayout.EAST); | ||
| 352 | pane.add(statusBar, BorderLayout.SOUTH); | ||
| 353 | |||
| 297 | // init state | 354 | // init state |
| 355 | setConnectionState(ConnectionState.NOT_CONNECTED); | ||
| 298 | onCloseJar(); | 356 | onCloseJar(); |
| 299 | 357 | ||
| 300 | this.frame.addWindowListener(new WindowAdapter() { | 358 | this.frame.addWindowListener(new WindowAdapter() { |
| @@ -334,18 +392,14 @@ public class Gui { | |||
| 334 | setEditorText(null); | 392 | setEditorText(null); |
| 335 | 393 | ||
| 336 | // update menu | 394 | // update menu |
| 337 | this.menuBar.closeJarMenu.setEnabled(true); | 395 | isJarOpen = true; |
| 338 | this.menuBar.openMappingsMenus.forEach(item -> item.setEnabled(true)); | ||
| 339 | this.menuBar.saveMappingsMenu.setEnabled(false); | ||
| 340 | this.menuBar.saveMappingsMenus.forEach(item -> item.setEnabled(true)); | ||
| 341 | this.menuBar.closeMappingsMenu.setEnabled(true); | ||
| 342 | this.menuBar.exportSourceMenu.setEnabled(true); | ||
| 343 | this.menuBar.exportJarMenu.setEnabled(true); | ||
| 344 | 396 | ||
| 397 | updateUiState(); | ||
| 345 | redraw(); | 398 | redraw(); |
| 346 | } | 399 | } |
| 347 | 400 | ||
| 348 | public void onCloseJar() { | 401 | public void onCloseJar() { |
| 402 | |||
| 349 | // update gui | 403 | // update gui |
| 350 | this.frame.setTitle(Constants.NAME); | 404 | this.frame.setTitle(Constants.NAME); |
| 351 | setObfClasses(null); | 405 | setObfClasses(null); |
| @@ -354,14 +408,10 @@ public class Gui { | |||
| 354 | this.classesPanel.removeAll(); | 408 | this.classesPanel.removeAll(); |
| 355 | 409 | ||
| 356 | // update menu | 410 | // update menu |
| 357 | this.menuBar.closeJarMenu.setEnabled(false); | 411 | isJarOpen = false; |
| 358 | this.menuBar.openMappingsMenus.forEach(item -> item.setEnabled(false)); | 412 | setMappingsFile(null); |
| 359 | this.menuBar.saveMappingsMenu.setEnabled(false); | ||
| 360 | this.menuBar.saveMappingsMenus.forEach(item -> item.setEnabled(false)); | ||
| 361 | this.menuBar.closeMappingsMenu.setEnabled(false); | ||
| 362 | this.menuBar.exportSourceMenu.setEnabled(false); | ||
| 363 | this.menuBar.exportJarMenu.setEnabled(false); | ||
| 364 | 413 | ||
| 414 | updateUiState(); | ||
| 365 | redraw(); | 415 | redraw(); |
| 366 | } | 416 | } |
| 367 | 417 | ||
| @@ -375,7 +425,7 @@ public class Gui { | |||
| 375 | 425 | ||
| 376 | public void setMappingsFile(Path path) { | 426 | public void setMappingsFile(Path path) { |
| 377 | this.enigmaMappingsFileChooser.setSelectedFile(path != null ? path.toFile() : null); | 427 | this.enigmaMappingsFileChooser.setSelectedFile(path != null ? path.toFile() : null); |
| 378 | this.menuBar.saveMappingsMenu.setEnabled(path != null); | 428 | updateUiState(); |
| 379 | } | 429 | } |
| 380 | 430 | ||
| 381 | public void setEditorText(String source) { | 431 | public void setEditorText(String source) { |
| @@ -561,10 +611,12 @@ public class Gui { | |||
| 561 | boolean isConstructorEntry = isToken && referenceEntry instanceof MethodEntry && ((MethodEntry) referenceEntry).isConstructor(); | 611 | boolean isConstructorEntry = isToken && referenceEntry instanceof MethodEntry && ((MethodEntry) referenceEntry).isConstructor(); |
| 562 | boolean isRenamable = isToken && this.controller.project.isRenamable(cursorReference); | 612 | boolean isRenamable = isToken && this.controller.project.isRenamable(cursorReference); |
| 563 | 613 | ||
| 564 | if (isToken) { | 614 | if (!isRenaming()) { |
| 565 | showCursorReference(cursorReference); | 615 | if (isToken) { |
| 566 | } else { | 616 | showCursorReference(cursorReference); |
| 567 | infoPanel.clearReference(); | 617 | } else { |
| 618 | infoPanel.clearReference(); | ||
| 619 | } | ||
| 568 | } | 620 | } |
| 569 | 621 | ||
| 570 | this.popupMenu.renameMenu.setEnabled(isRenamable); | 622 | this.popupMenu.renameMenu.setEnabled(isRenamable); |
| @@ -586,6 +638,11 @@ public class Gui { | |||
| 586 | } | 638 | } |
| 587 | 639 | ||
| 588 | public void startDocChange() { | 640 | public void startDocChange() { |
| 641 | EntryReference<Entry<?>, Entry<?>> curReference = cursorReference; | ||
| 642 | if (isRenaming()) { | ||
| 643 | finishRename(false); | ||
| 644 | } | ||
| 645 | renamingReference = curReference; | ||
| 589 | 646 | ||
| 590 | // init the text box | 647 | // init the text box |
| 591 | javadocTextArea = new JTextArea(10, 40); | 648 | javadocTextArea = new JTextArea(10, 40); |
| @@ -603,7 +660,8 @@ public class Gui { | |||
| 603 | String newName = javadocTextArea.getText(); | 660 | String newName = javadocTextArea.getText(); |
| 604 | if (saveName) { | 661 | if (saveName) { |
| 605 | try { | 662 | try { |
| 606 | this.controller.changeDocs(cursorReference, newName); | 663 | this.controller.changeDocs(renamingReference, newName); |
| 664 | this.controller.sendPacket(new ChangeDocsC2SPacket(renamingReference.getNameableEntry(), newName)); | ||
| 607 | } catch (IllegalNameException ex) { | 665 | } catch (IllegalNameException ex) { |
| 608 | javadocTextArea.setBorder(BorderFactory.createLineBorder(Color.red, 1)); | 666 | javadocTextArea.setBorder(BorderFactory.createLineBorder(Color.red, 1)); |
| 609 | javadocTextArea.setToolTipText(ex.getReason()); | 667 | javadocTextArea.setToolTipText(ex.getReason()); |
| @@ -665,14 +723,19 @@ public class Gui { | |||
| 665 | else | 723 | else |
| 666 | renameTextField.selectAll(); | 724 | renameTextField.selectAll(); |
| 667 | 725 | ||
| 726 | renamingReference = cursorReference; | ||
| 727 | |||
| 668 | redraw(); | 728 | redraw(); |
| 669 | } | 729 | } |
| 670 | 730 | ||
| 671 | private void finishRename(boolean saveName) { | 731 | private void finishRename(boolean saveName) { |
| 672 | String newName = renameTextField.getText(); | 732 | String newName = renameTextField.getText(); |
| 733 | |||
| 673 | if (saveName && newName != null && !newName.isEmpty()) { | 734 | if (saveName && newName != null && !newName.isEmpty()) { |
| 674 | try { | 735 | try { |
| 675 | this.controller.rename(cursorReference, newName, true); | 736 | this.controller.rename(renamingReference, newName, true); |
| 737 | this.controller.sendPacket(new RenameC2SPacket(renamingReference.getNameableEntry(), newName, true)); | ||
| 738 | renameTextField = null; | ||
| 676 | } catch (IllegalNameException ex) { | 739 | } catch (IllegalNameException ex) { |
| 677 | renameTextField.setBorder(BorderFactory.createLineBorder(Color.red, 1)); | 740 | renameTextField.setBorder(BorderFactory.createLineBorder(Color.red, 1)); |
| 678 | renameTextField.setToolTipText(ex.getReason()); | 741 | renameTextField.setToolTipText(ex.getReason()); |
| @@ -681,18 +744,20 @@ public class Gui { | |||
| 681 | return; | 744 | return; |
| 682 | } | 745 | } |
| 683 | 746 | ||
| 684 | // abort the rename | ||
| 685 | JPanel panel = (JPanel) infoPanel.getComponent(0); | ||
| 686 | panel.remove(panel.getComponentCount() - 1); | ||
| 687 | panel.add(Utils.unboldLabel(new JLabel(cursorReference.getNameableName(), JLabel.LEFT))); | ||
| 688 | |||
| 689 | renameTextField = null; | 747 | renameTextField = null; |
| 690 | 748 | ||
| 749 | // abort the rename | ||
| 750 | showCursorReference(cursorReference); | ||
| 751 | |||
| 691 | this.editor.grabFocus(); | 752 | this.editor.grabFocus(); |
| 692 | 753 | ||
| 693 | redraw(); | 754 | redraw(); |
| 694 | } | 755 | } |
| 695 | 756 | ||
| 757 | private boolean isRenaming() { | ||
| 758 | return renameTextField != null; | ||
| 759 | } | ||
| 760 | |||
| 696 | public void showInheritance() { | 761 | public void showInheritance() { |
| 697 | 762 | ||
| 698 | if (cursorReference == null) { | 763 | if (cursorReference == null) { |
| @@ -783,8 +848,10 @@ public class Gui { | |||
| 783 | 848 | ||
| 784 | if (!Objects.equals(obfEntry, deobfEntry)) { | 849 | if (!Objects.equals(obfEntry, deobfEntry)) { |
| 785 | this.controller.removeMapping(cursorReference); | 850 | this.controller.removeMapping(cursorReference); |
| 851 | this.controller.sendPacket(new RemoveMappingC2SPacket(cursorReference.getNameableEntry())); | ||
| 786 | } else { | 852 | } else { |
| 787 | this.controller.markAsDeobfuscated(cursorReference); | 853 | this.controller.markAsDeobfuscated(cursorReference); |
| 854 | this.controller.sendPacket(new MarkDeobfuscatedC2SPacket(cursorReference.getNameableEntry())); | ||
| 788 | } | 855 | } |
| 789 | } | 856 | } |
| 790 | 857 | ||
| @@ -850,6 +917,7 @@ public class Gui { | |||
| 850 | ClassEntry prevDataChild = (ClassEntry) childNode.getUserObject(); | 917 | ClassEntry prevDataChild = (ClassEntry) childNode.getUserObject(); |
| 851 | ClassEntry dataChild = new ClassEntry(data + "/" + prevDataChild.getSimpleName()); | 918 | ClassEntry dataChild = new ClassEntry(data + "/" + prevDataChild.getSimpleName()); |
| 852 | this.controller.rename(new EntryReference<>(prevDataChild, prevDataChild.getFullName()), dataChild.getFullName(), false); | 919 | this.controller.rename(new EntryReference<>(prevDataChild, prevDataChild.getFullName()), dataChild.getFullName(), false); |
| 920 | this.controller.sendPacket(new RenameC2SPacket(prevDataChild, dataChild.getFullName(), false)); | ||
| 853 | childNode.setUserObject(dataChild); | 921 | childNode.setUserObject(dataChild); |
| 854 | } | 922 | } |
| 855 | node.setUserObject(data); | 923 | node.setUserObject(data); |
| @@ -857,8 +925,10 @@ public class Gui { | |||
| 857 | this.deobfPanel.deobfClasses.reload(); | 925 | this.deobfPanel.deobfClasses.reload(); |
| 858 | } | 926 | } |
| 859 | // class rename | 927 | // class rename |
| 860 | else if (data instanceof ClassEntry) | 928 | else if (data instanceof ClassEntry) { |
| 861 | this.controller.rename(new EntryReference<>((ClassEntry) prevData, ((ClassEntry) prevData).getFullName()), ((ClassEntry) data).getFullName(), false); | 929 | this.controller.rename(new EntryReference<>((ClassEntry) prevData, ((ClassEntry) prevData).getFullName()), ((ClassEntry) data).getFullName(), false); |
| 930 | this.controller.sendPacket(new RenameC2SPacket((ClassEntry) prevData, ((ClassEntry) data).getFullName(), false)); | ||
| 931 | } | ||
| 862 | } | 932 | } |
| 863 | 933 | ||
| 864 | public void moveClassTree(EntryReference<Entry<?>, Entry<?>> obfReference, String newName) { | 934 | public void moveClassTree(EntryReference<Entry<?>, Entry<?>> obfReference, String newName) { |
| @@ -920,4 +990,69 @@ public class Gui { | |||
| 920 | return searchDialog; | 990 | return searchDialog; |
| 921 | } | 991 | } |
| 922 | 992 | ||
| 993 | |||
| 994 | public MenuBar getMenuBar() { | ||
| 995 | return menuBar; | ||
| 996 | } | ||
| 997 | |||
| 998 | public void addMessage(Message message) { | ||
| 999 | JScrollBar verticalScrollBar = messageScrollPane.getVerticalScrollBar(); | ||
| 1000 | boolean isAtBottom = verticalScrollBar.getValue() >= verticalScrollBar.getMaximum() - verticalScrollBar.getModel().getExtent(); | ||
| 1001 | messageModel.addElement(message); | ||
| 1002 | if (isAtBottom) { | ||
| 1003 | SwingUtilities.invokeLater(() -> verticalScrollBar.setValue(verticalScrollBar.getMaximum() - verticalScrollBar.getModel().getExtent())); | ||
| 1004 | } | ||
| 1005 | statusLabel.setText(message.translate()); | ||
| 1006 | } | ||
| 1007 | |||
| 1008 | public void setUserList(List<String> users) { | ||
| 1009 | userModel.clear(); | ||
| 1010 | users.forEach(userModel::addElement); | ||
| 1011 | connectionStatusLabel.setText(String.format(I18n.translate("status.connected_user_count"), users.size())); | ||
| 1012 | } | ||
| 1013 | |||
| 1014 | private void sendMessage() { | ||
| 1015 | String text = chatBox.getText().trim(); | ||
| 1016 | if (!text.isEmpty()) { | ||
| 1017 | getController().sendPacket(new MessageC2SPacket(text)); | ||
| 1018 | } | ||
| 1019 | chatBox.setText(""); | ||
| 1020 | } | ||
| 1021 | |||
| 1022 | /** | ||
| 1023 | * Updates the state of the UI elements (button text, enabled state, ...) to reflect the current program state. | ||
| 1024 | * This is a central place to update the UI state to prevent multiple code paths from changing the same state, | ||
| 1025 | * causing inconsistencies. | ||
| 1026 | */ | ||
| 1027 | public void updateUiState() { | ||
| 1028 | menuBar.connectToServerMenu.setEnabled(isJarOpen && connectionState != ConnectionState.HOSTING); | ||
| 1029 | menuBar.connectToServerMenu.setText(I18n.translate(connectionState != ConnectionState.CONNECTED ? "menu.collab.connect" : "menu.collab.disconnect")); | ||
| 1030 | menuBar.startServerMenu.setEnabled(isJarOpen && connectionState != ConnectionState.CONNECTED); | ||
| 1031 | menuBar.startServerMenu.setText(I18n.translate(connectionState != ConnectionState.HOSTING ? "menu.collab.server.start" : "menu.collab.server.stop")); | ||
| 1032 | |||
| 1033 | menuBar.closeJarMenu.setEnabled(isJarOpen); | ||
| 1034 | menuBar.openMappingsMenus.forEach(item -> item.setEnabled(isJarOpen)); | ||
| 1035 | menuBar.saveMappingsMenu.setEnabled(isJarOpen && enigmaMappingsFileChooser.getSelectedFile() != null && connectionState != ConnectionState.CONNECTED); | ||
| 1036 | menuBar.saveMappingsMenus.forEach(item -> item.setEnabled(isJarOpen)); | ||
| 1037 | menuBar.closeMappingsMenu.setEnabled(isJarOpen); | ||
| 1038 | menuBar.exportSourceMenu.setEnabled(isJarOpen); | ||
| 1039 | menuBar.exportJarMenu.setEnabled(isJarOpen); | ||
| 1040 | |||
| 1041 | connectionStatusLabel.setText(I18n.translate(connectionState == ConnectionState.NOT_CONNECTED ? "status.disconnected" : "status.connected")); | ||
| 1042 | |||
| 1043 | if (connectionState == ConnectionState.NOT_CONNECTED) { | ||
| 1044 | logSplit.setLeftComponent(null); | ||
| 1045 | splitRight.setRightComponent(tabs); | ||
| 1046 | } else { | ||
| 1047 | splitRight.setRightComponent(logSplit); | ||
| 1048 | logSplit.setLeftComponent(tabs); | ||
| 1049 | } | ||
| 1050 | } | ||
| 1051 | |||
| 1052 | public void setConnectionState(ConnectionState state) { | ||
| 1053 | connectionState = state; | ||
| 1054 | statusLabel.setText(I18n.translate("status.ready")); | ||
| 1055 | updateUiState(); | ||
| 1056 | } | ||
| 1057 | |||
| 923 | } | 1058 | } |