/******************************************************************************** * * * (c) Copyright 2010 Verizon Communications USA and The Open University UK * * * * This software is freely distributed in accordance with * * the GNU Lesser General Public (LGPL) license, version 3 or later * * as published by the Free Software Foundation. * * For details see LGPL: http://www.fsf.org/licensing/licenses/lgpl.html * * and GPL: http://www.fsf.org/licensing/licenses/gpl-3.0.html * * * * This software is provided by the copyright holders and contributors "as is" * * and any express or implied warranties, including, but not limited to, the * * implied warranties of merchantability and fitness for a particular purpose * * are disclaimed. In no event shall the copyright owner or contributors be * * liable for any direct, indirect, incidental, special, exemplary, or * * consequential damages (including, but not limited to, procurement of * * substitute goods or services; loss of use, data, or profits; or business * * interruption) however caused and on any theory of liability, whether in * * contract, strict liability, or tort (including negligence or otherwise) * * arising in any way out of the use of this software, even if advised of the * * possibility of such damage. * * * ********************************************************************************/ package com.compendium.ui.movie; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Font; import java.awt.Point; import java.awt.dnd.DropTargetDropEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.sql.SQLException; import java.util.Vector; import java.util.concurrent.TimeUnit; import javax.media.Player; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.UIDefaults; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.compendium.LanguageProperties; import com.compendium.ProjectCompendium; import com.compendium.core.datamodel.ModelSessionException; import com.compendium.core.datamodel.Movie; import com.compendium.core.datamodel.MovieMapView; import com.compendium.core.datamodel.MovieProperties; import com.compendium.core.datamodel.View; import com.compendium.ui.UINode; import com.compendium.ui.UIViewFrame; import com.compendium.ui.UIViewPane; import com.compendium.ui.plaf.ViewPaneUI; /** * This class is the main class that draws and handles Compendium planner maps and their events. * * @author Michelle Bachler */ public class UIMovieMapViewPane extends UIViewPane implements PropertyChangeListener { static final Logger log = LoggerFactory.getLogger(UIMovieMapViewPane.class); /** uinode added property for use with property change events */ public final static String UINODE_ADDED = "uinodeadded"; //$NON-NLS-1$ /** uinode added property for use with property change events */ public final static String UINODE_REMOVED = "uinoderemoved"; //$NON-NLS-1$ /** uinode added property for use with property change events */ public final static String UIMOVIE_ADDED = "uimovieadded"; //$NON-NLS-1$ /** uinode added property for use with property change events */ public final static String UIMOVIE_REMOVED = "uimovieremoved"; //$NON-NLS-1$ /** A reference to the layer to hold a movie. */ public final static Integer MOVIE_LAYER = new Integer(240); /** Holds the list of all movies in this pane.*/ private Vector<UIMoviePanel> vtMovies = new Vector<UIMoviePanel>(51); /** The hint label displayed when there are no movies added.*/ private JLabel oHint = null; /** * Constructor. Creates and initializes a new instance of UIViewPane. * @param view the view holding the data for this pane to display. * @param viewFrame the parent frame containing this view pane */ public UIMovieMapViewPane(View view, UIViewFrame viewframe) { super(view, viewframe); oHint = new JLabel(LanguageProperties.getString(LanguageProperties.MOVIE_BUNDLE, "UIMovieMapViewPane.movieHint")); //$NON-NLS-1$ oHint.setFont(new Font("Dialog", Font.BOLD, 20)); //$NON-NLS-1$ oHint.setForeground(Color.gray); oHint.setLocation(30,30); oHint.setSize(oHint.getPreferredSize()); oHint.setVisible(false); add(oHint, MOVIE_LAYER); checkToolTip(); } /** * Check if the passed movie has a path and then process according to type. * @param movie the Movie data object to process. * @return A movie panel */ public UIMoviePanel processMovie(Movie movie) { String sLink = movie.getLink(); UIMoviePanel panel = null; if (!sLink.equals("")) { //$NON-NLS-1$ if (sLink.indexOf(".") != -1) { //UIImages.isMovie(sLink)) { //$NON-NLS-1$ panel = addMovie(movie); } else if (sLink.indexOf(".") == -1) { //$NON-NLS-1$ //treat it as a stream panel = addGridMovie(movie); } } else { ProjectCompendium.APP.displayError(LanguageProperties.getString(LanguageProperties.MOVIE_BUNDLE, "UIMovieMapViewPane.errorEmptyPath")); //$NON-NLS-1$ } if (panel != null) { panel.setName(sLink); } return panel; } /** * Add a background movie for this view from a grid stream. * * @param movie the Movie to add. */ public UIMoviePanel addGridMovie(Movie movie) { String sMoviePath = movie.getLink(); UIMoviePanel oMoviePanel = null; try { oMoviePanel = new UIMoviePanel(movie, (MovieMapView)oView, this); Player player = oMoviePanel.createGridStreamPlayer(sMoviePath, 0, 1.0); if (player != null) { vtMovies.addElement(oMoviePanel); Dimension pref = oMoviePanel.getPreferredSize(); int width = pref.width; int height = pref.height; MovieMapView oMovieMapView = (MovieMapView)oView; MovieProperties props = movie.getStartingProperties(); if (props != null) { width = props.getWidth(); height = props.getHeight(); if (width <= 0 && height <= 0) { oMovieMapView.updateMovieProperties(props.getId(), props.getMovieID(), props.getXPos(), props.getYPos(), pref.width, pref.height, props.getTransparency(), props.getTime()); width = pref.width; height = pref.height; } } oMoviePanel.setSize(new Dimension(width, height)); oMoviePanel.setLocation(props.getXPos(), props.getYPos()); oMoviePanel.setVisible(true); add(oMoviePanel, MOVIE_LAYER); this.setPosition(oMoviePanel, 0); firePropertyChange(UIMOVIE_ADDED, null, oMoviePanel); } else { oMoviePanel = null; // If the movie failed to load, delete the movie from the database. MovieMapView oMovieMapView = (MovieMapView)oView; oMovieMapView.deleteMovie(movie.getId()); } } catch (ModelSessionException se) { ProjectCompendium.APP.displayError(LanguageProperties.getString(LanguageProperties.MOVIE_BUNDLE, "UIMovieMapViewPane.errorUpdatingProperties")+"\n\n"+ se.getLocalizedMessage()); //$NON-NLS-1$ } catch (SQLException sql) { ProjectCompendium.APP.displayError(LanguageProperties.getString(LanguageProperties.MOVIE_BUNDLE, "UIMovieMapViewPane.errorUpdatingProperties")+"\n\n"+ sql.getLocalizedMessage()); //$NON-NLS-1$ } catch(Exception e) { log.error("Error...", e); System.out.flush(); } checkToolTip(); return oMoviePanel; } /** * Add a background movie for this view. * * @param movie the Movie to add. */ public UIMoviePanel addMovie(Movie movie) { String sMoviePath = movie.getLink(); UIMoviePanel oMoviePanel = null; try { oMoviePanel = new UIMoviePanel(movie,(MovieMapView)oView, this); Player player = oMoviePanel.createMoviePlayer(sMoviePath); if (player != null) { vtMovies.addElement(oMoviePanel); Dimension pref = oMoviePanel.getPreferredSize(); int width = pref.width; int height = pref.height; MovieMapView oMovieMapView = (MovieMapView)oView; MovieProperties props = movie.getStartingProperties(); int x=0; int y=0; if (props != null) { x = props.getXPos(); y = props.getYPos(); width = props.getWidth(); height = props.getHeight(); if (width <= 0 && height <= 0) { oMovieMapView.updateMovieProperties(props.getId(), props.getMovieID(), props.getXPos(), props.getYPos(), pref.width, pref.height, props.getTransparency(), props.getTime()); width = pref.width; height = pref.height; } } oMoviePanel.setSize(new Dimension(width, height)); oMoviePanel.setLocation(x, y); oMoviePanel.setVisible(true); add(oMoviePanel, MOVIE_LAYER); this.setPosition(oMoviePanel, 0); firePropertyChange(UIMOVIE_ADDED, null, oMoviePanel); } else { oMoviePanel = null; // If the movie failed to load, delete the movie from the database. MovieMapView oMovieMapView = (MovieMapView)oView; oMovieMapView.deleteMovie(movie.getId()); } } catch (ModelSessionException se) { ProjectCompendium.APP.displayError(LanguageProperties.getString(LanguageProperties.MOVIE_BUNDLE, "UIMovieMapViewPane.errorUpdatingProperties")+"\n\n"+ se.getLocalizedMessage()); //$NON-NLS-1$ } catch (SQLException sql) { ProjectCompendium.APP.displayError(LanguageProperties.getString(LanguageProperties.MOVIE_BUNDLE, "UIMovieMapViewPane.errorUpdatingProperties")+"\n\n"+ sql.getLocalizedMessage()); //$NON-NLS-1$ } catch(Exception e) { log.error("Error...", e); System.out.flush(); } checkToolTip(); return oMoviePanel; } /** * Remove a background movie for this view. * * @param movie the Movie to remove. */ public void removeMovie(String id) { if (vtMovies.size() > 0) { int count = vtMovies.size(); for (int i =0; i<count; i++) { UIMoviePanel next = vtMovies.elementAt(i); if (next != null && next.getMovieData().getId().equals(id)) { next.getMediaPlayer().close(); vtMovies.remove(next); remove(next); firePropertyChange(UIMOVIE_REMOVED, null, next); break; } } } checkToolTip(); } /** * Stop any running movies and close them */ public void closeMovies() { if (vtMovies.size() > 0) { int count = vtMovies.size(); for (int i =0; i<count; i++) { UIMoviePanel oMoviePanel = vtMovies.elementAt(i); if (oMoviePanel != null) { oMoviePanel.stop(); oMoviePanel.getMediaPlayer().close(); oMoviePanel.clean(); } } } } /** * Stop any running movies */ public void stopMovies() { if (vtMovies.size() > 0) { int count = vtMovies.size(); for (int i =0; i<count; i++) { UIMoviePanel oMoviePanel = vtMovies.elementAt(i); if (oMoviePanel != null) { oMoviePanel.stop(); } } } } /** * Start any running movies */ public void startMovies() { if (vtMovies.size() > 0) { int count = vtMovies.size(); for (int i =0; i<count; i++) { UIMoviePanel oMoviePanel = vtMovies.elementAt(i); if (oMoviePanel != null) { oMoviePanel.start(); } } } } /** * Reset movies to start */ public void resetMovies() { if (vtMovies.size() > 0) { int count = vtMovies.size(); for (int i =0; i<count; i++) { UIMoviePanel oMoviePanel = vtMovies.elementAt(i); if (oMoviePanel != null) { oMoviePanel.reset(); } } } } /** * Return all the movie panels. * @return all the movie panels. */ public Vector<UIMoviePanel> getMovies() { return vtMovies; } /** * Return the movie panel for the given id. * @param id the id of the movie whose panel to return * @return the movie panel for the given id or null if not found. */ public UIMoviePanel getMovie(String id) { UIMoviePanel oMoviePanel = null; if (vtMovies.size() > 0) { int count = vtMovies.size(); for (int i =0; i<count; i++) { UIMoviePanel next = vtMovies.elementAt(i); if (next != null && next.getMovieData().getId().equals(id)) { oMoviePanel = next; break; } } } return oMoviePanel; } /** * Return the movie duration in milliseconds for the given id. * @param id the id of the movie whose duration to return * @return the movie duration in milliseconds for the given id or 0 if not found. */ public long getDuration(String id) { long duration = 0; UIMoviePanel oMoviePanel = null; if (vtMovies.size() > 0) { int count = vtMovies.size(); for (int i =0; i<count; i++) { UIMoviePanel next = vtMovies.elementAt(i); if (next != null && next.getMovieData().getId().equals(id)) { duration = next.getDuration().getNanoseconds(); duration = TimeUnit.NANOSECONDS.toMillis(duration); break; } } } return duration; } /** * Listen for the MovieMapView having movie change events add/delete/change */ public void propertyChange(PropertyChangeEvent evt) { String prop = evt.getPropertyName(); Object source = evt.getSource(); Object newvalue = evt.getNewValue(); if (source instanceof MovieMapView) { if (prop.equals(MovieMapView.MOVIEPROPERTIES_CHANGED_PROPERTY)) { MovieProperties props = (MovieProperties)newvalue; UIMoviePanel moviepanel = getMovie(props.getMovieID()); if (moviepanel != null) { MovieProperties currentProps = moviepanel.getCurrentProperties(); if (currentProps.getId().equals(props.getId())) { moviepanel.setCurrentProperties(props); } } } if (prop.equals(MovieMapView.MOVIE_CHANGED_PROPERTY)) { Movie movie = (Movie)newvalue; UIMoviePanel moviepanel = getMovie(movie.getId()); if (moviepanel != null) { Movie currentMovie = moviepanel.getMovieData(); moviepanel.setMovieData(movie); // If a movie link has changed, update the panel completely. if (!currentMovie.getLink().equals(movie.getLink())) { removeMovie(movie.getId()); processMovie(movie); } } } else if (prop.equals(MovieMapView.MOVIE_ADDED_PROPERTY)) { Movie movie = (Movie)newvalue; processMovie(movie); } else if (prop.equals(MovieMapView.MOVIE_REMOVED_PROPERTY)) { String sMovieID = (String)newvalue; removeMovie(sMovieID); } } else { super.propertyChange(evt); } } /** * If there are no movie and no nodes add a tooltip to the viewpane to instruct user. */ private void checkToolTip() { Component[] nodes = getComponentsInLayer((NODE_LAYER).intValue()); if (vtMovies != null && vtMovies.size() == 0 && nodes.length == 0) { showHint(); } else { hideHint(); } } public void showHint() { if (oHint != null) { oHint.setVisible(true); } } public void hideHint() { if (oHint != null) { oHint.setVisible(false); } } /** * Adds a component to this view. Override to fire an event * * @param c the component to be added. * @param constraints an object expressing layout constraints for this component. * @see java.awt.LayoutManager */ public void add(Component c, Object constraints) { UINode oldnode = null; UINode node = null; if (c instanceof UINode) { node = (UINode)c; oldnode = (UINode)get(node.getNode().getId()); } super.add(c, constraints); if (c instanceof UINode && oldnode == null) { checkToolTip(); firePropertyChange(UINODE_ADDED, oldnode, node); } } /** * Removes a component from this view. Override to fire an event * * @param c the component to be removed * @see java.awt.LayoutManager */ public void remove(Component c) { super.remove(c); if (c instanceof UINode) { checkToolTip(); firePropertyChange(UINODE_REMOVED, null, (UINode)c); } } /** * Create and display an instance of the right-click popup menu for this view. * @param viewpaneui the ui object for this view required as a parameter for the popup. * @param x the x position of the trigger event for this request. Used to calculate the popup x position. * @param y the y position of the trigger event for this request. Used to calculate the popup y position. */ public void showPopupMenu(ViewPaneUI viewpaneui, int x, int y) { viewPopup = new UIMovieMapViewPopupMenu("View Popup menu", viewpaneui); //$NON-NLS-1$ UIViewFrame viewFrame = oViewFrame; Dimension dim = ProjectCompendium.APP.getScreenSize(); int screenWidth = dim.width - 70; //to accomodate for the scrollbar int screenHeight = dim.height-120; //to accomodate for the menubar... Point point = getViewFrame().getViewPosition(); int realX = Math.abs(point.x - x)+20; int realY = Math.abs(point.y - y)+20; int endXCoordForPopUpMenu = realX + viewPopup.getWidth(); int endYCoordForPopUpMenu = realY + viewPopup.getHeight(); int offsetX = (screenWidth) - endXCoordForPopUpMenu; int offsetY = (screenHeight) - endYCoordForPopUpMenu; if(offsetX > 0) offsetX = 0; if(offsetY > 0) offsetY = 0; viewPopup.setCoordinates(realX+offsetX, realY+offsetY); viewPopup.setViewPane(this); viewPopup.show(viewFrame,realX+offsetX, realY+offsetY); } /** * Create and display an instance of the right-click popup menu for this view. * @param viewpaneui the ui object for this view required as a parameter for the popup. * @param x the x position of the trigger event for this request. Used to calculate the popup x position. * @param y the y position of the trigger event for this request. Used to calculate the popup y position. * @param UIMoviePanel the movie the user was over when they opened the menu. */ public void showPopupMenu(ViewPaneUI viewpaneui, int x, int y, UIMoviePanel movie) { viewPopup = new UIMovieMapViewPopupMenu("View Popup menu", viewpaneui, movie); //$NON-NLS-1$ UIViewFrame viewFrame = oViewFrame; Dimension dim = ProjectCompendium.APP.getScreenSize(); int screenWidth = dim.width - 70; //to accomodate for the scrollbar int screenHeight = dim.height-120; //to accomodate for the menubar... Point point = getViewFrame().getViewPosition(); int realX = Math.abs(point.x - x)+20; int realY = Math.abs(point.y - y)+20; int endXCoordForPopUpMenu = realX + viewPopup.getWidth(); int endYCoordForPopUpMenu = realY + viewPopup.getHeight(); int offsetX = (screenWidth) - endXCoordForPopUpMenu; int offsetY = (screenHeight) - endYCoordForPopUpMenu; if(offsetX > 0) offsetX = 0; if(offsetY > 0) offsetY = 0; viewPopup.setCoordinates(realX+offsetX, realY+offsetY); viewPopup.setViewPane(this); viewPopup.show(viewFrame,realX+offsetX, realY+offsetY); } // DRAG AND DROP STUFF /** * Override to stop movie before processing drop. * @param e the <code>DropTargetDropEvent</code> */ public void drop(DropTargetDropEvent e) { ((UIMovieMapViewFrame)oViewFrame).stopTimeLine(); super.drop(e); } // UI METHODS /** * Returns the L&F object that renders this component. * * @return ViewPaneUI, the object that renders this component. */ public MovieMapViewPaneUI getUI() { return (MovieMapViewPaneUI)oViewPaneUI; } /** * Sets the L&F object that renders this component. * <p>CURRENTLY DOES NOTHING</p> * @param ui, the MovieMapViewPaneUI L&F object. */ public void setUI(ViewPaneUI ui) { // if ((ViewPaneUI)this.ui != ui) { // super.setUI(ui); // repaint(); // } } /** * Notification from the UIManager that the L&F has changed. * Replaces the current UI object with the latest version from the * UIManager. * * @see JComponent#updateUI */ public void updateUI() { oViewPaneUI = new MovieMapViewPaneUI(this); invalidate(); } /** * Returns the name of the L&F class that renders this component. * * @return "MovieMapViewPaneUI" * @see JComponent#getUIClassID * @see UIDefaults#getUI */ public String getUIClassID() { return "MovieMapViewPaneUI"; //$NON-NLS-1$ } /** * Clean up the components and variables used by this class to help with garbage collection. */ public void cleanUp() { super.cleanUp(); ((UIMovieMapViewFrame)oViewFrame).stopTimeLine(); } }