GUIView.java

// Package name
package views;

// System imports
import java.awt.Dimension;
import java.io.File;

import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import javax.swing.filechooser.FileNameExtensionFilter;

//Local imports
import controller.UMLController;
import core.ErrorHandler;
import model.UMLClassManager;
import observe.Observable;
import views.components.DiagramPanel;
import views.components.testable.JOptionPaneWrapper;
import views.components.testable.TestableFileChooser;
import views.components.testable.TestableOptionPane;

/**
 * A graphical view of the UML editor
 * @author Ryan
 *
 */
public class GUIView extends View {
	private UMLClassManager model;
	private UMLController controller;
	
	// Window elements
	private JFrame window;
	private JScrollPane scrollPane;
	private DiagramPanel umlDiagram;
	
	// Option pane
	private JOptionPaneWrapper optionPane;
	private TestableOptionPane testOP;
	
	// File chooser
	private JFileChooser fileChooser;
	
	private boolean isHuman;
	
	/**
	 * Create a GUI view for a human
	 * @param controller
	 * @param model
	 */
	public GUIView(UMLController controller, UMLClassManager model) {
		this(controller, model, true);
	}
	
	/**
	 * Create a GUI view of the passed in model
	 * @param controller
	 * @param model
	 * @param isHuman
	 */
	public GUIView(UMLController controller, UMLClassManager model, boolean isHuman) {
		// Setup look and feel
		if(isHuman && setLook() != 0);

		// Setup controller and model
		this.controller = controller;
		this.model = model;
		this.controller.addObserver(this);
		
		this.isHuman = isHuman;

		// Setup options
		optionPane = new JOptionPaneWrapper();
		if(isHuman) {
			// Set to a regular file chooser
			setFileChooser(new JFileChooser());
			setupWindow();
		}
		// Set to a blank test pane otherwise (to avoid null pointers)
		else {
			setOptionPane(new TestableOptionPane(""));
			setFileChooser(new TestableFileChooser(new File("")));
		}
		
		setupDiagram();
		
		if(isHuman)
			window.pack();
	}
	
	/**
	 * Set the view to be visible
	 */
	public void show() {
		window.setVisible(true);
	}
	
	/**
	 * Setup the GUI window with some default properties
	 */
	private void setupWindow() {
		// Initialize frame with title
		window = new JFrame("UML Editor");
		
		// Set the initial size of the window
		window.setSize(new Dimension(600, 600));
		
		// Set the close button behavior to exit the program
		window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}
	
	/**
	 * Initialize the diagram panel where the model will be represented
	 */
	private void setupDiagram() {
		// Setup a JPanel to display the classes and relationships
		umlDiagram = isHuman() ? new DiagramPanel(this, true) : new DiagramPanel(this, false);
		
		// Add the umlDiagram to the list of listeners for model changes
		controller.addObserver(umlDiagram);
		
		// Create scroll view
		scrollPane = new JScrollPane(umlDiagram);
		
		// Add the scroll pane to the frame
		if(isHuman())
			window.add(scrollPane);
	}
	
	/**
	 * Prompt the user for String input
	 * @param message - The message directing the user what to enter
	 * @return - User entered String
	 */
	public Object promptInput(String message) {
		// Prompt the user for input and return the input
		return optionPane.showInputDialog(window, message, testOP);
	}
	
	/**
	 * Prompt the user for input given selection
	 * @param message - The message directing the user what to enter
	 * @return - User entered String
	 */
	public Object promptSelection(String message, Object[] options) {
		// Prompt the user for input with a list of selections and return the input
		return optionPane.showInputDialog(window, message, "Selection", JOptionPane.QUESTION_MESSAGE, null, options, options[0], testOP);
	}
	
	/**
	 * Display an error message with the associated error
	 * @param parent - Parent component, can be null
	 * @param errorCode
	 */
	@SuppressWarnings("static-access")
	public void showError(JComponent parent, int errorCode) {
		// Create error message
		optionPane.showMessageDialog(parent, ErrorHandler.toString(errorCode), "Error", JOptionPane.ERROR_MESSAGE, testOP);
	}
	
	/**
	 * Open a JFileChooser and get a file from the user
	 * @param desc - description of the extension
	 * @param extension - the extension of the file, null if no filter
	 * @param title - the title of the windoer
	 * @param type - the type of chooser
	 * @return - The chosen file
	 */
	public File getFile(String desc, String extension, String title, int type) {
		// Set title of the chooser
		fileChooser.setDialogTitle(title);
		
		// Set extension filter to only allow extension
		// Make sure extension filter is not null and not empty
		if(desc != null && !desc.isEmpty() && extension != null && !extension.isEmpty())
			fileChooser.setFileFilter(new FileNameExtensionFilter(desc, extension));
		
		// Choose a file
		int result;
		if(type == JFileChooser.SAVE_DIALOG) {
			result = fileChooser.showSaveDialog(window);
		}
		else {
			result = fileChooser.showOpenDialog(window);
		}
		
		// Make sure input wasn't cancel
		if(result == JFileChooser.APPROVE_OPTION) {
			File file = fileChooser.getSelectedFile();
			return file;
		}
		
		return null;
	}
	
	/**
	 * Get the instance of the controller
	 * @return
	 */
	public UMLController getController() {
		return controller;
	}
	
	/**
	 * Try to set the GUI look and feel to match the OS
	 * @return - return code, 0 if successful
	 */
	private int setLook() {
		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch(Exception e) {
			return ErrorHandler.setCode(110);
		}
		return ErrorHandler.setCode(0);
	}
	
	/**
	 * Get the component that has the given name
	 * @param name - name of the component
	 * @return - associated JComponent
	 */
	public JComponent getComponent(String name) {
		return (JComponent)umlDiagram.findComponent(name);
	}
	
	/**
	 * Get the entire window instance.
	 * @return - window JFrame
	 */
	public JFrame getWindow() {
		return window;
	}
	
	/**
	 * Get the instance of the diagram panel
	 * @return - diagramPanel
	 */
	public DiagramPanel getDiagram() {
		return umlDiagram;
	}
	
	/**
	 * Get the view's model
	 * @return - model
	 */
	public UMLClassManager getModel() {
		return model;
	}
	
	/**
	 * Set the option pane for prompts
	 * @param pane - option pane instance
	 */
	public void setOptionPane(TestableOptionPane pane) {
		this.testOP = pane;
	}
	
	/**
	 * Set the file chooser for selecting files
	 * @param chooser - file chooser instance
	 */
	public void setFileChooser(JFileChooser chooser) {
		this.fileChooser = chooser;
	}

	@Override
	public void updated(Observable src, String tag, Object data) {
		
	}

	/**
	 * Get whether GUI is running in human or testable mode
	 * @return isHuman
	 */
	public boolean isHuman() {
		return isHuman;
	}

	/**
	 * Update the scroll pane to reflect dimension changes
	 */
	public void updateFrame() {
		scrollPane.revalidate();
	}
}