summaryrefslogtreecommitdiff
path: root/src/plugins/videos/src/com/motorola/studio/android/videos/ui/views/MOTODEVVideosView.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/videos/src/com/motorola/studio/android/videos/ui/views/MOTODEVVideosView.java')
-rw-r--r--src/plugins/videos/src/com/motorola/studio/android/videos/ui/views/MOTODEVVideosView.java1077
1 files changed, 1077 insertions, 0 deletions
diff --git a/src/plugins/videos/src/com/motorola/studio/android/videos/ui/views/MOTODEVVideosView.java b/src/plugins/videos/src/com/motorola/studio/android/videos/ui/views/MOTODEVVideosView.java
new file mode 100644
index 0000000..f5fc912
--- /dev/null
+++ b/src/plugins/videos/src/com/motorola/studio/android/videos/ui/views/MOTODEVVideosView.java
@@ -0,0 +1,1077 @@
+/*
+ * Copyright (C) 2012 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.motorola.studio.android.videos.ui.views;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.net.URL;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jface.action.ControlContribution;
+import org.eclipse.jface.action.ToolBarManager;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.browser.Browser;
+import org.eclipse.swt.browser.BrowserFunction;
+import org.eclipse.swt.browser.ProgressAdapter;
+import org.eclipse.swt.browser.ProgressEvent;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.ControlListener;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Device;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.layout.RowData;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Link;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.IViewSite;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.browser.IWebBrowser;
+import org.eclipse.ui.browser.IWorkbenchBrowserSupport;
+import org.eclipse.ui.part.ViewPart;
+import org.osgi.framework.Bundle;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+import com.motorola.studio.android.common.log.UsageDataConstants;
+import com.motorola.studio.android.common.utilities.EclipseUtils;
+import com.motorola.studio.android.videos.Activator;
+import com.motorola.studio.android.videos.i18n.VideosNLS;
+import com.motorola.studio.android.videos.model.Video;
+import com.motorola.studio.android.videos.model.VideoManager;
+import com.motorola.studio.android.videos.ui.utils.UiUtilities;
+
+/**
+ * The view that contains all MOTODEV Video Tutorials
+ */
+public class MOTODEVVideosView extends ViewPart
+{
+
+ /*
+ * The ID of the view as specified by the extension.
+ */
+ public static final String ID = "com.motorola.studio.android.videos.views.MOTODEVVideosView";
+
+ /*
+ * View state
+ */
+ private final String OPEN_EXTERNAL_BROWSER_PREFERENCE = "open.external.browser";
+
+ /*
+ * Video Manager
+ */
+ private VideoManager videoManager;
+
+ /*
+ * Resource constants
+ */
+ private final String VIDEO_WATCH_EMBED_HTML = "resources/watch_video.html";
+
+ private final String VIDEO_WATCH_EMBED_HTML_JS_LIBRARY = "resources/swfobject.js";
+
+ private final String VIEW_LOADING_ICON = "icons/loading_icon.gif";
+
+ private final String VIEW_ERROR_ICON = "icons/error_icon.png";
+
+ /*
+ * Containers
+ */
+ private Composite parentComposite = null;
+
+ private Composite container = null;
+
+ private VideosListComposite videosListComposite;
+
+ private SashForm sash;
+
+ private VideoPlayerComposite videoPlayerArea;
+
+ private String videoWatchURL;
+
+ private String videoWatchJSLibraryURL;
+
+ private Boolean flashPlayerSupport = null;
+
+ private Boolean isBrowserLoaded = null;
+
+ private static Boolean openExternalBrowser = null;
+
+ public static int PLAY_LISTENER = 43214321;
+
+ private Color backgroundColor = null;
+
+ private Image viewErrorImg = null;
+
+ private String loadingImgFullPath = null;
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.part.ViewPart#init(org.eclipse.ui.IViewSite, org.eclipse.ui.IMemento)
+ */
+ @Override
+ public void init(IViewSite site, IMemento memento) throws PartInitException
+ {
+
+ super.init(site, memento);
+
+ try
+ {
+
+ Device device = getDefaultImage().getDevice();
+ Bundle bundle = Activator.getDefault().getBundle();
+ Display display = getSite().getShell().getDisplay();
+
+ /*
+ * Retrieve view state
+ */
+ if (openExternalBrowser == null && memento != null)
+ {
+ openExternalBrowser = memento.getBoolean(OPEN_EXTERNAL_BROWSER_PREFERENCE);
+ }
+
+ /*
+ * Colors
+ */
+ backgroundColor = display.getSystemColor(SWT.COLOR_LIST_BACKGROUND);
+
+ /*
+ * HTML to be embedded in the browser
+ */
+ videoWatchURL =
+ FileLocator.toFileURL(bundle.getEntry(VIDEO_WATCH_EMBED_HTML)).getFile();
+
+ // using the method getAbsolutePath is necessary for this to work on all systems
+ videoWatchJSLibraryURL =
+ new Path(FileLocator.toFileURL(
+ bundle.getEntry(VIDEO_WATCH_EMBED_HTML_JS_LIBRARY)).getFile())
+ .toPortableString();
+
+ /*
+ * Images to be used
+ */
+ viewErrorImg =
+ new Image(device, FileLocator.toFileURL(bundle.getEntry(VIEW_ERROR_ICON))
+ .getPath());
+
+ loadingImgFullPath =
+ FileLocator.toFileURL(
+ Activator.getDefault().getBundle().getEntry(VIEW_LOADING_ICON))
+ .getPath();
+
+ }
+ catch (IOException e)
+ {
+ StudioLogger.error(this.getClass(), "Error while initializing Videos View", e);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public void createPartControl(Composite parent)
+ {
+
+ // just point to the parent so that it can be accessed by the Job that will be created
+ parentComposite = parent;
+
+ clearContent();
+
+ /*
+ * Display a loading screen while the content is not loaded
+ */
+ displayLoadingScreen(parent);
+
+ /*
+ * Create a Job to load the view content
+ */
+ Job refreshViews = new Job(VideosNLS.UI_Job_Refresh_View)
+ {
+ @Override
+ protected IStatus run(IProgressMonitor monitor)
+ {
+
+ final Boolean[] showErrorComposite = new Boolean[1];
+ showErrorComposite[0] = false;
+
+ final String[] errorMessage = new String[1];
+ errorMessage[0] = null;
+
+ /*
+ * Try to load the videos information.
+ * If an exception is thrown, log the error and prepare to show
+ * the error screen
+ */
+ try
+ {
+ videoManager = VideoManager.getInstance();
+ videoManager.load();
+ videoManager.sort(VideoManager.SORT_MOST_RECENT);
+ }
+ catch (Exception e)
+ {
+ showErrorComposite[0] = true;
+ errorMessage[0] = VideosNLS.UI_ErrorMsg + " " + e.getLocalizedMessage();
+ StudioLogger.error(this.getClass(), "Error while initializing Videos View", e);
+ }
+
+ if (!monitor.isCanceled())
+ {
+
+ /*
+ * Run the following code in the UI thread, whether it's the
+ * error screen or the videos screen itself. Also, disable the
+ * loading composite that is being displayed
+ */
+ Display.getDefault().asyncExec(new Runnable()
+ {
+ public void run()
+ {
+
+ // dispose the loading composite
+ clearContent();
+
+ if (showErrorComposite[0])
+ {
+ // if an error occurred, display the error screen
+ displayErrorScreen(parentComposite, errorMessage[0]);
+ }
+ else
+ {
+ // ... otherwise, continue with the normal workflow
+ displayVideosScreen(parentComposite);
+ }
+
+ }
+ });
+
+ }
+
+ return Status.OK_STATUS;
+ }
+
+ @Override
+ public boolean belongsTo(Object family)
+ {
+ // relate the Job to this view
+ return getTitle().equals(family);
+ }
+
+ };
+
+ // Schedule the job to run
+ refreshViews.schedule();
+
+ }
+
+ /**
+ * Display the videos screen
+ *
+ * @param parent the parent composite
+ */
+ private void displayVideosScreen(Composite parent)
+ {
+
+ // Create the main composite container
+ container = new Composite(parent, SWT.NONE);
+ container.setLayoutData(new GridData(GridData.FILL_BOTH));
+ container.setLayout(new GridLayout(1, false));
+
+ sash = new SashForm(container, SWT.VERTICAL | SWT.SMOOTH | SWT.BORDER);
+
+ sash.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+
+ // Create a global media player area, with the media player and info related to the video
+ createMediaPlayerAndToolbarArea(sash);
+
+ // Create videos list area
+ createVideosListArea(sash);
+
+ // Adjust the media player size then the view changes its size
+ sash.getChildren()[0].addControlListener(new ControlListener()
+ {
+ public void controlResized(ControlEvent e)
+ {
+ videoPlayerArea.adjustMediaPlayerSize(sash);
+ }
+
+ public void controlMoved(ControlEvent e)
+ {
+ //do nothing
+ }
+ });
+
+ sash.setWeights(new int[]
+ {
+ 1, 2
+ });
+ parentComposite.layout();
+
+ }
+
+ /**
+ * Display the loading screen
+ *
+ * @param parent the parent composite
+ * @return the loading composite
+ */
+ private void displayLoadingScreen(Composite parent)
+ {
+ container =
+ displayInfoScreen(parent, loadingImgFullPath, null, VideosNLS.UI_Loading, null,
+ false);
+
+ parentComposite.layout();
+ }
+
+ /**
+ * Display the error screen
+ *
+ * @param parent the parent composite
+ */
+ private void displayErrorScreen(Composite parent, String error)
+ {
+
+ container = displayInfoScreen(parent, null, viewErrorImg, error, new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ EclipseUtils.openNetworkPreferences(getSite().getShell());
+ }
+ }, true);
+
+ parentComposite.layout();
+
+ }
+
+ /**
+ * Generic method that display a information message (loading, error, warning, etc) in
+ * the screen, being composed of an image, a text and possibly a reload button
+ *
+ * @param parent the parent composite
+ * @param imagePath path to the image that must be displayed
+ * @param image alternatively, if no path is provided (null), an Image object can be used
+ * @param message the message to be displayed (a Link will be used to display the message)
+ * @param selectionListener handler to be called when the user clicks on the message
+ * @param reloadButton whether a "reload" button should be displayed or not
+ * @return the composite created to construct the view
+ */
+ private Composite displayInfoScreen(Composite parent, String imagePath, Image image,
+ String message, SelectionListener selectionListener, boolean reloadButton)
+ {
+
+ Composite mainComposite = new Composite(parent, SWT.NONE);
+ mainComposite.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));
+ mainComposite.setLayout(new GridLayout(1, false));
+ mainComposite.setBackground(backgroundColor);
+
+ Composite centeredComposite = new Composite(mainComposite, SWT.NONE);
+ centeredComposite.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));
+ centeredComposite.setLayout(new GridLayout(1, false));
+ centeredComposite.setBackground(backgroundColor);
+
+ /*
+ * Status image
+ */
+ final Label infoImg = new Label(centeredComposite, SWT.NONE);
+ infoImg.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false));
+ infoImg.setBackground(backgroundColor);
+
+ // Checking the mime type doesn't work on Linux
+ // MimetypesFileTypeMap.getDefaultFileTypeMap().getContentType(new File(imagePath)).equals("image/gif"))
+ // Instead of "image/gif", it returns "application/octet-stream"
+ if (imagePath != null && imagePath.endsWith(".gif"))
+ {
+ UiUtilities.displayAnimatedGIF(getDefaultImage().getDevice(), imagePath, infoImg);
+ }
+ else if (image != null)
+ {
+ infoImg.setImage(image);
+ }
+
+ /*
+ * Status text
+ */
+ Link infoText = new Link(centeredComposite, SWT.NONE);
+ GridData loadingTextGridData = new GridData(SWT.CENTER, SWT.NONE, true, false);
+ loadingTextGridData.verticalIndent = 10;
+ infoText.setLayoutData(loadingTextGridData);
+ infoText.setBackground(backgroundColor);
+ infoText.setText(message);
+ if (selectionListener != null)
+ {
+ infoText.addSelectionListener(selectionListener);
+ }
+
+ /*
+ * Reload button, if requested
+ */
+ if (reloadButton)
+ {
+ Button button = new Button(centeredComposite, SWT.NONE);
+ GridData buttonGridData = new GridData(SWT.CENTER, SWT.NONE, false, false);
+ buttonGridData.verticalIndent = 10;
+ button.setLayoutData(buttonGridData);
+ button.setText(VideosNLS.UI_Reload);
+ button.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ reloadView();
+ }
+ });
+ }
+
+ return mainComposite;
+ }
+
+ /**
+ * Select the initial video to be displayed
+ * It's the first video of the first channel
+ */
+ private void selectInitialVideo()
+ {
+
+ if (openExternalBrowser != null && !openExternalBrowser)
+ {
+ Video firstVideo = null;
+ try
+ {
+ firstVideo = videoManager.getActiveChannels().get(0).getVideos().get(0);
+ }
+ catch (Exception e)
+ {
+ StudioLogger.error(this.getClass(), "No initial video to set", e);
+ }
+
+ if (firstVideo != null)
+ {
+ playVideo(firstVideo);
+ }
+
+ videoPlayerArea.adjustVideoPlayerInitialSize();
+ }
+ }
+
+ /**
+ * Clear view content, i.e. remove everything being displayed
+ */
+ private void clearContent()
+ {
+ if (container != null && !container.isDisposed())
+ {
+ container.dispose();
+ }
+
+ }
+
+ /**
+ * Try to reload the view
+ */
+ private void reloadView()
+ {
+ createPartControl(parentComposite);
+ }
+
+ /**
+ * Create the view toolbar, with search field and a checkbox to
+ * define if the video must be displayed inside the view or in
+ * the external browser
+ */
+ private void createToolBar()
+ {
+ ToolBarManager tbManager =
+ (ToolBarManager) getViewSite().getActionBars().getToolBarManager();
+ tbManager.add(new ToolbarContribution("MOTODEV Video Tutorials Toolbar"));
+ tbManager.update(true);
+ getViewSite().getActionBars().updateActionBars();
+ }
+
+ /**
+ * Create the area that contains the media player (browser embedded) as well as
+ * the information about the video being watched.
+ *
+ * Additionally, the toolbar are is also created after the browser is loaded, since
+ * it depends on information acquired during browser loading (such as browser compatibility
+ * and Flash Player availability)
+ *
+ * @param parent the parent SashForm composite
+ */
+ private void createMediaPlayerAndToolbarArea(SashForm parent)
+ {
+ Composite newPage = new Composite(parent, SWT.BORDER);
+ GridLayout layout = new GridLayout(1, false);
+ layout.marginWidth = 1;
+ layout.marginHeight = 1;
+ newPage.setLayout(layout);
+ newPage.setVisible(false);
+
+ videoPlayerArea = new VideoPlayerComposite(newPage);
+ videoPlayerArea.createVideoPlayerArea(new Font(getDefaultImage().getDevice(), getSite()
+ .getShell().getDisplay().getSystemFont().getFontData()[0].getName(), 12, SWT.BOLD));
+ Browser browser = videoPlayerArea.getBrowser();
+ new FlashPlayerDetection(browser, "hasFlashPlayer");
+ // identify when the page is loaded
+ browser.addProgressListener(new ProgressAdapter()
+ {
+
+ @Override
+ public void completed(ProgressEvent event)
+ {
+ // only the first loading matters, so that we remove the listener,
+ // otherwise it would be called each time a new video is selected to
+ // be played
+ isBrowserLoaded = true;
+ videoPlayerArea.getBrowser().removeProgressListener(this);
+
+ /*
+ * The toolbar is only created when the embedded page is loaded
+ */
+ createToolBar();
+ selectInitialVideo();
+ }
+ });
+
+ // Set the JavaScript library source (with the real path) and open the URL
+ File file = getVideoWatchHTML(videoWatchURL, videoWatchJSLibraryURL);
+ browser.setUrl(file.toString());
+ }
+
+ /**
+ * Get the HTML to be used in runtime, with the JavasScript library real path
+ * set. This is necessary because relative paths do not work, and loading
+ * the lib programmatically using JavaScript doesn't work on Linux and MacOS
+ * since this is a async process and the objects defined in the lib might not
+ * be loaded when you try to use them.
+ *
+ * @param fileURL the original HTML file
+ * @param javascriptSrc the JavaScript full path
+ * @return a file with the original HTML file, but with the JavasScript full path set
+ */
+ private File getVideoWatchHTML(String fileURL, String javascriptSrc)
+ {
+
+ File tempFile = null;
+
+ BufferedReader bReader = null;
+ BufferedWriter bWriter = null;
+ FileReader fReader = null;
+ FileWriter fWriter = null;
+ try
+ {
+ // the original file
+ File originalFile = new File(fileURL);
+
+ // the temp file, with the same name as the original
+ String[] tempFileName = originalFile.getName().split("\\.");
+ tempFile = File.createTempFile(tempFileName[0], "." + tempFileName[1]);
+ tempFile.deleteOnExit();
+
+ /*
+ * Read the original file and copy it's content to the temp file,
+ * at the same time that the placeholders for the javascript library
+ * path is replaced by the real path(s)
+ */
+ fReader = new FileReader(originalFile);
+ fWriter = new FileWriter(tempFile);
+ bReader = new BufferedReader(fReader);
+ bWriter = new BufferedWriter(fWriter);
+ String line;
+ StringBuffer stringBuffer = new StringBuffer();
+ while ((line = bReader.readLine()) != null)
+ {
+ stringBuffer.append(line);
+ }
+ bWriter.write(stringBuffer.toString().replace("@@JAVASCRIPT_SRC@@", javascriptSrc));
+
+ }
+ catch (IOException e)
+ {
+ StudioLogger.error(this.getClass(),
+ "Could not create the HTML to be diplayed in the Browser widget", e);
+ }
+ finally
+ {
+ // close both reader/writer
+ try
+ {
+ bWriter.close();
+ bReader.close();
+ fWriter.close();
+ fReader.close();
+ }
+ catch (IOException e)
+ {
+ StudioLogger.error(e.getMessage());
+ }
+
+ }
+
+ return tempFile;
+ }
+
+ /**
+ * Crate the tabs, which represent the playlists
+ *
+ * @param parent the parent composite
+ */
+ private void createVideosListArea(Composite parent)
+ {
+ Composite newPage = new Composite(parent, SWT.NONE);
+ newPage.setLayout(new GridLayout(1, false));
+
+ videosListComposite =
+ new VideosListComposite(newPage, SWT.NONE, videoManager.getActiveChannels(),
+ videoManager.getDefaultChannel().getName());
+ videosListComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ videosListComposite.addListener(MOTODEVVideosView.PLAY_LISTENER, new Listener()
+ {
+ public void handleEvent(Event event)
+ {
+ playVideo((Video) event.data);
+ }
+ });
+ }
+
+ /**
+ * Play the video, whether using the internal or external browser
+ *
+ * @param video the video to be played
+ */
+ private void playVideo(Video video)
+ {
+
+ if (openExternalBrowser == null || openExternalBrowser)
+ {
+ openVideoInExternalBrowser(video);
+ }
+ else
+ {
+ openVideoInEmbeddedBrowser(video);
+ }
+
+ // Log video playback
+ try
+ {
+
+ StudioLogger.collectUsageData(UsageDataConstants.WHAT_VIDEOS_PLAY,
+ UsageDataConstants.KIND_VIDEOS,
+ "Video Played: "
+ + video.getId()
+ + "|"
+ + video.getTitle()
+ + "|"
+ + (openExternalBrowser != null ? openExternalBrowser.toString()
+ : "null"), Activator.PLUGIN_ID, Activator.getDefault()
+ .getBundle().getVersion().toString());
+ }
+ catch (Exception e)
+ {
+ // do nothing, just do that to be safe and to not break the functionality
+ // due to errors when logging usage information
+ }
+
+ }
+
+ /**
+ * Play the video using the embedded browser
+ *
+ * @param video the video to be played
+ */
+ private void openVideoInEmbeddedBrowser(Video video)
+ {
+ videoPlayerArea.openVideo(video);
+ /*
+ * Select video in the list
+ */
+ videosListComposite.setSelectedVideo(video);
+
+ parentComposite.layout();
+
+ /*
+ * Adjust size
+ */
+ videoPlayerArea.adjustMediaPlayerSize(sash);
+ }
+
+ /**
+ * Open the external browser
+ *
+ * @param video the video to be opened
+ */
+ private void openVideoInExternalBrowser(Video video)
+ {
+
+ IWorkbenchBrowserSupport browserSupport = PlatformUI.getWorkbench().getBrowserSupport();
+ IWebBrowser browser;
+ try
+ {
+
+ browser =
+ browserSupport.createBrowser(IWorkbenchBrowserSupport.LOCATION_BAR
+ | IWorkbenchBrowserSupport.NAVIGATION_BAR
+ | IWorkbenchBrowserSupport.AS_EXTERNAL, VideosNLS.UI_MOTODEV_Video
+ + video.getTitle(), null, null);
+ browser.openURL(new URL(video.getExternalLink()));
+
+ }
+ catch (Exception e)
+ {
+ StudioLogger.error(this.getClass(), "Error opening video on external browser", e);
+ }
+ }
+
+ /**
+ * Filter videos in the UI based on the search results
+ *
+ * @param keyword search keyword
+ */
+ private void searchAndFilter(String keyword)
+ {
+ // execute trim and remove duplicated blank spaces
+ keyword = removeDuplicatedBlankSpaces(keyword.trim());
+
+ // search and filter
+ videosListComposite.filter(videoManager.search(keyword), keyword.equals(""));
+ // highlight keywords
+ videosListComposite.highlightKeywords(keyword);
+
+ }
+
+ /**
+ * Remove all duplicated spaces in a given string
+ *
+ * @param text the string to have duplicated spaces removed
+ * @return the string passed as parameter with no duplicated spaces
+ */
+ private String removeDuplicatedBlankSpaces(String text)
+ {
+ Pattern pattern = Pattern.compile("\\s+");
+ Matcher matcher = pattern.matcher(text);
+ matcher.find();
+ return matcher.replaceAll(" ");
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.part.WorkbenchPart#dispose()
+ */
+ @Override
+ public void dispose()
+ {
+ super.dispose();
+ if (container != null && !container.isDisposed())
+ {
+ container.dispose();
+ }
+ // cancel all jobs related to this view
+ Job.getJobManager().cancel(getTitle());
+ }
+
+ /*
+ * Save the view state when the workbench is closed
+ *
+ * @see org.eclipse.ui.part.ViewPart#saveState(org.eclipse.ui.IMemento)
+ */
+ @Override
+ public void saveState(IMemento memento)
+ {
+ if (canPlayEmbeddedVideo() && openExternalBrowser != null)
+ {
+ memento.putBoolean(OPEN_EXTERNAL_BROWSER_PREFERENCE, openExternalBrowser);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.part.WorkbenchPart#setFocus()
+ */
+ @Override
+ public void setFocus()
+ {
+ // nothing
+ }
+
+ /**
+ * Check if the browser can load web pages. Due to several problems of the
+ * Browser widget on Linux, we are disabling this feature on this OS for now.
+ *
+ * Some of the problems on Linux are:
+ * - Browser doesn't work with some proxies
+ * - Intermitent crashes of SWT
+ * - The Browser widget blinks on the screen
+ *
+ * For MacOS X, it's enabled only from Snow Leopard on (> 10.6), since the Browser
+ * widget might not work correctly in Leopard with Flash Player 64 bits, since the
+ * kernel modules themselves run in 32 bits, what causes a crash (Studio closes).
+ *
+ * @return "true" if the browser can load pages, "false" otherwise
+ */
+ private boolean canPlayEmbeddedVideo()
+ {
+
+ Boolean result = false;
+
+ // for now, the correct version will only be analyzed on MacOSX
+ boolean correctVersion = true;
+
+ if (Platform.getOS().equals(Platform.OS_MACOSX))
+ {
+ String versionText = System.getProperty("os.version");
+
+ // Get the version as a number
+ float versionNumber = 0;
+ try
+ {
+
+ if (!versionText.contains("."))
+ {
+ versionNumber = Integer.parseInt(versionText);
+ }
+ else
+ {
+ String[] versionPieces = versionText.split("\\.");
+ versionNumber =
+ Float.parseFloat(versionPieces[0] + "."
+ + (!versionPieces[1].equals("") ? versionPieces[1] : "0"));
+
+ }
+ }
+ catch (NumberFormatException e)
+ {
+ StudioLogger.error(this.getClass(), "Cannot get the OS version", e);
+ }
+
+ // Leopard = 10.5 = not supported
+ if (versionNumber <= 10.5)
+ {
+ correctVersion = false;
+ }
+
+ }
+
+ // If we are not on Linux and the MacOS X has the correct version,
+ // check if the browser could load the web page and, consequently,
+ // if the flash player is supported or not
+ if (!Platform.getOS().equals(Platform.OS_LINUX) && correctVersion)
+ {
+ if (isBrowserLoaded != null && isBrowserLoaded && flashPlayerSupport != null)
+ {
+ result = true;
+ }
+ }
+
+ // Log player support
+ try
+ {
+
+ StudioLogger.collectUsageData(UsageDataConstants.WHAT_VIDEOS_PLAYER_SUPPORT,
+ UsageDataConstants.KIND_VIDEOS, result.toString() + "|" + Platform.getOS()
+ + "|" + correctVersion, Activator.PLUGIN_ID, Activator.getDefault()
+ .getBundle().getVersion().toString());
+ }
+ catch (Exception e)
+ {
+ // do nothing, just do that to be safe and to not break the functionality
+ // due to errors when logging usage information
+ }
+
+ return result;
+ }
+
+ /**
+ * Check if an appropriate version of Flash Player was found, which
+ * means that the videos can be displayed in the embedded browser
+ *
+ * @return "true" if an appropriate version of Flash Player was found, "false" otherwise
+ */
+ private boolean hasFlashPlayer()
+ {
+ Boolean result = false;
+
+ if (isBrowserLoaded != null && isBrowserLoaded && flashPlayerSupport != null)
+ {
+ result = flashPlayerSupport;
+ }
+
+ // Log flash player support
+ try
+ {
+
+ StudioLogger.collectUsageData(UsageDataConstants.WHAT_VIDEOS_PLAYER_SUPPORT,
+ UsageDataConstants.KIND_VIDEOS, result.toString(), Activator.PLUGIN_ID,
+ Activator.getDefault().getBundle().getVersion().toString());
+ }
+ catch (Exception e)
+ {
+ // do nothing, just do that to be safe and to not break the functionality
+ // due to errors when logging usage information
+ }
+
+ return result;
+ }
+
+ /**
+ * Get the message that will be displayed to the user to inform that
+ * the appropriate version of Flash Player was not found
+ *
+ * @return the "no Flash Player" message
+ */
+ private String getNoFlashMessage()
+ {
+ String message = VideosNLS.UI_No_Flash_Player + " ";
+
+ if (Platform.getOSArch().equals(Platform.ARCH_X86))
+ {
+ // 32 bits
+ message +=
+ NLS.bind(VideosNLS.UI_No_Flash_Player_32bits_Extension,
+ VideosNLS.UI_Flash_Player_Link_32bits);
+ }
+ else
+ {
+ // 64 bits
+ message +=
+ NLS.bind(VideosNLS.UI_No_Flash_Player_64bits_Extension,
+ VideosNLS.UI_Flash_Player_Link_64bits);
+ }
+
+ return message;
+ }
+
+ /**
+ * Create the toolbar, with a search field and a checkbox to
+ * define if the video must be displayed inside the view or in
+ * the external browser
+ */
+ private class ToolbarContribution extends ControlContribution
+ {
+
+ protected ToolbarContribution(String id)
+ {
+ super(id);
+ }
+
+ @Override
+ protected Control createControl(Composite parent)
+ {
+
+ Composite toolbarComposite = new Composite(parent, SWT.NONE);
+ toolbarComposite.setLayout(new RowLayout(SWT.HORIZONTAL));
+
+ final Text searchText = new Text(toolbarComposite, SWT.SEARCH);
+ searchText.setLayoutData(new RowData(150, SWT.DEFAULT));
+ searchText.setMessage(VideosNLS.UI_Search);
+
+ searchText.addModifyListener(new ModifyListener()
+ {
+ public void modifyText(ModifyEvent e)
+ {
+ searchAndFilter(searchText.getText());
+ }
+ });
+
+ if (canPlayEmbeddedVideo())
+ {
+
+ // recover the state, if there is flash player
+ // if there is NO flash player, the checkbox is always selected
+ boolean enablement = hasFlashPlayer();
+ boolean selection =
+ !enablement ? true : openExternalBrowser != null ? openExternalBrowser
+ : false;
+ final Button openExternal = new Button(toolbarComposite, SWT.CHECK);
+ openExternal.setText(VideosNLS.UI_Open_External_Browser);
+ openExternal.setToolTipText(VideosNLS.UI_Open_External_Browser);
+ openExternal.setEnabled(enablement);
+ openExternal.setSelection(selection);
+ openExternalBrowser = selection;
+
+ if (!enablement)
+ {
+ Label warningImg = new Label(toolbarComposite, SWT.NONE);
+ warningImg.setImage(PlatformUI.getWorkbench().getSharedImages()
+ .getImage(ISharedImages.IMG_OBJS_WARN_TSK));
+ warningImg.setToolTipText(getNoFlashMessage());
+ }
+
+ openExternal.addSelectionListener(new SelectionAdapter()
+ {
+ @Override
+ public void widgetSelected(SelectionEvent e)
+ {
+ openExternalBrowser = openExternal.getSelection();
+ }
+ });
+
+ }
+
+ return toolbarComposite;
+
+ }
+ }
+
+ /**
+ * Function called from JavaScript to inform if the browser
+ * could find Adobe Flash Player or not
+ */
+ private class FlashPlayerDetection extends BrowserFunction
+ {
+
+ @Override
+ public Object function(Object[] arguments)
+ {
+ flashPlayerSupport = new Boolean(arguments[0].toString());
+ return null;
+ }
+
+ public FlashPlayerDetection(Browser browser, String name)
+ {
+ super(browser, name);
+ }
+
+ }
+
+} \ No newline at end of file