/** * eAdventure (formerly <e-Adventure> and <e-Game>) is a research project of the * <e-UCM> research group. * * Copyright 2005-2010 <e-UCM> research group. * * You can access a list of all the contributors to eAdventure at: * http://e-adventure.e-ucm.es/contributors * * <e-UCM> is a research group of the Department of Software Engineering * and Artificial Intelligence at the Complutense University of Madrid * (School of Computer Science). * * C Profesor Jose Garcia Santesmases sn, * 28040 Madrid (Madrid), Spain. * * For more info please visit: <http://e-adventure.e-ucm.es> or * <http://www.e-ucm.es> * * **************************************************************************** * * This file is part of eAdventure, version 2.0 * * eAdventure is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * eAdventure 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with eAdventure. If not, see <http://www.gnu.org/licenses/>. */ package es.eucm.ead.editor.view.panel.asset; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Graphics; import java.awt.GridBagConstraints; import java.awt.Insets; import java.awt.image.BufferedImage; import java.io.File; import javax.imageio.ImageIO; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import es.eucm.ead.editor.control.Command; import es.eucm.ead.editor.control.commands.ChangeFieldCommand; import es.eucm.ead.editor.control.commands.ChangeFileCommand; import es.eucm.ead.editor.control.commands.FileCache; import es.eucm.ead.editor.model.ModelEvent; import es.eucm.ead.editor.model.nodes.asset.ImageAssetNode; import es.eucm.ead.editor.view.components.ZoomablePanel; import es.eucm.ead.editor.view.components.ZoomablePanelHolder; import es.eucm.ead.editor.view.generic.FileNameOption; import es.eucm.ead.editor.view.generic.FileOption; import es.eucm.ead.editor.view.generic.OptionPanel; import es.eucm.ead.editor.view.generic.PanelImpl; import es.eucm.ead.editor.view.generic.accessors.Accessor; import es.eucm.ead.editor.view.generic.accessors.ConvertingAccessor; import es.eucm.ead.editor.view.generic.accessors.IntrospectingAccessor; import es.eucm.ead.editor.view.panel.AbstractElementPanel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import es.eucm.ead.model.assets.drawable.basics.Image; import es.eucm.ead.editor.view.components.FileDrop; import es.eucm.ead.editor.view.generic.TextOption; import es.eucm.ead.tools.java.utils.FileUtils; import es.eucm.ead.editor.util.SwingUtilities; /** * A panel that displays all assets, by type. A preview is available * on the left-hand side. * * @author mfreire */ public class ImageAssetPanel extends AbstractElementPanel<ImageAssetNode> { static private Logger logger = LoggerFactory .getLogger(ImageAssetPanel.class); private static FileCache fileCache; private ImageAssetNode imageAsset; private File imageFile; private ZoomableImagePanel jpCanvas; private OptionPanel controlPanel; private FileDrop.Listener dropListener = new FileDrop.Listener() { @Override public void filesDropped(File[] files) { if (files.length != 1 || !files[0].exists() || !files[0].isFile()) { // bad file: too many, too few, non-existent or is-a-dir } else { setFile(files[0]); } } }; private void setFile(File f) { if (f != null && f.getName().toLowerCase().matches(".*[.](png|jpg|jpeg)") && f.exists()) { if (!f.getAbsolutePath().equals( imageAsset.getFile().getAbsolutePath())) { fileOption.updateValue(f); } imageFile = f; jpCanvas.refreshImage(); } else { logger.warn("Bad file: {}", f.getAbsolutePath()); } } public ImageAssetPanel() { initComponents(); jpCanvas = new ZoomableImagePanel(); ZoomablePanelHolder holder = new ZoomablePanelHolder(jpCanvas); jpCanvasContainer.add(holder, BorderLayout.CENTER); FileDrop fd = new FileDrop(null, jpCanvas, true, dropListener); } private class ZoomableImagePanel extends ZoomablePanel { private BufferedImage image; public ZoomableImagePanel() { super(true, true); } public void refreshImage() { try { logger .info( "RefreshImage at {}: setting max size reference to {}x{}", new Object[] { ImageAssetPanel.this.hashCode(), jpCanvasContainer.getWidth(), jpCanvasContainer.getHeight() }); setMaxSizeReference(jpCanvasContainer); image = ImageIO.read(imageFile); baseWidth = image.getWidth(); baseHeight = image.getHeight(); resetZoom(); repaint(); jlDescription.setText("Image '" + imageFile.getName() + "' " + baseWidth + "x" + baseHeight + ", " + imageFile.length() + " bytes"); } catch (Exception e) { logger.error("Error refreshing image to {}", imageFile); } } @Override public void paint(Graphics g) { g.clearRect(0, 0, width, height); if (image != null) { // try to center g.drawImage(image, 0, 0, width, height, this); } } } public void openExt(Object with) { System.err.println("opening with " + with); } public void nameChanged(String text) { System.err.println("name changed to " + text); } public void setNotes(String text) { System.err.println("notes changed to " + text); } public static File chooseFile(Component p, String message, boolean toOpen, int fileType) { JFileChooser jfc = new JFileChooser(); jfc.setDialogTitle(message); jfc.setFileSelectionMode(fileType); File f = null; while (f == null) { int rc = (toOpen ? jfc.showOpenDialog(p) : jfc.showSaveDialog(p)); if (rc == JFileChooser.CANCEL_OPTION) { f = null; break; } f = jfc.getSelectedFile(); if (f == null || (!f.exists() && toOpen) || (fileType == JFileChooser.FILES_ONLY && f.isDirectory())) { JOptionPane.showMessageDialog(null, "Error: " + message + " invalid", "Error", JOptionPane.ERROR_MESSAGE); f = null; continue; } } return f; } /** This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; jbZoomNative = new javax.swing.JButton(); jpView = new javax.swing.JPanel(); jlDescription = new javax.swing.JLabel(); jpViewControls = new javax.swing.JPanel(); jbOpenExt = new javax.swing.JButton(); jcbOpenWith = new javax.swing.JComboBox(); jbResetZoom = new javax.swing.JButton(); jbZoomPixel = new javax.swing.JButton(); jpCanvasContainer = new javax.swing.JPanel(); jbZoomNative.setText("1:1"); setLayout(new java.awt.GridBagLayout()); jpView.setLayout(new java.awt.GridBagLayout()); jlDescription.setText("<no image loaded>"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5); jpView.add(jlDescription, gridBagConstraints); jpViewControls.setLayout(new java.awt.GridBagLayout()); jbOpenExt.setText("Open with"); jbOpenExt.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { jbOpenExtActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; jpViewControls.add(jbOpenExt, gridBagConstraints); jcbOpenWith.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" })); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 0; gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.BASELINE_LEADING; gridBagConstraints.weightx = 0.5; gridBagConstraints.insets = new java.awt.Insets(0, 1, 0, 16); jpViewControls.add(jcbOpenWith, gridBagConstraints); jbResetZoom.setText("Zoom to fit"); jbResetZoom.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { jbResetZoomActionPerformed(evt); } }); jpViewControls.add(jbResetZoom, new java.awt.GridBagConstraints()); jbZoomPixel.setText("Zoom 1:1"); jbZoomPixel.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { jbZoomPixelActionPerformed(evt); } }); jpViewControls.add(jbZoomPixel, new java.awt.GridBagConstraints()); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5); jpView.add(jpViewControls, gridBagConstraints); jpCanvasContainer.setBackground(new java.awt.Color(245, 246, 249)); jpCanvasContainer.setLayout(new java.awt.BorderLayout()); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5); jpView.add(jpCanvasContainer, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.weightx = 0.2; gridBagConstraints.weighty = 0.2; add(jpView, gridBagConstraints); } private void jbOpenExtActionPerformed(java.awt.event.ActionEvent evt) { // TODO add your handling code here: openExt(jcbOpenWith.getSelectedItem()); } private void jbResetZoomActionPerformed(java.awt.event.ActionEvent evt) { jpCanvas.resetZoom(); } private void jbZoomPixelActionPerformed(java.awt.event.ActionEvent evt) { // TODO add your handling code here: jpCanvas.resetZoomNative(); } // Variables declaration - do not modify private JButton jbZoomNative; private JButton jbOpenExt; private JButton jbResetZoom; private JButton jbZoomPixel; private JComboBox jcbOpenWith; private JLabel jlDescription; private JPanel jpCanvasContainer; private JPanel jpView; private JPanel jpViewControls; private FileOption fileOption; // End of variables declaration @Override protected void rebuild() { imageAsset = target; final Image image = (Image) imageAsset.getFirst().getContent(); if (fileCache == null) { try { fileCache = new FileCache(FileUtils.createTempDir("ead", "cache")); } catch (Exception e) { logger.error("Could not initialize cache"); } } if (controlPanel == null) { controlPanel = new PanelImpl("Configuration", OptionPanel.LayoutPolicy.VerticalBlocks, 4); final Accessor<String> uriAccessor = new ConvertingAccessor<String, String>( String.class, new IntrospectingAccessor<String>(image, "uri")) { @Override public String innerToOuter(String b) { return b; } @Override public String outerToInner(String a) { return a; } }; FileNameOption fno = new FileNameOption("Name", "Internal name of asset (should be unique)", uriAccessor, false, imageAsset) { @Override public File resolveFile(String value) { return imageAsset.resolveUri(value); } @Override public Command createUpdateCommand() { return new ChangeFieldCommand<String>(getControlValue(), accessor, imageAsset) { @Override protected ModelEvent setValue(String value) { File src = resolveFile(accessor.read()); ModelEvent me = super.setValue(value); imageFile = resolveFile(value); if (!src.renameTo(imageFile)) { logger.warn("---- Could not rename {} --> {}", new Object[] { src, target }); } return me; } }; } }; fileOption = new FileOption("Source", "Asset source-file (.png or .jpg only)", "Choose...", imageAsset, "source", fileCache, imageAsset) { @Override public Command createUpdateCommand() { return new ChangeFileCommand(getControlValue(), accessor, fileCache, imageAsset) { @Override protected ModelEvent setValue(File value) { ModelEvent me = super.setValue(value); writeFile(imageAsset.resolveUri(uriAccessor.read())); return me; } }; } @Override public void valueUpdated(File oldValue, File newValue) { logger.info("Updating the image-file internally at {}", ImageAssetPanel.this.hashCode()); ImageAssetPanel.this.setFile(newValue); } }; controlPanel.add(fno); controlPanel.add(fileOption); controlPanel.add(new TextOption("Notes", "Notes on this asset", imageAsset, "notes", TextOption.ExpectedLength.LONG, imageAsset)); panels.add(controlPanel); GridBagConstraints gbc = new GridBagConstraints(0, 1, 1, 1, .1, .1, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(4, 4, 4, 4), 0, 0); add(controlPanel.getComponent(controller.getCommandManager()), gbc); } // FIXE: should not be necessary, but button-press needed otherwise new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(100); SwingUtilities.doInEDT(new Runnable() { @Override public void run() { setFile(imageAsset.getFile()); } }); } catch (InterruptedException ie) { logger.warn("Interrupted while napping before image-set"); } } }).start(); } }