| /* |
| * 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); |
| } |
| |
| } |
| |
| } |