FileDocCategorySizeDatePackage
SlideModel.javaAPI DocAndroid 1.5 API14215Wed May 06 22:42:46 BST 2009com.android.mms.model

SlideModel.java

/*
 * Copyright (C) 2008 Esmertec AG.
 * Copyright (C) 2008 The Android Open Source Project
 *
 * 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 com.android.mms.model;

import com.android.mms.ContentRestrictionException;
import com.android.mms.dom.smil.SmilParElementImpl;

import org.w3c.dom.events.Event;
import org.w3c.dom.events.EventListener;
import org.w3c.dom.smil.ElementTime;

import android.util.Config;
import android.util.Log;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

public class SlideModel extends Model
        implements List<MediaModel>, EventListener {
    private static final String TAG = "SlideModel";
    private static final boolean DEBUG = false;
    private static final boolean LOCAL_LOGV = DEBUG ? Config.LOGD : Config.LOGV;
    private static final int DEFAULT_SLIDE_DURATION = 5000;

    private final ArrayList<MediaModel> mMedia = new ArrayList<MediaModel>();

    private MediaModel mText;
    private MediaModel mImage;
    private MediaModel mAudio;
    private MediaModel mVideo;

    private boolean mCanAddImage = true;
    private boolean mCanAddAudio = true;
    private boolean mCanAddVideo = true;

    private int mDuration;
    private boolean mVisible = true;
    private short mFill;
    private int mSlideSize;
    private SlideshowModel mParent;

    public SlideModel(SlideshowModel slideshow) {
        this(DEFAULT_SLIDE_DURATION, slideshow);
    }

    public SlideModel(int duration, SlideshowModel slideshow) {
        mDuration = duration;
        mParent = slideshow;
    }

    /**
     * Create a SlideModel with exist media collection.
     *
     * @param duration The duration of the slide.
     * @param mediaList The exist media collection.
     *
     * @throws IllegalStateException One or more media in the mediaList cannot
     *         be added into the slide due to a slide cannot contain image
     *         and video or audio and video at the same time.
     */
    public SlideModel(int duration, ArrayList<MediaModel> mediaList) {
        mDuration = duration;

        int maxDur = 0;
        for (MediaModel media : mediaList) {
            internalAdd(media);

            int mediaDur = media.getDuration();
            if (mediaDur > maxDur) {
                maxDur = mediaDur;
            }
        }

        updateDuration(maxDur);
    }

    private void internalAdd(MediaModel media) throws IllegalStateException {
        if (media == null) {
            // Don't add null value into the list.
            return;
        }

        if (media.isText()) {
            internalAddOrReplace(mText, media);
            mText = media;
        } else if (media.isImage()) {
            if (mCanAddImage) {
                internalAddOrReplace(mImage, media);
                mImage = media;
                mCanAddVideo = false;
            } else {
                throw new IllegalStateException();
            }
        } else if (media.isAudio()) {
            if (mCanAddAudio) {
                internalAddOrReplace(mAudio, media);
                mAudio = media;
                mCanAddVideo = false;
            } else {
                throw new IllegalStateException();
            }
        } else if (media.isVideo()) {
            if (mCanAddVideo) {
                internalAddOrReplace(mVideo, media);
                mVideo = media;
                mCanAddImage = false;
                mCanAddAudio = false;
            } else {
                throw new IllegalStateException();
            }
        }
    }

    private void internalAddOrReplace(MediaModel old, MediaModel media) {
        int addSize = media.getMediaSize();
        int removeSize;
        if (old == null) {
            if (null != mParent) {
                mParent.checkMessageSize(addSize);
            }
            mMedia.add(media);
            increaseSlideSize(addSize);
            increaseMessageSize(addSize);
        } else {
            removeSize = old.getMediaSize();
            if (addSize > removeSize) {
                if (null != mParent) {
                    mParent.checkMessageSize(addSize - removeSize);
                }
                increaseSlideSize(addSize - removeSize);
                increaseMessageSize(addSize - removeSize);
            } else {
                decreaseSlideSize(removeSize - addSize);
                decreaseMessageSize(removeSize - addSize);
            }
            mMedia.set(mMedia.indexOf(old), media);
            old.unregisterAllModelChangedObservers();
        }

        for (IModelChangedObserver observer : mModelChangedObservers) {
            media.registerModelChangedObserver(observer);
        }
    }

    private boolean internalRemove(Object object) {
        if (mMedia.remove(object)) {
            if (object instanceof TextModel) {
                mText = null;
            } else if (object instanceof ImageModel) {
                mImage = null;
                mCanAddVideo = true;
            } else if (object instanceof AudioModel) {
                mAudio = null;
                mCanAddVideo = true;
            } else if (object instanceof VideoModel) {
                mVideo = null;
                mCanAddImage = true;
                mCanAddAudio = true;
            }
            int decreaseSize = ((MediaModel) object).getMediaSize();
            decreaseSlideSize(decreaseSize);
            decreaseMessageSize(decreaseSize);

            ((Model) object).unregisterAllModelChangedObservers();

            return true;
        }

        return false;
    }

    /**
     * @return the mDuration
     */
    public int getDuration() {
        return mDuration;
    }

    /**
     * @param duration the mDuration to set
     */
    public void setDuration(int duration) {
        mDuration = duration;
        notifyModelChanged(true);
    }

    public int getSlideSize() {
        return mSlideSize;
    }

    public void increaseSlideSize(int increaseSize) {
        if (increaseSize > 0) {
            mSlideSize += increaseSize;
        }
    }

    public void decreaseSlideSize(int decreaseSize) {
        if (decreaseSize > 0) {
            mSlideSize -= decreaseSize;
        }
    }

    public void setParent(SlideshowModel parent) {
        mParent = parent;
    }

    public void increaseMessageSize(int increaseSize) {
        if ((increaseSize > 0) && (null != mParent)) {
            int size = mParent.getCurrentMessageSize();
            size += increaseSize;
            mParent.setCurrentMessageSize(size);
        }
    }

    public void decreaseMessageSize(int decreaseSize) {
        if ((decreaseSize > 0) && (null != mParent)) {
            int size = mParent.getCurrentMessageSize();
            size -= decreaseSize;
            mParent.setCurrentMessageSize(size);
        }
    }

    //
    // Implement List<E> interface.
    //

    /**
     * Add a MediaModel to the slide. If the slide has already contained
     * a media object in the same type, the media object will be replaced by
     * the new one.
     *
     * @param object A media object to be added into the slide.
     * @return true
     * @throws IllegalStateException One or more media in the mediaList cannot
     *         be added into the slide due to a slide cannot contain image
     *         and video or audio and video at the same time.
     * @throws ContentRestrictionException when can not add this object.
     *
     */
    public boolean add(MediaModel object) {
        internalAdd(object);
        notifyModelChanged(true);
        return true;
    }

    public boolean addAll(Collection<? extends MediaModel> collection) {
        throw new UnsupportedOperationException("Operation not supported.");
    }

    public void clear() {
        if (mMedia.size() > 0) {
            for (MediaModel media : mMedia) {
                media.unregisterAllModelChangedObservers();
                int decreaseSize = media.getMediaSize();
                decreaseSlideSize(decreaseSize);
                decreaseMessageSize(decreaseSize);
            }
            mMedia.clear();

            mText = null;
            mImage = null;
            mAudio = null;
            mVideo = null;

            mCanAddImage = true;
            mCanAddAudio = true;
            mCanAddVideo = true;

            notifyModelChanged(true);
        }
    }

    public boolean contains(Object object) {
        return mMedia.contains(object);
    }

    public boolean containsAll(Collection<?> collection) {
        return mMedia.containsAll(collection);
    }

    public boolean isEmpty() {
        return mMedia.isEmpty();
    }

    public Iterator<MediaModel> iterator() {
        return mMedia.iterator();
    }

    public boolean remove(Object object) {
        if ((object != null) && (object instanceof MediaModel)
                && internalRemove(object)) {
            notifyModelChanged(true);
            return true;
        }
        return false;
    }

    public boolean removeAll(Collection<?> collection) {
        throw new UnsupportedOperationException("Operation not supported.");
    }

    public boolean retainAll(Collection<?> collection) {
        throw new UnsupportedOperationException("Operation not supported.");
    }

    public int size() {
        return mMedia.size();
    }

    public Object[] toArray() {
        return mMedia.toArray();
    }

    public <T> T[] toArray(T[] array) {
        return mMedia.toArray(array);
    }

    public void add(int location, MediaModel object) {
        throw new UnsupportedOperationException("Operation not supported.");
    }

    public boolean addAll(int location,
            Collection<? extends MediaModel> collection) {
        throw new UnsupportedOperationException("Operation not supported.");
    }

    public MediaModel get(int location) {
        return mMedia.get(location);
    }

    public int indexOf(Object object) {
        return mMedia.indexOf(object);
    }

    public int lastIndexOf(Object object) {
        return mMedia.lastIndexOf(object);
    }

    public ListIterator<MediaModel> listIterator() {
        return mMedia.listIterator();
    }

    public ListIterator<MediaModel> listIterator(int location) {
        return mMedia.listIterator(location);
    }

    public MediaModel remove(int location) {
        MediaModel media = mMedia.get(location);
        if ((media != null) && internalRemove(media)) {
            notifyModelChanged(true);
        }
        return media;
    }

    public MediaModel set(int location, MediaModel object) {
        throw new UnsupportedOperationException("Operation not supported.");
    }

    public List<MediaModel> subList(int start, int end) {
        return mMedia.subList(start, end);
    }

    /**
     * @return the mVisible
     */
    public boolean isVisible() {
        return mVisible;
    }

    /**
     * @param visible the mVisible to set
     */
    public void setVisible(boolean visible) {
        mVisible = visible;
        notifyModelChanged(true);
    }

    /**
     * @return the mFill
     */
    public short getFill() {
        return mFill;
    }

    /**
     * @param fill the mFill to set
     */
    public void setFill(short fill) {
        mFill = fill;
        notifyModelChanged(true);
    }

    @Override
    protected void registerModelChangedObserverInDescendants(
            IModelChangedObserver observer) {
        for (MediaModel media : mMedia) {
            media.registerModelChangedObserver(observer);
        }
    }

    @Override
    protected void unregisterModelChangedObserverInDescendants(
            IModelChangedObserver observer) {
        for (MediaModel media : mMedia) {
            media.unregisterModelChangedObserver(observer);
        }
    }

    @Override
    protected void unregisterAllModelChangedObserversInDescendants() {
        for (MediaModel media : mMedia) {
            media.unregisterAllModelChangedObservers();
        }
    }

    // EventListener Interface
    public void handleEvent(Event evt) {
        if (evt.getType().equals(SmilParElementImpl.SMIL_SLIDE_START_EVENT)) {
            if (LOCAL_LOGV) {
                Log.v(TAG, "Start to play slide: " + this);
            }
            mVisible = true;
        } else if (mFill != ElementTime.FILL_FREEZE) {
            if (LOCAL_LOGV) {
                Log.v(TAG, "Stop playing slide: " + this);
            }
            mVisible = false;
        }

        notifyModelChanged(false);
    }

    public boolean hasText() {
        return mText != null;
    }

    public boolean hasImage() {
        return mImage != null;
    }

    public boolean hasAudio() {
        return mAudio != null;
    }

    public boolean hasVideo() {
        return mVideo != null;
    }

    public boolean removeText() {
        return remove(mText);
    }

    public boolean removeImage() {
        return remove(mImage);
    }

    public boolean removeAudio() {
        return remove(mAudio);
    }

    public boolean removeVideo() {
        return remove(mVideo);
    }

    public TextModel getText() {
        return (TextModel) mText;
    }

    public ImageModel getImage() {
        return (ImageModel) mImage;
    }

    public AudioModel getAudio() {
        return (AudioModel) mAudio;
    }

    public VideoModel getVideo() {
        return (VideoModel) mVideo;
    }

    public void updateDuration(int duration) {
        if (duration <= 0) {
            return;
        }

        if ((duration > mDuration)
                || (mDuration == DEFAULT_SLIDE_DURATION)) {
            mDuration = duration;
        }
    }
}