Package com.scratchdisk.script.rhino

Source Code of com.scratchdisk.script.rhino.ListWrapper

/*
* Scriptographer
*
* This file is part of Scriptographer, a Scripting Plugin for Adobe Illustrator
* http://scriptographer.org/
*
* Copyright (c) 2002-2010, Juerg Lehni
* http://scratchdisk.com/
*
* All rights reserved. See LICENSE file for details.
*
* File created on 11.02.2005.
*/

package com.scratchdisk.script.rhino;

import org.mozilla.javascript.Callable;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.ScriptRuntime;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import org.mozilla.javascript.Wrapper;

import com.scratchdisk.list.List;
import com.scratchdisk.list.ReadOnlyList;
import com.scratchdisk.list.ReadOnlyStringIndexList;
import com.scratchdisk.list.StringIndexList;
import com.scratchdisk.script.ChangeReceiver;

/**
* Wrapper class for com.scriptographer.util.List objects to make them behave
* like NativeArray. The prototype is set to the js Array prototype, so all
* Array functions can be used on list objects.
*
* Unlike MapWrapper, this is still an ExtendedJavaObject at the same time, so
* native methods get passed through too. The reasoning behind this is that in
* Map<->Object wrapping, such methods could interfere with the expected
* behavior of a native Object (e.g. script.preferences.values returning the
* values() method from Map), whereas on lists, such clashes are not going to
* happen, and right now list classes still often define other functionality in
* Scriptographer, e.g. HierarchyListBox in the UI framework.
*
* TODO: In the future, this should be handled in the same way as MapAdapter,
* making the list behave like a 100% native array.
*
* It adds array-like properties, so it is possible to access lists like this:
* list[i] It also defines getIds(), so enumeration is possible too: for (var i
* in list) ...
*
* @author lehni
*/
public class ListWrapper extends ExtendedJavaObject {
  public ListWrapper(Scriptable scope, ReadOnlyList list,
      Class staticType, boolean unsealed) {
    super(scope, list, staticType, unsealed);
    // Make ListWrappers behave exactly like arrays and inherit all features
    // from them.
    // Thanks to the great functionality of our ExtendedJavaObject, there is
    // no difference between a java List and a JavaScript Array after this,
    // all features work as long as the list is not read-only!
    setPrototype(ScriptableObject.getArrayPrototype(scope));
  }

  public Object[] getIds() {
    if (javaObject != null) {
      // act like a JS javaObject:
      Integer[] ids = new Integer[((ReadOnlyList) javaObject).size()];
      for (int i = 0; i < ids.length; i++) {
        ids[i] = new Integer(i);
      }
      return ids;
    } else {
      return new Object[] {};
    }
  }

  public boolean has(int index, Scriptable start) {
    return javaObject != null && index < ((ReadOnlyList) javaObject).size();
  }

  @SuppressWarnings("unchecked")
  public void put(int index, Scriptable start, Object value) {
    if (javaObject != null && javaObject instanceof List) {
      List list = ((List) javaObject);
      int size = list.size();
      value = coerceComponentType(value);
      if (index >= size) {
        for (int i = size; i < index; i++)
          list.add(i, null);
        list.add(index, value);
      } else {
        list.set(index, value);
      }
      if (changeReceiver != null)
        updateChangeReceiver();
    }
  }

  public Object get(int index, Scriptable start) {
    if (javaObject != null) {
      if (changeReceiver != null)
        fetchChangeReceiver();
      try {
        Object obj = ((ReadOnlyList) javaObject).get(index);
        if (obj != null) {
          Object result = Context.javaToJS(obj, getParentScope());
          if (javaObject instanceof ChangeReceiver)
            handleChangeEmitter(result, Integer.toString(index));
          return result;
        }
      } catch (IndexOutOfBoundsException e) {
        // Don't report
      }
    }
    return Scriptable.NOT_FOUND;
  }

  public boolean has(String name, Scriptable start) {
    return super.has(name, start) || name.equals("length") ||
      javaObject instanceof ReadOnlyStringIndexList && javaObject != null
      && ((ReadOnlyStringIndexList) javaObject).get(name) != null;
  }

  @SuppressWarnings("unchecked")
  public void put(String name, Scriptable start, Object value) {
    // Since lists have the native size method that's already accessible
    // through "length", offer access here to get/setSize if these are
    // present, such as in Scriptographer's HierarchyListBox, where they
    // get / set the item's dimensions.
    if (name.equals("size") && members.has("setSize", false)) {
      Object obj = members.get(this, "setSize", javaObject, false);
      if (obj instanceof Callable) {
        ((Callable) obj).call(Context.getCurrentContext(),
            start.getParentScope(), this, new Object[] { value });
        return;
      }
    } else if (javaObject != null) {
      if (javaObject instanceof List && name.equals("length")) {
        // from NativeArray#setLength(Object value)
            double d = ScriptRuntime.toNumber(value);
            int length = ScriptRuntime.toInt32(d);
            if (length != d) {
                String msg = ScriptRuntime.getMessage0("msg.arraylength.bad");
                throw ScriptRuntime.constructError("RangeError", msg);
            }
        List list = ((List) javaObject);
        int size = list.size();
        if (length < size) {
          list.remove(length, size);
        } else {
          for (int i = size; i < length; i++)
            list.add(null);
        }
      } else if (javaObject instanceof StringIndexList
          && !members.has(name, false)) {
        ((StringIndexList) javaObject).put(name, coerceComponentType(value));
        return;
      }
    }
    super.put(name, start, value);
  }

  public Object get(String name, Scriptable start) {
    // Again, allow access to getSize, if it's there. See #put
    if (name.equals("size") && members.has("getSize", false)) {
      Object obj = members.get(this, "getSize", javaObject, false);
      if (obj instanceof Callable)
        return ((Callable) obj).call(Context.getCurrentContext(),
            start.getParentScope(), this, new Object[] {});
    } else if (javaObject != null) {
      if (name.equals("length")) {
        return new Integer(((ReadOnlyList) javaObject).size());
      } else if (javaObject instanceof ReadOnlyStringIndexList
          && !members.has(name, false)) {
        // Only check ReadOnlyStringIndexList if members does not
        // define the same property
        Object obj = ((ReadOnlyStringIndexList) javaObject).get(name);
        if (obj != null)
          return Context.javaToJS(obj, getParentScope());
      }
    }
    return super.get(name, start);
  }

  public Object getDefaultValue(Class hint) {
    if (hint == null || hint == ScriptRuntime.StringClass) {
      StringBuffer buffer = new StringBuffer();
      ReadOnlyList list = (ReadOnlyList) javaObject;
      for (int i = 0, l = list.size(); i < l; i++) {
        if (i > 0)
          buffer.append(",");
        Object entry = list.get(i);
        if (entry != null) {
                  Scriptable obj = Context.toObject(entry, this);
                  buffer.append(obj.getDefaultValue(hint));
        } else {
            buffer.append("null");
        }
      }
      return buffer.toString();
    } else {
      return super.getDefaultValue(hint);
    }
  }

  private Object coerceComponentType(Object value) {
    Object unwrapped = value;
    if (unwrapped instanceof Wrapper)
      unwrapped = ((Wrapper) unwrapped).unwrap();
    Class type = ((List) javaObject).getComponentType();
    // Use WrapFactory to coerce type if not compatible
    return type.isInstance(unwrapped)
        ? unwrapped
        : Context.getCurrentContext().getWrapFactory().coerceType(
            type, value, unwrapped);
  }
}
TOP

Related Classes of com.scratchdisk.script.rhino.ListWrapper

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.