001/** 002 * Copyright (c) 2011, The University of Southampton and the individual contributors. 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without modification, 006 * are permitted provided that the following conditions are met: 007 * 008 * * Redistributions of source code must retain the above copyright notice, 009 * this list of conditions and the following disclaimer. 010 * 011 * * Redistributions in binary form must reproduce the above copyright notice, 012 * this list of conditions and the following disclaimer in the documentation 013 * and/or other materials provided with the distribution. 014 * 015 * * Neither the name of the University of Southampton nor the names of its 016 * contributors may be used to endorse or promote products derived from this 017 * software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030package org.openimaj.content.slideshow; 031 032import java.awt.BorderLayout; 033import java.awt.Color; 034import java.awt.Component; 035import java.awt.Dimension; 036import java.awt.Graphics; 037import java.awt.Graphics2D; 038import java.awt.GridBagConstraints; 039import java.awt.GridBagLayout; 040import java.awt.event.KeyEvent; 041import java.awt.event.KeyListener; 042import java.awt.event.MouseAdapter; 043import java.awt.event.MouseEvent; 044import java.awt.image.BufferedImage; 045import java.io.IOException; 046import java.util.List; 047 048import javax.swing.JPanel; 049import javax.swing.JScrollPane; 050import javax.swing.RootPaneContainer; 051import javax.swing.UIManager; 052 053/** 054 * Implementation of a slideshow made up of {@link Slide}s. Binds the left and 055 * right arrow keys to forward/backward, 'q' to quit and 'f' to toggle 056 * fullscreen mode. If the current slide being displayed is also a 057 * {@link KeyListener} then keypresses other than these will be passed to the 058 * slide. 059 * 060 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 061 * 062 */ 063public abstract class Slideshow implements KeyListener { 064 protected RootPaneContainer container; 065 066 protected List<Slide> slides; 067 protected int currentSlideIndex = -1; 068 protected Component currentSlideComp; 069 070 protected int slideWidth; 071 protected int slideHeight; 072 073 protected Slide currentSlide; 074 075 private JPanel contentPanel; 076 077 private boolean hidden = false; 078 079 /** 080 * Default constructor. 081 * 082 * @param container 083 * the root window 084 * @param slides 085 * the slides 086 * @param slideWidth 087 * the width to display the slides 088 * @param slideHeight 089 * the height to display the slides 090 * @param background 091 * a background image to display behind the slides (the slides need 092 * to be transparent!) 093 * @throws IOException 094 * if the first slide can't be loaded 095 */ 096 public Slideshow(RootPaneContainer container, List<Slide> slides, final int slideWidth, final int slideHeight, 097 BufferedImage background) 098 throws IOException 099 { 100 this.container = container; 101 102 this.slideWidth = slideWidth; 103 this.slideHeight = slideHeight; 104 105 final BufferedImage bg; 106 if (background == null) { 107 bg = new BufferedImage(slideWidth, slideHeight, BufferedImage.TYPE_3BYTE_BGR); 108 final Graphics2D g = bg.createGraphics(); 109 g.setColor(UIManager.getColor("Panel.background")); 110 g.fillRect(0, 0, bg.getWidth(), bg.getHeight()); 111 } else { 112 bg = background; 113 } 114 115 contentPanel = new JPanel() { 116 private static final long serialVersionUID = 1L; 117 118 @Override 119 public void paintComponent(Graphics g) { 120 super.paintComponent(g); 121 g.drawImage(bg, 0, 0, slideWidth, slideHeight, null); 122 }; 123 124 @Override 125 public void paint(Graphics g) { 126 if (!hidden) 127 super.paint(g); 128 } 129 }; 130 contentPanel.setOpaque(false); 131 contentPanel.setSize(slideWidth, slideHeight); 132 contentPanel.setPreferredSize(new Dimension(slideWidth, slideHeight)); 133 contentPanel.setLayout(new GridBagLayout()); 134 135 final JPanel scrollContent = new JPanel(); 136 scrollContent.setLayout(new GridBagLayout()); 137 scrollContent.setSize(contentPanel.getSize()); 138 scrollContent.setPreferredSize(contentPanel.getSize()); 139 scrollContent.add(contentPanel); 140 scrollContent.setBackground(Color.BLACK); 141 142 container.getContentPane().setBackground(Color.BLACK); 143 144 final JScrollPane scroller = new JScrollPane(scrollContent); 145 scroller.setBackground(Color.BLACK); 146 scroller.setBorder(null); 147 container.getContentPane().add(scroller, BorderLayout.CENTER); 148 149 ((Component) container).addKeyListener(this); 150 151 this.slides = slides; 152 153 displayNextSlide(); 154 pack(); 155 156 ((Component) container).setVisible(true); 157 } 158 159 protected abstract void pack(); 160 161 /** 162 * Display the next slide 163 * 164 * @throws IOException 165 */ 166 public void displayNextSlide() throws IOException { 167 if (currentSlideIndex < slides.size() - 1) { 168 currentSlideIndex++; 169 displaySlide(slides.get(currentSlideIndex)); 170 } 171 } 172 173 /** 174 * Display the previous slide 175 * 176 * @throws IOException 177 */ 178 public void displayPrevSlide() throws IOException { 179 if (currentSlideIndex > 0) { 180 currentSlideIndex--; 181 displaySlide(slides.get(currentSlideIndex)); 182 } 183 } 184 185 protected void displaySlide(Slide slide) throws IOException { 186 if (currentSlideComp != null) { 187 contentPanel.remove(currentSlideComp); 188 currentSlide.close(); 189 } 190 191 currentSlide = slide; 192 currentSlideComp = currentSlide.getComponent(slideWidth, slideHeight); 193 currentSlideComp.setPreferredSize(new Dimension(slideWidth, slideHeight)); 194 currentSlideComp.setMaximumSize(new Dimension(slideWidth, slideHeight)); 195 196 contentPanel.add(currentSlideComp, new GridBagConstraints()); 197 198 currentSlideComp.setFocusable(true); 199 currentSlideComp.requestFocus(); 200 currentSlideComp.addKeyListener(this); 201 currentSlideComp.addMouseListener(new MouseAdapter() { 202 @Override 203 public void mouseClicked(MouseEvent e) { 204 currentSlideComp.requestFocus(); 205 } 206 }); 207 208 contentPanel.validate(); 209 ((Component) container).repaint(); 210 } 211 212 @Override 213 public void keyTyped(KeyEvent e) { 214 if (currentSlide instanceof KeyListener) { 215 ((KeyListener) currentSlide).keyTyped(e); 216 } 217 } 218 219 @Override 220 public void keyPressed(KeyEvent e) { 221 try { 222 switch (e.getKeyCode()) { 223 case KeyEvent.VK_LEFT: 224 if (!hidden) 225 displayPrevSlide(); 226 break; 227 case KeyEvent.VK_PAGE_UP: 228 if (!hidden) 229 displayPrevSlide(); 230 break; 231 case KeyEvent.VK_UP: 232 if (!hidden) 233 displayPrevSlide(); 234 break; 235 case KeyEvent.VK_RIGHT: 236 if (!hidden) 237 displayNextSlide(); 238 break; 239 case KeyEvent.VK_PAGE_DOWN: 240 if (!hidden) 241 displayNextSlide(); 242 break; 243 case KeyEvent.VK_DOWN: 244 if (!hidden) 245 displayNextSlide(); 246 break; 247 case KeyEvent.VK_F: 248 toggleFullscreen(); 249 break; 250 case KeyEvent.VK_F5: 251 if (e.isShiftDown()) 252 toggleFullscreen(); 253 break; 254 case KeyEvent.VK_ESCAPE: 255 setFullscreen(false); 256 break; 257 case KeyEvent.VK_B: 258 System.out.println(this.hidden); 259 if (!e.isShiftDown()) { 260 this.hidden = !this.hidden; 261 this.contentPanel.repaint(); 262 } 263 break; 264 case KeyEvent.VK_Q: 265 System.exit(0); 266 } 267 } catch (final Exception ex) { 268 ex.printStackTrace(); 269 } 270 271 if (currentSlide instanceof KeyListener) { 272 ((KeyListener) currentSlide).keyPressed(e); 273 } 274 } 275 276 private void toggleFullscreen() { 277 setFullscreen(!isFullscreen()); 278 } 279 280 protected abstract boolean isFullscreen(); 281 282 /** 283 * Method allows changing whether this window is displayed in fullscreen or 284 * windowed mode. 285 * 286 * @param fullscreen 287 * true = change to fullscreen, false = change to windowed 288 */ 289 public abstract void setFullscreen(boolean fullscreen); 290 291 @Override 292 public void keyReleased(KeyEvent e) { 293 if (currentSlide instanceof KeyListener) { 294 ((KeyListener) currentSlide).keyReleased(e); 295 } 296 } 297}