Package com.scriptographer.ai

Source Code of com.scriptographer.ai.Timer

/*
* 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 May 29, 2010.
*/

package com.scriptographer.ai;

import com.scratchdisk.script.Callable;
import com.scratchdisk.util.ConversionUtils;
import com.scratchdisk.util.IntMap;
import com.scriptographer.ScriptographerEngine;
import com.scriptographer.ScriptographerException;
import com.scriptographer.sg.Script;

/**
* @author lehni
*
*/
public class Timer extends NativeObject {

  private int period;
  private boolean periodic;

  private Script script = null;

  private static IntMap<Timer> timers = new IntMap<Timer>();

  /**
   * Creates a timer object.
   *
   * @param period The timer's period in milliseconds.
   * @param periodic Controls whether the timer is one-shop or periodic.
   */
  public Timer(int period, boolean periodic) {
    script = ScriptographerEngine.getCurrentScript();
    this.period = period;
    this.periodic = periodic;
    handle = nativeCreate(period);
    if (handle == 0)
      throw new ScriptographerException("Unable to create Timer.");
    timers.put(handle, this);
  }

  public Timer(int period) {
    this(period, true);
  }

  public void abort() {
    if (handle != 0) {
      timers.remove(handle);
      nativeAbort(handle);
      handle = 0;
    }
  }

  private native int nativeCreate(int period);
  private native void nativeAbort(int handle);

  public double getPeriod() {
    return period;
  }
 
  public boolean isPeriodic() {
    return periodic;
  }
 
  protected boolean canAbort(boolean ignoreKeepAlive) {
    return script == null || script.canRemove(ignoreKeepAlive);
  }

  public static void abortAll(boolean ignoreKeepAlive, boolean force) {
    // As abort() modifies the Map, using an iterator is not possible here:
    Object[] timers = Timer.timers.values().toArray();
    for (int i = 0; i < timers.length; i++) {
      Timer timer = (Timer) timers[i];
      if (force || timer.canAbort(ignoreKeepAlive))
        timer.abort();
    }
  }
 
  private Callable onExecute = null;

  public void setOnExecute(Callable onExecute) {
    this.onExecute = onExecute;
  }
 
  public Callable getOnExecute() {
    return onExecute;
  }

  /**
   * The timer callback.
   *
   * Return true if document should be redrawn automatically.
   */
  protected boolean onExecute() {
    if (onExecute != null) {
      Object result = ScriptographerEngine.invoke(onExecute, this);
      if (result != null)
        return ConversionUtils.toBoolean(result);
    }
    return false;
  }

  /**
   * To be called from the native environment:
   */
  private static boolean onExecute(int handle) {
    Timer timer = getTimer(handle);
    if (timer != null) {
      try {
        Document document = Document.getActiveDocument();
        // Produce a normal undo cycle if in the previous cycle we have
        // created or removed items. Otherwise just merge the changes of
        // this cycle with the previous one.
        // It is important to create new cycles when such changes
        // happen, as they affect the live span of items within the undo
        // history, and if all cycles were merged, the history tracking
        // code in Document would not be able to track their life span.
        int undoType = document == null || document.hasCreatedState()
            || document.hasRemovedState()
                ? Document.UNDO_STANDARD
                : Document.UNDO_MERGE;
        // Clear changed states now to track for new changes in
        // onExecute()
        if (document != null)
          document.clearChangedStates();
        boolean changed = timer.onExecute()
            || document != null && document.hasChangedSates();
        // Only change undo type if the document have actually changed,
        // or if the type is MERGE, in which case we will not add new
        // unto levels. This is actually needed to prevent a weird bug
        // that occasionally happens where Ai keeps adding new levels.
        // To not set STANDARD in all cases prevents issues with
        // situations where Timers are used for ADM interface stuff,
        // e.g. invokeLater().
        if (document != null
            && (changed || undoType == Document.UNDO_MERGE)) {
          document.setUndoType(undoType);
        }
        return changed;
      } finally {
        // Simulate one shot timers by aborting:
        if (!timer.periodic)
          timer.abort();
      }
    }
    return false;
  }

  private static Timer getTimer(int handle) {
    return timers.get(handle);
  }

  protected void finalize() {
    abort();
  }

  public Object getId() {
    // Return the integer handle as id instead of a formated string, as the
    // script side wants to work with numeric timer ids.
    return handle;
  }
}
TOP

Related Classes of com.scriptographer.ai.Timer

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.