/** * */ package cz.cuni.mff.peckam.java.origamist.gui.viewer; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import javax.swing.AbstractAction; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JToolBar; import javax.swing.border.Border; import javax.swing.origamist.BackgroundImageSupport; import javax.swing.origamist.BackgroundImageSupport.BackgroundRepeat; import javax.swing.origamist.JMultilineLabel; import javax.swing.origamist.JPanelWithOverlay; import javax.swing.origamist.JToolBarWithBgImage; import com.jgoodies.forms.layout.CellConstraints; import com.jgoodies.forms.layout.FormLayout; import cz.cuni.mff.peckam.java.origamist.gui.common.StepRenderer; import cz.cuni.mff.peckam.java.origamist.model.Origami; import cz.cuni.mff.peckam.java.origamist.model.Step; import cz.cuni.mff.peckam.java.origamist.services.ServiceLocator; import cz.cuni.mff.peckam.java.origamist.services.interfaces.ConfigurationManager; import cz.cuni.mff.peckam.java.origamist.utils.ParametrizedCallable; /** * This panel renders the given state of the model. * * Provides the following properties: * <ul> * <li><code>fullscreenModeRequested</code> - fired when the user clicks the "fullscreen" button</li> * <li>repeats all property changes happening in renderer</li> * </ul> * * @author Martin Pecka */ public class StepRendererWithControls extends JPanelWithOverlay { /** */ private static final long serialVersionUID = 6989958008007575800L; /** The mode to display this renderer in. */ protected DisplayMode displayMode; // COMPONENTS /** The renderer used to render the step. */ protected StepRenderer renderer; /** The label that shows the descripton of the shown step. */ protected final JMultilineLabel descLabel; /** The toolbar used for this renderer to control the display of the step. */ protected JToolBarWithBgImage toolbar; /** Button for zooming in. */ protected final JButton zoomIn; /** Button for zooming out. */ protected final JButton zoomOut; /** The button to show this step in Diagram view, if it is displayed in the Page view. */ protected final JButton fullscreenBtn; /** The border the toolbar buttons have in the time they are created. */ protected Border defaultToolbarButtonBorder; /** The listener to update the text. */ protected PropertyChangeListener diagramLocaleListener; public StepRendererWithControls() { setBorder(BorderFactory.createEmptyBorder(2, 5, 2, 5)); addMouseListener(new MouseListener()); addMouseWheelListener(new MouseListener()); renderer = new StepRenderer(); renderer.addMouseListener(new MouseListener()); renderer.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { firePropertyChange(evt.getPropertyName(), evt.getOldValue(), evt.getNewValue()); } }); descLabel = new JMultilineLabel(""); descLabel.setFont(descLabel.getFont().deriveFont(Font.PLAIN)); Border emptyBorder = BorderFactory.createEmptyBorder(); toolbar = new JToolBarWithBgImage("viewer"); toolbar.setFloatable(false); toolbar.setOpaque(false); // MAGIC toolbar.setBackground(new Color(231, 231, 184, 230)); toolbar.setBorder(emptyBorder); zoomIn = toolbar.createToolbarButton(new ZoomInAction(), "StepRenderer.zoom.in", "zoom-in-24.png"); zoomOut = toolbar.createToolbarButton(new ZoomOutAction(), "StepRenderer.zoom.out", "zoom-out-24.png"); fullscreenBtn = toolbar.createToolbarButton(new FullscreenAction(), "StepRenderer.fullscreen", "fullscreen-24.png"); getOverlay().setOpaque(false); getContent().setOpaque(false); // MAGIC setOpaque(true); showOverlay(); // Rows labelled MAGIC are important and shouldn't be changed in the future. If you for instance decide to // replace toolbar.setOpaque(false) with toolbar.setBackground(new Color(255,255,255,0)), ugly visual artifacts // appear on the toolbar buttons diagramLocaleListener = new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { updateText(); } }; ServiceLocator.get(ConfigurationManager.class).get() .addPropertyChangeListener("diagramLocale", diagramLocaleListener); buildLayout(); setDisplayMode(DisplayMode.PAGE); } /** * Add the components to their containers. */ protected void buildLayout() { getContent().setLayout(new BorderLayout()); getContent().add(renderer, BorderLayout.CENTER); // just a workaround - the canvas needs to know its size before the size of its container can be determined renderer.setSize(new Dimension(20, 20)); getContent().add(descLabel, BorderLayout.SOUTH); toolbar.add(zoomIn); toolbar.add(zoomOut); toolbar.add(fullscreenBtn); // MAGIC: If you set this property before the button is added to the toolbar, the border isn't the same after it // is added to it. On the second look, it seems to be evident - toolbar buttons look differently than regular // butons. defaultToolbarButtonBorder = zoomIn.getBorder(); getOverlay().setLayout(new FormLayout("right:pref:grow", "pref")); getOverlay().add(toolbar, new CellConstraints(1, 1)); } public StepRendererWithControls(Origami o) { this(); setOrigami(o); } /** * @return the origami */ public Origami getOrigami() { return renderer.getOrigami(); } /** * @param origami the origami to set */ public void setOrigami(Origami origami) { renderer.setOrigami(origami); if (origami != null) setBackground(origami.getPaper().getBackgroundColor()); else setBackground(Color.GRAY); } /** * @return the step */ public Step getStep() { return renderer.getStep(); } /** * @param step the step to set * @param afterSetCallback The callback to call after the step is changed. Will be run outside EDT. * @param exceptionCallback The callback to call if the setting thread encounters an * {@link InvalidOperationException}. Will be run outside EDT. */ public void setStep(final Step step, final Runnable afterSetCallback, final ParametrizedCallable<?, ? super Exception> exceptionCallback) { renderer.setStep(step, afterSetCallback, exceptionCallback); updateText(); } /** * Reload the description of the step. */ protected void updateText() { if (getStep() != null) { descLabel.setText(getStep().getDescriptionWithId( ServiceLocator.get(ConfigurationManager.class).get().getDiagramLocale())); } else { descLabel.setText(""); } } /** * @return the toolbar The toolbar used for this renderer to control the display of the step. */ public JToolBar getToolbar() { return toolbar; } /** * @return The mode to display this renderer in. */ public DisplayMode getDisplayMode() { return displayMode; } /** * @param displayMode The mode to display this renderer in. */ public void setDisplayMode(DisplayMode displayMode) { this.displayMode = displayMode; if (DisplayMode.PAGE.equals(displayMode)) { toolbar.setOpaque(false); toolbar.setBackgroundImage(null); toolbar.setVisible(true); fullscreenBtn.setVisible(true); Border emptyBorder = BorderFactory.createEmptyBorder(); for (Component c : toolbar.getComponents()) { if (c instanceof JComponent) { ((JComponent) c).setBorder(emptyBorder); } } } else { toolbar.setVisible(false); toolbar.setOpaque(true); toolbar.setBackgroundImage(new BackgroundImageSupport(getClass().getResource( "/resources/images/tooltip-bg.png"), toolbar, 0, 0, BackgroundRepeat.REPEAT_X)); fullscreenBtn.setVisible(false); for (Component c : toolbar.getComponents()) { if (c instanceof JComponent) { ((JComponent) c).setBorder(defaultToolbarButtonBorder); } } } } /** * @return the zoom */ public double getZoom() { return renderer.getZoom(); } /** * @param zoom the zoom to set */ public void setZoom(double zoom) { renderer.setZoom(zoom); } /** * Increase zoom by 10%. */ public void incZoom() { renderer.incZoom(); } /** * Decrease zoom by 10%. */ public void decZoom() { renderer.decZoom(); } /** * @return The renderer. */ public StepRenderer getRenderer() { return renderer; } /** * Show this step in DIAGRAM mode. * * @author Martin Pecka */ class FullscreenAction extends AbstractAction { /** */ private static final long serialVersionUID = -2874524093660872372L; @Override public void actionPerformed(ActionEvent e) { StepRendererWithControls.this.firePropertyChange("fullscreenModeRequested", false, true); } } /** * Zooms the step by 10% in. * * @author Martin Pecka */ class ZoomInAction extends AbstractAction { /** */ private static final long serialVersionUID = -8216187646844261072L; @Override public void actionPerformed(ActionEvent e) { incZoom(); } } /** * Zooms the step by 10% out. * * @author Martin Pecka */ class ZoomOutAction extends AbstractAction { /** */ private static final long serialVersionUID = -4073236265184373224L; @Override public void actionPerformed(ActionEvent e) { decZoom(); } } /** * Mouse event handling. * * @author Martin Pecka */ class MouseListener extends MouseAdapter { @Override public void mouseClicked(MouseEvent e) { if (displayMode.equals(DisplayMode.PAGE) && e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() > 1) { new FullscreenAction().actionPerformed(new ActionEvent(StepRendererWithControls.this, ActionEvent.ACTION_LAST, "fullscreen")); } } } }