<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>my2cents &#187; Eclipse</title>
	<atom:link href="http://www.frightanic.com/tag/eclipse/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.frightanic.com</link>
	<description>&#34;The Earth was made round so that we would not see too far down the road&#34; - Karen Blixen</description>
	<lastBuildDate>Sat, 04 Sep 2010 07:13:56 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Animated GIF in SWT table/tree viewer cell</title>
		<link>http://www.frightanic.com/2010/02/09/animated-gif-in-swt-tabletree-viewer-cell/</link>
		<comments>http://www.frightanic.com/2010/02/09/animated-gif-in-swt-tabletree-viewer-cell/#comments</comments>
		<pubDate>Tue, 09 Feb 2010 20:45:32 +0000</pubDate>
		<dc:creator>frightanic</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Eclipse]]></category>
		<category><![CDATA[LabelProvider]]></category>
		<category><![CDATA[SWT]]></category>

		<guid isPermaLink="false">http://www.frightanic.com/?p=459</guid>
		<description><![CDATA[In a recent stackoverflow.com question I asked for input on how to implemented animated GIFs in SWT table/tree viewer cells. Below is some code of the final solution. Animation thread The animation thread can be asked for the &#8220;current frame index&#8221; (CFI) by interested parties. The CFI thusly denotes the frame of an animated GIF [...]]]></description>
			<content:encoded><![CDATA[<p>In a <a href="http://stackoverflow.com/questions/2037353/animated-gif-in-swt-table-tree-viewer-cell/" target="_blank">recent stackoverflow.com question</a> I asked for input on how to implemented animated GIFs in SWT table/tree viewer cells. Below is some code of the final solution.</p>
<h2>Animation thread</h2>
<p>The animation thread can be asked for the &#8220;current frame index&#8221; (CFI) by interested parties. The CFI thusly denotes the frame of an animated GIF which should be rendered. LabelProviders are the interested parties in this context because they actually render the images.</p>
<p>The thread increments the CFI in its run method. Also, Display#asyncExec is triggered in the run method. During the async execution the table/tree is ask to redraw and update &#8211; see lines 69ff.</p>
<pre class="brush: java;" lang="java">/**
 * This animation thread doesn't actually animate anything itself. However, it acts as a pace maker
 * for other components that are able to render animated images. In a loop this thread marks
 * designated columns of a tree viewer (see constructor) for redrawing and calls
 * <code>update()</code> on the tree itself. Label providers on the other hand ask this thread for
 * the current frame index whenever they're triggered provide an image for the designated column.
 *
 * The viewer's content provider is ideally suited to control the life cycle of this thread. It can
 * create/destroy a thread instance whenever the viewer's content is updated.
 *
 */
public class BuildColorAnimationThread extends Thread {

  private final TreeViewer viewer;
  private final int animationColumnIndex;
  private final ImageLoader sampleImage;
  private int currentFrameIndex;
  private boolean cancel;
  private static BuildColorAnimationThread runningInstance;

  /**
   * C'tor which sets this instance to be the one running instance.
   *
   * @param viewer the viewer whose content should be animated
   * @param animationColumnIndex the index of the column to be animated
   * @param sampleImage a sample image which resembles the animation images in the viewer, the
   *        thread uses it to extract repeat-counts and frame delays
   * @see BuildColorAnimationThread#getRunningInstance()
   */
  public BuildColorAnimationThread(final TreeViewer viewer, final int animationColumnIndex,
      final ImageLoader sampleImage) {
    this.viewer = viewer;
    this.animationColumnIndex = animationColumnIndex;
    this.sampleImage = sampleImage;
    this.currentFrameIndex = 0;
    BuildColorAnimationThread.setRunningInstance(this);
  }

  /**
   * Returns the running instance of the animation thread or null if there's none.
   *
   * @return the running instance of the animation thread or null if there's none
   */
  public static BuildColorAnimationThread getRunningInstance() {
    return runningInstance;
  }

  private static void setRunningInstance(BuildColorAnimationThread runningInstance) {
    BuildColorAnimationThread.runningInstance = runningInstance;
  }

  @Override
  public void run() {
    int repeatCount = this.sampleImage.repeatCount;
    /*
     * The repeat count takes into consideration that an animated image might not be animated
     * infinitely but only for a given number of loops.
     */
    while (!this.cancel &amp;&amp; !this.viewer.getTree().isDisposed()
        &amp;&amp; (this.sampleImage.repeatCount == 0 || repeatCount &gt; 0)) {
      this.viewer.getTree().getDisplay().asyncExec(new Runnable() {

        public void run() {
          final BuildColorAnimationThread thread = BuildColorAnimationThread.this;
          final Tree tree = thread.viewer.getTree();
          if (!tree.isDisposed()) {
            final Rectangle clientArea = tree.getClientArea();
            // Marks ONLY the animation column to be redrawn and not the entire table!
            tree.redraw(clientArea.x, clientArea.y, tree.getColumn(thread.animationColumnIndex)
                .getWidth(), clientArea.height, false);
            tree.update();
            // During the first loop currentFrameIndex=0...then currentFrameIndex=1,etc.
            thread.currentFrameIndex =
                (thread.currentFrameIndex + 1) % thread.sampleImage.data.length;
          }
        }
      });

      try {
        int ms = this.sampleImage.data[this.currentFrameIndex].delayTime * 10;
        if (ms &lt; 20) {
          ms += 30;
        }
        if (ms &lt; 30) {
          ms += 10;
        }
        Thread.sleep(ms);
      } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
      }
      /*
       * If the last frame was signaled as being the current frame, decrement the repeat count and
       * start again.
       */
      if (this.currentFrameIndex == this.sampleImage.data.length - 1) {
        repeatCount--;
      }
    }
  }

  /**
   * Returns the index of the current frame. Animation providers (i.e. renderers) call this method
   * in order to find out which frame of an animated image they should render at any given point in
   * time.
   *
   * @return frame index starting at 0
   */
  public int getCurrentFrameIndex() {
    return this.currentFrameIndex;
  }

  /**
   * Signals the thread to stop. It will finish the current execution in its run method and will
   * then stop.
   */
  public void cancel() {
    this.cancel = true;
  }
}</pre>
<h2>LabelProvider</h2>
<p>I use my own implementation of an OwnerDrawLableProvider which paints a static image if the icon doesn&#8217;t have to be animated. If it needs to be animated (based on some attribute of the row&#8217;s input) it paints the frame of an animated GIF. The index of the frame to draw is determined by the animation thread shown above. Hint: the getImage() method is called by paint().</p>
<pre class="brush: java;" lang="java">  /*
   * For each (animated) job color the provider keeps a map of frame_index-to-image entries. This
   * speeds up the process of delivering images for rendering because they don't have to be created
   * all the time from ImageData objects.
   */
  private final Map&gt; imagesMap =
      new HashMap&gt;();

  @Override
  protected Image getImage(Event event, Object element) {
    final IJob job = (IJob) element;
    Image image = BuildColorInfo.getIconImage(job.getColor());
    if (job.isRunning()) {
      final BuildColorAnimationThread animationThread =
          BuildColorAnimationThread.getRunningInstance();
      /*
       * Should no animation thread be running, the static image fetched a few lines above will be
       * returned.
       */
      if (animationThread != null) {
        final int currentFrameIndex = animationThread.getCurrentFrameIndex();
        Map images = this.imagesMap.get(job.getColor());
        if (images == null) {
          images = new HashMap();
          this.imagesMap.put(job.getColor(), images);
        }
        image = images.get(Integer.valueOf(currentFrameIndex));
        if (image == null) {
          image = createNewImage(event, job.getColor(), currentFrameIndex);
          images.put(Integer.valueOf(currentFrameIndex), image);
        }
      }
    }
    return image;
  }

  private Image createNewImage(Event event, JobColor color, int currentFrameIndex) {
    final ImageLoader imageLoader = BuildColorInfo.getImageLoader(color);
    return new Image(event.gc.getDevice(), imageLoader.data[currentFrameIndex]);
  }</pre>
<h2>&#8220;Controller&#8221;</h2>
<p>The controller is responsible to start/stop the animation thread. Basically, whenever the viewer&#8217;s input changes the running animation thread must be canceled and a new thread must be started. The best hook for that is the viewer&#8217;s content provider &#8211; an implementation of I&lt;Tree|Table&gt;ContentProvider as it declares an inputChanged() method.</p>
<pre class="brush: java;" lang="java">    @Override
    public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
      if (this.animationThread != null) {
        this.animationThread.cancel();
      }
      // Animates the first column.
      this.animationThread =
          new BuildColorAnimationThread((TreeViewer) viewer, 0, BuildColorInfo
              .getImageLoader(JobColor.BLUE_ANIME));
      this.animationThread.start();
    }</pre>
<p>The code presented here was implemented for <a href="http://kenai.com/projects/h2eclipse" target="_blank">H2Eclipse</a>, the Hudson plugin for Eclipse.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.frightanic.com/2010/02/09/animated-gif-in-swt-tabletree-viewer-cell/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
