package nl.tudelft.bw4t.environmentstore.editor.menu.controller; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.util.ArrayList; import java.util.List; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JScrollPane; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import nl.tudelft.bw4t.environmentstore.editor.controller.MapPanelController; import nl.tudelft.bw4t.environmentstore.editor.controller.MapPreviewController; import nl.tudelft.bw4t.environmentstore.editor.controller.ZoneController; import nl.tudelft.bw4t.environmentstore.editor.menu.view.MenuBar; import nl.tudelft.bw4t.environmentstore.editor.model.MapConverter; import nl.tudelft.bw4t.environmentstore.editor.model.SolvabilityAlgorithm; import nl.tudelft.bw4t.environmentstore.main.controller.EnvironmentStoreController; import nl.tudelft.bw4t.environmentstore.main.view.EnvironmentStore; import nl.tudelft.bw4t.environmentstore.sizedialog.view.SizeDialog; import nl.tudelft.bw4t.map.BlockColor; import nl.tudelft.bw4t.map.NewMap; import nl.tudelft.bw4t.map.renderer.MapRenderer; public abstract class AbstractMenuOption implements ActionListener { /** the menu the option is on */ private MenuBar view; /** the environment controller */ private EnvironmentStoreController envController; /** the mappanel controller being used */ private MapPanelController mapController; // made a variable for this so we can call it during testing private JFileChooser currentFileChooser; /** * The constructor for AbstractMenuOption * @param newView the file menu * @param envController the controller of environmentstore */ public AbstractMenuOption(final MenuBar newView, final EnvironmentStoreController envController) { this.view = newView; this.envController = envController; this.mapController = envController.getMapController(); /* * Set the intial file chooser and option prompt, can eventually be * changed when tests need to be ran. */ setCurrentFileChooser(new JFileChooser()); } /** * Gets the current file chooser. * * @return The current file chooser. */ public JFileChooser getCurrentFileChooser() { return currentFileChooser; } /** * Sets the new current file chooser. * * @param newFileChooser * The new file chooser to set. */ public void setCurrentFileChooser(final JFileChooser newFileChooser) { currentFileChooser = newFileChooser; } /** * Opens a new size Dialog that lets the user start from scratch. */ public void newMap() { if (envController.notAnEmptyMap()) { boolean doSave = envController.promptUserToSave(); if (doSave) { saveFile(true); } } // Close Environmenst Store envController.getMainView().dispose(); // Open new Size Dialog SizeDialog dialog = new SizeDialog(); dialog.setVisible(true); } /** * Saves a file. */ public void saveFile() { saveFile(!view.hasLastFileLocation()); } /** * Saves the configuration to Map. When the configuration hasn't been saved * before an file chooser is opened. * * @param saveAs * Whether or not to open a file chooser. */ public void saveFile(final boolean saveAs) { String error = checkConsistency(); if (error != null) { EnvironmentStore.showDialog("Save failed: " + error); return; } NewMap map = MapConverter.createMap(mapController.getEnvironmentMap()); String mapSolve = SolvabilityAlgorithm.mapIsSolvable(map); if (mapSolve != null) { int response = JOptionPane .showConfirmDialog(null, "The map is unsolvable. The reason is as follows:\n" + mapSolve + "\n" + "Are you sure you want to save this map?", "Unsolvable map", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); if (response == JOptionPane.NO_OPTION) { return; } } String path = view.getLastFileLocation(); if (view.hasLastFileLocation() && !new File(path).exists()) { view.setLastFileLocation(null); currentFileChooser.setCurrentDirectory(new File(".")); } if (saveAs || !view.hasLastFileLocation()) { currentFileChooser = getCurrentFileChooser(); currentFileChooser.setFileFilter(FileFilters.mapFilter()); int returnVal = currentFileChooser.showSaveDialog(null); if (returnVal == JFileChooser.APPROVE_OPTION) { File file = currentFileChooser.getSelectedFile(); path = file.getAbsolutePath(); String extension = ".map"; if (!path.endsWith(extension)) { path += extension; file = new File(path); } envController.getMainView().setWindowTitle(file.getName()); } else { return; } } try { // Check if the file path was not externally deleted. saveMapFile(path); } catch (JAXBException e) { EnvironmentStore.showDialog("Saving the Map to file has failed."); } catch (FileNotFoundException e) { EnvironmentStore.showDialog("No file has been found."); } } /** * Saves the map to that location * @param path the location where it should be saved * @throws JAXBException * @throws FileNotFoundException */ public void saveMapFile(String path) throws JAXBException, FileNotFoundException { NewMap map = MapConverter.createMap(envController.getMapController().getEnvironmentMap()); NewMap.toXML(map, new FileOutputStream(new File(path))); view.setLastFileLocation(path); } /** * Preview the map that is currently being edited. */ public void previewMap() { JFrame preview = new JFrame("Map Preview"); preview.add(new JScrollPane(new MapRenderer(new MapPreviewController(mapController)))); preview.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); preview.pack(); preview.setVisible(true); } /** * Exit the editor with a check whether the user really wants to quit. */ public void exitEditor() { if (envController.notAnEmptyMap()) { boolean doSave = envController.promptUserToSave(); if (doSave) { saveFile(true); } else { envController.getMainView().closeEnvironmentStore(); } } else { envController.getMainView().closeEnvironmentStore(); } } /** * check consistency of the map. The sequence length must be 1 at least. returns string with error message, or null * if all ok * * @return null, or string with error message. */ public String checkConsistency() { boolean foundDropZone = false; boolean foundStartZone = false; // check if all blocks for sequence are there. // first accumulate all blocks from all rooms List<BlockColor> allblocks = new ArrayList<BlockColor>(); for (int i = 0; i < mapController.getZoneControllers().length; i++) { for (int j = 0; j < mapController.getZoneControllers()[0].length; j++) { ZoneController zone = mapController.getZoneController(i, j); allblocks.addAll(zone.getColors()); if (zone.isDropZone()) { if (foundDropZone) { return ("Map can only contain one drop zone."); } foundDropZone = true; } if (zone.isStartZone()) { foundStartZone = true; } } } if (!foundStartZone && !foundDropZone) { return ("The map must contain one starting zone and drop zone."); } else if (!foundStartZone) { return ("There should be at least one start zone."); } else if (!foundDropZone) { return ("There should be one drop zone."); } if (mapController.getSequence().size() <= 0) { return ("Sequence must contain at least one block color."); } // remove all colors from the sequence. That will throw exception if // impossible. try { allblocks.removeAll(mapController.getSequence()); } catch (IllegalArgumentException e) { return e.getMessage(); } return null; } public MapPanelController getMapController() { return mapController; } public EnvironmentStoreController getEnvironmentStoreController() { return envController; } public MenuBar getView() { return view; } /** * Gets called when the button associated with this action is pressed. * * @param e * The action event. */ public abstract void actionPerformed(ActionEvent e); }