package amidst.gui.menu; import MoF.*; import amidst.Options; import amidst.Util; import amidst.gui.LicenseWindow; import amidst.logging.Log; import amidst.map.MapObjectPlayer; import amidst.map.layers.StrongholdLayer; import amidst.minecraft.MinecraftUtil; import amidst.preferences.BiomeColorProfile; import amidst.preferences.SelectPrefModel.SelectButtonModel; import amidst.resources.ResourceLoader; import javax.swing.*; import javax.swing.event.AncestorEvent; import javax.swing.event.AncestorListener; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import java.awt.*; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.ClipboardOwner; import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.Transferable; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.image.BufferedImage; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Random; /** Structured menubar-creation to alleviate the huge mess that it would be elsewise */ // TODO: This class is a mess-- it should be split into pieces. public class AmidstMenu extends JMenuBar { final JMenu fileMenu; //final JMenu scriptMenu; public final JMenu mapMenu; //TODO: protected final JMenu optionsMenu; final JMenu helpMenu; private final FinderWindow window; public AmidstMenu(FinderWindow window) { this.window = window; fileMenu = add(new FileMenu()); mapMenu = add(new MapMenu()); optionsMenu = add(new OptionsMenu()); helpMenu = add(new HelpMenu()); } private class FileMenu extends JMenu { private FileMenu() { super("File"); setMnemonic(KeyEvent.VK_F); add(new JMenu("New") {{ setMnemonic(KeyEvent.VK_N); add(new SeedMenuItem()); add(new FileMenuItem()); add(new RandomSeedMenuItem()); //add(new JMenuItem("From Server")); }}); add(new JMenuItem("Save player locations") {{ setEnabled(MinecraftUtil.getVersion().saveEnabled()); setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK)); addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { if (window.curProject.saveLoaded) { for (MapObjectPlayer player : window.curProject.save.getPlayers()) { if (player.needSave) { window.curProject.save.movePlayer(player.getName(), player.globalX, player.globalY); player.needSave = false; } } } } }); }}); add(new JMenuItem("Exit") {{ addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.exit(0); } }); }}); } private String showSeedPrompt(String title) { final String blankText = "A random seed will be generated if left blank."; final String leadingSpaceText = "Warning: There is a space at the start!"; final String trailingSpaceText = "Warning: There is a space at the end!"; final JTextField inputText = new JTextField(); inputText.addAncestorListener( new AncestorListener() { @Override public void ancestorAdded(AncestorEvent arg0) { inputText.requestFocus(); } @Override public void ancestorMoved(AncestorEvent arg0) { inputText.requestFocus(); } @Override public void ancestorRemoved(AncestorEvent arg0) { inputText.requestFocus(); } }); final JLabel inputInformation = new JLabel(blankText); inputInformation.setForeground(Color.red); inputInformation.setFont(new Font("arial", Font.BOLD, 10)); inputText.getDocument().addDocumentListener(new DocumentListener() { @Override public void changedUpdate(DocumentEvent e) { update(); } @Override public void insertUpdate(DocumentEvent e) { update(); } @Override public void removeUpdate(DocumentEvent e) { update(); } public void update() { String text = inputText.getText(); if (text.equals("")) { inputInformation.setText(blankText); inputInformation.setForeground(Color.red); } else if (text.startsWith(" ")) { inputInformation.setText(leadingSpaceText); inputInformation.setForeground(Color.red); } else if (text.endsWith(" ")) { inputInformation.setText(trailingSpaceText); inputInformation.setForeground(Color.red); } else { try { Long.parseLong(text); inputInformation.setText("Seed is valid."); inputInformation.setForeground(Color.gray); } catch (NumberFormatException e) { inputInformation.setText("This seed's value is " + text.hashCode() + "."); inputInformation.setForeground(Color.black); } } } }); final JComponent[] inputs = new JComponent[] { new JLabel("Enter your seed: "), inputInformation, inputText }; int result = JOptionPane.showConfirmDialog(window, inputs, title, JOptionPane.OK_CANCEL_OPTION); return (result == 0)?inputText.getText():null; } private class SeedMenuItem extends JMenuItem { private SeedMenuItem() { super("From seed"); setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, InputEvent.CTRL_DOWN_MASK)); addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { String seed = showSeedPrompt("New Project"); if (seed != null) { String worldTypePreference = Options.instance.worldType.get(); SaveLoader.Type worldType = null; if (worldTypePreference.equals("Prompt each time")) { worldType = choose("New Project", "Enter world type\n", SaveLoader.selectableTypes); } else { worldType = SaveLoader.Type.fromMixedCase(worldTypePreference); } if (seed.equals("")) seed = "" + (new Random()).nextLong(); if (worldType != null) { window.clearProject(); window.setProject(new Project(seed, worldType.getValue())); } } } }); } } private class RandomSeedMenuItem extends JMenuItem { private RandomSeedMenuItem() { super("From random seed"); setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.CTRL_DOWN_MASK)); addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { //Create the JOptionPane. Random random = new Random(); long seed = random.nextLong(); String worldTypePreference = Options.instance.worldType.get(); SaveLoader.Type worldType = null; if (worldTypePreference.equals("Prompt each time")) { worldType = choose("New Project", "Enter world type\n", SaveLoader.selectableTypes); } else { worldType = SaveLoader.Type.fromMixedCase(worldTypePreference); } //If a string was returned, say so. if (worldType != null) { window.clearProject(); window.setProject(new Project(seed, worldType.getValue())); } } }); } } private class FileMenuItem extends JMenuItem { private FileMenuItem() { super("From file or folder"); addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { JFileChooser fc = new JFileChooser(); fc.setFileFilter(SaveLoader.getFilter()); fc.setAcceptAllFileFilterUsed(false); fc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); File savesDir = null; if (Util.profileDirectory != null) savesDir = new File(Util.profileDirectory, "saves"); else savesDir = new File(Util.minecraftDirectory, "saves"); //if (!savesDir.mkdirs()) { // Log.w("Unable to create save directory!"); // return; //} fc.setCurrentDirectory(savesDir); fc.setFileHidingEnabled(false); if (fc.showOpenDialog(window) == JFileChooser.APPROVE_OPTION) { File f = fc.getSelectedFile(); SaveLoader s = null; if (f.isDirectory()) s = new SaveLoader(new File(f.getAbsoluteFile() + "/level.dat")); else s = new SaveLoader(f); window.clearProject(); window.setProject(new Project(s)); } } }); } } } public class DisplayingCheckbox extends JCheckBoxMenuItem { private DisplayingCheckbox(String text, BufferedImage icon, int key, JToggleButton.ToggleButtonModel model) { super(text, (icon != null) ? new ImageIcon(icon) : null); if (key != -1) setAccelerator(KeyStroke.getKeyStroke(key, InputEvent.CTRL_DOWN_MASK)); setModel(model); } } private class MapMenu extends JMenu { private MapMenu() { super("Map"); setEnabled(false); setMnemonic(KeyEvent.VK_M); add(new FindMenu()); add(new GoToMenu()); add(new LayersMenu()); add(new CopySeedMenuItem()); add(new CaptureMenuItem()); } private class FindMenu extends JMenu { private FindMenu() { super("Find"); //add(new JMenuItem("Biome")); //add(new JMenuItem("Village")); add(new JMenuItem("Stronghold") {{ setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.CTRL_DOWN_MASK)); addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { goToChosenPoint(StrongholdLayer.instance.getStrongholds(), "Stronghold"); } }); }}); } } private class GoToMenu extends JMenu { private GoToMenu() { super("Go to"); add(new JMenuItem("Coordinate") {{ setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_G, InputEvent.CTRL_DOWN_MASK));addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { String s = JOptionPane.showInputDialog(null, "Enter coordinates: (Ex. 123,456)", "Go To", JOptionPane.QUESTION_MESSAGE); if (s != null) { String[] c = s.replaceAll(" ", "").split(","); try { long x = Long.parseLong(c[0]); long y = Long.parseLong(c[1]); window.curProject.moveMapTo(x, y); } catch (NumberFormatException e1) { Log.w("Invalid location entered, ignoring."); e1.printStackTrace(); } } } }); }}); add(new JMenuItem("Player") {{ addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { if (window.curProject.saveLoaded) { List<MapObjectPlayer> playerList = window.curProject.save.getPlayers(); MapObjectPlayer[] players = playerList.toArray(new MapObjectPlayer[playerList.size()]); goToChosenPoint(players, "Player"); MapObjectPlayer p = choose("Go to", "Select player:", players); if (p != null) window.curProject.moveMapTo(p.globalX, p.globalY); } } }); }}); //add(new JMenuItem("Spawn")); //add(new JMenuItem("Chunk")); } } private class LayersMenu extends JMenu { private LayersMenu() { super("Layers"); add(new DisplayingCheckbox("Grid", ResourceLoader.getImage("grid.png"), KeyEvent.VK_1, Options.instance.showGrid)); add(new DisplayingCheckbox("Slime chunks", ResourceLoader.getImage("slime.png"), KeyEvent.VK_2, Options.instance.showSlimeChunks)); add(new DisplayingCheckbox("Village Icons", ResourceLoader.getImage("village.png"), KeyEvent.VK_3, Options.instance.showVillages)); add(new DisplayingCheckbox("Ocean Monument Icons", ResourceLoader.getImage("ocean_monument.png"), KeyEvent.VK_4, Options.instance.showOceanMonuments)); add(new DisplayingCheckbox("Temple/Witch Hut Icons", ResourceLoader.getImage("desert.png"), KeyEvent.VK_5, Options.instance.showTemples)); add(new DisplayingCheckbox("Stronghold Icons", ResourceLoader.getImage("stronghold.png"), KeyEvent.VK_6, Options.instance.showStrongholds)); add(new DisplayingCheckbox("Player Icons", ResourceLoader.getImage("player.png"), KeyEvent.VK_7, Options.instance.showPlayers)); add(new DisplayingCheckbox("Nether Fortress Icons", ResourceLoader.getImage("nether_fortress.png"), KeyEvent.VK_8, Options.instance.showNetherFortresses)); add(new DisplayingCheckbox("Spawn Location Icon", ResourceLoader.getImage("spawn.png"), KeyEvent.VK_9, Options.instance.showSpawn)); } } private class CaptureMenuItem extends JMenuItem { private CaptureMenuItem() { super("Capture"); setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_T, InputEvent.CTRL_DOWN_MASK)); addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { JFileChooser fc = new JFileChooser(); fc.setFileFilter(new PNGFileFilter()); fc.setAcceptAllFileFilterUsed(false); int returnVal = fc.showSaveDialog(window); if (returnVal == JFileChooser.APPROVE_OPTION) { String s = fc.getSelectedFile().toString(); if (!s.toLowerCase().endsWith(".png")) s += ".png"; window.curProject.map.saveToFile(new File(s)); } } }); } } private class CopySeedMenuItem extends JMenuItem { private CopySeedMenuItem() { super("Copy Seed to Clipboard"); setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_DOWN_MASK)); addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { StringSelection stringSelection = new StringSelection(Options.instance.seed + ""); Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); clipboard.setContents(stringSelection, new ClipboardOwner() { @Override public void lostOwnership(Clipboard arg0, Transferable arg1) { // TODO Auto-generated method stub } }); } }); } } } private class OptionsMenu extends JMenu { private OptionsMenu() { super("Options"); add(new MapOptionsMenu()); if (BiomeColorProfile.isEnabled) add(new BiomeColorMenu()); add(new WorldTypeMenu()); setMnemonic(KeyEvent.VK_M); } private class BiomeColorMenu extends JMenu { private ArrayList<JCheckBoxMenuItem> profileCheckboxes = new ArrayList<JCheckBoxMenuItem>(); private JMenuItem reloadMenuItem; private class BiomeProfileActionListener implements ActionListener { private BiomeColorProfile profile; private ArrayList<JCheckBoxMenuItem> profileCheckboxes; private JCheckBoxMenuItem checkBox; public BiomeProfileActionListener(BiomeColorProfile profile, JCheckBoxMenuItem checkBox, ArrayList<JCheckBoxMenuItem> profileCheckboxes) { this.profile = profile; this.checkBox = checkBox; this.profileCheckboxes = profileCheckboxes; } @Override public void actionPerformed(ActionEvent e) { for (int i = 0; i < profileCheckboxes.size(); i++) profileCheckboxes.get(i).setSelected(false); checkBox.setSelected(true); profile.activate(); } } private BiomeColorMenu() { super("Biome profile"); reloadMenuItem = new JMenuItem("Reload Menu"); final BiomeColorMenu biomeColorMenu = this; reloadMenuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg) { profileCheckboxes.clear(); Log.i("Reloading additional biome color profiles."); File colorProfileFolder = new File("./biome"); biomeColorMenu.removeAll(); scanAndLoad(colorProfileFolder, biomeColorMenu); biomeColorMenu.add(reloadMenuItem); } }); reloadMenuItem.setAccelerator(KeyStroke.getKeyStroke("ctrl B")); Log.i("Checking for additional biome color profiles."); File colorProfileFolder = new File("./biome"); scanAndLoad(colorProfileFolder, this); profileCheckboxes.get(0).setSelected(true); add(reloadMenuItem); } private boolean scanAndLoad(File folder, JMenu menu) { File[] files = folder.listFiles(); BiomeColorProfile profile; boolean foundProfiles = false; for (int i = 0; i < files.length; i++) { if (files[i].isFile()) { if ((profile = BiomeColorProfile.createFromFile(files[i])) != null) { JCheckBoxMenuItem menuItem = new JCheckBoxMenuItem(profile.name); menuItem.addActionListener(new BiomeProfileActionListener(profile, menuItem, profileCheckboxes)); if (profile.shortcut != null) { KeyStroke accelerator = KeyStroke.getKeyStroke(profile.shortcut); if (accelerator != null) menuItem.setAccelerator(accelerator); else Log.i("Unable to create keyboard shortcut from: " + profile.shortcut); } menu.add(menuItem); profileCheckboxes.add(menuItem); foundProfiles = true; } } else { JMenu subMenu = new JMenu(files[i].getName()); if (scanAndLoad(files[i], subMenu)) { menu.add(subMenu); } } } return foundProfiles; } } private class MapOptionsMenu extends JMenu { private MapOptionsMenu() { super("Map"); add(new DisplayingCheckbox("Map Flicking (Smooth Scrolling)", null, KeyEvent.VK_I, Options.instance.mapFlicking)); add(new DisplayingCheckbox("Restrict Maximum Zoom", null, KeyEvent.VK_Z, Options.instance.maxZoom)); add(new DisplayingCheckbox("Show Framerate", null, KeyEvent.VK_L, Options.instance.showFPS)); add(new DisplayingCheckbox("Show Scale", null, KeyEvent.VK_K, Options.instance.showScale)); add(new DisplayingCheckbox("Use Fragment Fading", null, -1, Options.instance.mapFading)); add(new DisplayingCheckbox("Show Debug Info", null, -1, Options.instance.showDebug)); } } private class WorldTypeMenu extends JMenu { private WorldTypeMenu() { super("World type"); SelectButtonModel[] buttonModels = Options.instance.worldType.getButtonModels(); for (int i = 0; i < buttonModels.length; i++) { add(new DisplayingCheckbox(buttonModels[i].getName(), null, -1, buttonModels[i])); } } } } private class HelpMenu extends JMenu { private HelpMenu() { super("Help"); add(new JMenuItem("Check for updates") {{ addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { new UpdateManager(window).start(); } }); }}); add(new JMenuItem("View licenses") {{ addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { new LicenseWindow(); } }); }}); add(new JMenuItem("About") {{ addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { JOptionPane.showMessageDialog(window, "Advanced Minecraft Interfacing and Data/Structure Tracking (AMIDST)\n" + "By Skidoodle ([email protected])"); } }); }}); } } /** Allows the user to choose one of several things. * * Convenience wrapper around JOptionPane.showInputDialog */ private <T> T choose(String title, String message, T[] choices) { return (T) JOptionPane.showInputDialog( window, message, title, JOptionPane.PLAIN_MESSAGE, null, choices, choices[0]); } /** Lets the user decide one of the given points and go to it * @param points Given points to choose from * @param name name displayed in the choice */ private <T extends Point> void goToChosenPoint(T[] points, String name) { T p = choose("Go to", "Select " + name + ":", points); if (p != null) window.curProject.moveMapTo(p.x, p.y); } }