Package com.cburch.logisim.gui.main

Source Code of com.cburch.logisim.gui.main.SelectionAttributes$Listener

/* 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.gui.main;

import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.cburch.logisim.circuit.Circuit;
import com.cburch.logisim.circuit.Wire;
import com.cburch.logisim.comp.Component;
import com.cburch.logisim.data.AbstractAttributeSet;
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.proj.Project;
import com.cburch.logisim.util.UnmodifiableList;

class SelectionAttributes extends AbstractAttributeSet {
  private static final Attribute<?>[] EMPTY_ATTRIBUTES = new Attribute<?>[0];
  private static final Object[] EMPTY_VALUES = new Object[0];
 
  private class Listener implements Selection.Listener, AttributeListener {
    public void selectionChanged(Selection.Event e) {
      updateList(true);
    }

    public void attributeListChanged(AttributeEvent e) {
      if (listening) {
        updateList(false);
      }
    }

    public void attributeValueChanged(AttributeEvent e) {
      if (listening) {
        updateList(false);
      }
    }
  }
 
  private Canvas canvas;
  private Selection selection;
  private Listener listener;
  private boolean listening;
  private Set<Component> selected;
  private Attribute<?>[] attrs;
  private boolean[] readOnly;
  private Object[] values;
  private List<Attribute<?>> attrsView;
 
  public SelectionAttributes(Canvas canvas, Selection selection) {
    this.canvas = canvas;
    this.selection = selection;
    this.listener = new Listener();
    this.listening = true;
    this.selected = Collections.emptySet();
    this.attrs = EMPTY_ATTRIBUTES;
    this.values = EMPTY_VALUES;
    this.attrsView = Collections.emptyList();

    selection.addListener(listener);
    updateList(true);
    setListening(true);
  }
 
  public Selection getSelection() {
    return selection;
  }
 
  void setListening(boolean value) {
    if (listening != value) {
      listening = value;
      if (value) {
        updateList(false);
      }
    }
  }
 
  private void updateList(boolean ignoreIfSelectionSame) {
    Selection sel = selection;
    Set<Component> oldSel = selected;
    Set<Component> newSel;
    if (sel == null) newSel = Collections.emptySet();
    else newSel = createSet(sel.getComponents());
    if (haveSameElements(newSel, oldSel)) {
      if (ignoreIfSelectionSame) return;
      newSel = oldSel;
    } else {
      for (Component o : oldSel) {
        if (!newSel.contains(o)) {
          o.getAttributeSet().removeAttributeListener(listener);
        }
      }
      for (Component o : newSel) {
        if (!oldSel.contains(o)) {
          o.getAttributeSet().addAttributeListener(listener);
        }
      }
    }
   
    LinkedHashMap<Attribute<Object>,Object> attrMap = computeAttributes(newSel);
    boolean same = isSame(attrMap, this.attrs, this.values);
   
    if (same) {
      if (newSel != oldSel) this.selected = newSel;
    } else {
      Attribute<?>[] oldAttrs = this.attrs;
      Object[] oldValues = this.values;
      Attribute<?>[] newAttrs = new Attribute[attrMap.size()];
      Object[] newValues = new Object[newAttrs.length];
      boolean[] newReadOnly = new boolean[newAttrs.length];
      int i = -1;
      for (Map.Entry<Attribute<Object>,Object> entry : attrMap.entrySet()) {
        i++;
        newAttrs[i] = entry.getKey();
        newValues[i] = entry.getValue();
        newReadOnly[i] = computeReadOnly(newSel, newAttrs[i]);
      }
      if (newSel != oldSel) this.selected = newSel;
      this.attrs = newAttrs;
      this.attrsView = new UnmodifiableList<Attribute<?>>(newAttrs);
      this.values = newValues;
      this.readOnly = newReadOnly;
     
      boolean listSame = oldAttrs != null && oldAttrs.length == newAttrs.length;
      if (listSame) {
        for (i = 0; i < oldAttrs.length; i++) {
          if (!oldAttrs[i].equals(newAttrs[i])) {
            listSame = false;
            break;
          }
        }
      }
     
      if (listSame) {
        for (i = 0; i < oldValues.length; i++) {
          Object oldVal = oldValues[i];
          Object newVal = newValues[i];
          boolean sameVals = oldVal == null ? newVal == null
              : oldVal.equals(newVal);
          if (!sameVals) {
            @SuppressWarnings("unchecked")
            Attribute<Object> attr = (Attribute<Object>) oldAttrs[i];
            fireAttributeValueChanged(attr, newVal);
          }
        }
      } else {
        fireAttributeListChanged();
      }
    }
  }
 
  private static Set<Component> createSet(Collection<Component> comps) {
    boolean includeWires = true;
    for (Component comp : comps) {
      if (!(comp instanceof Wire)) { includeWires = false; break; }
    }
   
    if (includeWires) {
      return new HashSet<Component>(comps);
    } else {
      HashSet<Component> ret = new HashSet<Component>();
      for (Component comp : comps) {
        if (!(comp instanceof Wire)) ret.add(comp);
      }
      return ret;
    }
  }

  private static boolean haveSameElements(Collection<Component> a, Collection<Component> b) {
    if (a == null) {
      return b == null ? true : b.size() == 0;
    } else if (b == null) {
      return a.size() == 0;
    } else if (a.size() != b.size()) {
      return false;
    } else {
      for (Component item : a) {
        if (!b.contains(item)) return false;
      }
      return true;
    }
  }
 
  private static LinkedHashMap<Attribute<Object>,Object> computeAttributes(Collection<Component> newSel)  {
    LinkedHashMap<Attribute<Object>,Object> attrMap;
    attrMap = new LinkedHashMap<Attribute<Object>,Object>();
    Iterator<Component> sit = newSel.iterator();
    if (sit.hasNext()) {
      AttributeSet first = sit.next().getAttributeSet();
      for (Attribute<?> attr : first.getAttributes()) {
        @SuppressWarnings("unchecked")
        Attribute<Object> attrObj = (Attribute<Object>) attr;
        attrMap.put(attrObj, first.getValue(attr));
      }
      while (sit.hasNext()) {
        AttributeSet next = sit.next().getAttributeSet();
        Iterator<Attribute<Object>> ait = attrMap.keySet().iterator();
        while (ait.hasNext()) {
          Attribute<Object> attr = ait.next();
          if (next.containsAttribute(attr)) {
            Object v = attrMap.get(attr);
            if (v != null && !v.equals(next.getValue(attr))) {
              attrMap.put(attr, null);
            }
          } else {
            ait.remove();
          }
        }
      }
    }
    return attrMap;
  }
 
  private static boolean isSame(LinkedHashMap<Attribute<Object>,Object> attrMap,
      Attribute<?>[] oldAttrs, Object[] oldValues) {
    if (oldAttrs.length != attrMap.size()) {
      return false;
    } else {
      int j = -1;
      for (Map.Entry<Attribute<Object>,Object> entry : attrMap.entrySet()) {
        j++;

        Attribute<Object> a = entry.getKey();
        if (!oldAttrs[j].equals(a) || j >= oldValues.length) return false;
        Object ov = oldValues[j];
        Object nv = entry.getValue();
        if (ov == null ? nv != null : !ov.equals(nv)) return false;
      }
      return true;
    }
  }
 
  private static boolean computeReadOnly(Collection<Component> sel, Attribute<?> attr) {
    for (Component comp : sel) {
      AttributeSet attrs = comp.getAttributeSet();
      if (attrs.isReadOnly(attr)) return true;
    }
    return false;
  }

  @Override
  protected void copyInto(AbstractAttributeSet dest) {
    throw new UnsupportedOperationException("SelectionAttributes.copyInto");
  }

  @Override
  public List<Attribute<?>> getAttributes() {
    Circuit circ = canvas.getCircuit();
    if (selected.isEmpty() && circ != null) {
      return circ.getStaticAttributes().getAttributes();
    } else {
      return attrsView;
    }
  }
 
  @Override
  public boolean isReadOnly(Attribute<?> attr) {
    Project proj = canvas.getProject();
    Circuit circ = canvas.getCircuit();
    if (!proj.getLogisimFile().contains(circ)) {
      return true;
    } else if (selected.isEmpty() && circ != null) {
      return circ.getStaticAttributes().isReadOnly(attr);
    } else {
      int i = findIndex(attr);
      boolean[] ro = readOnly;
      return i >= 0 && i < ro.length ? ro[i] : true;
    }
  }
 
  @Override
  public boolean isToSave(Attribute<?> attr) {
    return false;
  }

  @Override
  public <V> V getValue(Attribute<V> attr) {
    Circuit circ = canvas.getCircuit();
    if (selected.isEmpty() && circ != null) {
      return circ.getStaticAttributes().getValue(attr);
    } else {
      int i = findIndex(attr);
      Object[] vs = values;
      @SuppressWarnings("unchecked")
      V ret = (V) (i >= 0 && i < vs.length ? vs[i] : null);
      return ret;
    }
  }

  @Override
  public <V> void setValue(Attribute<V> attr, V value) {
    Circuit circ = canvas.getCircuit();
    if (selected.isEmpty() && circ != null) {
      circ.getStaticAttributes().setValue(attr, value);
    } else {
      int i = findIndex(attr);
      Object[] vs = values;
      if (i >= 0 && i < vs.length) {
        vs[i] = value;
        for (Component comp : selected) {
          comp.getAttributeSet().setValue(attr, value);
        }
      }
    }
  }
 
  private int findIndex(Attribute<?> attr) {
    if (attr == null) return -1;
    Attribute<?>[] as = attrs;
    for (int i = 0; i < as.length; i++) {
      if (attr.equals(as[i])) return i;
    }
    return -1;
  }
}
TOP

Related Classes of com.cburch.logisim.gui.main.SelectionAttributes$Listener

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.