⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 backgroundtreecontentprovider.java

📁 Novocode的 SWT 控件框架 丰富了MDI功能
💻 JAVA
字号:
/*******************************************************************************
 * Copyright (c) 2004 Stefan Zeiger and others.
 * All rights reserved. This program and the accompanying materials 
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.novocode.com/legal/epl-v10.html
 * 
 * Contributors:
 *     Stefan Zeiger (szeiger@novocode.com) - initial API and implementation
 *******************************************************************************/

package com.novocode.naf.jface.viewers;

import java.util.ArrayList;
import java.util.Iterator;

import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.widgets.Display;


/**
 * An ITreeContentProvider which delegates getElements(), getChildren()
 * and hasChildren() method calls to another ITreeContentProvider in a
 * background thread to provide timely feedback for long-running queries.
 *
 * @author Stefan Zeiger (szeiger@novocode.com)
 * @since Dec 8, 2004
 * @version $Id: BackgroundTreeContentProvider.java,v 1.1 2004/12/16 14:52:04 szeiger Exp $
 */

public final class BackgroundTreeContentProvider implements ITreeContentProvider
{
  private static final int DEFAULT_TIME_GET = 100;
  private static final int DEFAULT_TIME_HAS =  10;

  private static final int METHOD_GETCHILDREN = 0;
  private static final int METHOD_GETELEMENTS = 1;
  private static final int METHOD_HASCHILDREN = 2;

  private final ITreeContentProvider parent;
  private final ArrayList<PendingGet> pendingGetList = new ArrayList<PendingGet>();
  private final ArrayList<PendingHas> pendingHasList = new ArrayList<PendingHas>();

  private volatile TreeViewer treeViewer;
  private volatile Display display;
  private volatile int timeGet = DEFAULT_TIME_GET;
  private volatile int timeHas = DEFAULT_TIME_HAS;
  private volatile ArrayList<BackgroundTreeContentListener> listeners;
  private volatile boolean disposed;


  private static abstract class Pending
  {
    abstract void updateResult(Object value);
  }


  private final class PendingGet extends Pending
  {
    final Object parent;
    volatile Object[] result = new Object[] { this };

    PendingGet(Object parent, DelegateThread r)
    {
      this.parent = parent;
      r.pending = this;
      pendingGetList.add(this);
    }

    void updateResult(Object value)
    {
      // [TODO] Start background hasChildren() operations on all children and cache their results
      result = (Object[])value;
      treeViewer.refresh(parent);
      removePending(this, pendingGetList);
      if(listeners != null)
        for(BackgroundTreeContentListener l : listeners) l.pendingGetFinished(parent);
    }
  }


  private final class PendingHas extends Pending
  {
    final Object element;
    volatile boolean result = true;

    PendingHas(Object element, DelegateThread r)
    {
      this.element = element;
      r.pending = this;
      pendingHasList.add(this);
    }

    void updateResult(Object value)
    {
      if(value != Boolean.TRUE)
      {
        result = false;
        treeViewer.refresh(element);
      }
      removePending(this, pendingHasList);
      if(listeners != null)
        for(BackgroundTreeContentListener l : listeners) l.pendingHasFinished(element);
    }
  }


  private final class DelegateThread extends Thread
  {
    final int method;
    final Object arg;
    volatile Object res;
    volatile RuntimeException ex;
    volatile boolean done;
    volatile Pending pending;

    DelegateThread(int method, Object arg)
    {
      this.method = method;
      this.arg = arg;
      setDaemon(true);
      try { setPriority(getPriority()+1); } catch(Throwable ignored) {}
    }

    public void run()
    {
      //long t0 = System.currentTimeMillis();
      try
      {
        switch(method)
        {
          case METHOD_GETCHILDREN: res = parent.getChildren(arg); break;
          case METHOD_GETELEMENTS: res = parent.getElements(arg); break;
          case METHOD_HASCHILDREN: res = parent.hasChildren(arg) ? Boolean.TRUE : Boolean.FALSE; break;
        }
      }
      catch(RuntimeException ex) { DelegateThread.this.ex = ex; }
      //long t1 = System.currentTimeMillis();
      //System.out.println("Method "+method+" took "+(t1-t0)+"ms");

      boolean processPending;
      synchronized(DelegateThread.this)
      {
        done = true;
        DelegateThread.this.notify();
        processPending = (pending != null);
      }

      if(processPending)
      {
        display.asyncExec(new Runnable()
        {
          public void run()
          {
            if(disposed || treeViewer.getTree().isDisposed()) return;
            //System.out.println("Processing PENDING state");
            pending.updateResult(res);
            //System.out.println("PENDING state processed");
          }
        });
      }
    }
  }


