001package jmri.jmrit.symbolicprog; 002 003import java.awt.event.ActionEvent; 004import java.beans.PropertyChangeEvent; 005import java.beans.PropertyChangeListener; 006 007import javax.swing.AbstractAction; 008 009import jmri.jmrit.roster.RosterEntry; 010import jmri.jmrit.symbolicprog.tabbedframe.PaneProgFrame; 011import jmri.jmrix.can.CanSystemConnectionMemo; 012import jmri.util.swing.JmriJOptionPane; 013 014import org.openlcb.OlcbInterface; 015import org.openlcb.NodeID; 016import org.openlcb.cdi.impl.ConfigRepresentation; 017/** 018 * Action to upload the function labels from a roster entry to a TCS CS-105. 019 * 020 * @author Bob Jacobsen Copyright (C) 2003 021 */ 022public class TcsUploadAction extends AbstractAction implements PropertyChangeListener { 023 024 public TcsUploadAction(String actionName, CvTableModel pModel, VariableTableModel vModel, RosterEntry rosterEntry, PaneProgFrame pParent) { 025 super(actionName); 026 cvTable = pModel; 027 this.vModel = vModel; 028 frame = pParent; 029 this.rosterEntry = rosterEntry; 030 } 031 032 // will this be enabled if created? 033 static public boolean willBeEnabled() { 034 // see if there's an openlcb connection 035 var cscm = getSystemConnectionMemo(); 036 if (cscm == null) { 037 return false; 038 } 039 if (cscm.get(org.openlcb.NodeID.class) == null) { 040 return false; 041 } 042 return true; 043 } 044 045 static CanSystemConnectionMemo getSystemConnectionMemo() { 046 return jmri.InstanceManager.getNullableDefault(CanSystemConnectionMemo.class); 047 } 048 049 PaneProgFrame frame; 050 RosterEntry rosterEntry; 051 CvTableModel cvTable; 052 VariableTableModel vModel; 053 ConfigRepresentation configRep; 054 055 @Override 056 public void actionPerformed(ActionEvent e) { 057 boolean isLong = cvTable.holdsLongAddress(); 058 int addr = cvTable.holdsAddress(); 059 log.debug("computed address is {} long: {}", addr, isLong); 060 061 // Create the train's node ID 062 byte upperAddressByte = (byte) (isLong ? (192+(addr>>8)) : 0); 063 byte lowerAddressByte = (byte) (addr & 0xFF); 064 var nodeID = new NodeID(new byte[]{6,1,0,0,upperAddressByte, lowerAddressByte}); 065 log.debug("node ID {}", nodeID); 066 067 // check for Node ID already known 068 var nodeStore = getSystemConnectionMemo().get(org.openlcb.MimicNodeStore.class); 069 var nodeMemo = nodeStore.findNode(nodeID); 070 if (nodeMemo == null) { 071 JmriJOptionPane.showMessageDialog(frame, "Entry "+addr+" not found in CS-105, canceling"); 072 return; 073 } 074 075 // get the CD/CDI information 076 configRep = new ConfigRepresentation(getSystemConnectionMemo().get(OlcbInterface.class),nodeID); 077 configRep.addPropertyChangeListener(this); 078 079 } 080 081 @Override 082 public void propertyChange(PropertyChangeEvent event) { 083 switch (event.getPropertyName()) { 084 case ConfigRepresentation.UPDATE_STATE : 085 // Normal. Indicates that the load is proceeding. 086 case ConfigRepresentation.UPDATE_REP : 087 // Normal, CDI is read in, loading caches next 088 return; 089 case ConfigRepresentation.UPDATE_CACHE_COMPLETE : 090 log.debug("CDI read done"); 091 092 // look for values 093 processValuesFromGUI(); 094 return; 095 default: 096 log.error("Unexpected PropertyChangeEvent {}", event); 097 return; 098 } 099 } 100 101 /** 102 * Construct and execute a listener that sets 103 * the appropriate values from the GUI elements. 104 */ 105 void processValuesFromGUI() { 106 log.trace("processValuesFromGUI"); 107 configRep.visit(new ConfigRepresentation.Visitor() { 108 @Override 109 public void visitString(ConfigRepresentation.StringEntry e) { 110 log.trace("String entry {} is {}", e.key, e.getValue()); 111 112 if (e.key.startsWith("Train.User Description")) { 113 e.setValue(frame.getRosterPane().getComment()); 114 } else if (e.key.startsWith("Train.Functions")) { 115 int index = getNumberField(e.key); 116 if (index == -1) { 117 log.warn("Unexpected format \"{}\"", e.key); 118 return; 119 } 120 if (e.key.endsWith("Description")) { 121 String value = frame.getFnLabelPane().getLabel(index+1).getText(); 122 if (value==null) { 123 value = ""; 124 } 125 log.debug(".Description found function {} roster description \"{}\"", index, value); 126 log.trace(" mapping gives {}", TcsExportAction.intFromFunctionString( 127 rosterEntry.getFunctionLabel(index+1)) ); 128 if (TcsExportAction.intFromFunctionString( 129 frame.getFnLabelPane().getLabel(index+1).getText() 130 ) == 0) { 131 e.setValue(value); 132 } 133 } else { 134 log.warn("Unexpected content \"{}\"", e.key); 135 } 136 } 137 } 138 139 @Override 140 public void visitInt(ConfigRepresentation.IntegerEntry e) { 141 log.trace("Integer entry {} is {}", e.key, e.getValue()); 142 143 // is this the last entry? 144 if (e.key.startsWith("Train.Delete From Roster")) { 145 // TODO: This is firing much too soon 146 JmriJOptionPane.showMessageDialog(frame, "Upload complete."); 147 } else if (e.key.startsWith("Train.Functions")) { 148 int index = getNumberField(e.key); 149 if (index == -1) { 150 log.warn("Unexpected format \"{}\"", e.key); 151 return; 152 } 153 if (e.key.endsWith(".Momentary")) { 154 long value = 1; 155 if (frame.getFnLabelPane().getLockable(index+1).isSelected()) { 156 value = 0; // lockable is not Momentary 157 } 158 e.setValue(value); 159 } else if (e.key.endsWith(".Consist Behavior")) { 160 161 // process consist bit 162 // first, see if function variable exists 163 var variable = vModel.findVar("Consist Address Active For F"+(index+1)); 164 if (variable != null) { 165 // it exists, so we transfer that to the consist info 166 int value = variable.getIntValue(); 167 e.setValue(value); 168 } else { 169 log.debug("Variable {} not found", "Consist Address Active For F"+(index+1) ); 170 } 171 172 } else if (e.key.endsWith(".Display")) { 173 // do a reverse lookup and store 174 int value = TcsExportAction.intFromFunctionString( 175 frame.getFnLabelPane().getLabel(index+1).getText() 176 ); 177 e.setValue(value); 178 log.debug(".display found function {} roster description \"{}\"", index, value); 179 } else { 180 log.warn("Unexpected content \"{}\"", e.key); 181 } 182 } 183 } 184 185 @Override 186 public void visitEvent(ConfigRepresentation.EventEntry e) { 187 log.trace("Event entry {} is {}", e.key, e.getValue()); 188 } 189 }); 190 } 191 192 // Extract the number from e.g. Train.Functions(25).Momentary 193 static int getNumberField(String value) { 194 int first = value.indexOf("("); 195 int last = value.indexOf(")"); 196 if (first > 0 && last > 0 && last > first + 1) { 197 var digits = value.substring(first+1, last); 198 return Integer.parseInt(digits); 199 } 200 return -1; 201 } 202 203 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TcsUploadAction.class); 204}