001package jmri.jmrix.mqtt; 002 003import java.awt.*; 004import java.text.DecimalFormat; 005import java.util.*; 006import java.util.List; 007 008import javax.swing.*; 009import javax.swing.border.TitledBorder; 010import javax.annotation.Nonnull; 011 012import jmri.*; 013import jmri.jmrit.beantable.signalmast.SignalMastAddPane; 014 015import org.openide.util.lookup.ServiceProvider; 016 017/** 018 * A pane for configuring VirtualSignalMast objects. 019 * 020 * @see jmri.jmrit.beantable.signalmast.SignalMastAddPane 021 * @author Bob Jacobsen Copyright (C) 2018, 2021 022 */ 023public class MqttSignalMastAddPane extends SignalMastAddPane { 024 025 public MqttSignalMastAddPane() { 026 initPanel(); 027 } 028 029 final void initPanel() { 030 031 setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); 032 // lit/unlit controls 033 JPanel p = new JPanel(); 034 p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS)); 035 p.add(new JLabel(Bundle.getMessage("AllowUnLitLabel") + ": ")); 036 p.add(allowUnLit); 037 p.setAlignmentX(Component.LEFT_ALIGNMENT); 038 add(p); 039 040 // Address part 041 add(addressDataPane()); 042 043 // disabled aspects controls 044 TitledBorder disableborder = BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.black)); 045 disableborder.setTitle(Bundle.getMessage("DisableAspectsLabel")); 046 JScrollPane disabledAspectsScroll = new JScrollPane(disabledAspectsPanel); 047 disabledAspectsScroll.setBorder(disableborder); 048 add(disabledAspectsScroll); 049 } 050 051 JPanel addressDataPane() { 052 JPanel p = new JPanel(); 053 054 TitledBorder border = BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.black)); 055 //border.setTitle("Mast Number"); 056 p.setBorder(border); 057 058 p.setLayout(new jmri.util.javaworld.GridLayout2(1, 2)); 059 060 p.add(aspectAddressLabel); 061 062 aspectAddressField.setText(paddedNumber.format(MqttSignalMast.getLastRef() + 1)); 063 aspectAddressField.setEnabled(true); 064 p.add(aspectAddressField); 065 066 return p; 067 } 068 JLabel aspectAddressLabel = new JLabel(Bundle.getMessage("TopicSuffix")); 069 JTextField aspectAddressField = new JTextField(5); 070 071 /** {@inheritDoc} */ 072 @Override 073 @Nonnull public String getPaneName() { 074 return Bundle.getMessage("MqttMast"); 075 } 076 077 JCheckBox allowUnLit = new JCheckBox(); 078 079 LinkedHashMap<String, JCheckBox> disabledAspects = new LinkedHashMap<>(NOTIONAL_ASPECT_COUNT); 080 JPanel disabledAspectsPanel = new JPanel(); 081 082 MqttSignalMast currentMast = null; 083 084 /** {@inheritDoc} */ 085 @Override 086 public void setAspectNames(@Nonnull SignalAppearanceMap map, @Nonnull SignalSystem sigSystem) { 087 Enumeration<String> aspects = map.getAspects(); 088 // update immediately 089 disabledAspects = new LinkedHashMap<>(NOTIONAL_ASPECT_COUNT); 090 disabledAspectsPanel.removeAll(); 091 while (aspects.hasMoreElements()) { 092 String aspect = aspects.nextElement(); 093 JCheckBox disabled = new JCheckBox(aspect); 094 disabledAspects.put(aspect, disabled); 095 } 096 097 for (Map.Entry<String, JCheckBox> entry : disabledAspects.entrySet()) { 098 disabledAspectsPanel.add(entry.getValue()); 099 } 100 101 disabledAspectsPanel.setLayout(new jmri.util.javaworld.GridLayout2(0, 1)); // 0 means enough 102 103 disabledAspectsPanel.revalidate(); 104 } 105 106 /** {@inheritDoc} */ 107 @Override 108 public boolean canHandleMast(@Nonnull SignalMast mast) { 109 return mast instanceof MqttSignalMast; 110 } 111 112 /** {@inheritDoc} */ 113 @Override 114 public void setMast(SignalMast mast) { 115 log.trace("setMast {} start", mast); 116 if (mast == null) { 117 currentMast = null; 118 return; 119 } 120 121 if (! (mast instanceof MqttSignalMast) ) { 122 log.error("mast was wrong type: {} {}", mast.getSystemName(), mast.getClass().getName()); 123 return; 124 } 125 126 aspectAddressField.setEnabled(false); 127 String[] pieces = mast.getSystemName().split("\\("); 128 if (pieces.length == 2) { 129 String number = pieces[1].substring(1, pieces[1].length()-1); // starts with ($) 130 aspectAddressField.setText(number); 131 } else { 132 log.warn("not just one '(' in {}",mast.getSystemName()); 133 } 134 135 currentMast = (MqttSignalMast) mast; 136 List<String> disabled = currentMast.getDisabledAspects(); 137 if (disabled != null) { 138 for (String aspect : disabled) { 139 if (disabledAspects.containsKey(aspect)) { 140 disabledAspects.get(aspect).setSelected(true); 141 } 142 } 143 } 144 145 allowUnLit.setSelected(currentMast.allowUnLit()); 146 147 log.trace("setMast {} end", mast); 148 } 149 150 DecimalFormat paddedNumber = new DecimalFormat("0000"); 151 152 /** {@inheritDoc} */ 153 @Override 154 public boolean createMast(@Nonnull 155 String sigsysname, @Nonnull 156 String mastname, @Nonnull 157 String username) { 158 log.trace("createMast {} {} {} start with currentMast: {}", sigsysname, mastname, username, currentMast); 159 if (currentMast == null) { 160 // create a mast 161 String name = "IF$mqm:" 162 + sigsysname 163 + ":" + mastname.substring(11, mastname.length() - 4); 164 name += "($" + aspectAddressField.getText()+ ")"; 165 currentMast = new MqttSignalMast(name); 166 if (!username.isEmpty()) { 167 currentMast.setUserName(username); 168 } 169 currentMast.setMastType(mastname.substring(11, mastname.length() - 4)); 170 try { 171 InstanceManager.getDefault(SignalMastManager.class).register(currentMast); 172 } catch (jmri.NamedBean.DuplicateSystemNameException e) { 173 // clear the signal mast and rethrow 174 currentMast = null; 175 throw e; 176 } 177 178 } 179 180 // load a new or existing mast 181 for (Map.Entry<String, JCheckBox> entry : disabledAspects.entrySet()) { 182 if (entry.getValue().isSelected()) { 183 currentMast.setAspectDisabled(entry.getKey()); 184 } else { 185 currentMast.setAspectEnabled(entry.getKey()); 186 } 187 } 188 currentMast.setAllowUnLit(allowUnLit.isSelected()); 189 190 // update to next option 191 aspectAddressField.setText((paddedNumber.format(MqttSignalMast.getLastRef() + 1))); 192 193 log.trace("createMast {} {} {} end", sigsysname, mastname, username); 194 return true; 195 } 196 197 @ServiceProvider(service = SignalMastAddPane.SignalMastAddPaneProvider.class) 198 static public class SignalMastAddPaneProvider extends SignalMastAddPane.SignalMastAddPaneProvider { 199 /** 200 * {@inheritDoc} 201 * Requires a valid MQTT connection 202 */ 203 @Override 204 public boolean isAvailable() { 205 for (SystemConnectionMemo memo : InstanceManager.getList(SystemConnectionMemo.class)) { 206 if (memo instanceof jmri.jmrix.mqtt.MqttSystemConnectionMemo) { 207 return true; 208 } 209 } 210 return false; 211 } 212 213 /** {@inheritDoc} */ 214 @Override 215 @Nonnull public String getPaneName() { 216 return Bundle.getMessage("MqttMast"); 217 } 218 /** {@inheritDoc} */ 219 @Override 220 @Nonnull public SignalMastAddPane getNewPane() { 221 return new MqttSignalMastAddPane(); 222 } 223 } 224 225 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(MqttSignalMastAddPane.class); 226 227}