  private Object getChildrenOrElements(int method, Object element)
  {
    if(element instanceof PendingGet) return null;
    for(PendingGet p : pendingGetList)
    {
      if(p.parent == element) return p.result;
    }
    DelegateThread t = new DelegateThread(method, element);
    t.start();
    try
    {
      synchronized(t)
      {
        //long t0 = System.currentTimeMillis();
        t.wait(timeGet);
        //long t1 = System.currentTimeMillis();
        //System.out.println("waited "+(t1-t0)+"ms for GET");
        if(!t.done)
        {
          if(listeners != null)
            for(BackgroundTreeContentListener l : listeners) l.pendingGet(element);
          //System.out.println("FEEDBACK_TIME has passed");
          return new PendingGet(element, t).result;
        }
      }
      if(t.ex != null) throw t.ex;
      else return t.res;
    }
    catch(InterruptedException ex)
    {
      throw new RuntimeException("InterruptedException while waiting for DelegateThread", ex);
    }
  }


  public BackgroundTreeContentProvider(ITreeContentProvider parent, TreeViewer treeViewer)
  {
    this.parent = parent;
    setTreeViewer(treeViewer);
  }


  public BackgroundTreeContentProvider(ITreeContentProvider parent)
  {
    this.parent = parent;
  }


  public Object[] getChildren(Object element)
  {
    //System.out.println("getChildren() called for "+element);
    return (Object[])getChildrenOrElements(METHOD_GETCHILDREN, element);
  }


  public Object[] getElements(Object element)
  {
    //System.out.println("getElements() called for "+element);
    return (Object[])getChildrenOrElements(METHOD_GETELEMENTS, element);
  }


  public Object getParent(Object element)
  {
    //System.out.println("getParent() called for "+element);
    if(element instanceof PendingGet) return ((PendingGet)element).parent;
    return parent.getParent(element);
  }


  public boolean hasChildren(Object element)
  {
    //System.out.println("hasChildren() called for "+element);
    if(element instanceof PendingGet) return false;
    for(PendingHas p : pendingHasList)
    {
      if(p.element == element) return p.result;
    }
    for(PendingGet p : pendingGetList)
    {
      if(p.parent == element) return p.result.length > 0;
    }
    DelegateThread t = new DelegateThread(METHOD_HASCHILDREN, element);
    t.start();
    try
    {
      synchronized(t)
      {
        t.wait(timeHas);
        if(!t.done)
        {
          if(listeners != null)
            for(BackgroundTreeContentListener l : listeners) l.pendingHas(element);
          //System.out.println("HASCHILDREN_TIME has passed for element "+element);
          return new PendingHas(element, t).result;
        }
      }
      if(t.ex != null) throw t.ex;
      else return t.res == Boolean.TRUE;
    }
    catch(InterruptedException ex)
    {
      throw new RuntimeException("InterruptedException while waiting for DelegateThread", ex);
    }
  }


  public void dispose()
  {
    disposed = true;
    parent.dispose();
  }


  public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
  {
    //System.out.println("inputChanged from "+oldInput+" to "+newInput);
    parent.inputChanged(viewer, oldInput, newInput);
  }


  public static final boolean isPending(Object element)
  {
    return element instanceof PendingGet;
  }


  private static <T extends Pending> void removePending(Pending pending, Iterable<T> pendingList)
  {
    for(Iterator<T> it = pendingList.iterator(); it.hasNext();)
    {
      if(it.next() == pending) { it.remove(); return; }
    }
  }
  
  
  public void addBackgroundTreeContentListener(BackgroundTreeContentListener l)
  {
    if(l == null) return;
    if(listeners == null) listeners = new ArrayList<BackgroundTreeContentListener>();
    listeners.add(l);
  }
  
  
  public void removeBackgroundTreeContentListener(BackgroundTreeContentListener l)
  {
    if(listeners == null || l == null) return;
    for(Iterator<BackgroundTreeContentListener> it = listeners.iterator(); it.hasNext();)
    {
      if(it.next() == l) { it.remove(); return; }
    }
  }
  
  
  public void setTimeGet(int millis) { timeGet = millis; }
  
  
  public void setTimeHas(int millis) { timeHas = millis; }
  
  
  public void setTreeViewer(TreeViewer tv)
  {
    treeViewer = tv;
    display = tv.getTree().getDisplay();
  }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -