Package com.cburch.logisim.instance

Source Code of com.cburch.logisim.instance.InstanceComponent

/* Copyright (c) 2010, Carl Burch. License information is located in the
* com.cburch.logisim.Main source code and at www.cburch.com/logisim/. */

package com.cburch.logisim.instance;

import java.awt.Font;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;

import com.cburch.logisim.circuit.CircuitState;
import com.cburch.logisim.comp.Component;
import com.cburch.logisim.comp.ComponentDrawContext;
import com.cburch.logisim.comp.ComponentEvent;
import com.cburch.logisim.comp.ComponentFactory;
import com.cburch.logisim.comp.ComponentListener;
import com.cburch.logisim.comp.ComponentUserEvent;
import com.cburch.logisim.comp.EndData;
import com.cburch.logisim.data.Attribute;
import com.cburch.logisim.data.AttributeEvent;
import com.cburch.logisim.data.AttributeListener;
import com.cburch.logisim.data.AttributeSet;
import com.cburch.logisim.data.BitWidth;
import com.cburch.logisim.data.Bounds;
import com.cburch.logisim.data.Location;
import com.cburch.logisim.tools.TextEditable;
import com.cburch.logisim.tools.ToolTipMaker;
import com.cburch.logisim.util.EventSourceWeakSupport;
import com.cburch.logisim.util.StringGetter;
import com.cburch.logisim.util.UnmodifiableList;

class InstanceComponent implements Component, AttributeListener, ToolTipMaker {
  private EventSourceWeakSupport<ComponentListener> listeners;
  private InstanceFactory factory;
  private Instance instance;
  private Location loc;
  private Bounds bounds;
  private List<Port> portList;
  private EndData[] endArray;
  private List<EndData> endList;
  private boolean hasToolTips;
  private HashSet<Attribute<BitWidth>> widthAttrs;
  private AttributeSet attrs;
  private boolean attrListenRequested;
  private InstanceTextField textField;
 
  InstanceComponent(InstanceFactory factory, Location loc,
      AttributeSet attrs) {
    this.listeners = null;
    this.factory = factory;
    this.instance = new Instance(this);
    this.loc = loc;
    this.bounds = factory.getOffsetBounds(attrs).translate(loc.getX(), loc.getY());
    this.portList = factory.getPorts();
    this.endArray = null;
    this.hasToolTips = false;
    this.attrs = attrs;
    this.attrListenRequested = false;
    this.textField = null;

    computeEnds();
  }
 
  private void computeEnds() {
    List<Port> ports = portList;
    EndData[] esOld = endArray;
    int esOldLength = esOld == null ? 0 : esOld.length;
    EndData[] es = esOld;
    if (es == null || es.length != ports.size()) {
      es = new EndData[ports.size()];
      if (esOldLength > 0) {
        int toCopy = Math.min(esOldLength, es.length);
        System.arraycopy(esOld, 0, es, 0, toCopy);
      }
    }
    HashSet<Attribute<BitWidth>> wattrs = null;
    boolean toolTipFound = false;
    ArrayList<EndData> endsChangedOld = null;
    ArrayList<EndData> endsChangedNew = null;
    Iterator<Port> pit = ports.iterator();
    for (int i = 0; pit.hasNext() || i < esOldLength; i++) {
      Port p = pit.hasNext() ? pit.next() : null;
      EndData oldEnd = i < esOldLength ? esOld[i] : null;
      EndData newEnd = p == null ? null : p.toEnd(loc, attrs);
      if (oldEnd == null || !oldEnd.equals(newEnd)) {
        if (newEnd != null) es[i] = newEnd;
        if (endsChangedOld == null) {
          endsChangedOld = new ArrayList<EndData>();
          endsChangedNew = new ArrayList<EndData>();
        }
        endsChangedOld.add(oldEnd);
        endsChangedNew.add(newEnd);
      }
     
      if (p != null) {
        Attribute<BitWidth> attr = p.getWidthAttribute();
        if (attr != null) {
          if (wattrs == null) {
            wattrs = new HashSet<Attribute<BitWidth>>();
          }
          wattrs.add(attr);
        }
       
        if (p.getToolTip() != null) toolTipFound = true;
      }
    }
    if (!attrListenRequested) {
      HashSet<Attribute<BitWidth>> oldWattrs = widthAttrs;
      if (wattrs == null && oldWattrs != null) {
        getAttributeSet().removeAttributeListener(this);
      } else if (wattrs != null && oldWattrs == null) {
        getAttributeSet().addAttributeListener(this);
      }
    }
    if (es != esOld) {
      endArray = es;
      endList = new UnmodifiableList<EndData>(es);
    }
    widthAttrs = wattrs;
    hasToolTips = toolTipFound;
    if (endsChangedOld != null) {
      fireEndsChanged(endsChangedOld, endsChangedNew);
    }
  }
 
  //
  // listening methods
  //
  public void addComponentListener(ComponentListener l) {
    EventSourceWeakSupport<ComponentListener> ls = listeners;
    if (ls == null) {
      ls = new EventSourceWeakSupport<ComponentListener>();
      ls.add(l);
      listeners = ls;
    } else {
      ls.add(l);
    }
  }

  public void removeComponentListener(ComponentListener l) {
    if (listeners != null) {
      listeners.remove(l);
      if (listeners.isEmpty()) listeners = null;
    }
  }
 
