/** * 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.Dimension; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import javax.swing.JButton; import javax.swing.JPanel; import javax.swing.JSplitPane; import javax.swing.JTabbedPane; import es.eucm.ead.editor.view.panel.AbstractElementPanel; import org.jdesktop.swingx.JXRadioGroup; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import es.eucm.ead.model.assets.drawable.EAdDrawable; import es.eucm.ead.editor.model.ModelEvent; import es.eucm.ead.editor.model.nodes.DependencyNode; import es.eucm.ead.editor.model.nodes.EditorNode; import es.eucm.ead.editor.model.nodes.asset.AssetNode; import es.eucm.ead.editor.model.nodes.asset.AssetsNode; import es.eucm.ead.editor.view.components.EditorLinkFactory; import es.eucm.ead.editor.view.components.NodeBrowserPanel; import es.eucm.ead.editor.view.components.PropertiesTablePanel; import es.eucm.ead.editor.view.components.ThumbnailPanel; import es.eucm.ead.engine.desktop.utils.assetviewer.AssetViewer; import es.eucm.ead.engine.desktop.utils.assetviewer.AssetViewer.ImageGrabber; /** * A panel that displays all assets, by type. A preview is available * on the left-hand side. * * @author mfreire */ public class AssetsPanel extends AbstractElementPanel<AssetsNode> { static private Logger logger = LoggerFactory.getLogger(AssetsPanel.class); private AssetsNode assetsNode; private JSplitPane split; private JTabbedPane tabs; private AssetPreviewer previewer; private HashMap<String, NodeBrowserPanel> thumbPanels; private AssetViewer rootAssetViewer; private HashMap<String, ArrayList<EditorNode>> nodesByCategory = new HashMap<String, ArrayList<EditorNode>>(); private Class<? extends NodeBrowserPanel> nodeBrowserClass; private void setNodeBrowserClass( Class<? extends NodeBrowserPanel> nodeBrowserClass) { this.nodeBrowserClass = nodeBrowserClass; rebuild(); } private NodeBrowserPanel createNodeBrowserPanel() { try { return nodeBrowserClass.newInstance(); } catch (Exception e) { throw new IllegalArgumentException("unable to instantiate " + nodeBrowserClass, e); } } private String iconBrowserButtonName = "Icons"; private String detailedBrowserButtonName = "Details"; public AssetsPanel() { final JXRadioGroup<String> jxrg = new JXRadioGroup<String>( new String[] { detailedBrowserButtonName, iconBrowserButtonName }); jxrg.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent ae) { Class<? extends NodeBrowserPanel> next = jxrg .getSelectedValue().equals(detailedBrowserButtonName) ? PropertiesTablePanel.class : ThumbnailPanel.class; if (nodeBrowserClass == null) { nodeBrowserClass = next; } else if (!next.equals(nodeBrowserClass)) { setNodeBrowserClass(next); } } }); jxrg.setSelectedValue(detailedBrowserButtonName); JPanel radioHolder = new JPanel(new FlowLayout()); radioHolder.add(jxrg); thumbPanels = new HashMap<String, NodeBrowserPanel>(); tabs = new JTabbedPane(); JPanel tabsHolder = new JPanel(new BorderLayout()); tabsHolder.add(tabs, BorderLayout.CENTER); tabsHolder.add(radioHolder, BorderLayout.SOUTH); previewer = new AssetPreviewer(); split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, tabsHolder, previewer); split.setDividerLocation(500); setLayout(new BorderLayout()); add(split, BorderLayout.CENTER); } /** * Internal class that previews individual assets */ private class AssetPreviewer extends JPanel { private EditorNode previewedNode; private JButton prev = new JButton("<"); private JPanel current = new JPanel(); private JButton next = new JButton(">"); private AssetPreviewer() { setLayout(new BorderLayout()); JPanel buttonsPanel = new JPanel(new BorderLayout()); buttonsPanel.add(prev, BorderLayout.WEST); buttonsPanel.add(current, BorderLayout.CENTER); buttonsPanel.add(next, BorderLayout.EAST); add(buttonsPanel, BorderLayout.SOUTH); prev.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { NodeBrowserPanel selectedPane = (NodeBrowserPanel) tabs .getSelectedComponent(); EditorNode prev = selectedPane.getPrevious(); if (prev != null) { setNode(prev); } } }); next.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { NodeBrowserPanel selectedPane = (NodeBrowserPanel) tabs .getSelectedComponent(); EditorNode next = selectedPane.getNext(); if (next != null) { setNode(next); } } }); } @Override public void setSize(Dimension d) { super.setSize(d); updateCanvasSize(); } @Override public void setSize(int w, int h) { super.setSize(w, h); updateCanvasSize(); } private void updateCanvasSize() { int m = Math.max(0, Math.min(getWidth(), getHeight() - 40)); rootAssetViewer.getCanvas().setPreferredSize(new Dimension(m, m)); doLayout(); } public void setNode(final EditorNode node) { logger.info("Setting preview to node {}", node.getId()); previewedNode = node; if (rootAssetViewer == null) { rootAssetViewer = controller.createAssetViewer(); add(rootAssetViewer.getCanvas(), BorderLayout.CENTER); updateCanvasSize(); } current.removeAll(); current.add(EditorLinkFactory.createLink(node, controller)); if (node.getFirst().getContent() instanceof EAdDrawable) { EAdDrawable d = (EAdDrawable) node.getFirst().getContent(); rootAssetViewer.setDrawable(d); final ImageGrabber grabber = new ImageGrabber(); grabber.setCallback(new Runnable() { @Override public void run() { node.setThumbnail(grabber.getImage()); tabs.getSelectedComponent().repaint(); } }); new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(100); rootAssetViewer.grabImage(grabber); } catch (InterruptedException ex) { logger.warn("interrupt while grabbing image"); } } }).start(); } revalidate(); repaint(); } } private void addThumbnailPanel(String fullClassName) { NodeBrowserPanel tp = createNodeBrowserPanel(); tp.setController(controller); tp.addPropertyChangeListener(NodeBrowserPanel.selectedPropertyName, new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { EditorNode node = ((NodeBrowserPanel) evt.getSource()) .getLastSelected(); previewer.setNode(node); } }); tabs.add(fullClassName.substring(fullClassName.lastIndexOf('.') + 1), tp); thumbPanels.put(fullClassName, tp); } @Override protected void rebuild() { this.assetsNode = target; tabs.removeAll(); thumbPanels.clear(); nodesByCategory.clear(); for (AssetNode n : assetsNode.getNodes(controller.getModel())) { String cn = n.getFirst().getContent().getClass().getName(); NodeBrowserPanel tp = thumbPanels.get(cn); ArrayList<EditorNode> al = nodesByCategory.get(cn); if (tp == null) { addThumbnailPanel(cn); al = new ArrayList<EditorNode>(); nodesByCategory.put(cn, al); logger.info("Added category {}", cn); } al.add((EditorNode) n); } for (String s : thumbPanels.keySet()) { logger.info("Setting {} nodes for category {}", new Object[] { nodesByCategory.get(s).size(), s }); thumbPanels.get(s).setNodes(nodesByCategory.get(s)); } if (thumbPanels.containsKey("Image")) { tabs.setSelectedComponent(thumbPanels.get("Image")); } tabs.revalidate(); previewer.revalidate(); } /** * Determines if a modelChange affects this panel. Any change that * adds or removes assets, or changes them, is interpreted to affect us. * * @param event */ @Override public void modelChanged(ModelEvent event) { HashSet<String> toRefresh = new HashSet<String>(); for (DependencyNode[] array : new DependencyNode[][] { event.getAdded(), event.getRemoved(), event.getChanged() }) { for (DependencyNode n : array) { if (n instanceof AssetNode) { AssetNode an = (AssetNode) n; String cn = an.getFirst().getContent().getClass().getName(); if (nodesByCategory.get(cn) == null) { ArrayList<EditorNode> al = new ArrayList<EditorNode>(); nodesByCategory.put(cn, al); al.add(an); toRefresh.add(cn); } else if (!nodesByCategory.get(cn).contains(an)) { nodesByCategory.get(cn).add(an); toRefresh.add(cn); } else { toRefresh.add(cn); } // also update previews if (previewer.previewedNode.getId() == n.getId()) { previewer.setNode(an); } } } } for (String cn : toRefresh) { if (thumbPanels.get(cn) == null) { addThumbnailPanel(cn); } thumbPanels.get(cn).modelChanged(event); } } }