/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jpa.tools.swing; import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.lang.ref.WeakReference; import java.net.URL; import java.util.ArrayList; import java.util.List; import javax.swing.Box; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSpinner; import javax.swing.SpinnerNumberModel; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import openbook.client.Images; /** * Displays and navigates PowerPoint slides. * * @author Pinaki Poddar * */ @SuppressWarnings("serial") public class PowerPointViewer extends JPanel { private List<WeakReference<ImageIcon>> _slides = new ArrayList<WeakReference<ImageIcon>>(); private int _total; // Total number of slides in the deck. private String _dir; private List<URL> _slideURLs; private JButton _prev, _next; private JSpinner _goto; private JButton[] _navButtons; private int MAX_BUTTONS = 10; // Total number of navigation buttons excluding the PREVIOUS and NEXT button. // The slide private JLabel _view; // The key for client property in the navigation buttons denoting the 0-based index of the slides. private static final String SLIDE_INDEX = "slide.index"; /** * Create a viewer with slides in the specified directory. * * @param dir path to a directory containing PowerPoint slides. * @param slides name of the slides */ public PowerPointViewer(String dir, List<String> slides) { super(true); _dir = dir.endsWith("/") ? dir : dir + "/"; _slideURLs = validateSlides(_dir, slides); _total = _slideURLs.size(); for (int i = 0; i < _total; i++) { _slides.add(null); } setLayout(new BorderLayout()); _view = new JLabel(getSlideAt(0)); add(new JScrollPane(_view), BorderLayout.CENTER); add(createNavigationButtons(), BorderLayout.SOUTH); } /** * Create buttons to navigate the slides. * * @return a panel containing the navigation buttons. */ private JPanel createNavigationButtons() { JPanel buttons = new JPanel(); _navButtons = new JButton[Math.min(MAX_BUTTONS, _total)]; _prev = new RoundButton(Images.BACK); buttons.add(_prev); _prev.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { prevPage(); } }); buttons.add(Box.createHorizontalGlue()); for (int i = 0; i < _navButtons.length; i++) { if (i == _navButtons.length/2) { JLabel gotoLabel = new JLabel("Go to "); _goto = new JSpinner(new SpinnerNumberModel(1,1,_total,1)); buttons.add(gotoLabel); buttons.add(_goto); _goto.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { Integer page = (Integer)_goto.getValue(); showPage(page-1); } }); } int slideIndex = i + 2; _navButtons[i] = new JButton(String.format("%02d", slideIndex)); buttons.add(_navButtons[i]); _navButtons[i].putClientProperty(SLIDE_INDEX, i+1); _navButtons[i].addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { JButton button = (JButton)e.getSource(); int index = (Integer)button.getClientProperty(SLIDE_INDEX); showPage(index); } }); } _next = new RoundButton(Images.NEXT); buttons.add(Box.createHorizontalGlue()); buttons.add(_next); _next.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { nextPage(); } }); return buttons; } /** * Show the next page. */ private void nextPage() { int current = getCurrentPageIndex(); if (current >= _total-1) return; current += 1; showPage(current); } private void prevPage() { int current = getCurrentPageIndex(); if (current <= 0) return; current -= 1; showPage(current); } int getCurrentPageIndex() { return (Integer)_goto.getValue()-1; } /** * Shows the slide at the given index. * * @param index 0-based index of the slides. */ private void showPage(int index) { _view.setIcon(getSlideAt(index)); updateButtons(index); } /** * Updates the buttons. * * @param current 0-based index of the currently displayed slide. */ private void updateButtons(int index) { _goto.setValue(index+1); int last = index + _navButtons.length; if (last >= _total) return; for (int i = 0; i < _navButtons.length; i++) { int slideIndex = index+i+2; _navButtons[i].setText(String.format("%02d", slideIndex)); _navButtons[i].putClientProperty(SLIDE_INDEX, (index+i+1)); } } public int getSlideCount() { return _total; } public ImageIcon getSlideAt(int index) { WeakReference<ImageIcon> weak = _slides.get(index); if (weak == null) { return loadSlide(index); } return (weak.get() == null) ? loadSlide(index) : weak.get(); } ImageIcon loadSlide(int index) { URL imgURL = _slideURLs.get(index); ImageIcon icon = new ImageIcon(imgURL); _slides.add(index, new WeakReference<ImageIcon>(icon)); return icon; } List<URL> validateSlides(String dir, List<String> slides) { List<URL> valid = new ArrayList<URL>(); for (String slide : slides) { URL url = findResource(dir + slide); if (url != null) { valid.add(url); } } return valid; } private URL findResource(String path) { if (path == null) return null; URL imgURL = Thread.currentThread().getContextClassLoader().getResource(path); if (imgURL == null) { imgURL = getClass().getResource(path); if (imgURL == null) { System.err.println("Couldn't find file: " + path); return null; } } return imgURL; } }