From af43eb7a98c0c2dc017b37bba72721c46ecc4afe Mon Sep 17 00:00:00 2001 From: Modmuss50 Date: Tue, 19 Feb 2019 19:00:31 +0000 Subject: Added Basic Search (#102) * 3am code for a basic search box, needs some cleanup * Cleanup the code a bit * Add missing header * Fix indentation, + unneeded check --- build.gradle | 1 + src/main/java/cuchaz/enigma/gui/Gui.java | 4 + .../cuchaz/enigma/gui/dialog/SearchDialog.java | 158 +++++++++++++++++++++ .../java/cuchaz/enigma/gui/elements/MenuBar.java | 7 + 4 files changed, 170 insertions(+) create mode 100644 src/main/java/cuchaz/enigma/gui/dialog/SearchDialog.java diff --git a/build.gradle b/build.gradle index 91419cd..5f7ae2d 100644 --- a/build.gradle +++ b/build.gradle @@ -97,6 +97,7 @@ dependencies { application name: "darcula", version: "1.0.0" application 'de.sciss:syntaxpane:1.2.+' + application 'me.xdrop:fuzzywuzzy:1.2.0' testCompile 'junit:junit:4.+' testCompile 'org.hamcrest:hamcrest-all:1.+' diff --git a/src/main/java/cuchaz/enigma/gui/Gui.java b/src/main/java/cuchaz/enigma/gui/Gui.java index 3593e4f..c419aae 100644 --- a/src/main/java/cuchaz/enigma/gui/Gui.java +++ b/src/main/java/cuchaz/enigma/gui/Gui.java @@ -839,4 +839,8 @@ public class Gui { this.deobfPanel.deobfClasses.restoreExpansionState(this.deobfPanel.deobfClasses, stateDeobf); this.obfPanel.obfClasses.restoreExpansionState(this.obfPanel.obfClasses, stateObf); } + + public PanelDeobf getDeobfPanel() { + return deobfPanel; + } } diff --git a/src/main/java/cuchaz/enigma/gui/dialog/SearchDialog.java b/src/main/java/cuchaz/enigma/gui/dialog/SearchDialog.java new file mode 100644 index 0000000..da09c52 --- /dev/null +++ b/src/main/java/cuchaz/enigma/gui/dialog/SearchDialog.java @@ -0,0 +1,158 @@ +/******************************************************************************* + * Copyright (c) 2015 Jeff Martin. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Lesser General Public + * License v3.0 which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/lgpl.html + *

+ * Contributors: + * Jeff Martin - initial API and implementation + ******************************************************************************/ + +package cuchaz.enigma.gui.dialog; + +import com.google.common.collect.Lists; +import cuchaz.enigma.gui.Gui; +import cuchaz.enigma.translation.representation.entry.ClassEntry; +import me.xdrop.fuzzywuzzy.FuzzySearch; +import me.xdrop.fuzzywuzzy.model.ExtractedResult; + +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import java.awt.*; +import java.awt.event.*; +import java.util.List; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +public class SearchDialog { + + private JTextField searchField; + private JList classList; + private JFrame frame; + + private Gui parent; + private List deobfClasses; + + private KeyEventDispatcher keyEventDispatcher; + + public SearchDialog(Gui parent) { + this.parent = parent; + + deobfClasses = Lists.newArrayList(); + this.parent.getController().getDeobfuscator().getSeparatedClasses(Lists.newArrayList(), deobfClasses); + deobfClasses.removeIf(ClassEntry::isInnerClass); + } + + public void show() { + frame = new JFrame("Search"); + frame.setVisible(false); + JPanel pane = new JPanel(); + pane.setBorder(new EmptyBorder(5, 10, 5, 10)); + + addRow(pane, jPanel -> { + searchField = new JTextField("", 20); + + searchField.addKeyListener(new KeyAdapter() { + @Override + public void keyTyped(KeyEvent keyEvent) { + updateList(); + } + }); + + jPanel.add(searchField); + }); + + addRow(pane, jPanel -> { + classList = new JList<>(); + classList.setLayoutOrientation(JList.VERTICAL); + classList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + + classList.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent mouseEvent) { + if(mouseEvent.getClickCount() >= 2){ + openSelected(); + } + } + }); + jPanel.add(classList); + }); + + + keyEventDispatcher = keyEvent -> { + if(!frame.isVisible()){ + return false; + } + if(keyEvent.getKeyCode() == KeyEvent.VK_DOWN){ + int next = classList.isSelectionEmpty() ? 0 : classList.getSelectedIndex() + 1; + classList.setSelectedIndex(next); + } + if(keyEvent.getKeyCode() == KeyEvent.VK_UP){ + int next = classList.isSelectionEmpty() ? classList.getModel().getSize() : classList.getSelectedIndex() - 1; + classList.setSelectedIndex(next); + } + if(keyEvent.getKeyCode() == KeyEvent.VK_ENTER){ + openSelected(); + } + if(keyEvent.getKeyCode() == KeyEvent.VK_ESCAPE){ + close(); + } + return false; + }; + + KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(keyEventDispatcher); + + frame.setContentPane(pane); + frame.setLayout(new BoxLayout(pane, BoxLayout.Y_AXIS)); + + frame.setSize(360, 500); + frame.setAlwaysOnTop(true); + frame.setResizable(false); + frame.setLocationRelativeTo(parent.getFrame()); + frame.setVisible(true); + frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + + searchField.requestFocusInWindow(); + } + + private void openSelected(){ + close(); + if(classList.isSelectionEmpty()){ + return; + } + deobfClasses.stream() + .filter(classEntry -> classEntry.getSimpleName().equals(classList.getSelectedValue())). + findFirst() + .ifPresent(classEntry -> { + parent.navigateTo(classEntry); + parent.getDeobfPanel().deobfClasses.setSelectionClass(classEntry); + }); + } + + private void close(){ + frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING)); + KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventDispatcher(keyEventDispatcher); + } + + private void addRow(JPanel pane, Consumer consumer) { + JPanel panel = new JPanel(new FlowLayout()); + consumer.accept(panel); + pane.add(panel, BorderLayout.CENTER); + } + + //Updates the list of class names + private void updateList() { + DefaultListModel listModel = new DefaultListModel<>(); + + //Basic search using the Fuzzy libary + //TODO improve on this, to not just work from string and to keep the ClassEntry + List results = FuzzySearch.extractTop(searchField.getText(), deobfClasses.stream().map(ClassEntry::getSimpleName).collect(Collectors.toList()), 25); + results.forEach(extractedResult -> listModel.addElement(extractedResult.getString())); + + classList.setModel(listModel); + } + + + +} diff --git a/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java b/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java index dfbfa65..14ad53d 100644 --- a/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java +++ b/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java @@ -4,6 +4,7 @@ import cuchaz.enigma.config.Config; import cuchaz.enigma.config.Themes; import cuchaz.enigma.gui.Gui; import cuchaz.enigma.gui.dialog.AboutDialog; +import cuchaz.enigma.gui.dialog.SearchDialog; import cuchaz.enigma.throwables.MappingParseException; import cuchaz.enigma.translation.mapping.serde.MappingFormat; @@ -205,6 +206,12 @@ public class MenuBar extends JMenuBar { themes.add(theme); theme.addActionListener(event -> Themes.setLookAndFeel(gui, lookAndFeel)); } + + JMenuItem search = new JMenuItem("Search"); + search.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, InputEvent.SHIFT_MASK)); + menu.add(search); + search.addActionListener(event -> new SearchDialog(this.gui).show()); + } } { -- cgit v1.2.3