/******************************************************************************** * * * (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.Cursor; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.Enumeration; import java.util.Hashtable; import java.util.Vector; import java.util.concurrent.TimeUnit; import javax.media.Controller; import javax.media.ControllerEvent; import javax.media.ControllerListener; import javax.media.MediaTimeSetEvent; import javax.media.Player; import javax.media.Time; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.SwingUtilities; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.compendium.ProjectCompendium; import com.compendium.core.datamodel.Movie; import com.compendium.core.datamodel.MovieMapView; import com.compendium.core.datamodel.MovieProperties; import com.compendium.ui.UIImages; import com.sun.media.util.MediaThread; public class UITimeLineForMovie extends JComponent implements MouseListener, MouseMotionListener, ComponentListener, PropertyChangeListener, Runnable, ControllerListener { /** * class's own logger */ final Logger log = LoggerFactory.getLogger(getClass()); /** the colour of the time span elements.*/ private static final Color SPAN_COLOUR = Color.darkGray; /** the colour of the time span elements.*/ private static final Color SELECTED_SPAN_COLOUR = Color.yellow; int width; int leftBorder = 0; int rightBorder = 0; int sliderWidth; long pressedAt = 0; protected boolean justSeeked = false; protected boolean stopTimer = false; private MediaThread timer = null; private Integer localLock = new Integer(0); private boolean resetMediaTime = false; private MovieProperties currentProps = null; //private boolean onBar = false; private boolean onProps = false; private boolean onMovie = false; private boolean dragging = false; private Rectangle movieRectangle = null; ImageIcon iGrabberMiniYellow = null; ImageIcon iGrabberMini = null; ImageIcon iMiniGrabberMain = null; int miniGrabberWidth; int miniGrabberHeight; private UITimeLinesController controlPanel; private MasterTimer player; private MovieMapView oMovieMapView = null; //private UIMovieMapViewPane oViewPane = null; private UIMoviePanel oMoviePanel = null; private Movie oMovie = null; private UIMovieMapViewPane oMovieMapViewPane = null; private UIMovieTimeLinePopupMenu popup = null; private Hashtable<Rectangle, MovieProperties> htTimeProps = null; /** Holds the currently selected items in this timeline */ private Hashtable<String, Object> selectedItems = new Hashtable<String, Object>(); /** How many Milliseconds of a second that a screen pixel represents. */ private int pixel_time_scale = UITimeLinesController.DEFAULT_PIXEL_TIME_SCALE; public UITimeLineForMovie(UIMoviePanel m, UIMovieMapViewPane pane, MovieMapView view, UITimeLinesController cp, MasterTimer p) { this.oMovieMapViewPane = pane; this.oMoviePanel = m; this.oMovie = oMoviePanel.getMovieData(); this.controlPanel = cp; this.player = p; this.oMovieMapView = view; //this.oMovieMapView.addPropertyChangeListener(this); //this.addMouseListener( this ); //this.addMouseMotionListener( this ); //this.addComponentListener ( this ); //this.player.addControllerListener ( this ); this.iGrabberMini = new ImageIcon(UIImages.sPATH + "video-key-marker2.png"); //$NON-NLS-1$ this.iMiniGrabberMain = new ImageIcon(UIImages.sPATH + "grabbershortmain.gif"); //$NON-NLS-1$ this.miniGrabberWidth = iGrabberMini.getIconWidth(); this.miniGrabberHeight = iGrabberMini.getIconHeight(); this.iGrabberMiniYellow = new ImageIcon(UIImages.sPATH + "video-key-marker-yellow.png"); //$NON-NLS-1$ this.leftBorder = UITimeLinesController.TIMELINE_LEFT_OFFSET; this.rightBorder = controlPanel.rightBorder; this.sliderWidth = this.width - leftBorder - rightBorder; } /** * Set the new scale to use to draw this time line header, then redraw it. * @param scale the scale to use - in hundreths of a second per pixel. */ public void setScale(int scale) { this.pixel_time_scale = scale; setSize(controlPanel.timeline_length, getHeight()); setPreferredSize(new Dimension(controlPanel.timeline_length, getHeight())); repaint(); } //*********************** RUNNABLE RELATED STUFF ***************************/ public void addNotify() { super.addNotify(); timer = new MediaThread(this); timer.setName("UITimeLineForMovie thread"); //$NON-NLS-1$ timer.useControlPriority(); this.oMovieMapView.addPropertyChangeListener(this); this.addMouseListener( this ); this.addMouseMotionListener( this ); this.addComponentListener ( this ); this.player.addControllerListener ( this ); stopTimer = false; timer.start(); } // Cannot make removeNotify synchronized. It will deadlock // with other mouse event listeners. So we'll have to create // another lock to synchronize removeNotify and dispose. Object disposeLock = new Object(); Object syncStop = new Object(); public void removeNotify() { if (timer != null) { synchronized (syncStop) { stopTimer = true; timer = null; } } oMovieMapView.removePropertyChangeListener(this); removeComponentListener ( this ); removeMouseListener( this ); removeMouseMotionListener( this ); player.removeControllerListener ( this ); super.removeNotify(); } public synchronized void dispose() { synchronized (syncStop) { if (timer != null) { stopTimer = true; } } timer = null; } public void run() { int counter = 0; int pausecnt = -1; int sleepTime; boolean doUpdate = true; while (!stopTimer) { try { if ( player != null && player.getState() == Controller.Started) { doUpdate = true; pausecnt = -1; } else if (player != null && pausecnt < 5) { pausecnt ++; doUpdate = true; } else if ( resetMediaTime ) { doUpdate = true; resetMediaTime = false; } else { doUpdate = false; } try { if (doUpdate) { long nanoDuration = player.getDuration().getNanoseconds(); if (nanoDuration >= 0) { long nanoTime = player.getMediaTime().getNanoseconds(); long currentTimeMilliseconds = TimeUnit.NANOSECONDS.toMillis(nanoTime); setCurrentMovieProperties(currentTimeMilliseconds); } } } catch (Exception e) { } sleepTime = (isEnabled() ? 200 : 1000); try { Thread.sleep(sleepTime); } catch (Exception e) {} counter++; if (counter == 1000/sleepTime) { counter = 0; } if (justSeeked) { justSeeked = false; try { Thread.sleep(1000); } catch (Exception e) {} } } catch (Exception e) {} } } public synchronized void controllerUpdate ( ControllerEvent event ) { synchronized (localLock) { if (player == null) return; if (event instanceof MediaTimeSetEvent) { Thread.yield (); resetMediaTime = true; } } } //*********************** PROPERTY CHANGE LISTENER *************************/ /** * Handles property change events for the TimeMapView else calls super. * @param evt, the associated PropertyChangeEvent object. */ public void propertyChange(PropertyChangeEvent evt) { final String prop = evt.getPropertyName(); final Object source = evt.getSource(); //Object oldvalue = evt.getOldValue(); final Object newvalue = evt.getNewValue(); //Tried to add this thread to help repaint glitch when transition point removed. Thread thread = new Thread("UITimeLineForMovie") { //$NON-NLS-1$ public void run() { if (source instanceof MovieMapView) { if (prop.equals(MovieMapView.MOVIEPROPERTIES_ADDED_PROPERTY) || prop.equals(MovieMapView.MOVIEPROPERTIES_CHANGED_PROPERTY)) { MovieProperties props = (MovieProperties)newvalue; long newPoint = props.getTime()/pixel_time_scale; if (newPoint > sliderWidth) { controlPanel.recalculateRequiredTimeline(); } //If an update happens while a selection is in place // update the object in the selectedItems list. if (selectedItems.containsKey(props.getId())) { selectedItems.put(props.getId(), props); } checkMovieProperties(TimeUnit.NANOSECONDS.toMillis(player.getMediaNanoseconds())); } if (prop.equals(MovieMapView.MOVIEPROPERTIES_REMOVED_PROPERTY)) { String id = (String)newvalue; //If an update happens while a selection is in place // update the object in the selectedItems list. if (selectedItems.containsKey(id)) { selectedItems.remove(id); } } if (prop.equals(MovieMapView.MOVIE_CHANGED_PROPERTY)) { Movie newMovie = (Movie)newvalue; if (newMovie.getId().equals(oMovie.getId())) { oMovie = newMovie; //If an update happens while a selection is in place // update the object in the selectedItems list. if (selectedItems.containsKey(oMovie.getId())) { selectedItems.put(oMovie.getId(), oMovie); } } } repaint(); } } }; thread.start(); } public void refreshMovieDialog() { /*Long time = new Double(player.getMediaTime().getSeconds()).longValue(); int count = vtTimes.size(); boolean inVisiblePeriod = false; int x=-1; int y=-1; if (count > 0) { for (int i=0; i < count; i++) { NodePositionTime nextTime = (NodePositionTime)vtTimes.elementAt(i); long starttime = nextTime.getTimeToShow(); long stoptime = nextTime.getTimeToHide(); int xPos = nextTime.getXPos(); int yPos = nextTime.getYPos(); if (time >= starttime && time < stoptime || (starttime == 0 && stoptime == 0)) { Point loc = oNode.getLocation(); try { this.oMovieMapView.updateNodeTime(nextTime.getId(), oNode.getNode().getId(), nextTime.getTimeToShow(), nextTime.getTimeToHide(), loc.x, loc.y); //setCurrentNodeView(new Double(player.getMediaTime().getSeconds()).longValue()); oNode.refreshTimeDialog(nextTime); } catch(Exception ex) { log.error("Error...", ex); } break; } } }*/ } /** * Return the UINode associated with this timeline. * @return */ public UIMoviePanel getMovie() { return this.oMoviePanel; } /** * Set the current properties that the movie should use and * start or stop the movie if required. * @param time the current time to check against in milliseconds. */ public void setCurrentMovieProperties(long time) { // CHECK IF PROPERTIES NEED APPLYING checkMovieProperties(time); //CHECK IF MOVIE NEEDS STARTING OR STOPING OR RESETTING long startTime = oMovie.getStartTime(); long duration = TimeUnit.NANOSECONDS.toMillis(oMoviePanel.getDuration().getNanoseconds()); long stopTime = oMovie.getStartTime()+duration; if (this.player.getState() == MasterTimer.Started) { if (time>= startTime && time < stopTime) { if (oMoviePanel.getMediaPlayer().getState() != Player.Started) { oMoviePanel.start(); } } else if (time >= stopTime) { if (oMoviePanel.getMediaPlayer().getState() == Player.Started) { oMoviePanel.stop(); } } else if (time < startTime) { oMoviePanel.getMediaPlayer().setMediaTime(new Time(0)); } } } /** * Set the current properties that the movie should use. * @param time the current time to check against in milliseconds. */ public void checkMovieProperties(long millis) { Vector<MovieProperties> vtProperties = oMovie.getProperties(); int count = vtProperties.size(); if (count == 1) { return; } long setTime = -1; MovieProperties setProps = null; MovieProperties currentProps = null; for (int i=0; i < count; i++) { currentProps = (MovieProperties)vtProperties.elementAt(i); long nexttime = currentProps.getTime(); if(nexttime == millis) { setProps = currentProps; break; } else if (nexttime < millis && nexttime > setTime) { setTime = nexttime; setProps = currentProps; } } if (setProps != null) { oMoviePanel.setCurrentProperties(setProps); } } /** * Set the current media time of the associated movie. * @param millis the time in milliseconds to set. */ public void setMovieTime(long millis) { checkMovieProperties(millis); long startTime = oMovie.getStartTime(); long duration = TimeUnit.NANOSECONDS.toMillis(oMoviePanel.getDuration().getNanoseconds()); long stopTime = oMovie.getStartTime()+duration; if (oMoviePanel.getMediaPlayer().getState() != Player.Started) { long movieTime = millis-startTime; if (movieTime < 0) { movieTime = 0; } else if (movieTime > duration) { movieTime = duration; } long time = TimeUnit.MILLISECONDS.toNanos(movieTime); try { oMoviePanel.getMediaPlayer().setMediaTime(new Time(time)); } catch(Exception e) {} } } /** * If the user has dragged the movie bar along. * Reset the movie play position to the current bar position if required. * Or to the start or end depending on bar. */ private void checkMovieState() { try { long currentPosition = player.getMediaNanoseconds(); long currentPositionMillis = TimeUnit.NANOSECONDS.toMillis(currentPosition); long duration = TimeUnit.NANOSECONDS.toMillis(oMoviePanel.getDuration().getNanoseconds()); if (currentPositionMillis > oMovie.getStartTime() && currentPositionMillis < oMovie.getStartTime()+duration) { long newPosition = currentPositionMillis-oMovie.getStartTime(); oMoviePanel.getMediaPlayer().setMediaTime(new Time(TimeUnit.MILLISECONDS.toNanos(newPosition))); } else if (currentPositionMillis < oMovie.getStartTime()) { oMoviePanel.getMediaPlayer().setMediaTime(new Time(0)); } else if (currentPositionMillis > oMovie.getStartTime()+duration) { oMoviePanel.getMediaPlayer().setMediaTime(new Time(oMoviePanel.getDuration().getNanoseconds())); } } catch(Exception e) {} } /** * Start the movie if it should be playing. */ public void startMovie(long time) { long startTime = oMovie.getStartTime(); long duration = TimeUnit.NANOSECONDS.toMillis(oMoviePanel.getDuration().getNanoseconds()); long stopTime = oMovie.getStartTime()+duration; if (time>= startTime && time < stopTime) { if (oMoviePanel.getMediaPlayer().getState() != Player.Started) { oMoviePanel.start(); } } } /** * Stop the movie if it is playing. */ public void stopMovie() { if (oMoviePanel.getMediaPlayer().getState() == Player.Started) { oMoviePanel.stop(); } } public void paintComponent(Graphics g) { int y; y = (getHeight() / 2) - 2; // Draw main bar g.setColor( getBackground() ); g.drawRect (leftBorder, y, sliderWidth, 3); g.draw3DRect(leftBorder, y, sliderWidth, 3, false); if (isEnabled()) { // draw movie bar long duration = oMoviePanel.getDuration().getNanoseconds(); long millisecondsduration = (int) TimeUnit.NANOSECONDS.toMillis(duration); int spanWidth = new Long(millisecondsduration/pixel_time_scale).intValue(); long startTime = oMovie.getStartTime(); int start = new Long(startTime/pixel_time_scale).intValue(); if (start < 0) { start = 0; } if (this.selectedItems.containsKey(oMovie.getId())) { g.setColor( SELECTED_SPAN_COLOUR ); } else { g.setColor( SPAN_COLOUR ); } g.fillRect(start+leftBorder, y-1, spanWidth, 6); movieRectangle = new Rectangle(start+leftBorder, y-1, spanWidth, 6); Vector<MovieProperties> vtProperties = oMovie.getProperties(); int count = vtProperties.size(); if (htTimeProps != null) { htTimeProps.clear(); } else { this.htTimeProps = new Hashtable<Rectangle, MovieProperties>(count); } for (int i=0; i<count; i++) { MovieProperties nextTime = (MovieProperties)vtProperties.elementAt(i); long starttime = nextTime.getTime(); if (starttime < 0) { starttime = 0; } int startProperties = new Long(starttime/pixel_time_scale).intValue(); if (starttime == 0) { iMiniGrabberMain.paintIcon(this, g, startProperties, y-2); } else { if (this.selectedItems.containsKey(nextTime.getId())) { iGrabberMiniYellow.paintIcon(this, g, startProperties, y-2); } else { iGrabberMini.paintIcon(this, g, startProperties, y-2); } } //leftBorder-(miniGrabberWidth/2)- minigrabberWidth = 8 so this led to painting -1 outside the canvas htTimeProps.put(new Rectangle(startProperties, y-2, this.miniGrabberWidth, this.miniGrabberHeight), nextTime); } } } // public Dimension getPreferredSize() { // return new Dimension(super.getPreferredSize().width, UITimeLinesController.ROW_HEIGHT); // } /** * Set the MasterTimer time to reflect the current location that the bar has been dragged to. * @param pixels the current location of the bar in pixels. */ private void sliderSeek(long pixels) { if (player == null) return; long millisvalue = (pixels*pixel_time_scale); long locationNano = TimeUnit.MILLISECONDS.toNanos(millisvalue); justSeeked = true; if (locationNano >= 0) { long duration = player.getDuration().getNanoseconds(); if (locationNano > duration) { locationNano = duration; } player.setMediaTime(new Time(locationNano)); controlPanel.setMovieTimes(millisvalue); } } public int mouseToSlider(int x) { if (x < leftBorder) x = leftBorder; if (x > this.width - rightBorder) x = this.width - rightBorder; x -= leftBorder; return x; } /** * Return true if the given point is in a property time point * @param p the point to check. * @return true if the given point is in a property time point, else false. */ private MovieProperties isInTimeProps(Point p) { MovieProperties props = null; //long time = (p.x*pixel_time_scale); if (htTimeProps != null) { for (Enumeration e = this.htTimeProps.keys(); e.hasMoreElements();) { Rectangle nextRec = (Rectangle)e.nextElement(); if (nextRec.contains(p)) { props = (MovieProperties)htTimeProps.get(nextRec); } } } return props; } public void mousePressed(MouseEvent e) { if (!isEnabled() || this.player == null || this.player.getState() == Player.Started) return; //onBar = false; onProps = false; onMovie = false; dragging = false; MovieProperties props = isInTimeProps(e.getPoint()); if (props != null) { if (props.getTime() != 0) { onProps = true; controlPanel.setCursor(new Cursor(java.awt.Cursor.HAND_CURSOR)); currentProps = props; } } else if (movieRectangle.contains(e.getPoint())) { controlPanel.setCursor(new Cursor(java.awt.Cursor.HAND_CURSOR)); onMovie = true; pressedAt = e.getX(); } else { //onBar = true; controlPanel.setCursor(new Cursor(java.awt.Cursor.DEFAULT_CURSOR)); } } public synchronized void mouseReleased(MouseEvent e) { if (!isEnabled() || player == null) return; //boolean isRightMouse = SwingUtilities.isRightMouseButton(e); boolean isLeftMouse = SwingUtilities.isLeftMouseButton(e); if (ProjectCompendium.isMac && (e.getButton() == 3 && e.isShiftDown())) { //isRightMouse = true; isLeftMouse = false; } controlPanel.setCursor(new Cursor(java.awt.Cursor.DEFAULT_CURSOR)); if (dragging) { if (onMovie) { if (selectedItems.containsKey(oMovie.getId())) { this.controlPanel.dragComplete(oMovie.getId()); } else { try { oMovieMapView.updateMovie(oMovie.getId(), oMovie.getLink(), oMovie.getMovieName(), oMovie.getStartTime()); } catch(Exception ex) { log.info("Unable to update movie start time dues to\n\n:"+ex.getLocalizedMessage()); //$NON-NLS-1$ } } } if (onProps && isLeftMouse) { if (selectedItems.containsKey(currentProps.getId())) { this.controlPanel.dragComplete(currentProps.getId()); } else { try { this.oMovieMapView.updateMovieProperties(currentProps.getId(), currentProps.getMovieID(), currentProps.getXPos(), currentProps.getYPos(), currentProps.getWidth(), currentProps.getHeight(), currentProps.getTransparency(), currentProps.getTime()); } catch(Exception ex) { log.error("Error...", ex); } } currentProps = null; } } dragging = false; pressedAt = 0; repaint(); } public synchronized void mouseDragged(MouseEvent e) { if (!isEnabled() || player == null) return; //boolean isRightMouse = SwingUtilities.isRightMouseButton(e); boolean isLeftMouse = SwingUtilities.isLeftMouseButton(e); if (ProjectCompendium.isMac && (e.getButton() == 3 && e.isShiftDown())) { //isRightMouse = true; isLeftMouse = false; } dragging = true; if (onMovie && isLeftMouse) { int newPosition = mouseToSlider(e.getX()); long oldStart = oMovie.getStartTime(); long offset = (newPosition-pressedAt); long millioffset = (offset*pixel_time_scale); long newStart = millioffset+oldStart; if (newStart < 0) { newStart = 0; millioffset = 0; } pressedAt = newPosition; if (selectedItems.containsKey(oMovie.getId())) { this.controlPanel.dragMove(oMovie.getId(), millioffset); } else { oMovie.setStartTime(newStart); checkMovieState(); repaint(); } } else if (onProps && isLeftMouse) { int newPosition = mouseToSlider(e.getX()); long oldPosition = currentProps.getTime(); long newPositionMillis = (newPosition*pixel_time_scale); if (!checkForExisting(currentProps.getId(), newPositionMillis)) { long millioffset = newPositionMillis-oldPosition; if (selectedItems.containsKey(currentProps.getId())) { this.controlPanel.dragMove(currentProps.getId(), millioffset); } else { currentProps.setTime(newPositionMillis); } } } } /** * Check to see if the passed time is the same as another time. * @param time the time to check * @return true if it is the same as an existing span, else false; */ private boolean checkForExisting(String id, long time) { int count = oMovie.getPropertiesCount(); Vector<MovieProperties> vtProperties = oMovie.getProperties(); boolean same = false; for (int i=0; i<count; i++) { MovieProperties props = (MovieProperties)vtProperties.elementAt(i); if (!id.equals(props.getId())) { if (props.getTime() == time) { same = true; break; } } } return same; } /** * Open the MovieProperties dialog. * @param props */ public void showMovieDialog(MovieProperties props, boolean onMovie) { if (onMovie) { ((UIMovieMapViewFrame)oMovieMapViewPane.getViewFrame()).showMovieDialog(oMovie); } else { ((UIMovieMapViewFrame)oMovieMapViewPane.getViewFrame()).showMovieDialog(props); } } /** * delete the properties with the given id. * @param sMoviePropertiesID the id of the properties to delete. */ public void delete(String sMoviePropertiesID) { try { oMovieMapView.deleteMovieProperties(sMoviePropertiesID, oMovie.getId()); } catch(Exception e) { log.error("Error...", e); } } /** * Create a new MovieProperties object for this movie at the location given. * @param location */ public MovieProperties createProps(long location) { MovieProperties props = null; long time = (location*pixel_time_scale); try { props = oMovieMapView.addMovieProperties(oMovie.getId(), oMoviePanel.getX(), oMoviePanel.getY(), oMoviePanel.getWidth(), oMoviePanel.getHeight(), 1.0f, time); showMovieDialog(props, onMovie); } catch(Exception e) { log.info(e.getLocalizedMessage()); } return props; } /** * Can all the selected items move the required amount? * @param changeValue the amount to check for the move * @return true if all the items can move, else false. */ public synchronized boolean canAllMove(long changeValue) { boolean canMove = true; Object next = null; for (Enumeration<Object> bars = selectedItems.elements(); bars.hasMoreElements();) { next = (Object)bars.nextElement(); if (next instanceof Movie) { Movie nextMovie = (Movie)next; long newStart = nextMovie.getStartTime()+changeValue; if (newStart < 0) { canMove = false; break; } } else if (next instanceof MovieProperties) { MovieProperties nextProp = (MovieProperties) next; long newValue = nextProp.getTime()+changeValue; if (checkForExisting(nextProp.getId(), newValue) || newValue < 0) { canMove = false; break; } } } return canMove; } /** * Update all selected items by the amount given in milliseconds */ public synchronized void dragMove(String fromID, long changeValue) { Object next = null; if (changeValue != 0) { for (Enumeration<Object> bars = selectedItems.elements(); bars.hasMoreElements();) { next = (Object)bars.nextElement(); if (next instanceof Movie) { Movie nextMovie = (Movie)next; long newStart = nextMovie.getStartTime()+changeValue; if (newStart < 0) { changeValue = 0; break; } else { nextMovie.setStartTime(newStart); } } } } if (changeValue != 0) { for (Enumeration<Object> bars = selectedItems.elements(); bars.hasMoreElements();) { next = (Object)bars.nextElement(); if (next instanceof MovieProperties) { MovieProperties nextProp = (MovieProperties) next; long newValue = nextProp.getTime()+changeValue; if (!checkForExisting(nextProp.getId(), newValue)) { nextProp.setTime(newValue); } } } } checkMovieState(); repaint(); } /** * Save the change to all selected items */ public synchronized void dragComplete(String fromID) { Object next = null; for (Enumeration<Object> bars = selectedItems.elements(); bars.hasMoreElements();) { next = (Object)bars.nextElement(); if (next instanceof Movie) { Movie nextMovie = (Movie)next; try { oMovieMapView.updateMovie(nextMovie.getId(), nextMovie.getLink(), nextMovie.getMovieName(), nextMovie.getStartTime()); } catch(Exception ex) { log.info("Unable to update movie start time dues to\n\n:"+ex.getLocalizedMessage()); //$NON-NLS-1$ } } else if (next instanceof MovieProperties) { MovieProperties nextProp = (MovieProperties) next; try { this.oMovieMapView.updateMovieProperties(nextProp.getId(), nextProp.getMovieID(), nextProp.getXPos(), nextProp.getYPos(), nextProp.getWidth(), nextProp.getHeight(), nextProp.getTransparency(), nextProp.getTime()); } catch(Exception ex) { log.error("Error...", ex); } } } repaint(); } /** * Clear all selected items */ public void clearSelection() { selectedItems.clear(); } /** * Handle mouseClicked events. * @param e the MouseEvent for this mouse click. */ public void mouseClicked(MouseEvent e) { if (!isEnabled() || player == null) return; controlPanel.setCursor(new Cursor(java.awt.Cursor.DEFAULT_CURSOR)); boolean isRightMouse = SwingUtilities.isRightMouseButton(e); boolean isLeftMouse = SwingUtilities.isLeftMouseButton(e); if (ProjectCompendium.isMac && ( (e.getButton() == 3 && e.isShiftDown()) || (e.getButton() == 1 && e.isControlDown()) )) { isRightMouse = true; isLeftMouse = false; } MovieProperties props = isInTimeProps(e.getPoint()); if (!e.isShiftDown()) { this.controlPanel.clearSelection(); } int clickCount = e.getClickCount(); if (isLeftMouse) { if (clickCount >= 2) { if (props != null) { showMovieDialog(props, onMovie); } else { createProps(mouseToSlider(e.getX())); } } else if (clickCount == 1) { if (e.isShiftDown()) { if (props != null) { if (props.getTime() != 0) { if (!selectedItems.containsKey(props.getId())) { selectedItems.put(props.getId(), props); } else { selectedItems.remove(props.getId()); } } } else if (onMovie) { if (!selectedItems.containsKey(oMovie.getId())) { selectedItems.put(oMovie.getId(), oMovie); } else { selectedItems.remove(oMovie.getId()); } } } else { if (props != null) { // if you are on a span, move time position to start of span. long starttime = props.getTime(); long newPosition = starttime/pixel_time_scale; sliderSeek(newPosition); } else if (onMovie) { // if you are on the movie span, move time position to start of movie. long starttime = oMovie.getStartTime(); long newPosition = starttime/pixel_time_scale; sliderSeek(newPosition); } } } } else if (isRightMouse) { // || (ProjectCompendium.isMac && (e.getModifiers() & MouseEvent.CTRL_MASK) != 0)) { if (popup != null) { popup.setVisible(false); popup = null; } //Point place = e.getLocationOnScreen(); Point place = SwingUtilities.convertPoint((Component)e.getSource(), e.getX(), e.getY(), ProjectCompendium.APP); popup = new UIMovieTimeLinePopupMenu(this, props, oMovie.getId(), e.getPoint(), onMovie); popup.show(ProjectCompendium.APP, place.x, place.y); } repaint(); onMovie = false; currentProps = null; onProps = false; } public synchronized void mouseEntered(MouseEvent e) { //if (!isEnabled() || player == null || this.player.getState() == MasterTimer.Started) // return; /*entered = true; repaint();*/ } public synchronized void mouseExited(MouseEvent e) { //if (!isEnabled() || player == null || this.player.getState() == MasterTimer.Started) // return; /*entered = false; //onBar = false; onProps = false; currentProps = null; this.setCursor(new Cursor(java.awt.Cursor.DEFAULT_CURSOR)); */ //repaint(); } public synchronized void mouseMoved(MouseEvent e) { if (!isEnabled() || player == null || this.player.getState() == MasterTimer.Started) return; controlPanel.setCursor(new Cursor(java.awt.Cursor.DEFAULT_CURSOR)); MovieProperties props = isInTimeProps(e.getPoint()); if (props != null) { if (props.getTime() != 0) { controlPanel.setCursor(new Cursor(java.awt.Cursor.HAND_CURSOR)); } } else if (movieRectangle.contains(e.getPoint())) { controlPanel.setCursor(new Cursor(java.awt.Cursor.HAND_CURSOR)); } } public void componentResized ( ComponentEvent event ) { Dimension dim = this.getSize(); if ( dim.width - leftBorder - rightBorder < 1 ) return; this.width = dim.width; sliderWidth = this.width - leftBorder - rightBorder; repaint(); } public void componentMoved ( ComponentEvent event ) {} public void componentShown ( ComponentEvent event ) {} public void componentHidden ( ComponentEvent event ) {} }