Package org.eclipse.ui.internal.services

Source Code of org.eclipse.ui.internal.services.EvaluationAuthority

/*******************************************************************************
* Copyright (c) 2007 IBM Corporation 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.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     IBM Corporation - initial API and implementation
******************************************************************************/

package org.eclipse.ui.internal.services;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.eclipse.core.commands.util.Tracing;
import org.eclipse.core.expressions.Expression;
import org.eclipse.core.expressions.ExpressionInfo;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.ui.ISources;
import org.eclipse.ui.internal.WorkbenchPlugin;
import org.eclipse.ui.internal.misc.Policy;

/**
* @since 3.3
*
*/
public class EvaluationAuthority extends ExpressionAuthority {

  /**
   *
   */
  private static final String COMPONENT = "EVALUATION"; //$NON-NLS-1$

  /**
   * A bucket sort of the evaluation references based on source priority. Each
   * reference will appear only once per set, but may appear in multiple sets.
   * If no references are defined for a particular priority level, then the
   * array at that index will only contain <code>null</code>.
   */
  private final Map cachesBySourceName = new HashMap();
  private ListenerList serviceListeners = new ListenerList();
  private int notifying = 0;

  // private final Map cachesByExpression = new HashMap();

  public void addEvaluationListener(IEvaluationReference ref) {
    // we update the source priority bucket sort of activations.
    String[] sourceNames = getNames(ref);
    for (int i = 0; i < sourceNames.length; i++) {
      Map cachesByExpression = (HashMap) cachesBySourceName
          .get(sourceNames[i]);
      if (cachesByExpression == null) {
        cachesByExpression = new HashMap(1);
        cachesBySourceName.put(sourceNames[i], cachesByExpression);
      }
      final Expression expression = ref.getExpression();
      Set caches = (Set) cachesByExpression.get(expression);
      if (caches == null) {
        caches = new HashSet();
        cachesByExpression.put(expression, caches);
      }
      caches.add(ref);
    }

    boolean result = evaluate(ref);
    firePropertyChange(ref, null, new Boolean(result));
  }

