/* * To change this template, choose Tools | Templates * and open the template in the editor. /** * 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.components; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.Graphics; import java.awt.LayoutManager; import java.awt.Rectangle; import java.awt.datatransfer.Transferable; import java.awt.dnd.DnDConstants; import java.awt.dnd.DragGestureEvent; import java.awt.dnd.DragGestureListener; import java.awt.dnd.DragSource; import java.awt.dnd.DragSourceAdapter; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.Collection; import java.util.HashMap; import javax.swing.JPanel; import javax.swing.JScrollPane; import es.eucm.ead.editor.model.ModelEvent; import es.eucm.ead.editor.model.ModelEventUtils; import es.eucm.ead.editor.model.nodes.DependencyNode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import es.eucm.ead.editor.model.nodes.EditorNode; /** * A panel that displays thumbnails for a number of elements. * Element thumbnails can be selected (all or some), and have, as titles, the * EditorLinks. * @author mfreire */ public class ThumbnailPanel extends NodeBrowserPanel { static private Logger logger = LoggerFactory .getLogger(ThumbnailPanel.class); private JPanel inner; private int thumbImageSize = 64; private int thumbWidth = 128; private int thumbHeight = 92; private int thumbInnerMargins = 3; private DynamicGridLayout dgl; private NodeTransferHandler transferHandler = new NodeTransferHandler(); private HashMap<Integer, Thumbnail> thumbMap = new HashMap<Integer, Thumbnail>(); public ThumbnailPanel() { inner = new JPanel(); dgl = new DynamicGridLayout(); inner.setLayout(dgl); WidthSensitiveScrollPane scroll = new WidthSensitiveScrollPane(); scroll.getVerticalScrollBar().setUnitIncrement(16); scroll.setViewportView(inner); scroll.setParent(this); inner.setTransferHandler(transferHandler); add(scroll, BorderLayout.CENTER); } @Override public void modelChanged(ModelEvent event) { for (DependencyNode n : nodes) { if (ModelEventUtils.changes(event, n)) { int pos = thumbMap.get(n.getId()).index; inner.remove(pos); thumbMap.put(n.getId(), new Thumbnail((EditorNode) n, pos)); inner.add(thumbMap.get(n.getId()), pos); } } } private class Thumbnail extends JPanel { private final EditorNode node; private final int index; public Thumbnail(EditorNode node, int index) { this.node = node; this.index = index; setLayout(null); DragSource.getDefaultDragSource() .createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY, new DragGestureListener() { @Override public void dragGestureRecognized( DragGestureEvent dge) { Transferable t = transferHandler .createTransferable(ThumbnailPanel.this); dge.startDrag(DragSource.DefaultCopyNoDrop, t, new DragSourceAdapter() { }); } }); int m = (thumbWidth - (thumbImageSize + thumbInnerMargins * 2)) / 2; Thumb t = new Thumb(); t.setBounds(m, thumbInnerMargins, thumbImageSize, thumbImageSize); t.setSize(thumbImageSize, thumbImageSize); add(t); EditorLink e = EditorLinkFactory.createLink(node, controller); e.setBounds(0, thumbImageSize, thumbWidth, (int) e .getPreferredSize().getHeight()); e.setSize(thumbWidth, (int) e.getPreferredSize().getHeight()); add(e); addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { EditorNode node = Thumbnail.this.node; int ctrlDown = MouseEvent.CTRL_DOWN_MASK; boolean wasSelected = selected.contains(node); if ((e.getModifiersEx() & ctrlDown) != ctrlDown) { selected.clear(); if (!wasSelected) { selected.add(node); } } else { if (!wasSelected) { selected.add(node); } else { selected.remove(node); } } lastSelected = node; ThumbnailPanel.this.firePropertyChange( selectedPropertyName, null, node); getParent().repaint(); } }); } @Override public void paint(Graphics g) { if (selected.contains(node)) { super.paintComponent(g); g.setColor(new Color(0.8f, 0.8f, 1.0f)); g.fillRoundRect(1, 1, getWidth() - 3, getHeight() - 3, 2, 2); super.paintChildren(g); } else { super.paint(g); } } private class Thumb extends JPanel { public Thumb() { setPreferredSize(new Dimension(64, 64)); } @Override public void paint(Graphics g) { g.drawImage(node.getThumbnail(), 0, 0, getWidth(), getHeight(), this); } } } private class DynamicGridLayout implements LayoutManager { private int margin = 5; private int minMargin = 5; public int colsFor(int width) { return (width - minMargin) / (thumbWidth + minMargin); } public void updateMarginFromWidth(int width, int cols) { int need = cols * thumbWidth; int extra = width - need; margin = extra / (cols + 1); logger .info( "UpdateMargin: width {}, {} cols; need {}, {} left-over - setting margin to {}", new Object[] { width, cols, need, extra, margin }); } public int widthFor(int cols) { return cols * (thumbWidth + minMargin) + minMargin; } private int heightFor(int n, int cols) { if (n == 0 || cols == 0) { return 0; } int rows = n / cols + ((n % cols > 0) ? 1 : 0); return rows * (thumbHeight + minMargin) + minMargin; } @Override public void addLayoutComponent(String name, Component comp) { } @Override public void removeLayoutComponent(Component comp) { } @Override public Dimension preferredLayoutSize(Container parent) { int w = Math.max(parent.getWidth(), margin + thumbWidth + margin); int cols = colsFor(w); return new Dimension(widthFor(cols), heightFor(parent .getComponentCount(), cols)); } @Override public Dimension minimumLayoutSize(Container parent) { return preferredLayoutSize(parent); } @Override public void layoutContainer(Container parent) { Rectangle r = new Rectangle(margin, minMargin, thumbWidth, thumbHeight); int cols = Math.max(1, colsFor(parent.getWidth())); for (int i = 0; i < parent.getComponentCount(); i++) { int row = i / cols; int col = i % cols; r.x = margin + col * (thumbWidth + margin); r.y = minMargin + row * (thumbHeight + minMargin); Component c = parent.getComponent(i); c.setBounds(r); c.setSize(thumbWidth, thumbHeight); } } } private class WidthSensitiveScrollPane extends JScrollPane { private ComponentListener resizeListener = new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { Dimension p = e.getComponent().getSize(); Component v = getViewport().getComponent(0); Dimension c = new Dimension(v.getPreferredSize()); int cols = dgl.colsFor(p.width - 4); c.width = dgl.widthFor(cols); dgl.updateMarginFromWidth(p.width - 4, cols); v.setPreferredSize(c); v.doLayout(); } }; public void setParent(Component parent) { parent.addComponentListener(resizeListener); } } @Override public void setNodes(Collection<EditorNode> nodes) { selected.clear(); inner.removeAll(); this.nodes.clear(); for (EditorNode n : nodes) { addNode(n); } inner.revalidate(); revalidate(); } @Override public void addNode(EditorNode node) { nodes.add(node); Thumbnail t = new ThumbnailPanel.Thumbnail(node, inner .getComponentCount()); thumbMap.put(node.getId(), t); inner.add(t); } }