summaryrefslogtreecommitdiff
path: root/src/plugins/videos/src/com/motorola/studio/android/videos/ui/utils/UiUtilities.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/videos/src/com/motorola/studio/android/videos/ui/utils/UiUtilities.java')
-rw-r--r--src/plugins/videos/src/com/motorola/studio/android/videos/ui/utils/UiUtilities.java289
1 files changed, 289 insertions, 0 deletions
diff --git a/src/plugins/videos/src/com/motorola/studio/android/videos/ui/utils/UiUtilities.java b/src/plugins/videos/src/com/motorola/studio/android/videos/ui/utils/UiUtilities.java
new file mode 100644
index 0000000..674b15e
--- /dev/null
+++ b/src/plugins/videos/src/com/motorola/studio/android/videos/ui/utils/UiUtilities.java
@@ -0,0 +1,289 @@
+/*
+ * 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.utils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.swt.custom.StyleRange;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.Device;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.ImageLoader;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+
+import com.motorola.studio.android.common.log.StudioLogger;
+
+/**
+ * General UI Utilities used by the MOTODEV Studio Videos View
+ */
+public class UiUtilities
+{
+
+ /**
+ * Highlight the search keyword in the styled text provided
+ *
+ * @param styledText the styled text to be decorated
+ * @param keyword the keyword to be highlighted in the styled text
+ * @param highlightTextColor the background color to be used to highlight the keyword
+ */
+ public static void highlightKeywords(StyledText styledText, String keyword,
+ Color highlightTextColor)
+ {
+
+ // split into multiple keywords
+ String[] keywordPieces = keyword.split(" ");
+
+ /*
+ * Define which characters must be highlighted by creating a boolean array with the text
+ * size plus 1 (the last position will remain with the default value - false, and that's
+ * important to define the last segment to be highlighted)
+ */
+ List<Integer> startOffsets = null;
+ boolean[] highlightedChars = null;
+ highlightedChars = new boolean[styledText.getText().length() + 1];
+
+ // for each keyword, define which characters must be highlighted in the string / StyledText
+ for (String keywordPiece : keywordPieces)
+ {
+ // find all occurrences of that keyword
+ startOffsets =
+ findAllIndexOf(styledText.getText().toUpperCase(), keywordPiece.toUpperCase());
+
+ if (startOffsets.size() > 0)
+ {
+ // for each occurrence, mark the characters that must be highlighted
+ for (int startOffset : startOffsets)
+ {
+ for (int i = startOffset; i < startOffset + keywordPiece.length(); i++)
+ {
+ highlightedChars[i] = true;
+ }
+ }
+
+ }
+ }
+
+ // finally, create and set the style ranges based on the boolean array with the
+ // information about what characters that must be highlighted
+ styledText.setStyleRanges(createStyleRanges(highlightedChars, highlightTextColor));
+ }
+
+ /**
+ * Create and return an array of StyleRanges based on a boolean array defining which characters
+ * must be highlighted in the StyledText
+ *
+ * @param highlightedChars a boolean array defining which characters must be highlighted in the StyledText
+ * @param highlightTextColor the background color to be used to highlight the keyword
+ * @return an array of the StyleRanges that must be applied to the StyledText
+ */
+ private static StyleRange[] createStyleRanges(boolean[] highlightedChars,
+ Color highlightTextColor)
+ {
+
+ List<StyleRange> styleRanges = new ArrayList<StyleRange>();
+
+ // the start variable marks the start of a new segment
+ Integer start = null;
+ for (int j = 0; j < highlightedChars.length; j++)
+ {
+ if (highlightedChars[j] == true)
+ {
+ // this is the beginning of a new segment. If start is not
+ // null, then this is just an adjacent character in the current segment
+ if (start == null)
+ {
+ start = j;
+ }
+ }
+ else
+ {
+ // end of the current segment, register it and continue searching for the next segment
+ if (start != null)
+ {
+ styleRanges.add(getHighlightStyle(start, j - start, highlightTextColor));
+ start = null;
+ }
+ }
+ }
+
+ return styleRanges.toArray(new StyleRange[styleRanges.size()]);
+
+ }
+
+ /**
+ * Find all "indexOf" of a keyword in a string, and not only the
+ * first one, as the method available in the String type implementation
+ *
+ * @param text the base string
+ * @param keyword the keyword to be find in the base string
+ * @return a list with all indexes
+ */
+ private static List<Integer> findAllIndexOf(String text, String keyword)
+ {
+ List<Integer> allIndexes = new ArrayList<Integer>();
+
+ if (!keyword.equals(""))
+ {
+ int index = text.indexOf(keyword);
+ while (index >= 0)
+ {
+ allIndexes.add(index);
+ index = text.indexOf(keyword, index + keyword.length());
+ }
+ }
+
+ return allIndexes;
+ }
+
+ /**
+ * Create the StyleRange that will be used to highlight the keyword in a given location
+ *
+ * @param startOffset where the keyword starts in a string
+ * @param length the size of the keyword
+ * @param highlightTextColor the background color to be used to highlight the keyword
+ * @return the corresponding StyleRange
+ */
+ private static StyleRange getHighlightStyle(int startOffset, int length,
+ Color highlightTextColor)
+ {
+ StyleRange styleRange = new StyleRange();
+ styleRange.start = startOffset;
+ styleRange.length = length;
+ styleRange.background = highlightTextColor;
+ return styleRange;
+ }
+
+ /**
+ * Display an animated GIF in a Label
+ *
+ * @param device the device object to be used to create the UI components
+ * @param path the GIF path
+ * @param container the Label where the GIF will be displayed
+ */
+ public static void displayAnimatedGIF(final Device device, final String path,
+ final Label container)
+ {
+
+ // create the image loader
+ final ImageLoader imageLoader = new ImageLoader();
+ imageLoader.load(path);
+
+ // create GC and set the first image
+ final Image firstImage = new Image(device, imageLoader.data[0]);
+ final GC gc = new GC(firstImage);
+ container.setImage(firstImage);
+
+ // the paint listener is important because just calling redraw on the
+ // container doesn't update the content (actually, that works on Windows,
+ // but on Linux and MacOS it doesn't)
+ container.addPaintListener(new PaintListener()
+ {
+ public void paintControl(PaintEvent e)
+ {
+ e.gc.drawImage(firstImage, 0, 0);
+ }
+ });
+
+ /*
+ * Create a thread that flip among the other images in the GIF
+ */
+ final Thread thread = new Thread()
+ {
+ @Override
+ public void run()
+ {
+
+ try
+ {
+ final Integer[] imageNumber = new Integer[1];
+ imageNumber[0] = 0;
+
+ /*
+ * Do it until the thread is interrupted
+ */
+ while (true)
+ {
+
+ // wait the appropriate time
+ int delayTime = imageLoader.data[imageNumber[0]].delayTime;
+ Thread.sleep(delayTime * 10);
+
+ // draw the next image
+ // it's a sync call so that the executions are not delayed and grouped in the
+ // feature. Ex: after some time, 10 calls are executed one right after another,
+ // what will flip among 10 images in the GIF almost at the same time, which
+ // has no value to the user. Using syncExec we prevent that.
+ Display.getDefault().syncExec(new Runnable()
+ {
+ public void run()
+ {
+ // cyclic counter
+ imageNumber[0] =
+ imageNumber[0].intValue() == imageLoader.data.length - 1
+ ? 0 : imageNumber[0] + 1;
+
+ ImageData nextImageData = imageLoader.data[imageNumber[0]];
+ Image nextImage = new Image(device, nextImageData);
+
+ gc.drawImage(nextImage, nextImageData.x, nextImageData.y);
+ nextImage.dispose();
+
+ // redraw
+ if (!container.isDisposed())
+ {
+ container.redraw();
+ }
+ }
+ });
+
+ }
+ }
+ catch (InterruptedException e)
+ {
+ StudioLogger.info(this.getClass(),
+ "Thread displaying animated GIF was interrupted: " + path);
+ }
+ }
+ };
+
+ /*
+ * When the container is disposed, the thread that flips
+ * among the images in the GIF is also stopped
+ */
+ container.addDisposeListener(new DisposeListener()
+ {
+
+ public void widgetDisposed(DisposeEvent e)
+ {
+ thread.interrupt();
+ }
+ });
+
+ // start the thread
+ thread.start();
+
+ }
+
+}