/*******************************************************************************
* This file is part of logisim-evolution.
*
* logisim-evolution is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* logisim-evolution is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with logisim-evolution. If not, see <http://www.gnu.org/licenses/>.
*
* Original code by Carl Burch (http://www.cburch.com), 2011.
* Subsequent modifications by :
* + Haute École Spécialisée Bernoise
* http://www.bfh.ch
* + Haute École du paysage, d'ingénierie et d'architecture de Genève
* http://hepia.hesge.ch/
* + Haute École d'Ingénierie et de Gestion du Canton de Vaud
* http://www.heig-vd.ch/
* The project is currently maintained by :
* + REDS Institute - HEIG-VD
* Yverdon-les-Bains, Switzerland
* http://reds.heig-vd.ch
*******************************************************************************/
package com.cburch.logisim.util;
import java.awt.event.KeyEvent;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import javax.swing.JOptionPane;
import com.bfh.logisim.designrulecheck.CorrectLabel;
import com.cburch.logisim.circuit.Circuit;
import com.cburch.logisim.comp.Component;
import com.cburch.logisim.comp.ComponentFactory;
import com.cburch.logisim.data.AttributeSet;
import com.cburch.logisim.data.Location;
import com.cburch.logisim.instance.StdAttr;
import com.cburch.logisim.tools.SetAttributeAction;
public class AutoLabel {
static final Integer[] UsedKeyStrokes = new Integer[] {KeyEvent.VK_L,KeyEvent.VK_T,KeyEvent.VK_V,KeyEvent.VK_H,KeyEvent.VK_A};
public static Set<Integer> KeyStrokes = new HashSet<Integer>(Arrays.asList(UsedKeyStrokes));
private HashMap<Circuit,String> LabelBase = new HashMap<Circuit,String>();
private HashMap<Circuit,Integer> CurrentIndex = new HashMap<Circuit,Integer>();
private HashMap<Circuit,Boolean> UseLabelBaseOnly = new HashMap<Circuit,Boolean>();
private HashMap<Circuit,Boolean> UseUnderscore = new HashMap<Circuit,Boolean>();
private HashMap<Circuit,Boolean> active = new HashMap<Circuit,Boolean>();
private HashMap<Circuit,String> CurrentLabel = new HashMap<Circuit,String>();
public AutoLabel() {
this("",null,false);
}
public AutoLabel(String Label,
Circuit circ) {
this(Label,circ,true);
}
public AutoLabel(String Label,
Circuit circ,
boolean UseFirstLabel) {
update(circ,Label,UseFirstLabel,null);
Activate(circ);
}
public boolean hasNext(Circuit circ) {
if (circ==null||!active.containsKey(circ))
return false;
return active.get(circ);
}
public String GetCurrent(Circuit circ,ComponentFactory me) {
if (circ == null||!CurrentLabel.containsKey(circ)||CurrentLabel.get(circ).isEmpty())
return "";
if (Circuit.IsCorrectLabel(CurrentLabel.get(circ), circ.getNonWires(),null,me,false))
return CurrentLabel.get(circ);
else if (hasNext(circ)) {
return GetNext(circ,me);
} else {
SetLabel("",circ,me);
}
return "";
}
public String GetNext(Circuit circ,ComponentFactory me) {
if (circ==null)
return "";
if (UseLabelBaseOnly.get(circ)) {
UseLabelBaseOnly.put(circ, false);
return LabelBase.get(circ);
}
String NewLabel="";
int CurIdx = CurrentIndex.get(circ);
String BaseLab = LabelBase.get(circ);
boolean Undescore = UseUnderscore.get(circ);
do {CurIdx++;
NewLabel = BaseLab;
if (Undescore)
NewLabel = NewLabel.concat("_");
NewLabel = NewLabel.concat(Integer.toString(CurIdx));
} while (!Circuit.IsCorrectLabel(NewLabel, circ.getNonWires(), null,me,false));
CurrentIndex.put(circ, CurIdx);
CurrentLabel.put(circ, NewLabel);
return NewLabel;
}
public boolean IsActive(Circuit circ) {
if (circ==null)
return false;
if (!active.containsKey(circ))
return false;
return active.get(circ);
}
public void SetLabel(String Label,Circuit circ,ComponentFactory me) {
if (circ==null)
return;
update(circ,Label,true,me);
}
public void Activate(Circuit circ) {
if (circ == null)
return;
if (LabelBase.containsKey(circ)&&
CurrentIndex.containsKey(circ)&&
UseLabelBaseOnly.containsKey(circ)&&
UseUnderscore.containsKey(circ))
active.put(circ, !LabelBase.get(circ).isEmpty());
}
public void Stop(Circuit circ) {
if (circ == null)
return;
SetLabel("",circ,null);
active.put(circ, false);
}
public static boolean LabelEndsWithNumber(String Label) {
return CorrectLabel.Numbers.contains(Label.substring(Label.length()-1));
}
private int GetLabelBaseEndIndex(String Label) {
int index = Label.length();
while ((index >1)&&
CorrectLabel.Numbers.contains(Label.substring(index-1,index)))
index--;
return (index-1);
}
private void update(Circuit circ,String Label , boolean UseFirstLabel, ComponentFactory me) {
if (circ == null)
return;
if (Label.isEmpty()||
!SyntaxChecker.isVariableNameAcceptable(Label,false)) {
LabelBase.put(circ, "");
CurrentIndex.put(circ, 0);
UseLabelBaseOnly.put(circ, false);
CurrentLabel.put(circ, "");
return;
}
UseLabelBaseOnly.put(circ, UseFirstLabel);
if (LabelEndsWithNumber(Label)) {
int Index = GetLabelBaseEndIndex(Label);
CurrentIndex.put(circ, Integer.valueOf(Label.substring(Index+1,Label.length())));
LabelBase.put(circ, Label.substring(0,Index+1));
UseUnderscore.put(circ, false);
UseLabelBaseOnly.put(circ, false);
} else {
LabelBase.put(circ, Label);
CurrentIndex.put(circ, 0);
UseUnderscore.put(circ, !Label.substring(Label.length()-1).equals("_"));
}
if (UseFirstLabel)
CurrentLabel.put(circ, Label);
else
CurrentLabel.put(circ, GetNext(circ,me));
}
private static class ComponentSorter implements Comparator<Component> {
@Override
public int compare(Component o1, Component o2) {
if (o1==o2)
return 0;
Location l1 = o1.getLocation();
Location l2 = o2.getLocation();
if (l2.getY() != l1.getY())
return l1.getY()-l2.getY();
if (l2.getX() != l1.getX())
return l1.getX()-l2.getX();
return -1;
}
}
public static SortedSet<Component> Sort(Set<Component> comps) {
SortedSet<Component> sorted = new TreeSet<Component>(new ComponentSorter());
sorted.addAll(comps);
return sorted;
}
public String AskAndSetLabel(String ComponentName,
String OldLabel,
Circuit circ,
Component comp,
ComponentFactory compfac,
AttributeSet attrs,
SetAttributeAction act,
boolean CreateAction) {
boolean correct = false;
String NewLabel = OldLabel;
while (!correct) {
NewLabel = (String) JOptionPane.showInputDialog(null,
Strings.get("editLabelQuestion")+" "+ComponentName,
Strings.get("editLabelDialog"),
JOptionPane.QUESTION_MESSAGE,null,null,
OldLabel);
if (NewLabel!=null) {
if (Circuit.IsCorrectLabel(NewLabel, circ.getNonWires(), attrs,compfac,true)&&
SyntaxChecker.isVariableNameAcceptable(NewLabel,true)&&
!CorrectLabel.IsKeyword(NewLabel,true)) {
if (CreateAction)
act.set(comp, StdAttr.LABEL, NewLabel);
else
SetLabel(NewLabel,circ,compfac);
correct = true;
}
}
else {
correct = true;
NewLabel = OldLabel;
}
}
return NewLabel;
}
public boolean LabelKeyboardHandler(int KeyCode,
AttributeSet attrs,
String ComponentName,
Component comp,
ComponentFactory compfac,
Circuit circ,
SetAttributeAction act,
boolean CreateAction) {
switch (KeyCode) {
case KeyEvent.VK_L:
if (attrs.containsAttribute(StdAttr.LABEL)) {
String OldLabel = attrs.getValue(StdAttr.LABEL);
String NewLabel = AskAndSetLabel(ComponentName,OldLabel,circ,comp,compfac,attrs,act,CreateAction);
if (!NewLabel.equals(OldLabel)) {
if (!NewLabel.isEmpty()&&
LabelEndsWithNumber(NewLabel)) {
Activate(circ);
} else {
active.put(circ, false);
}
}
}
return true;
case KeyEvent.VK_T:
if (attrs.containsAttribute(StdAttr.LABEL_VISIBILITY)) {
if (CreateAction)
act.set(comp, StdAttr.LABEL_VISIBILITY, !attrs.getValue(StdAttr.LABEL_VISIBILITY));
else
attrs.setValue(StdAttr.LABEL_VISIBILITY, !attrs.getValue(StdAttr.LABEL_VISIBILITY));
}
return true;
case KeyEvent.VK_V:
if (attrs.containsAttribute(StdAttr.LABEL_VISIBILITY)&&!attrs.getValue(StdAttr.LABEL_VISIBILITY)) {
if (CreateAction)
act.set(comp, StdAttr.LABEL_VISIBILITY, true);
else
attrs.setValue(StdAttr.LABEL_VISIBILITY, true);
}
return true;
case KeyEvent.VK_H:
if (attrs.containsAttribute(StdAttr.LABEL_VISIBILITY)&&attrs.getValue(StdAttr.LABEL_VISIBILITY)) {
if (CreateAction)
act.set(comp, StdAttr.LABEL_VISIBILITY, false);
else
attrs.setValue(StdAttr.LABEL_VISIBILITY, false);
}
return true;
case KeyEvent.VK_A:
Stop(circ);
return true;
}
return false;
}
}