ViewPanelHelper.java :  » Testing » jacareto » jacareto » trackimpl » Java Open Source

Java Open Source » Testing » jacareto 
jacareto » jacareto » trackimpl » ViewPanelHelper.java
/*
 * Jacareto Copyright (c) 2002-2005
 * Applied Computer Science Research Group, Darmstadt University of
 * Technology, Institute of Mathematics & Computer Science,
 * Ludwigsburg University of Education, and Computer Based
 * Learning Research Group, Aachen University. All rights reserved.
 *
 * Jacareto is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * Jacareto is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with Jacareto; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

package jacareto.trackimpl;


import jacareto.track.TrackModel;
import jacareto.track.block.Block;
import jacareto.track.block.BlockType;

import org.apache.commons.lang.Validate;

import java.awt.Point;
import java.awt.Rectangle;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

/**
 * <p>
 * Helper class which calculates coordinates for the {@link TrackViewPanel} from data of the
 * TrackModel.
 * </p>
 * 
 * <p>
 * The {@link TrackModel} has to be set and the ms per pixel have to be calculated before the
 * coordinates  can be calculated.
 * </p>
 *
 * @author Oliver Specht
 * @version $revision$
 */
public class ViewPanelHelper {
    /** The factor the y position of the blocks will be calculated from (~ % of the height) */
    private static final double Y_POSITION_FACTOR_AUDIO = 0.65;
    private static final double Y_POSITION_FACTOR_VIDEO = 0.15;

    /** The factor, the height of the blocks will be calculated from (~ % of the height) */
    private static final double HEIGHT_FACTOR_AUDIO = 0.2;
    private static final double HEIGHT_FACTOR_VIDEO = 0.2;

    /** The current heights and positions of the blocks */
    private int yPositionAudio;
    private int yPositionVideo;
    private int heightAudio;
    private int heightVideo;

    /** The TrackModel this Helper works with */
    TrackModel trackModel;

    /** The number of ms one pixel has to be interpreted */
    private double msPerPixel = 0.0;

    /** The width of the viewPanel */
    private int viewPanelWidth = 0;

    /** The height of the viewPanel */
    private int viewPanelHeight = 0;

    /** the block which has been marked by a mouse click */
    private Block markedBlock = null;

    /** The visible blocks */
    List visibleBlocks = new ArrayList();

    /** The time where the mouse pointer was when the left mouse button was clicked */
    private long mousePointerTimeOffset = 0;

    /**
     * Sets the width and height of the TrackViewPanel
     *
     * @param width width of the view panel
     * @param height height of the view panel
     */
    public void setViewPanelSize (int width, int height) {
        this.viewPanelWidth = width;
        this.viewPanelHeight = height;
        this.calculateMsPerPixel ();
        this.calculateBlockPositions ();
    }

