Java tutorial
/* * DoomManager * Copyright (C) 2014 Chris K * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package ca.wumbo.doommanager.client.controller; import java.io.File; import java.io.FileNotFoundException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; import javax.annotation.PostConstruct; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import ca.wumbo.doommanager.client.controller.file.ConnectWizardController; import ca.wumbo.doommanager.client.controller.file.DXMLProjectCreatorController; import ca.wumbo.doommanager.client.controller.file.TaskManagerController; import ca.wumbo.doommanager.client.file.ClientDoomFileManagerTab; import ca.wumbo.doommanager.client.util.Controllable; import ca.wumbo.doommanager.client.util.Resources; import ca.wumbo.doommanager.client.util.SelfInjectableController; import ca.wumbo.doommanager.file.dxml.DXML; import ca.wumbo.doommanager.file.dxml.DXMLCreationStatus; import ca.wumbo.doommanager.file.dxml.DXMLException; import ca.wumbo.doommanager.file.entry.designator.PK3EntryDesignator; import ca.wumbo.doommanager.file.entry.designator.WadEntryDesignator; import ca.wumbo.doommanager.file.entry.types.PK3Entry; import ca.wumbo.doommanager.file.entry.types.WadEntry; import ca.wumbo.doommanager.util.SpringContainer; import ca.wumbo.doommanager.util.Tickable; import javafx.fxml.FXML; import javafx.scene.Node; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Menu; import javafx.scene.control.MenuBar; import javafx.scene.control.MenuItem; import javafx.scene.control.TabPane; import javafx.scene.control.TabPane.TabClosingPolicy; import javafx.scene.control.ToolBar; import javafx.scene.image.ImageView; import javafx.scene.layout.BorderPane; import javafx.scene.layout.Pane; import javafx.scene.layout.VBox; import javafx.stage.FileChooser; import javafx.stage.Modality; import javafx.stage.Stage; /** * The controller for the file editor, which is responsible for editing files * and creating/saving/modifying Wads, PK's... etc. */ public class FileEditorController extends SelfInjectableController implements Controllable, Tickable { /** * The logger for this class. */ private static final Logger log = LogManager.getLogger(FileEditorController.class); @Autowired private CoreController coreController; @Autowired private TaskManagerController taskManagerController; @Autowired private Resources resources; @Value("${fileeditor.controller.fxmlpath}") private String fxmlPath; @Value("${css.default.path}") private String cssPath; //========================================================================= @FXML private BorderPane rootBorderPane; @FXML private VBox topVBox; @FXML private MenuBar menuBar; @FXML private Menu mainMenu; @FXML private Menu fileMenu; @FXML private Menu newMenu; @FXML private MenuItem newDXMLProjectMenuItem; @FXML private MenuItem newPK3MenuItem; @FXML private MenuItem newWadMenuItem; @FXML private MenuItem openFileMenuItem; @FXML private MenuItem connectFileMenuItem; @FXML private MenuItem exitMenuItem; @FXML private ToolBar toolbar; @FXML private Button newWadButton; @FXML private Button openFileButton; @FXML private Button connectButton; @FXML private Button taskManagerButton; @FXML private TabPane fileTabPane; //========================================================================= /** * Only to be instantiated by Spring. */ private FileEditorController() { } @FXML private void initialize() { // We only want the user to close the selected tab, not accidentally other tabs. fileTabPane.setTabClosingPolicy(TabClosingPolicy.SELECTED_TAB); // TODO - this should be configurable though as a user option. // We'll remove the text since its not needed (only useful in the SceneBuilder). for (Node node : toolbar.getItems()) { if (node instanceof Button) { Button button = (Button) node; button.setText(""); } } // Set menu item graphics. newMenu.setGraphic(new ImageView(resources.getImage("newfile"))); newWadMenuItem.setGraphic(new ImageView(resources.getImage("wadentry"))); newPK3MenuItem.setGraphic(new ImageView(resources.getImage("pk3entry"))); newDXMLProjectMenuItem.setGraphic(new ImageView(resources.getImage("dxmlprojectentry"))); openFileMenuItem.setGraphic(new ImageView(resources.getImage("folder"))); connectFileMenuItem.setGraphic(new ImageView(resources.getImage("network"))); exitMenuItem.setGraphic(new ImageView(resources.getImage("close"))); // Set button graphics. newWadButton.setGraphic(new ImageView(resources.getImage("newfile"))); openFileButton.setGraphic(new ImageView(resources.getImage("folder"))); connectButton.setGraphic(new ImageView(resources.getImage("network"))); taskManagerButton.setGraphic(new ImageView(resources.getImage("taskmanager"))); } /** * Loads the FXML data and injects it into this object. Should be called by * Spring right after the constructor and dependencies are linked. To * reduce code duplication, this functionality was moved to a containing * class. * * @throws NullPointerException * If the FXML path is null. * * @throws RuntimeException * If the FXML file is missing or corrupt. */ @PostConstruct public void loadFXML() { super.loadFXML(fxmlPath); } /** * Creates a new DXML project and has the user set it up, then places it in * the tab. */ public void newDXMLProject() { // Create the wizard and wait for the result. DXMLProjectCreatorController controller = SpringContainer.getContext() .getBean(DXMLProjectCreatorController.class); Scene scene = new Scene(controller.getRootPane()); scene.getStylesheets().add(cssPath); Stage stage = new Stage(); stage.setTitle("DXML Project Setup Wizard"); stage.setResizable(false); stage.initModality(Modality.WINDOW_MODAL); stage.initOwner(coreController.getStage()); stage.setScene(scene); controller.setStage(stage); // Required for it to be able to close properly. controller.setParentStage(coreController.getStage()); // Required as well to block input if browsing for files. stage.showAndWait(); // If the user finished the work, get the DXML file. if (!controller.wasClosedByUser()) { DXML dxmlData = controller.getDxmlData(); // The file must also be valid. This should not ever be false unless there is a coding error. if (dxmlData.isValidDXMLFile()) { // Create it on the disk. DXMLCreationStatus status = dxmlData.createOnDisk(); // If the status shows success, add it to the view. switch (status) { case SUCCESS: // Since it succeeded, open up the project now. String path = dxmlData.getProjectInfo().getProjectLocationPath() + File.separator; path += dxmlData.getCompilation().getFilename() + File.separator; path += dxmlData.getCompilation().getFilename() + ".dxml"; // TODO - support any case extension. openDXMLProject(Paths.get(path)); break; case ALREADY_EXISTS: log.warn("DXML project already exists at the specified location. Aborting."); break; case FOLDER_CREATION_FAILURE: log.warn("Unable to create directory for the project. Are your permissions correct? Aborting."); break; case DXML_FILE_EXISTS: log.warn("DXML file already exists at location, aborting to prevent potential overwrite."); break; case DXML_FILE_CREATION_FAILURE: log.warn("Unable to create DXML file at location, are your permissions correct? Aborting."); break; case XML_MARSHALL_ERROR: log.warn("Unable to create the .dxml file. Are your file permissions correct? Aborting."); break; case FAILED: log.warn("Unable to create the necessary DXML file/folder resources at the provided location."); break; case INVALID_DXML_DATA: case BAD_PROJECT_PATH: log.warn("DXML project has corrupt data. Contact a developer, Aborting [Reason: {}].", status.name()); break; default: throw new DXMLException( "DXML status for disk creation returned an unexpected enumeration. Contact a developer."); } } else { throw new DXMLException( "DXML Wizard has not properly generated a proper file. Please contact a developer."); } } else { log.info("DXML project cancelled by user."); } } /** * Creates a new PK3 and places it in the tab. */ public void newPK3() { log.info("Creating new empty PK3."); PK3Entry pk3Entry = new PK3Entry("NEWFILE.pk3"); ClientDoomFileManagerTab doomFileTab = new ClientDoomFileManagerTab(pk3Entry); fileTabPane.getTabs().add(doomFileTab); } /** * Creates a new wad and places it in the tab. */ public void newWad() { log.info("Creating new empty Wad."); WadEntry wadEntry = new WadEntry("NEWFILE.wad", false); ClientDoomFileManagerTab doomFileTab = new ClientDoomFileManagerTab(wadEntry); fileTabPane.getTabs().add(doomFileTab); } /** * Requests the user to select a file to open. */ public void openFile() { log.debug("Attempting to open file..."); // Provide a file chooser that looks for extensions we know. FileChooser fileChooser = new FileChooser(); fileChooser.setTitle("Open file"); fileChooser.getExtensionFilters().addAll( new FileChooser.ExtensionFilter("Any Doom File", "*.wad", "*.WAD", "*.pk3", "*.PK3", "*.dxml", "*.DXML"), new FileChooser.ExtensionFilter("DoomManager Project Files", "*.dxml", "*.DXML"), new FileChooser.ExtensionFilter("Wad Files", "*.wad", "*.WAD"), new FileChooser.ExtensionFilter("PK3 Files", "*.pk3", "*.PK3"), new FileChooser.ExtensionFilter("All files", "*.*")); List<File> files = fileChooser.showOpenMultipleDialog(coreController.getStage()); // If the user selected one or more files... if (files != null) { // For each file the user selected... for (File file : files) { Path filePath = file.toPath(); String lowerPath = filePath.toString().toLowerCase(); log.debug("Attempting to load file from {}...", filePath.toString()); // Handle based on ending: if (lowerPath.endsWith(".wad")) { openWad(filePath); } else if (lowerPath.endsWith(".pk3")) { openPK3(filePath); } else if (lowerPath.endsWith(".dxml")) { openDXMLProject(filePath); } } } } /** * Attempts to open a wad at the file path. * * @param filePath * The file path to open the wad at. */ private void openWad(Path filePath) { assert filePath != null : "Passed a null file path to openWad."; try { taskManagerController.processEntryDesignation(new WadEntryDesignator(fileTabPane, filePath)); } catch (FileNotFoundException e) { log.warn("Could not find file at {}.", filePath.toString()); } } /** * Attempts to open a pk3 at the file path. * * @param filePath * The file path to open the pk3 at. */ private void openPK3(Path filePath) { assert filePath != null : "Passed a null file path to openPK3."; try { taskManagerController.processEntryDesignation(new PK3EntryDesignator(fileTabPane, filePath)); } catch (FileNotFoundException e) { log.warn("Could not find file at {}.", filePath.toString()); } } /** * Attempts to open a DXML project at the file path. * * @param filePath * The file path to open the project at. */ private void openDXMLProject(Path filePath) { // try { // DXML dxml = new DXML(filePath.toFile()); // // // Only continue on if it's a valid file (if it's corrupt, we might not know where to get data). // if (dxml.isValidDXMLFile()) { // // Create the source folder from the project. // Entry projectEntryTreeItem = Designator.designateDXML(filePath.toFile(), dxml); // // // Add it to the tabs. // DoomFileManagerTab doomFileTab = new DoomFileManagerTab(projectEntryTreeItem, filePath); // fileTabPane.getTabs().add(doomFileTab); // // log.info("Loaded DXML file from {}", filePath.toString()); // } else { // log.warn("DXML file (at {}) is corrupt. Please check the DXML GUI menu for corrupt elements.", filePath.toString()); // } // } catch (DXMLException e) { // log.warn("Unable to properly read DXML file at {}.", filePath.toString()); // log.debug(e); // } catch (IOException e) { // log.warn("Error reading files/folders in the source directory for the DXML file at {}.", filePath.toString()); // log.debug(e); // } } /** * Starts the GUI for connecting to a server for a shared project. */ public void openConnectGUI() { log.debug("Loading a new connect wizard."); ConnectWizardController connectWizard = SpringContainer.getContext().getBean(ConnectWizardController.class); log.trace("Creating the scene."); Scene scene = new Scene(connectWizard.getRootPane()); scene.getStylesheets().add(cssPath); log.trace("Creating stage to display window with the scene."); Stage stage = new Stage(); stage.setTitle("Remote Project Connection"); stage.setResizable(false); stage.initModality(Modality.NONE); stage.initOwner(coreController.getStage()); stage.setResizable(false); stage.setScene(scene); stage.show(); log.trace("Connect wizard displayed."); } /** * Displays the task manager window. */ public void showTaskManager() { taskManagerController.showWindow(); } /** * Called when the client selects the "close" option. */ public void requestExit() { coreController.exit(); } @Override public Pane getRootPane() { return rootBorderPane; } @Override public void tick() { // TODO } }