summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/com/vaadin/service/FileTypeResolver.java5
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VAudio.java42
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VMediaBase.java129
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VVideo.java73
-rw-r--r--src/com/vaadin/ui/AbstractMedia.java217
-rw-r--r--src/com/vaadin/ui/Audio.java48
-rw-r--r--src/com/vaadin/ui/Video.java77
-rw-r--r--tests/src/com/vaadin/tests/components/media/Media.java74
8 files changed, 665 insertions, 0 deletions
diff --git a/src/com/vaadin/service/FileTypeResolver.java b/src/com/vaadin/service/FileTypeResolver.java
index 7e3dda29a3..5025184ccd 100644
--- a/src/com/vaadin/service/FileTypeResolver.java
+++ b/src/com/vaadin/service/FileTypeResolver.java
@@ -134,6 +134,9 @@ public class FileTypeResolver implements Serializable {
+ "audio/x-pn-realaudio ra rm ram,"
+ "audio/x-scpls pls,"
+ "audio/x-wav wav,"
+ + "audio/ogg ogg,"
+ + "audio/mp4 m4a,"
+ + "audio/x-aac aac,"
+ "image/bitmap bmp,"
+ "image/gif gif,"
+ "image/ief ief,"
@@ -190,6 +193,8 @@ public class FileTypeResolver implements Serializable {
+ "video/x-ms-asf asf asx,"
+ "video/x-msvideo avi,"
+ "video/x-sgi-movie movie,"
+ + "video/ogg ogv,"
+ + "video/mp4 mp4,"
+ "x-world/x-vrml vrm vrml wrl";
/**
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VAudio.java b/src/com/vaadin/terminal/gwt/client/ui/VAudio.java
new file mode 100644
index 0000000000..c8efba2657
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VAudio.java
@@ -0,0 +1,42 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.dom.client.AudioElement;
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.Style;
+import com.google.gwt.dom.client.Style.Unit;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.BrowserInfo;
+import com.vaadin.terminal.gwt.client.UIDL;
+
+public class VAudio extends VMediaBase {
+ private static String CLASSNAME = "v-audio";
+
+ private AudioElement audio;
+
+ public VAudio() {
+ audio = Document.get().createAudioElement();
+ setMediaElement(audio);
+ setStyleName(CLASSNAME);
+ }
+
+ @Override
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ super.updateFromUIDL(uidl, client);
+ Style style = audio.getStyle();
+
+ // Make sure that the controls are not clipped if visible.
+ if (shouldShowControls(uidl)
+ && (style.getHeight() == null || "".equals(style.getHeight()))) {
+ if (BrowserInfo.get().isChrome()) {
+ style.setHeight(32, Unit.PX);
+ } else {
+ style.setHeight(25, Unit.PX);
+ }
+ }
+ }
+
+ @Override
+ protected String getDefaultAltHtml() {
+ return "Your browser does not support the <code>audio</code> element.";
+ }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VMediaBase.java b/src/com/vaadin/terminal/gwt/client/ui/VMediaBase.java
new file mode 100644
index 0000000000..6d6474bbec
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VMediaBase.java
@@ -0,0 +1,129 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.MediaElement;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.Util;
+
+public abstract class VMediaBase extends Widget implements Paintable {
+ public static final String ATTR_PAUSE = "pause";
+ public static final String ATTR_PLAY = "play";
+ public static final String ATTR_MUTED = "muted";
+ public static final String ATTR_CONTROLS = "ctrl";
+ public static final String ATTR_AUTOPLAY = "auto";
+ public static final String TAG_SOURCE = "src";
+ public static final String ATTR_RESOURCE = "res";
+ public static final String ATTR_RESOURCE_TYPE = "type";
+ public static final String ATTR_HTML = "html";
+ public static final String ATTR_ALT_TEXT = "alt";
+
+ private MediaElement media;
+ protected ApplicationConnection client;
+
+ /**
+ * Sets the MediaElement that is to receive all commands and properties.
+ *
+ * @param element
+ */
+ public void setMediaElement(MediaElement element) {
+ setElement(element);
+ media = element;
+ }
+
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ if (client.updateComponent(this, uidl, true)) {
+ return;
+ }
+
+ this.client = client;
+
+ media.setControls(shouldShowControls(uidl));
+ media.setAutoplay(shouldAutoplay(uidl));
+ media.setMuted(isMediaMuted(uidl));
+
+ // Add all sources
+ for (int ix = 0; ix < uidl.getChildCount(); ix++) {
+ UIDL child = uidl.getChildUIDL(ix);
+ if (TAG_SOURCE.equals(child.getTag())) {
+ Element src = Document.get().createElement("source").cast();
+ src.setAttribute("src", getSourceUrl(child));
+ src.setAttribute("type", getSourceType(child));
+ media.appendChild(src);
+ }
+ }
+ setAltText(uidl);
+
+ evalPauseCommand(uidl);
+ evalPlayCommand(uidl);
+ }
+
+ protected boolean shouldShowControls(UIDL uidl) {
+ return uidl.getBooleanAttribute(ATTR_CONTROLS);
+ }
+
+ private boolean shouldAutoplay(UIDL uidl) {
+ return uidl.getBooleanAttribute(ATTR_AUTOPLAY);
+ }
+
+ private boolean isMediaMuted(UIDL uidl) {
+ return uidl.getBooleanAttribute(ATTR_MUTED);
+ }
+
+ /**
+ * @param uidl
+ * @return the URL of a resource to be used as a source for the media
+ */
+ private String getSourceUrl(UIDL uidl) {
+ String url = client.translateVaadinUri(uidl
+ .getStringAttribute(ATTR_RESOURCE));
+ if (url == null) {
+ return "";
+ }
+ return url;
+ }
+
+ /**
+ * @param uidl
+ * @return the mime type of the media
+ */
+ private String getSourceType(UIDL uidl) {
+ return uidl.getStringAttribute(ATTR_RESOURCE_TYPE);
+ }
+
+ private void setAltText(UIDL uidl) {
+ String alt = uidl.getStringAttribute(ATTR_ALT_TEXT);
+
+ if (alt == null || "".equals(alt)) {
+ alt = getDefaultAltHtml();
+ } else if (!allowHtmlContent(uidl)) {
+ alt = Util.escapeHTML(alt);
+ }
+ media.appendChild(Document.get().createTextNode(alt));
+ }
+
+ private boolean allowHtmlContent(UIDL uidl) {
+ return uidl.getBooleanAttribute(ATTR_HTML);
+ }
+
+ private void evalPlayCommand(UIDL uidl) {
+ if (uidl.hasAttribute(ATTR_PLAY)) {
+ media.play();
+ }
+ }
+
+ private void evalPauseCommand(UIDL uidl) {
+ if (uidl.hasAttribute(ATTR_PAUSE)) {
+ media.pause();
+ }
+ }
+
+ /**
+ * @return the default HTML to show users with browsers that do not support
+ * HTML5 media markup.
+ */
+ protected abstract String getDefaultAltHtml();
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VVideo.java b/src/com/vaadin/terminal/gwt/client/ui/VVideo.java
new file mode 100644
index 0000000000..61ca04544a
--- /dev/null
+++ b/src/com/vaadin/terminal/gwt/client/ui/VVideo.java
@@ -0,0 +1,73 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.Style.Unit;
+import com.google.gwt.dom.client.VideoElement;
+import com.google.gwt.user.client.Element;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.Util;
+
+public class VVideo extends VMediaBase {
+ public static final String ATTR_POSTER = "poster";
+
+ private static String CLASSNAME = "v-video";
+
+ private VideoElement video;
+
+ public VVideo() {
+ video = Document.get().createVideoElement();
+ setMediaElement(video);
+ setStyleName(CLASSNAME);
+
+ updateDimensionsWhenMetadataLoaded(getElement());
+ }
+
+ @Override
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ if (client.updateComponent(this, uidl, true)) {
+ return;
+ }
+ super.updateFromUIDL(uidl, client);
+ setPosterFromUIDL(uidl);
+ }
+
+ private void setPosterFromUIDL(UIDL uidl) {
+ if (uidl.hasAttribute(ATTR_POSTER)) {
+ video.setPoster(client.translateVaadinUri(uidl
+ .getStringAttribute(ATTR_POSTER)));
+ }
+ }
+
+ /**
+ * Registers a listener that updates the dimensions of the widget when the
+ * video metadata has been loaded.
+ *
+ * @param el
+ */
+ private native void updateDimensionsWhenMetadataLoaded(Element el)
+ /*-{
+ var self = this;
+ el.addEventListener('loadedmetadata', function(e) {
+ $entry(self.@com.vaadin.terminal.gwt.client.ui.VVideo::updateElementDynamicSize(II)(el.videoWidth, el.videoHeight));
+ }, false);
+
+ }-*/;
+
+ /**
+ * Updates the dimensions of the widget.
+ *
+ * @param w
+ * @param h
+ */
+ private void updateElementDynamicSize(int w, int h) {
+ video.getStyle().setWidth(w, Unit.PX);
+ video.getStyle().setHeight(h, Unit.PX);
+ Util.notifyParentOfSizeChange(this, true);
+ }
+
+ @Override
+ protected String getDefaultAltHtml() {
+ return "Your browser does not support the <code>video</code> element.";
+ }
+}
diff --git a/src/com/vaadin/ui/AbstractMedia.java b/src/com/vaadin/ui/AbstractMedia.java
new file mode 100644
index 0000000000..e085f04367
--- /dev/null
+++ b/src/com/vaadin/ui/AbstractMedia.java
@@ -0,0 +1,217 @@
+package com.vaadin.ui;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import com.vaadin.terminal.PaintException;
+import com.vaadin.terminal.PaintTarget;
+import com.vaadin.terminal.Resource;
+import com.vaadin.terminal.gwt.client.ui.VMediaBase;
+
+/**
+ * Abstract base class for the HTML5 media components.
+ *
+ * @author Vaadin Ltd
+ */
+public class AbstractMedia extends AbstractComponent {
+
+ private List<Resource> sources = new ArrayList<Resource>();
+
+ private boolean showControls;
+
+ private String altText;
+
+ private boolean htmlContentAllowed;
+
+ private boolean autoplay;
+
+ private boolean muted;
+
+ private boolean pause;
+
+ private boolean play;
+
+ /**
+ * Sets a single media file as the source of the media component.
+ *
+ * @param source
+ */
+ public void setSource(Resource source) {
+ sources.clear();
+ addSource(source);
+ }
+
+ /**
+ * Adds an alternative media file to the sources list. Which of the sources
+ * is used is selected by the browser depending on which file formats it
+ * supports. See <a
+ * href="http://en.wikipedia.org/wiki/HTML5_video#Table">wikipedia</a> for a
+ * table of formats supported by different browsers.
+ *
+ * @param source
+ */
+ public void addSource(Resource source) {
+ if (source != null) {
+ sources.add(source);
+ requestRepaint();
+ }
+ }
+
+ /**
+ * Set multiple sources at once. Which of the sources is used is selected by
+ * the browser depending on which file formats it supports. See <a
+ * href="http://en.wikipedia.org/wiki/HTML5_video#Table">wikipedia</a> for a
+ * table of formats supported by different browsers.
+ *
+ * @param sources
+ */
+ public void setSources(Resource... sources) {
+ this.sources.addAll(Arrays.asList(sources));
+ requestRepaint();
+ }
+
+ /**
+ * @return The sources pointed to in this media.
+ */
+ public List<Resource> getSources() {
+ return sources;
+ }
+
+ /**
+ * Sets whether or not the browser should show native media controls.
+ *
+ * @param showControls
+ */
+ public void setShowControls(boolean showControls) {
+ this.showControls = showControls;
+ requestRepaint();
+ }
+
+ /**
+ * @return true if the browser is to show native media controls.
+ */
+ public boolean isShowControls() {
+ return showControls;
+ }
+
+ /**
+ * Sets the alternative text to be displayed if the browser does not support
+ * HTML5. This text is rendered as HTML if
+ * {@link #setHtmlContentAllowed(boolean)} is set to true. With HTML
+ * rendering, this method can also be used to implement fallback to a
+ * flash-based player, see the <a href=
+ * "https://developer.mozilla.org/En/Using_audio_and_video_in_Firefox#Using_Flash"
+ * >Mozilla Developer Network</a> for details.
+ *
+ * @param text
+ */
+ public void setAltText(String text) {
+ altText = text;
+ requestRepaint();
+ }
+
+ /**
+ * @return The text/html that is displayed when a browser doesn't support
+ * HTML5.
+ */
+ public String getAltText() {
+ return altText;
+ }
+
+ /**
+ * Set whether the alternative text ({@link #setAltText(String)}) is
+ * rendered as HTML or not.
+ *
+ * @param htmlContentAllowed
+ */
+ public void setHtmlContentAllowed(boolean htmlContentAllowed) {
+ this.htmlContentAllowed = htmlContentAllowed;
+ requestRepaint();
+ }
+
+ /**
+ * @return true if the alternative text ({@link #setAltText(String)}) is to
+ * be rendered as HTML.
+ */
+ public boolean isHtmlContentAllowed() {
+ return htmlContentAllowed;
+ }
+
+ /**
+ * Sets whether the media is to automatically start playback when enough
+ * data has been loaded.
+ *
+ * @param autoplay
+ */
+ public void setAutoplay(boolean autoplay) {
+ this.autoplay = autoplay;
+ requestRepaint();
+ }
+
+ /**
+ * @return true if the media is set to automatically start playback.
+ */
+ public boolean isAutoplay() {
+ return autoplay;
+ }
+
+ /**
+ * Set whether to mute the audio or not.
+ *
+ * @param muted
+ */
+ public void setMuted(boolean muted) {
+ this.muted = muted;
+ requestRepaint();
+ }
+
+ /**
+ * @return true if the audio is muted.
+ */
+ public boolean isMuted() {
+ return muted;
+ }
+
+ /**
+ * Pauses the media.
+ */
+ public void pause() {
+ pause = true;
+ requestRepaint();
+ }
+
+ /**
+ * Starts playback of the media.
+ */
+ public void play() {
+ play = true;
+ requestRepaint();
+ }
+
+ @Override
+ public void paintContent(PaintTarget target) throws PaintException {
+ super.paintContent(target);
+ target.addAttribute(VMediaBase.ATTR_CONTROLS, isShowControls());
+ if (getAltText() != null) {
+ target.addAttribute(VMediaBase.ATTR_ALT_TEXT, getAltText());
+ }
+ target.addAttribute(VMediaBase.ATTR_HTML, isHtmlContentAllowed());
+ target.addAttribute(VMediaBase.ATTR_AUTOPLAY, isAutoplay());
+ for (Resource r : getSources()) {
+ target.startTag(VMediaBase.TAG_SOURCE);
+ target.addAttribute(VMediaBase.ATTR_RESOURCE, r);
+ target.addAttribute(VMediaBase.ATTR_RESOURCE_TYPE, r.getMIMEType());
+ target.endTag(VMediaBase.TAG_SOURCE);
+ }
+ target.addAttribute(VMediaBase.ATTR_MUTED, isMuted());
+ if (play) {
+ target.addAttribute(VMediaBase.ATTR_PLAY, true);
+ play = false;
+ }
+ if (pause) {
+ target.addAttribute(VMediaBase.ATTR_PAUSE, true);
+ pause = false;
+ }
+ }
+}
diff --git a/src/com/vaadin/ui/Audio.java b/src/com/vaadin/ui/Audio.java
new file mode 100644
index 0000000000..c3d7cf713e
--- /dev/null
+++ b/src/com/vaadin/ui/Audio.java
@@ -0,0 +1,48 @@
+package com.vaadin.ui;
+
+import com.vaadin.terminal.Resource;
+import com.vaadin.terminal.gwt.client.ui.VAudio;
+
+/**
+ * The Audio component translates into an HTML5 &lt;audio&gt; element and as
+ * such is only supported in browsers that support HTML5 media markup. Browsers
+ * that do not support HTML5 display the text or HTML set by calling
+ * {@link #setAltText(String)}.
+ *
+ * A flash-player fallback can be implemented by setting HTML content allowed (
+ * {@link #setHtmlContentAllowed(boolean)} and calling
+ * {@link #setAltText(String)} with the flash player markup. An example of flash
+ * fallback can be found at the <a href=
+ * "https://developer.mozilla.org/En/Using_audio_and_video_in_Firefox#Using_Flash"
+ * >Mozilla Developer Network</a>.
+ *
+ * @author Vaadin Ltd
+ * @since 6.7.0
+ */
+@ClientWidget(VAudio.class)
+public class Audio extends AbstractMedia {
+
+ public Audio() {
+ this("", null);
+ }
+
+ /**
+ * @param caption
+ * The caption of the audio component.
+ */
+ public Audio(String caption) {
+ this(caption, null);
+ }
+
+ /**
+ * @param caption
+ * The caption of the audio component
+ * @param source
+ * The audio file to play.
+ */
+ public Audio(String caption, Resource source) {
+ setCaption(caption);
+ setSource(source);
+ setShowControls(true);
+ }
+}
diff --git a/src/com/vaadin/ui/Video.java b/src/com/vaadin/ui/Video.java
new file mode 100644
index 0000000000..efa7e97317
--- /dev/null
+++ b/src/com/vaadin/ui/Video.java
@@ -0,0 +1,77 @@
+package com.vaadin.ui;
+
+import com.vaadin.terminal.PaintException;
+import com.vaadin.terminal.PaintTarget;
+import com.vaadin.terminal.Resource;
+import com.vaadin.terminal.gwt.client.ui.VVideo;
+
+/**
+ * The Video component translates into an HTML5 &lt;video&gt; element and as
+ * such is only supported in browsers that support HTML5 media markup. Browsers
+ * that do not support HTML5 display the text or HTML set by calling
+ * {@link #setAltText(String)}.
+ *
+ * A flash-player fallback can be implemented by setting HTML content allowed (
+ * {@link #setHtmlContentAllowed(boolean)} and calling
+ * {@link #setAltText(String)} with the flash player markup. An example of flash
+ * fallback can be found at the <a href=
+ * "https://developer.mozilla.org/En/Using_audio_and_video_in_Firefox#Using_Flash"
+ * >Mozilla Developer Network</a>.
+ *
+ * @author Vaadin Ltd
+ * @since 6.7.0
+ */
+@ClientWidget(VVideo.class)
+public class Video extends AbstractMedia {
+
+ private Resource poster;
+
+ public Video() {
+ this("", null);
+ }
+
+ /**
+ * @param caption
+ * The caption for this video.
+ */
+ public Video(String caption) {
+ this(caption, null);
+ }
+
+ /**
+ * @param caption
+ * The caption for this video.
+ * @param source
+ * The Resource containing the video to play.
+ */
+ public Video(String caption, Resource source) {
+ setCaption(caption);
+ setSource(source);
+ setShowControls(true);
+ }
+
+ /**
+ * Sets the poster image, which is shown in place of the video before the
+ * user presses play.
+ *
+ * @param poster
+ */
+ public void setPoster(Resource poster) {
+ this.poster = poster;
+ }
+
+ /**
+ * @return The poster image.
+ */
+ public Resource getPoster() {
+ return poster;
+ }
+
+ @Override
+ public void paintContent(PaintTarget target) throws PaintException {
+ super.paintContent(target);
+ if (getPoster() != null) {
+ target.addAttribute(VVideo.ATTR_POSTER, getPoster());
+ }
+ }
+}
diff --git a/tests/src/com/vaadin/tests/components/media/Media.java b/tests/src/com/vaadin/tests/components/media/Media.java
new file mode 100644
index 0000000000..ff25810042
--- /dev/null
+++ b/tests/src/com/vaadin/tests/components/media/Media.java
@@ -0,0 +1,74 @@
+package com.vaadin.tests.components.media;
+
+import com.vaadin.terminal.ExternalResource;
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.ui.Audio;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Button.ClickListener;
+import com.vaadin.ui.Video;
+
+public class Media extends TestBase {
+
+ @Override
+ protected void setup() {
+ final Video v = new Video("video");
+ v.setSources(
+ new ExternalResource(
+ "http://jonatan.virtuallypreinstalled.com/media/big_buck_bunny.mp4"),
+ new ExternalResource(
+ "http://jonatan.virtuallypreinstalled.com/media/big_buck_bunny.ogv"));
+ v.setWidth("640px");
+ v.setHeight("360px");
+ addComponent(v);
+ addComponent(new Button("Play video", new ClickListener() {
+
+ public void buttonClick(ClickEvent event) {
+ v.play();
+ }
+
+ }));
+ addComponent(new Button("Pause video", new ClickListener() {
+
+ public void buttonClick(ClickEvent event) {
+ v.pause();
+ }
+
+ }));
+
+ final Audio a = new Audio("audio");
+ a.setSources(
+ new ExternalResource(
+ "http://jonatan.virtuallypreinstalled.com/media/audio.mp3"),
+ new ExternalResource(
+ "http://jonatan.virtuallypreinstalled.com/media/audio.ogg"));
+ addComponent(a);
+
+ addComponent(new Button("Play audio", new ClickListener() {
+
+ public void buttonClick(ClickEvent event) {
+ a.play();
+ }
+
+ }));
+ addComponent(new Button("Pause audio", new ClickListener() {
+
+ public void buttonClick(ClickEvent event) {
+ a.pause();
+ }
+
+ }));
+ }
+
+ @Override
+ protected String getDescription() {
+ return "Video and audio files should play using the HTML5 elements. "
+ + "(Movie is (c) copyright 2008, Blender Foundation / www.bigbuckbunny.org)";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 6909;
+ }
+
+}