    /**
     * Returns true if block overlaps any block of the same type in the same track (~BlockType)
     *
     * @param toCheck block to check for overlapping
     * @param newStartTime new start time to be set for the block and to be checked
     *
     * @return boolean
     */
    public boolean isOverlapping (Block toCheck, long newStartTime) {
        Validate.notNull (toCheck);

        if (((newStartTime + toCheck.getDuration ()) > this.trackModel.getEndTime ()) ||
                (newStartTime < 0)) {
            return true;
        }

        List checkList = this.trackModel.getBlocksInRange (toCheck.getType (), newStartTime,
                newStartTime + toCheck.getDuration (), false);

        // more than one => overlapping
        if (checkList.size () > 1) {
            return true;
        } else if (checkList.size () == 1) {
            // only one => check if it is the block itself
            if (! checkList.get (0).equals (toCheck)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Calculate the position and height of the blocks depending on the size of the TrackViewPanel.
     */
    private void calculateBlockPositions () {
        this.heightAudio = (int) (this.viewPanelHeight * ViewPanelHelper.HEIGHT_FACTOR_AUDIO);
        this.heightVideo = (int) (this.viewPanelHeight * ViewPanelHelper.HEIGHT_FACTOR_VIDEO);
        this.yPositionAudio = (int) (this.viewPanelHeight * ViewPanelHelper.Y_POSITION_FACTOR_AUDIO);
        this.yPositionVideo = (int) (this.viewPanelHeight * ViewPanelHelper.Y_POSITION_FACTOR_VIDEO);
    }

    /**
     * Reruns the current Y position for the audio bar
     *
     * @return int
     */
    public int getYPositionAudio () {
        return this.yPositionAudio;
    }

    /**
     * Reruns the current Y position for the video bar
     *
     * @return int
     */
    public int getYPositionVideo () {
        return this.yPositionVideo;
    }

    /**
     * Reruns the current height of the audio bar
     *
     * @return int
     */
    public int getHeightAudio () {
        return this.heightAudio;
    }

    /**
     * Reruns the current height of the video bar
     *
     * @return int
     */
    public int getHeightVideo () {
        return this.heightVideo;
    }

    /**
     * Calculates the ms per Pixel
     */
    private void calculateMsPerPixel () {
        if (this.trackModel != null) {
            this.msPerPixel = ((double) this.trackModel.getEndTime () / (double) this.viewPanelWidth);
        }
    }

    /**
     * Sets a new {@link TrackModel} for this ViewPanelHelper.
     *
     * @param trackModel {@link TrackModel}
     */
    public void setModel (TrackModel trackModel) {
        this.trackModel = trackModel;
        this.clearVisibleBlocks ();

        // Add audio and video blocks
        this.visibleBlocks = this.trackModel.getBlocksInRange (BlockType.AUDIO, 0,
                this.trackModel.getEndTime (), false);
        this.visibleBlocks.addAll (this.trackModel.getBlocksInRange (BlockType.VIDEO, 0,
                this.trackModel.getEndTime (), false));
    }

    /**
     * <p>
     * Returns a rectangle which visualizes the given block.
     * </p>
     *
     * @param block {@link Block}
     *
     * @return {@link Rectangle}
     */
    public Rectangle getRectangle (Block block) {
        int x = (int) (this.trackModel.getStartTime (block) / this.msPerPixel);
        int width;

        if (this.trackModel.isEndAligned (block)) {
            long alignedToBlockStartTime = this.trackModel.getStartTime (this.trackModel.getAlignedToBlock (
                        block));
            width = (int) ((alignedToBlockStartTime / this.msPerPixel) - x);
        } else {
            width = (int) (block.getDuration () / this.msPerPixel);
        }

        if (block.getType ().equals (BlockType.AUDIO)) {
            return new Rectangle(x, this.yPositionAudio, width, this.heightAudio);
        } else if (block.getType ().equals (BlockType.VIDEO)) {
            return new Rectangle(x, this.yPositionVideo, width, this.heightVideo);
        }

        return null;
    }

    /**
     * Returns the block the user has clicked on or null if he didn't click in a block.
     *
     * @param point Point
     *
     * @return {@link Block} where the user clicked on
     */
    public Block getClickedBlock (Point point) {
        Iterator iter = this.visibleBlocks.iterator ();

        while (iter.hasNext ()) {
            Block block = (Block) iter.next ();
            Rectangle rect = getRectangle (block);

            if (rect.contains (point)) {
                return block;
            }
        }

        return null;
    }

    /**
     * <p>
     * Returns true if the wantedStartTime is less than zero or if the wantedStartTime + the
     * duration of the block is greater than the end time of the track model.
     * </p>
     *
     * @param block the {@link Block} to be checked
     * @param wantedStartTime the wanted start time
     *
     * @return boolean
     */
    public boolean isOutOfTrackModelTimes (Block block, long wantedStartTime) {
        if (wantedStartTime < 0) {
            return true;
        } else if ((wantedStartTime + block.getDuration ()) > this.trackModel.getEndTime ()) {
            return true;
        }

        return false;
    }

    /**
     * Returns the next possible start time for the given block. Next possible means that the block
     * will be shifted to the &quot;left&quot;,  so the start time will be reduced.
     *
     * @param block Block for which the next possible start time will be calculated
     * @param wantedStartTime the start time which should be set
     *
     * @return long new start time or -1 if no start time could be determined
     */
    public long getNextPossibleStartTime (Block block, long wantedStartTime) {
        long blockLength = this.trackModel.getStartTime (block) + block.getDuration ();

        // get all blocks which lie before the given block (ordered by start time)
        List previousBlocks = this.trackModel.getBlocksInRange (block.getType (), 0,
                wantedStartTime, false);

        // reverse the block list
        Collections.reverse (previousBlocks);

        Iterator iter = previousBlocks.iterator ();

        while (iter.hasNext ()) {
            Block currentBlock = (Block) iter.next ();

            long currentBlockEndTime = this.trackModel.getStartTime (currentBlock) +
                currentBlock.getDuration ();
            long nextBlockStartTime = this.getNextBlockStartTime (block.getType (),
                    currentBlockEndTime);

            if ((nextBlockStartTime - currentBlockEndTime) < blockLength) {
                return nextBlockStartTime - blockLength;
            }
        }

        return -1;
    }

    /**
     * Returns the time span to the next block or the time to the end of the track
     *
     * @param type BlockType for which the search should be performed
     * @param time time when the searching should start
     *
     * @return long
     */
    private long getNextBlockStartTime (BlockType type, long time) {
        long trackModelEndTime = this.trackModel.getEndTime ();
        Validate.isTrue (time < trackModelEndTime);
        Validate.isTrue (type.equals (BlockType.AUDIO) || type.equals (BlockType.VIDEO));

        List blockList = this.trackModel.getBlocksInRange (type, time, trackModelEndTime, false);

        if (blockList.size () > 0) {
            Block block = (Block) blockList.get (0);

            return this.trackModel.getStartTime (block);
        }

        return -1;
    }

    /**
     * Returns all the visible blocks.
     *
     * @return {@link List} of {@link Block blocks}
     */
    public List getVisibleBlocks () {
        return this.visibleBlocks;
    }

    /**
     * Returns the Block the user pressed the mouse button down or null if there was no block
     *
     * @param point Point where the user pressed the mouse down
     *
     * @return Block
     */
    public Block getMousePressedBlock (Point point) {
        Iterator iter = this.visibleBlocks.iterator ();

        while (iter.hasNext ()) {
            Block block = (Block) iter.next ();
            Rectangle rect = getRectangle (block);

            // block has been selected to drag and drop
            if (rect.contains (point)) {
                this.mousePointerTimeOffset = this.getTime (point) -
                    this.trackModel.getStartTime (block);

                return block;
            }
        }

        return null;
    }

    /**
     * <p>
     * Save the position where the user has clicked on to provide correct drag and drop.
     * </p>
     *
     * @param point {@link Point} the user has clicked to
     * @param block {@link Block} the user has clicked in
     */
    public void setMousePointerTimeOffset (Point point, Block block) {
        this.mousePointerTimeOffset = this.getTime (point) - this.trackModel.getStartTime (block);
    }

    /**
     * Returns the mousePointerTimeOffset for the {@link TrackViewPanel} to move  the blocks
     * correctly.
     *
     * @return long mousePointerTimeOffset
     */
    public long getMousePointerTimeOffset () {
        return this.mousePointerTimeOffset;
    }

    /**
     * <p>
     * Returns the {@link BlockType} of the track where the user has clicked into.
     * </p>
     *
     * @param point {@link Point}
     *
     * @return {@link BlockType}
     */
    public BlockType getClickedTrack (Point point) {
        Rectangle rectAudio = new Rectangle(0, this.getYPositionAudio (), this.viewPanelWidth,
                this.getHeightAudio ());
        Rectangle rectVideo = new Rectangle(0, this.getYPositionVideo (), this.viewPanelWidth,
                this.getHeightVideo ());

        if (rectAudio.contains (point)) {
            return BlockType.AUDIO;
        } else if (rectVideo.contains (point)) {
            return BlockType.VIDEO;
        }

        return null;
    }

    /**
     * <p>
     * Returns the time the given {@link Point} represents depending on the msPerPixel.
     * </p>
     *
     * @param point point the (start-) time should be calculated for
     *
     * @return long the (new start-) time in ms
     */
    public long getTime (Point point) {
        long returnValue = (long) (point.getX () * this.msPerPixel);

        int blockWidth = 0;

        if (this.trackModel.isEndAligned (this.markedBlock)) {
            blockWidth = (int) ((this.trackModel.getStartTime (this.markedBlock) +
                this.trackModel.getStartTime (this.trackModel.getAlignedToBlock (this.markedBlock))) / this.msPerPixel);
        } else {
            blockWidth = (int) ((this.trackModel.getStartTime (this.markedBlock) +
                this.markedBlock.getDuration ()) / this.msPerPixel);
        }

        if ((point.getX () + blockWidth) > this.viewPanelWidth) {
            // TODO: Abchecken!!! Da muss noch berlegt werden, da ein Block evtl. 
            // aligned ist und solange er verschoben wird, muss das Alignment 
            // aufgehoben werden oder nicht angezeigt
        }

        return returnValue;
    }

    /**
     * Clears the visible blocks so the newly visible blocks can be calculated
     */
    public void clearVisibleBlocks () {
        this.visibleBlocks.clear ();
    }

    /**
     * True, if the given point is contained in a block
     *
     * @param point {@link Point} where the event occured
     *
     * @return boolean
     */
    public boolean isPointInBlock (Point point) {
        Iterator iter = this.visibleBlocks.iterator ();

        while (iter.hasNext ()) {
            Block block = (Block) iter.next ();
            Rectangle rect = getRectangle (block);

            if (rect.contains (point)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Returns the block which contains the point
     *
     * @param point
     *
     * @return Block
     */
    public Block getBlock (Point point) {
        Iterator iter = this.visibleBlocks.iterator ();

        while (iter.hasNext ()) {
            Block block = (Block) iter.next ();

            if (getRectangle (block).contains (point)) {
                return block;
            }
        }

        return null;
    }

    /**
     * Returns the {@link Block} whch is currently marked (~mouse over)
     *
     * @return Block {@link Block}
     */
    public Block getMarkedBlock () {
        return this.markedBlock;
    }

    /**
     * Marks the block so he is drawn in another color.
     *
     * @param block
     */
    public void markBlock (Block block) {
        this.markedBlock = block;
    }

    /**
     * Unmarks the markedBlock field
     */
    public void unmarkBlock () {
        this.markedBlock = null;
    }

    /**
     * True, if the given block equals the markedBlock
     *
     * @param block
     *
     * @return true, if given {@link Block} is marked
     */
    public boolean isBlockMarked (Block block) {
        if ((this.markedBlock != null) && (block.equals (this.markedBlock))) {
            return true;
        }

        return false;
    }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.