  /**
   * @param ref
   * @return
   */
  private String[] getNames(IEvaluationReference ref) {
    ExpressionInfo info = new ExpressionInfo();
    ref.getExpression().collectExpressionInfo(info);
    if (info.hasDefaultVariableAccess()) {
      ArrayList l = new ArrayList(Arrays.asList(info
          .getAccessedVariableNames()));
      l.add(ISources.ACTIVE_CURRENT_SELECTION_NAME);
      return (String[]) l.toArray(new String[l.size()]);
    }
    return info.getAccessedVariableNames();
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.ui.internal.services.ExpressionAuthority#sourceChanged(int)
   */
  protected void sourceChanged(int sourcePriority) {
    // no-op, we want the other one
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.ui.internal.services.ExpressionAuthority#sourceChanged(java.lang.String[])
   */
  protected void sourceChanged(String[] sourceNames) {
    startSourceChange(sourceNames);
    try {
      // evaluations to recompute
      for (int i = 0; i < sourceNames.length; i++) {
        Map cachesByExpression = (HashMap) cachesBySourceName
            .get(sourceNames[i]);
        if (cachesByExpression != null) {
          Collection v = cachesByExpression.values();
          Set[] expressionCaches = (Set[]) v
              .toArray(new Set[v.size()]);
          for (int j = 0; j < expressionCaches.length; j++) {
            if (expressionCaches[j].size() > 0) {
              IEvaluationReference[] refs = (IEvaluationReference[]) expressionCaches[j]
                  .toArray(new IEvaluationReference[expressionCaches[j]
                      .size()]);
              refsWithSameExpression(refs);
            }
          }
        }
      }
    } finally {
      endSourceChange(sourceNames);
    }
  }

  /**
   * This will evaluate all refs with the same expression.
   * @param refs
   */
  private void refsWithSameExpression(IEvaluationReference[] refs) {
    int k=0;
    while (k<refs.length && !refs[k].isPostingChanges()) {
      k++;
    }
    if (k>=refs.length) {
      return;
    }
    IEvaluationReference ref = refs[k];
    boolean oldValue = evaluate(ref);
    ref.clearResult();
    final boolean newValue = evaluate(ref);
    if (oldValue != newValue) {
      firePropertyChange(ref, new Boolean(oldValue),
          new Boolean(newValue));
    }
    for (k++; k < refs.length; k++) {
      ref = refs[k];
      // this is not as expensive as it looks
      if (ref.isPostingChanges()) {
        oldValue = evaluate(ref);
        if (oldValue != newValue) {
          ref.setResult(newValue);
          firePropertyChange(ref, new Boolean(oldValue), new Boolean(
              newValue));
        }
      }
    }
  }

  /**
   * @param sourceNames
   */
  private void startSourceChange(final String[] sourceNames) {
    if (Policy.DEBUG_SOURCES) {
      Tracing.printTrace(COMPONENT, "start source changed: " //$NON-NLS-1$
          + Arrays.asList(sourceNames));
    }
    notifying++;
    if (notifying == 1) {
      fireServiceChange(IEvaluationService.PROP_NOTIFYING, new Boolean(
          false), new Boolean(true));
    }
  }

  /**
   * @param sourceNames
   */
  private void endSourceChange(final String[] sourceNames) {
    if (Policy.DEBUG_SOURCES) {
      Tracing.printTrace(COMPONENT, "end source changed: " //$NON-NLS-1$
          + Arrays.asList(sourceNames));
    }
    if (notifying == 1) {
      fireServiceChange(IEvaluationService.PROP_NOTIFYING, new Boolean(
          true), new Boolean(false));
    }
    notifying--;
  }

  /**
   * @param ref
   */
  public void removeEvaluationListener(IEvaluationReference ref) {
    // Next we update the source priority bucket sort of activations.
    String[] sourceNames = getNames(ref);
    for (int i = 0; i < sourceNames.length; i++) {
      Map cachesByExpression = (HashMap) cachesBySourceName
          .get(sourceNames[i]);
      if (cachesByExpression != null) {
        Set caches = (Set) cachesByExpression.get(ref.getExpression());
        if (caches != null) {
          caches.remove(ref);
          if (caches.isEmpty()) {
            cachesByExpression.remove(ref.getExpression());
          }
        }
        if (cachesByExpression.isEmpty()) {
          cachesBySourceName.remove(sourceNames[i]);
        }
      }
    }
    boolean result = evaluate(ref);
    firePropertyChange(ref, new Boolean(result), null);
  }

  /**
   * @param ref
   * @param oldValue
   * @param newValue
   */
  private void firePropertyChange(IEvaluationReference ref, Object oldValue,
      Object newValue) {
    ref.getListener().propertyChange(
        new PropertyChangeEvent(ref, ref.getProperty(), oldValue,
            newValue));
  }

  private void fireServiceChange(final String property,
      final Object oldValue, final Object newValue) {
    Object[] listeners = serviceListeners.getListeners();
    for (int i = 0; i < listeners.length; i++) {
      final IPropertyChangeListener listener = (IPropertyChangeListener) listeners[i];
      SafeRunner.run(new ISafeRunnable() {
        public void handleException(Throwable exception) {
          WorkbenchPlugin.log(exception);
        }

        public void run() throws Exception {
          listener.propertyChange(new PropertyChangeEvent(
              EvaluationAuthority.this, property, oldValue,
              newValue));
        }
      });
    }
  }

  /**
   * @param listener
   */
  public void addServiceListener(IPropertyChangeListener listener) {
    serviceListeners.add(listener);
  }

  /**
   * @param listener
   */
  public void removeServiceListener(IPropertyChangeListener listener) {
    serviceListeners.remove(listener);
  }
}
TOP

Related Classes of org.eclipse.ui.internal.services.EvaluationAuthority

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.