package bGUI; import data.*; import java.awt.GraphicsConfiguration; import java.awt.HeadlessException; import java.awt.Image; import javax.imageio.ImageIO; import javax.sound.sampled.*; import javax.swing.*; import script.Script; import sun.audio.AudioStream; import data.BDataModel; import data.BShape; import java.awt.*; import java.awt.event.*; import java.awt.image.BufferedImage; import java.beans.XMLDecoder; import java.beans.XMLEncoder; import java.io.*; import java.util.*; import java.util.List; /** * */ /** * @author Matthew Chun-Lum * */ public class BEditor extends JFrame { private static BDataModel currentModel; /** * creates a new data model */ public static void createNewDataModel() { currentModel = new BDataModel(); } /** * Sets the current data model * @param model */ public static void setDataModel(BDataModel model) { currentModel = model; } /** * Static method, adds a resource to the current data model * @param file */ public static void addResource(File file) { currentModel.addResource(file); currentModel.addResourceName(file); } /** * Static method, gets an Image from the current data model * @param name * @return */ public static Image getImage(String name) { return currentModel.getImage(name); } private BShapeInspectorPanel shapeInspector; private BResourceInspectorPanel resourceInspector; private BPageInspectorPanel pageInspector; private BInspectorContainer inspectorContainer; private BEditorToolbar toolbar; private BEditorCanvas canvas; private BEditorCatalog catalog; private JMenuBar menuBar; private JMenuItem saveItem; private JFileChooser fileChooser; private BGame game; private JButton nextPageButton; private JButton prevPageButton; //public static BPageCounter pageCounter = new BPageCounter(); //public static BShapeCounter shapeCounter = new BShapeCounter(); public BEditor() { this(null); } /** * Default constructor, sets up the GUI and other variables */ public BEditor(String targetDirectory) { currentModel = new BDataModel(); setLayout(new BorderLayout()); fileChooser = new JFileChooser(System.getProperty("user.dir")); // set up the GUI setUpMenuBar(); setUpToolbar(); setUpCatalogPanel(); setUpInspectorContainer(); setUpCanvas(); pack(); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent event) { boolean ok = doCheckQuit(); if (!ok) return; System.exit(0); } }); addPage(); canvas.setDirty(false); if(targetDirectory != null) { boolean success = false; File directory = new File(targetDirectory); if(directory.canRead()) { String indexPath = directory.getAbsolutePath() + File.separatorChar + "index.xml"; File index = new File(indexPath); if(index.canRead()) { doOpen(index); success = true; } } if(!success) { JOptionPane.showMessageDialog(this, "Invalid path argument!\nDefault document loaded."); } } this.setTitle("Bunny World"); } /** * */ public void playGame() { if(currentModel.getPage("page1") == null) return; game = new BGame("Bunny World", currentModel.clone(), this); this.setVisible(false); } /** * Displays and image chooser and gets the file */ public void promptForImageFile() { int retVal = fileChooser.showOpenDialog(this); if(retVal == JFileChooser.APPROVE_OPTION) { BEditor.addResource(fileChooser.getSelectedFile()); shapeInspector.addImageNameToImageChooser(fileChooser.getSelectedFile().getName()); catalog.addNewResource(currentModel.getResourcesMap().get(fileChooser.getSelectedFile().getName())); showPropertiesForResource(fileChooser.getSelectedFile().getName()); canvas.setDirty(true); } } public void promptForSoundFile() { int retVal = fileChooser.showOpenDialog(this); if(retVal == JFileChooser.APPROVE_OPTION) { BEditor.addResource(fileChooser.getSelectedFile()); catalog.addNewResource(currentModel.getResourcesMap().get(fileChooser.getSelectedFile().getName())); showPropertiesForResource(fileChooser.getSelectedFile().getName()); canvas.setDirty(true); } } /** * Gets the image names recognized by the document * @return an array of image names */ public String[] getImageNames() { // for now String[] temp = {""}; return temp; } public void addPage() { BPage page = new BPage(); canvas.setSelected(null); canvas.setCurrentPage(page); canvas.setDirty(true); page.setName(currentModel.getPageCounter().getPageName()); currentModel.addPage(page.getModel()); catalog.addNewPage(page.getModel()); selected(null); inspectorContainer.changeInspector(BInspectorContainer.PAGE_INSPECTOR); pageInspector.setInspectorForPage(page.getName()); } public void removeCurrentPage() { if(canvas.getCurrentPage() == null) return; if(canvas.getCurrentPage().getName().equals("page1")) { JOptionPane.showMessageDialog(this, "You cannot remove page1!", "Cannot Remove", JOptionPane.ERROR_MESSAGE); return; } Object[] options = {"Remove page", "Cancel"}; int ans = JOptionPane.showOptionDialog(this, "Are you sure you want to remove this page?\nThis action cannot be undone.", "Remove Page?", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, BIconHelper.WARNING_ICON, options, options[1]); if(ans == JOptionPane.YES_OPTION) { canvas.setSelected(null); selected(null); catalog.removePage(canvas.getCurrentPageModel()); currentModel.removePage(canvas.getCurrentPageModel()); canvas.setCurrentPage(null); canvas.repaint(); canvas.setDirty(true); } } /** * Adds a new shape to the current page */ public void addShape() { if(canvas.getCurrentPage() != null) { BShape shape = new BShape(); canvas.addShape(shape); shape.setName(currentModel.getShapeCounter().getShapeName()); currentModel.addShape(shape.getModel()); catalog.addNewShape(shape, canvas.getCurrentPageModel()); selected(shape); } } /** * Removes the selected shape from the canvas */ public void removeSelectedShape() { if(canvas.hasSelected()) { BShape shape = canvas.getSelected(); canvas.removeShape(shape); selected(null); catalog.removeShape(shape); canvas.setDirty(true); } } /** * Moves the selected shape to the front */ public void moveSelectedToFront() { if(canvas.hasSelected()) { canvas.getCurrentPage().moveToFront(canvas.getSelected()); canvas.repaint(canvas.getSelected().getBigBounds()); canvas.setDirty(true); } } /** * Moves the selected shape to the back */ public void moveSelectedToBack() { if(canvas.hasSelected()) { canvas.getCurrentPage().moveToBack(canvas.getSelected()); canvas.repaint(canvas.getSelected().getBigBounds()); canvas.setDirty(true); } } /** * Changes the text for the canvas' selected shape * @param text */ public void changeTextForSelected(String text) { if(canvas.hasSelected()) { canvas.getSelected().setText(text); canvas.repaint(canvas.getSelected().getBigBounds()); canvas.setDirty(true); } } /** * Changes the font for the selected shape * @param fontName */ public void changeFontForSelected(String fontName, boolean bold, boolean itallic) { if(canvas.hasSelected()) { BShape shape = canvas.getSelected(); shape.setFont(fontName); shape.setFontBold(bold); shape.setFontItalics(itallic); canvas.repaint(shape.getBigBounds()); canvas.setDirty(true); } } /** * Changes the color for the selected shape * @param newColor */ public void changeColorForSelected(Color newColor) { if(canvas.hasSelected()) { canvas.getSelected().setColor(newColor); canvas.repaint((canvas.getSelected().getBigBounds())); canvas.setDirty(true); } } public void changeImageForSelected(String imageName) { if(canvas.hasSelected()) { canvas.getSelected().setImageName(imageName); canvas.repaint(canvas.getSelected().getBigBounds()); catalog.shapeChanged(canvas.getSelected()); canvas.setDirty(true); } } /** * Changes the bounds for the selected shape with the passed bounds * @param bounds */ public void changeBoundsForSelected(Rectangle bounds) { if(canvas.hasSelected()) { BShape selected = canvas.getSelected(); Rectangle oldBounds = selected.getBigBounds(); selected.setBounds(bounds); canvas.repaint(oldBounds); canvas.repaint(selected.getBigBounds()); canvas.setDirty(true); } } /** * Changes the name for the selected object * @param name */ public void changeNameForSelected(String name) { if(canvas.hasSelected()) { name = Script.makeScriptSafe(name); canvas.getSelected().setName(name); catalog.shapeChanged(canvas.getSelected()); canvas.setDirty(true); } } public void changeNameForSelectedPage(String name) { if(canvas.getCurrentPage() != null && !name.equals("page1")) { canvas.getCurrentPageModel().setName(name); catalog.pageChanged(canvas.getCurrentPageModel()); canvas.setDirty(true); } } /** * Changes the current page for the canvas to the passed page * @param page */ public void changePage(BPageModel pageModel) { BPage page = new BPage(pageModel); page.setDrawKnobs(true); canvas.setCurrentPage(page); canvas.setSelected(null); catalog.setSelectedObject(page.getModel()); inspectorContainer.changeInspector(BInspectorContainer.PAGE_INSPECTOR); pageInspector.setInspectorForPage(pageModel.getName()); } public void changeSelectedShape(BShape shape) { if(canvas.getCurrentPage() != null) { canvas.setSelected(shape); selected(shape); catalog.setSelectedObject(shape); } } public void changeScriptForSelected(String script) { if(canvas.hasSelected()) { canvas.getSelected().getModel().setScript(script); canvas.setDirty(true); } } public void changeHiddenForSelected(boolean val) { if(canvas.hasSelected()){ canvas.getSelected().setHidden(val); canvas.setDirty(true); } } public void changeMovableForSelected(boolean val) { if(canvas.hasSelected()){ canvas.getSelected().setMovable(val); canvas.setDirty(true); } } /** * Method for telling the editor that we have selected * the current shape * @param shape */ public void selected(BShape shape) { inspectorContainer.changeInspector(BInspectorContainer.SHAPE_INSPECTOR); shapeInspector.setInspectorForShape(shape); if(shape == null) { catalog.setSelectedObject(canvas.getCurrentPageModel()); inspectorContainer.changeInspector(BInspectorContainer.PAGE_INSPECTOR); if(canvas.getCurrentPage() != null) { pageInspector.setInspectorForPage(canvas.getCurrentPageModel().getName()); } else { pageInspector.setInspectorForPage(""); } } else { catalog.setSelectedObject(shape); } } public void removeResource(String resourceName) { if(currentModel.resourceIsInUse(resourceName)) { Object[] options = {"Remove resource", "Cancel"}; int ans = JOptionPane.showOptionDialog(this, "Are you sure you want to remove this resource?\nIt is currently in use by at least one shape.", "Remove resource?", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, BIconHelper.WARNING_ICON, options, options[1]); if(ans == JOptionPane.NO_OPTION) return; } ResourceModel resource = currentModel.getResourcesMap().get(resourceName); catalog.removeResource(resource); if(resource.getDataType().equals("Image")) shapeInspector.removeImageNameFromImagechooser(resourceName); currentModel.removeResource(resourceName); canvas.repaint(); canvas.setDirty(true); inspectorContainer.changeInspector(BInspectorContainer.SHAPE_INSPECTOR); removeResourceFile(resourceName); } public void playSound(String soundName) { if(currentModel.getResourcesMap().containsKey(soundName)) currentModel.playAudio(soundName); } public void showPropertiesForResource(String resourceName) { canvas.setSelected(null); canvas.repaint(); shapeInspector.setInspectorForShape(null); inspectorContainer.changeInspector(BInspectorContainer.RESOURCE_INSPECTOR); resourceInspector.setResource(currentModel.getResourcesMap().get(resourceName)); } public void disableSave() { saveItem.setEnabled(false); } public void enableSave() { saveItem.setEnabled(true); } // -------------- Private ------------ // private void nextPage() { if(canvas.getCurrentPage() != null) { BPageModel model = catalog.getNextPage(canvas.getCurrentPageModel()); if(model != null) changePage(model); } } private void previousPage() { if(canvas.getCurrentPage() != null) { BPageModel model = catalog.getPreviousPage(canvas.getCurrentPageModel()); if(model != null) changePage(model); } } /** * writes the resources to the directory */ private void writeResourcesToFile() { Collection<ResourceModel> resources = currentModel.getResourcesMap().values(); Iterator<ResourceModel> it = resources.iterator(); while(it.hasNext()) { try { ResourceModel r = it.next(); String newFilePath = currentModel.getDocDirectory() + File.separatorChar + r.getName(); File resourceFile = new File(newFilePath); BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(resourceFile)); if(r.getDataType().equals("Image")) saveImage(r, outputStream); else if(r.getDataType().equals("AudioStream")) saveAudio(r, outputStream); r.setFilePath(newFilePath); outputStream.close(); } catch (IOException e) { System.out.println("uhoh"); } } } /** * helps to write images out * @param r * @param os */ public void saveImage(ResourceModel r, OutputStream os) { BufferedImage buffImage = (BufferedImage)r.getImage(); try { ImageIO.write(buffImage, "png", os); } catch (IOException ex) { ex.printStackTrace(); } } /** * helps to write audio out * @param r * @param os */ public void saveAudio(ResourceModel r, OutputStream os) { try { File f = new File(r.getFilePath()); if(!f.exists()) { AudioFileFormat format = AudioSystem.getAudioFileFormat(f); AudioFileFormat.Type type = format.getType(); AudioSystem.write(AudioSystem.getAudioInputStream(f), type, os); } } catch (IOException ex) { ex.printStackTrace(); } catch (UnsupportedAudioFileException e) { e.printStackTrace(); } } /** * write the bdatamodel out to index.xml */ private void writeDataToFile() { try { String newFilePath = currentModel.getDocDirectory() + File.separatorChar + "index.xml"; XMLEncoder e = new XMLEncoder(new BufferedOutputStream(new FileOutputStream(newFilePath))); e.writeObject(currentModel); e.close(); } catch (IOException e) { System.out.println("uhoh"); } } /** * opens the specified file of the user */ private void handleOpen() { doCheckQuit(); canvas.setDirty(false); fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); int status = fileChooser.showOpenDialog(this); if (status == JFileChooser.APPROVE_OPTION) { boolean success = false; File dest = fileChooser.getSelectedFile(); if(dest.isDirectory()) { String path = dest.getAbsolutePath() + File.separatorChar + "index.xml"; File index = new File(path); if(index.canRead()) { if(index.getName().endsWith(".xml")) success = true; doOpen(index); } } if(!success) { JOptionPane.showMessageDialog(this, "Could not open document from that directory!"); } } fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); } /** * opens the selected xml index file. * @param file */ private void doOpen(File file) { try { XMLDecoder d = new XMLDecoder(new BufferedInputStream(new FileInputStream(file))); BDataModel result = (BDataModel)d.readObject(); d.close(); currentModel = result; currentModel.setDocDirectory(file.getParent()); currentModel.loadResources(); List<String> resources = currentModel.getResourceNames(); shapeInspector.getImageChooser().removeAllItems(); shapeInspector.addImageNameToImageChooser("none"); for(int i=0; i<resources.size(); i++) { if(resources.get(i).endsWith(".jpeg") || resources.get(i).endsWith(".gif")) shapeInspector.addImageNameToImageChooser(resources.get(i)); } BPage newCurrent = new BPage(); newCurrent.setModel(currentModel.getPage("page1")); canvas.setCurrentPage(newCurrent); catalog.loadFromDataModel(currentModel); selected(null); } catch (IOException e) { System.out.println("uhoh"); } } // Asks if they want to save, and if so does it. // Returns false if they cancel. public boolean saveOk() { int result = JOptionPane.showConfirmDialog( this, "Save changes first?", "Save?", JOptionPane.YES_NO_CANCEL_OPTION); if (result == JOptionPane.YES_OPTION) { handleSave(); } return (result != JOptionPane.CANCEL_OPTION); } // Checks if quitting is ok, and saves if needed. // Returns false if they cancel. public boolean doCheckQuit() { if (canvas.getDirty()) { boolean ok = saveOk(); if (!ok) return false; } return true; } /** * Handles the save button, checks if the directory is null, and creates a new diectory if needed * saves the resources and bdatamodel */ private void handleSave() { if(currentModel.getDocDirectory()==null) { handleSaveAs(); return; } writeResourcesToFile(); writeDataToFile(); canvas.setDirty(false); } /** * prompts the user to enter a file name then calls its doSaveAs */ private void handleSaveAs() { int status = fileChooser.showSaveDialog(this); if (status == JFileChooser.APPROVE_OPTION) { File dest = fileChooser.getSelectedFile(); doSaveAs(dest); } } /** * makes a directory if needed and saves the resources and the bdatamodel * @param file */ private void doSaveAs(File file) { file.mkdir(); currentModel.setDocDirectory(file.getAbsolutePath()); currentModel.setSaved(true); writeResourcesToFile(); writeDataToFile(); canvas.setDirty(false); } private void removeResourceFile(String resourceName) { if(currentModel.getSaved()) { File file = new File(currentModel.getDocDirectory() + File.separatorChar + resourceName); if(file.exists()) file.delete(); } } private void createNewDocument() { currentModel = new BDataModel(); shapeInspector.getImageChooser().removeAllItems(); shapeInspector.addImageNameToImageChooser("none"); catalog.loadFromDataModel(currentModel); addPage(); selected(null); } // ------------ GUI SET UP ----------- // /** * Sets up the top menu bar for saving/opening, etc. */ private void setUpMenuBar() { menuBar = new JMenuBar(); JMenu fileMenu = new JMenu("File"); saveItem = new JMenuItem("Save"); saveItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { handleSave(); } }); saveItem.setMnemonic(KeyEvent.VK_S); saveItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, ActionEvent.CTRL_MASK)); JMenuItem saveAsItem = new JMenuItem("Save As"); saveAsItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { handleSaveAs(); } }); JMenuItem openItem = new JMenuItem("Open"); openItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { handleOpen(); } }); openItem.setMnemonic(KeyEvent.VK_O); openItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK)); JMenuItem newItem = new JMenuItem("New"); newItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { createNewDocument(); } }); fileMenu.add(newItem); fileMenu.add(saveItem); fileMenu.add(saveAsItem); fileMenu.add(openItem); JMenu aboutMenu = new JMenu("Bunny World"); JMenuItem aboutItem = new JMenuItem("About"); aboutItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { AboutBox about = new AboutBox(); } }); aboutMenu.add(aboutItem); menuBar.add(aboutMenu); menuBar.add(fileMenu); setJMenuBar(menuBar); } /** * Sets up the Toolbar (NORTH). We may want this, so it's here */ private void setUpToolbar() { toolbar = new BEditorToolbar(this); add(toolbar, BorderLayout.NORTH); } /** * Sets up the catalog panel (WEST) * will not be implemented for the early demo */ private void setUpCatalogPanel() { catalog = new BEditorCatalog(this); catalog.loadFromDataModel(currentModel); add(catalog, BorderLayout.WEST); } /** * Sets up the shape inspector panel (EAST) for editing/adding shapes */ private void setUpInspectorContainer() { resourceInspector = new BResourceInspectorPanel(this); shapeInspector = new BShapeInspectorPanel(this); pageInspector = new BPageInspectorPanel(this); inspectorContainer = new BInspectorContainer(this, shapeInspector, resourceInspector, pageInspector); inspectorContainer.changeInspector(BInspectorContainer.SHAPE_INSPECTOR); add(inspectorContainer, BorderLayout.EAST); } /** * Sets up the canvas portion, placing it in the * center of the border layout */ private void setUpCanvas() { canvas = new BEditorCanvas(this); canvas.setMaximumSize(canvas.getPreferredSize()); canvas.setBackground(Color.gray); JPanel controlPanel = new JPanel(); controlPanel.setLayout(new BoxLayout(controlPanel, BoxLayout.X_AXIS)); nextPageButton = new JButton("Next Page", BIconHelper.NEXT_ICON); BIconHelper.setPropertiesOfButtonToAcceptIcon(nextPageButton); nextPageButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { nextPage(); } }); prevPageButton = new JButton("Previous Page", BIconHelper.PREVIOUS_ICON); BIconHelper.setPropertiesOfButtonToAcceptIcon(prevPageButton); prevPageButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { previousPage(); } }); controlPanel.add(prevPageButton); controlPanel.add(nextPageButton); controlPanel.add(Box.createHorizontalGlue()); JPanel centerPanel = new JPanel(); centerPanel.setPreferredSize(canvas.getPreferredSize()); centerPanel.setLayout(new BoxLayout(centerPanel, BoxLayout.Y_AXIS)); centerPanel.setBackground(Color.gray); centerPanel.add(Box.createVerticalGlue()); centerPanel.add(canvas); centerPanel.add(Box.createVerticalGlue()); centerPanel.add(controlPanel); add(centerPanel, BorderLayout.CENTER); } }