001package jmri.jmrit.logixng.util; 002 003import java.beans.VetoableChangeListener; 004import java.util.*; 005 006import javax.annotation.Nonnull; 007 008import jmri.*; 009import jmri.jmrit.logixng.*; 010import jmri.jmrit.logixng.util.parser.*; 011import jmri.jmrit.logixng.util.parser.RecursiveDescentParser; 012import jmri.util.TypeConversionUtil; 013 014/** 015 * Select a string list for LogixNG actions and expressions. 016 * 017 * @author Daniel Bergqvist (C) 2025 018 */ 019public class LogixNG_SelectStringList implements VetoableChangeListener { 020 021 private boolean _onlyDirectAddressingAllowed; 022 023 private NamedBeanAddressing _addressing = NamedBeanAddressing.Direct; 024 private final List<String> _list = new ArrayList<>(); 025 private String _localVariable = ""; 026 private String _formula = ""; 027 private ExpressionNode _expressionNode; 028 029 030 public void setOnlyDirectAddressingAllowed() { 031 _onlyDirectAddressingAllowed = true; 032 } 033 034 public boolean isOnlyDirectAddressingAllowed() { 035 return _onlyDirectAddressingAllowed; 036 } 037 038 public void copy(LogixNG_SelectStringList copy) throws ParserException { 039 copy.setAddressing(_addressing); 040 copy._list.addAll(_list); 041 copy.setLocalVariable(_localVariable); 042 copy.setFormula(_formula); 043 } 044 045 public void setAddressing(@Nonnull NamedBeanAddressing addressing) throws ParserException { 046 if (_onlyDirectAddressingAllowed && (addressing != NamedBeanAddressing.Direct)) { 047 throw new IllegalArgumentException("Addressing must be Direct"); 048 } 049 this._addressing = addressing; 050 parseFormula(); 051 } 052 053 public boolean isDirectAddressing() { 054 return _addressing == NamedBeanAddressing.Direct; 055 } 056 057 public NamedBeanAddressing getAddressing() { 058 return _addressing; 059 } 060 061 public List<String> getList() { 062 return _list; 063 } 064 065 public void setLocalVariable(@Nonnull String localVariable) { 066 _localVariable = localVariable; 067 } 068 069 public String getLocalVariable() { 070 return _localVariable; 071 } 072 073 public void setFormula(@Nonnull String formula) throws ParserException { 074 _formula = formula; 075 parseFormula(); 076 } 077 078 public String getFormula() { 079 return _formula; 080 } 081 082 private void parseFormula() throws ParserException { 083 if (_addressing == NamedBeanAddressing.Formula) { 084 Map<String, Variable> variables = new HashMap<>(); 085 086 RecursiveDescentParser parser = new RecursiveDescentParser(variables); 087 _expressionNode = parser.parseExpression(_formula); 088 } else { 089 _expressionNode = null; 090 } 091 } 092 093 public List<String> evaluateValue(ConditionalNG conditionalNG) throws JmriException { 094 095 if (_addressing == NamedBeanAddressing.Direct) { 096 return _list; 097 } else { 098 Object val; 099 100 switch (_addressing) { 101 case LocalVariable: 102 SymbolTable symbolNamedBean = conditionalNG.getSymbolTable(); 103 val = symbolNamedBean.getValue(_localVariable); 104 break; 105 106 case Formula: 107 val = _expressionNode != null 108 ? _expressionNode.calculate(conditionalNG.getSymbolTable()) 109 : null; 110 break; 111 112 default: 113 throw new IllegalArgumentException("invalid _addressing state: " + _addressing.name()); 114 } 115 116 if (val instanceof String[]) { 117 return Arrays.asList( (String[])val ); 118 } else if (val instanceof List) { 119 List<String> resultList = new ArrayList<>(); 120 for (Object o : (List<?>)val) { 121 resultList.add(TypeConversionUtil.convertToString(o, false)); 122 } 123 return resultList; 124 } else { 125 throw new JmriException("value is not an array of String or a List of String. Class name: " 126 + (val != null ? val.getClass().getName() : null)); 127 } 128 } 129 } 130 131 public String getDescription(Locale locale) { 132 String enumName; 133 134 switch (_addressing) { 135 case Direct: 136 enumName = Bundle.getMessage(locale, "AddressByDirect", String.join(" ::: ", _list)); 137 break; 138 139 case LocalVariable: 140 enumName = Bundle.getMessage(locale, "AddressByLocalVariable", _localVariable); 141 break; 142 143 case Formula: 144 enumName = Bundle.getMessage(locale, "AddressByFormula", _formula); 145 break; 146 147 default: 148 throw new IllegalArgumentException("invalid _addressing: " + _addressing.name()); 149 } 150 return enumName; 151 } 152 153 /** 154 * Register listeners if this object needs that. 155 */ 156 public void registerListeners() { 157 // Do nothing 158 } 159 160 /** 161 * Unregister listeners if this object needs that. 162 */ 163 public void unregisterListeners() { 164 // Do nothing 165 } 166 167 @Override 168 public void vetoableChange(java.beans.PropertyChangeEvent evt) throws java.beans.PropertyVetoException { 169 // Do nothing 170 } 171 172// private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogixNG_SelectStringArray.class); 173}