  private void fireEndsChanged(ArrayList<EndData> oldEnds,
      ArrayList<EndData> newEnds) {
    EventSourceWeakSupport<ComponentListener> ls = listeners;
    if (ls != null) {
      ComponentEvent e = null;
      for (ComponentListener l : ls) {
        if (e == null) e = new ComponentEvent(this, oldEnds, newEnds);
        l.endChanged(e);
      }
    }
  }
 
  void fireInvalidated() {
    EventSourceWeakSupport<ComponentListener> ls = listeners;
    if (ls != null) {
      ComponentEvent e = null;
      for (ComponentListener l : ls) {
        if (e == null) e = new ComponentEvent(this);
        l.componentInvalidated(e);
      }
    }
  }

  //
  // basic information methods
  //
  public ComponentFactory getFactory() {
    return factory;
  }

  public AttributeSet getAttributeSet() {
    return attrs;
  }

  public Object getFeature(Object key) {
    Object ret = factory.getInstanceFeature(instance, key);
    if (ret != null) {
      return ret;
    } else if (key == ToolTipMaker.class) {
      Object defaultTip = factory.getDefaultToolTip();
      if (hasToolTips || defaultTip != null) return this;
    } else if (key == TextEditable.class) {
      InstanceTextField field = textField;
      if (field != null) return field;
    }
    return null;
  }

  //
  // location/extent methods
  //
  public Location getLocation() {
    return loc;
  }
 
  public Bounds getBounds() {
    return bounds;
  }

  public Bounds getBounds(Graphics g) {
    Bounds ret = bounds;
    InstanceTextField field = textField;
    if (field != null) ret = ret.add(field.getBounds(g));
    return ret;
  }

  public boolean contains(Location pt) {
    Location translated = pt.translate(-loc.getX(), -loc.getY());
    InstanceFactory factory = instance.getFactory();
    return factory.contains(translated, instance.getAttributeSet());
  }
 
  public boolean contains(Location pt, Graphics g) {
    InstanceTextField field = textField;
    if (field != null && field.getBounds(g).contains(pt)) return true;
    else return contains(pt);
  }
 
  //
  // propagation methods
  //
  public List<EndData> getEnds() {
    return endList;
  }

  public EndData getEnd(int index) {
    return endArray[index];
  }

  public boolean endsAt(Location pt) {
    EndData[] ends = endArray;
    for (int i = 0; i < ends.length; i++) {
      if (ends[i].getLocation().equals(pt)) return true;
    }
    return false;
  }

  public void propagate(CircuitState state) {
    factory.propagate(state.getInstanceState(this));
  }

  //
  // drawing methods
  //
  public void draw(ComponentDrawContext context) {
    InstancePainter painter = context.getInstancePainter();
    painter.setInstance(this);
    factory.paintInstance(painter);
  }

  public void expose(ComponentDrawContext context) {
    Bounds b = bounds;
    context.getDestination().repaint(b.getX(), b.getY(), b.getWidth(), b.getHeight());
  }
 
  public String getToolTip(ComponentUserEvent e) {
    int x = e.getX();
    int y = e.getY();
    int i = -1;
    for (EndData end : endArray) {
      i++;
      if (end.getLocation().manhattanDistanceTo(x, y) < 10) {
        Port p = portList.get(i);
        return p.getToolTip();
      }
    }
    StringGetter defaultTip = factory.getDefaultToolTip();
    return defaultTip == null ? null : defaultTip.get();
  }

  //
  // AttributeListener methods
  //
  public void attributeListChanged(AttributeEvent e) { }

  public void attributeValueChanged(AttributeEvent e) {
    Attribute<?> attr = e.getAttribute();
    if (widthAttrs != null && widthAttrs.contains(attr)) computeEnds();
    if (attrListenRequested) {
      factory.instanceAttributeChanged(instance, e.getAttribute());
    }
  }
 
  //
  // methods for InstancePainter
  //
  void drawLabel(ComponentDrawContext context) {
    InstanceTextField field = textField;
    if (field != null) field.draw(this, context);
  }

  //
  // methods for Instance
  //
  Instance getInstance() {
    return instance;
  }
 
  List<Port> getPorts() {
    return portList;
  }
 
  void setPorts(Port[] ports) {
    Port[] portsCopy = ports.clone();
    portList = new UnmodifiableList<Port>(portsCopy);
    computeEnds();
  }
 
  void recomputeBounds() {
    Location p = loc;
    bounds = factory.getOffsetBounds(attrs).translate(p.getX(), p.getY());
  }
 
  void addAttributeListener(Instance instance) {
    if (!attrListenRequested) {
      attrListenRequested = true;
      if (widthAttrs == null) getAttributeSet().addAttributeListener(this);
    }
  }
 
  void setTextField(Attribute<String> labelAttr, Attribute<Font> fontAttr,
      int x, int y, int halign, int valign) {
    InstanceTextField field = textField;
    if (field == null) {
      field = new InstanceTextField(this);
      field.update(labelAttr, fontAttr, x, y, halign, valign);
      textField = field;
    } else {
      field.update(labelAttr, fontAttr, x, y, halign, valign);
    }
  }

}
TOP

Related Classes of com.cburch.logisim.instance.InstanceComponent

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.