/* * 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.File; import java.util.ArrayList; import java.util.List; import org.eclipse.core.runtime.FileLocator; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.ScrolledComposite; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.dnd.Clipboard; import org.eclipse.swt.dnd.TextTransfer; import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.events.ControlListener; import org.eclipse.swt.events.MouseAdapter; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Cursor; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.ImageData; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; 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.Menu; import org.eclipse.swt.widgets.MenuItem; import com.motorola.studio.android.common.log.StudioLogger; 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; /** * A specialized Composite to be used to represent a single Video * */ public class VideoComposite extends Composite { /* * Video Manager */ private VideoManager videoManager; /* * The video that is being represented */ private Video video = null; /* * Resource constants */ private final String PLAY_ICON = "icons/play_icon.png"; private final String THUMBNAIL_LOADING_ICON = "icons/thumbnail_loading.png"; private final String THUMBNAIL_NOT_AVAILABLE_ICON = "icons/preview_not_available.png"; /* * Other global elements and resources */ private Image playImg = null; private Image thumbLoadingImg = null; private Font videoTitleFont = null; private Font videoTitleSelectedFont = null; private Color highlightTextColor = null; private Color backgroundColor = null; private boolean showAllDescription = false; /* * Some widgets in the composite */ private StyledText videoTitle = null; private final List<StyledText> styledTexts = new ArrayList<StyledText>(); /* * Parent class */ private VideosListComposite parentClass = null; private final ScrolledComposite scrollParent; /* * Layout details */ private final int MINIMUM_DESCRIPTION_COLUMN_WIDTH = 200; /** * Constructor responsible for creating the entire component * * @param parent the parent composite * @param style SWT style * @param video the video to be represented */ public VideoComposite(VideosListComposite parentClass, Composite parent, ScrolledComposite scrollParent, int style, Video video) { super(parent, style); this.video = video; this.parentClass = parentClass; this.scrollParent = scrollParent; init(); createControls(); } /** * Initialize variables and resources */ private void init() { try { // Video Manager instance videoManager = VideoManager.getInstance(); /* * Images to be used */ playImg = new Image(getShell().getDisplay(), FileLocator.toFileURL( Activator.getDefault().getBundle().getEntry(PLAY_ICON)).getPath()); thumbLoadingImg = new Image(getShell().getDisplay(), FileLocator.toFileURL( Activator.getDefault().getBundle().getEntry(THUMBNAIL_LOADING_ICON)) .getPath()); /* * Fonts */ videoTitleFont = new Font(getShell().getDisplay(), getShell().getDisplay().getSystemFont() .getFontData()[0].getName(), 10, SWT.BOLD); videoTitleSelectedFont = new Font(getShell().getDisplay(), getShell().getDisplay().getSystemFont() .getFontData()[0].getName(), 10, SWT.BOLD | SWT.ITALIC); /* * Colors */ backgroundColor = getShell().getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND); highlightTextColor = getShell().getDisplay().getSystemColor(SWT.COLOR_LIST_SELECTION); } catch (Exception e) { StudioLogger.error(this.getClass(), "Error while initializing Video Composite", e); } } /** * Create all widgets of this composite */ private void createControls() { // set the composite layout setLayout(new GridLayout(3, false)); setBackground(backgroundColor); // Set loading thumbnail image final Label videoImage = new Label(this, SWT.NONE); videoImage.setImage(thumbLoadingImg); // Get the real thumbnail Thread updateVideoImage = new Thread(new Runnable() { public void run() { // this operation is time consuming (require internet access) // that's why we are using a new thread and just after we have the // file download we use the UI thread final File thumbnail = videoManager.getThumbnail(video.getSnapshot()); Display.getDefault().syncExec(new Runnable() { public void run() { Image videoImg = thumbnail != null ? new Image(getShell().getDisplay(), thumbnail .toString()) : null; // make sure the element still exists, the view can be closed if (!videoImage.isDisposed()) { if (videoImg != null) { videoImage.setImage(videoImg); } else { ImageData notAvailable = Activator.imageDescriptorFromPlugin(Activator.PLUGIN_ID, THUMBNAIL_NOT_AVAILABLE_ICON).getImageData(); Point size = videoImage.getSize(); if (videoImage.getImage() != null && !videoImage.getImage().isDisposed()) { size = new Point(videoImage.getImage().getBounds().width, videoImage.getImage().getBounds().height); videoImage.getImage().dispose(); } videoImage.setImage(new Image(getShell().getDisplay(), notAvailable .scaledTo(size.x, size.y))); } } } }); } }); updateVideoImage.start(); videoImage.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false)); videoImage.setBackground(backgroundColor); final Composite titleAndDescriptionComposite = new Composite(this, SWT.WRAP | SWT.BACKGROUND); GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); data.widthHint = MINIMUM_DESCRIPTION_COLUMN_WIDTH; data.minimumWidth = MINIMUM_DESCRIPTION_COLUMN_WIDTH; data.heightHint = videoImage.getSize().y; titleAndDescriptionComposite.setLayoutData(data); titleAndDescriptionComposite.setLayout(new GridLayout(1, true)); titleAndDescriptionComposite.setBackground(backgroundColor); videoTitle = new StyledText(titleAndDescriptionComposite, SWT.WRAP | SWT.BACKGROUND); videoTitle.setEnabled(false); videoTitle.setBackground(backgroundColor); videoTitle.setFont(videoTitleFont); data = new GridData(SWT.FILL, SWT.FILL, true, false); videoTitle.setLayoutData(data); styledTexts.add(videoTitle); final StyledText videoDescription = new StyledText(titleAndDescriptionComposite, SWT.WRAP | SWT.BACKGROUND); videoDescription.setEnabled(false); videoDescription.setBackground(backgroundColor); data = new GridData(SWT.FILL, SWT.FILL, true, true); videoDescription.setLayoutData(data); styledTexts.add(videoDescription); Composite playButtonArea = new Composite(this, SWT.NONE); GridLayout layout = new GridLayout(1, true); playButtonArea.setLayoutData(new GridData(SWT.NONE, SWT.NONE, false, false)); playButtonArea.setLayout(layout); playButtonArea.setBackground(backgroundColor); Label playImage = new Label(playButtonArea, SWT.NONE); playImage.setImage(playImg); playImage.setBackground(backgroundColor); playImage.setToolTipText(VideosNLS.UI_Play_Video); playImage.setCursor(new Cursor(getShell().getDisplay(), SWT.CURSOR_HAND)); playImage.setLayoutData(new GridData(SWT.NONE, SWT.NONE, false, false)); videoTitle.setText(video.getTitle()); videoDescription.setText(video.getDescription()); final Label moreText = new Label(playButtonArea, SWT.WRAP | SWT.BACKGROUND); moreText.addMouseListener(new MouseListener() { public void mouseUp(MouseEvent e) { if (!showAllDescription) { showAllDescription = true; GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); data.widthHint = MINIMUM_DESCRIPTION_COLUMN_WIDTH; data.minimumWidth = MINIMUM_DESCRIPTION_COLUMN_WIDTH; titleAndDescriptionComposite.setLayoutData(data); } else { showAllDescription = false; GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); data.widthHint = MINIMUM_DESCRIPTION_COLUMN_WIDTH; data.minimumWidth = MINIMUM_DESCRIPTION_COLUMN_WIDTH; data.heightHint = videoImage.getSize().y; titleAndDescriptionComposite.setLayoutData(data); } // redraw everything parentClass.layout(); ((Composite) scrollParent.getContent()).layout(true); scrollParent.setMinSize(scrollParent.getContent().computeSize(SWT.DEFAULT, SWT.DEFAULT)); } public void mouseDown(MouseEvent e) { //do nothing } public void mouseDoubleClick(MouseEvent e) { //do nothing } }); titleAndDescriptionComposite.addControlListener(new ControlListener() { public void controlResized(ControlEvent e) { Point descriptionPreferedSize = videoDescription.computeSize(titleAndDescriptionComposite.getSize().x, SWT.DEFAULT); Point titlePreferedSize = videoTitle.computeSize(titleAndDescriptionComposite.getSize().x, SWT.DEFAULT); int preferedHeight = descriptionPreferedSize.y + titlePreferedSize.y; if (preferedHeight + 20 > videoImage.getSize().y) { moreText.setCursor(new Cursor(getShell().getDisplay(), SWT.CURSOR_HAND)); moreText.setBackground(backgroundColor); GridData data = new GridData(SWT.CENTER, SWT.TOP, false, false); moreText.setLayoutData(data); moreText.setVisible(true); if (!showAllDescription) { moreText.setText("(+)"); moreText.setToolTipText(VideosNLS.UI_More); } else { moreText.setText("(-)"); moreText.setToolTipText(VideosNLS.UI_Less); } } else { moreText.setVisible(false); moreText.setCursor(new Cursor(getShell().getDisplay(), SWT.CURSOR_ARROW)); } } public void controlMoved(ControlEvent e) { // do nothing } }); playImage.addMouseListener(new MouseAdapter() { @Override public void mouseDown(MouseEvent e) { Event event = new Event(); event.data = video; parentClass.notifyListeners(MOTODEVVideosView.PLAY_LISTENER, event); } }); // create and set the pop-up menu for the composite and all widgets in the composite setMenuForAllWidgets(this, createVideoPopupMenu()); } /** * Add a menu item in the video composite right-click, with options * to copy the video URL * * @param videoComposite the video composite * @param video the video being represented by the composite * @return the menu */ private Menu createVideoPopupMenu() { Menu popupMenu = new Menu(getShell(), SWT.POP_UP); MenuItem videoUrl = new MenuItem(popupMenu, SWT.NONE); videoUrl.setText(VideosNLS.UI_Copy_URL); MenuItem videoEmbeddedUrl = new MenuItem(popupMenu, SWT.NONE); videoEmbeddedUrl.setText(VideosNLS.UI_Copy_Embedded_URL); videoUrl.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { copyTextToClipboard(video.getExternalLink()); } }); videoEmbeddedUrl.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { copyTextToClipboard(video.getEmbeddedLink()); } }); return popupMenu; } /** * Recursively add the menu for all widgets * * @param mainComposite the main composite * @param popupMenu the menu to be added to the main composite all all children widgets */ private void setMenuForAllWidgets(Composite mainComposite, Menu popupMenu) { mainComposite.setMenu(popupMenu); for (Control control : mainComposite.getChildren()) { control.setMenu(popupMenu); if (control instanceof Composite && ((Composite) control).getChildren().length > 0) { setMenuForAllWidgets((Composite) control, popupMenu); } } } /** * Copy the selected text to clipboard * * @param text the text to be copied to the clipboard */ private void copyTextToClipboard(String text) { Clipboard clipboard = new Clipboard(getShell().getDisplay()); clipboard.setContents(new Object[] { text }, new Transfer[] { TextTransfer.getInstance() }); } /** * Change the element appearance to mark it as selected */ public void select() { videoTitle.setFont(videoTitleSelectedFont); } /** * Change the element appearance to the default one */ public void deselect() { videoTitle.setFont(videoTitleFont); } /** * Highlight the given keyword in the composite * * @param keyword the keyword to be highlighted */ public void highlightKeyword(String keyword) { for (StyledText styledText : styledTexts) { UiUtilities.highlightKeywords(styledText, keyword, highlightTextColor); } } /** * Retrieve the video being represented * * @return the video that is being represented */ public Video getVideo() { return video; } }