001package jmri.jmrit.sensorgroup; 002 003import java.awt.BorderLayout; 004import java.awt.event.ActionEvent; 005import java.awt.event.ActionListener; 006import java.util.ArrayList; 007import java.util.List; 008import javax.swing.*; 009import javax.swing.table.TableColumn; 010import javax.swing.table.TableColumnModel; 011import javax.swing.table.TableRowSorter; 012import jmri.*; 013import jmri.implementation.DefaultConditionalAction; 014import jmri.implementation.SensorGroupConditional; 015import jmri.swing.RowSorterUtil; 016import jmri.util.swing.JmriJOptionPane; 017 018/** 019 * User interface for creating and editing sensor groups. 020 * <p> 021 * Sensor groups are implemented by (groups) of Routes, not by any other object. 022 * 023 * @author Bob Jacobsen Copyright (C) 2007 024 * @author Pete Cressman Copyright (C) 2009 025 */ 026public class SensorGroupFrame extends jmri.util.JmriJFrame { 027 028 public SensorGroupFrame() { 029 super(); 030 } 031 032 private final static String namePrefix = "SENSOR GROUP:"; // should be upper case 033 private final static String nameDivider = ":"; 034 public final static String logixSysName; 035 public final static String logixUserName = "System Logix"; 036 public final static String ConditionalSystemPrefix; 037 private final static String ConditionalUserPrefix = "Sensor Group "; 038 private int rowHeight; 039 040 static { 041 String logixPrefix = InstanceManager.getDefault(jmri.LogixManager.class).getSystemNamePrefix(); 042 logixSysName = logixPrefix + ":SYS"; 043 ConditionalSystemPrefix = logixSysName + "_SGC_"; 044 } 045 046 SensorTableModel _sensorModel; 047 JScrollPane _sensorScrollPane; 048 JTextField _nameField; 049 JList<String> _sensorGroupList; 050 051 @Override 052 public void initComponents() { 053 addHelpMenu("package.jmri.jmrit.sensorgroup.SensorGroupFrame", true); 054 055 setTitle(Bundle.getMessage("Title")); 056 getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS)); 057 058 // add the sensor table 059 JPanel p2xs = new JPanel(); 060 061 JPanel p21s = new JPanel(); 062 p21s.setLayout(new BoxLayout(p21s, BoxLayout.Y_AXIS)); 063 p21s.add(new JLabel(Bundle.getMessage("SensorTableLabel1"))); 064 p21s.add(new JLabel(Bundle.getMessage("SensorTableLabel2"))); 065 p21s.add(new JLabel(Bundle.getMessage("SensorTableLabel3"))); 066 p21s.add(new JLabel(Bundle.getMessage("SensorTableLabel4"))); 067 p2xs.add(p21s); 068 _sensorModel = new SensorTableModel(); 069 JTable sensorTable = new JTable(_sensorModel); 070 071 TableRowSorter<SensorTableModel> sorter = new TableRowSorter<>(_sensorModel); 072 sorter.setComparator(SensorTableModel.SNAME_COLUMN, new jmri.util.AlphanumComparator()); 073 sorter.setComparator(SensorTableModel.UNAME_COLUMN, new jmri.util.AlphanumComparator()); 074 RowSorterUtil.setSortOrder(sorter, SensorTableModel.SNAME_COLUMN, SortOrder.ASCENDING); 075 sensorTable.setRowSorter(sorter); 076 077 sensorTable.setRowSelectionAllowed(false); 078 sensorTable.setPreferredScrollableViewportSize(new java.awt.Dimension(450, 200)); 079 TableColumnModel sensorColumnModel = sensorTable.getColumnModel(); 080 TableColumn includeColumnS = sensorColumnModel. 081 getColumn(SensorTableModel.INCLUDE_COLUMN); 082 includeColumnS.setResizable(false); 083 includeColumnS.setMinWidth(50); 084 includeColumnS.setMaxWidth(60); 085 TableColumn sNameColumnS = sensorColumnModel. 086 getColumn(SensorTableModel.SNAME_COLUMN); 087 sNameColumnS.setResizable(true); 088 sNameColumnS.setMinWidth(75); 089 sNameColumnS.setPreferredWidth(95); 090 TableColumn uNameColumnS = sensorColumnModel. 091 getColumn(SensorTableModel.UNAME_COLUMN); 092 uNameColumnS.setResizable(true); 093 uNameColumnS.setMinWidth(210); 094 uNameColumnS.setPreferredWidth(260); 095 096 rowHeight = sensorTable.getRowHeight(); 097 _sensorScrollPane = new JScrollPane(sensorTable); 098 p2xs.add(_sensorScrollPane, BorderLayout.CENTER); 099 getContentPane().add(p2xs); 100 p2xs.setVisible(true); 101 102 // add name field 103 JPanel p3 = new JPanel(); 104 p3.add(new JLabel(Bundle.getMessage("GroupName"))); 105 _nameField = new JTextField(20); 106 p3.add(_nameField); 107 getContentPane().add(p3); 108 109 // button 110 JPanel p4 = new JPanel(); 111 JButton viewButton = new JButton(Bundle.getMessage("ButtonViewGroup")); 112 viewButton.addActionListener(new ActionListener() { 113 @Override 114 public void actionPerformed(ActionEvent e) { 115 viewPressed(); 116 } 117 }); 118 p4.add(viewButton); 119 JButton addButton = new JButton(Bundle.getMessage("ButtonMakeGroup")); 120 addButton.addActionListener(new ActionListener() { 121 @Override 122 public void actionPerformed(ActionEvent e) { 123 addPressed(); 124 } 125 }); 126 p4.add(addButton); 127 JButton undoButton = new JButton(Bundle.getMessage("ButtonUndoGroup")); 128 undoButton.addActionListener(new ActionListener() { 129 @Override 130 public void actionPerformed(ActionEvent e) { 131 undoGroupPressed(); 132 } 133 }); 134 p4.add(undoButton); 135 getContentPane().add(p4); 136 137 JPanel p5 = new JPanel(); 138 139 DefaultListModel<String> groupModel = new DefaultListModel<>(); 140 // Look for Sensor group in Route table 141 RouteManager rm = InstanceManager.getDefault(jmri.RouteManager.class); 142 // List<String> routeList = rm.getSystemNameList(); 143 int i = 0; 144 for (NamedBean obj : rm.getNamedBeanSet()) { 145 String name = obj.getSystemName(); 146 if (name.startsWith(namePrefix)) { 147 name = name.substring(namePrefix.length()); 148 String group = name.substring(0, name.indexOf(nameDivider)); 149 String prefix = namePrefix + group + nameDivider; 150 do { 151 i++; 152 if (i >= rm.getNamedBeanSet().size()) { 153 break; 154 } 155 name = obj.getSystemName(); 156 } while (name.startsWith(prefix)); 157 groupModel.addElement(group); 158 } 159 i++; 160 } 161 // Look for Sensor group in Logix 162 Logix logix = getSystemLogix(); 163 for (i = 0; i < logix.getNumConditionals(); i++) { 164 String name = logix.getConditionalByNumberOrder(i); 165 Conditional c = InstanceManager.getDefault(jmri.ConditionalManager.class).getBySystemName(name); 166 String uname = null; 167 if (c !=null) { 168 uname = c.getUserName(); 169 } 170 if (uname != null) { 171 groupModel.addElement(uname.substring(ConditionalUserPrefix.length())); 172 } 173 } 174 _sensorGroupList = new JList<>(groupModel); 175 _sensorGroupList.setPrototypeCellValue(ConditionalUserPrefix + "XXXXXXXXXX"); 176 _sensorGroupList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 177 _sensorGroupList.setVisibleRowCount(5); 178 JScrollPane scrollPane = new JScrollPane(_sensorGroupList); 179 p5.add(scrollPane); 180 p5.add(Box.createHorizontalStrut(10)); 181 JButton doneButton = new JButton(Bundle.getMessage("ButtonDone")); 182 doneButton.addActionListener(new ActionListener() { 183 @Override 184 public void actionPerformed(ActionEvent e) { 185 donePressed(e); 186 } 187 }); 188 p5.add(doneButton); 189 getContentPane().add(p5); 190 191 // pack to cause display 192 pack(); 193 } 194 195 void addPressed() { 196 deleteGroup(false); 197 String group = _nameField.getText(); 198 if (group == null || group.length() == 0) { 199 JmriJOptionPane.showMessageDialog(this, 200 Bundle.getMessage("MessageError1"), Bundle.getMessage("ErrorTitle"), 201 JmriJOptionPane.ERROR_MESSAGE); 202 return; 203 } 204 Logix logix = getSystemLogix(); 205 logix.deActivateLogix(); 206 String cSystemName = ConditionalSystemPrefix + group; 207 String cUserName = ConditionalUserPrefix + group; 208 // add new Conditional 209 ArrayList<ConditionalVariable> variableList = new ArrayList<>(); 210 ArrayList<ConditionalAction> actionList = new ArrayList<>(); 211 int count = 0; 212 for (int i = 0; i < _sensorModel.getRowCount(); i++) { 213 if ((Boolean) _sensorModel.getValueAt(i, BeanTableModel.INCLUDE_COLUMN)) { 214 String sensor = (String) _sensorModel.getValueAt(i, BeanTableModel.UNAME_COLUMN); 215 if (sensor == null || sensor.length() == 0) { 216 sensor = (String) _sensorModel.getValueAt(i, BeanTableModel.SNAME_COLUMN); 217 } 218 variableList.add(new ConditionalVariable(false, Conditional.Operator.OR, 219 Conditional.Type.SENSOR_ACTIVE, sensor, true)); 220 actionList.add(new DefaultConditionalAction(Conditional.ACTION_OPTION_ON_CHANGE_TO_TRUE, 221 Conditional.Action.SET_SENSOR, sensor, 222 Sensor.INACTIVE, "")); 223 count++; 224 } 225 } 226 if (count < 2) { 227 JmriJOptionPane.showMessageDialog(this, 228 Bundle.getMessage("MessageError2"), Bundle.getMessage("ErrorTitle"), 229 JmriJOptionPane.ERROR_MESSAGE); 230 } 231 Conditional c = new SensorGroupConditional(cSystemName, cUserName); 232 c.setStateVariables(variableList); 233 c.setLogicType(Conditional.AntecedentOperator.ALL_OR, ""); 234 c.setAction(actionList); 235 logix.addConditional(cSystemName, 0); // Update the Logix Conditional names list 236 logix.addConditional(cSystemName, c); // Update the Logix Conditional hash map 237 logix.setEnabled(true); 238 logix.activateLogix(); 239 ((DefaultListModel<String>) _sensorGroupList.getModel()).addElement( 240 cUserName.substring(ConditionalUserPrefix.length())); 241 clear(); 242 } 243 244 void viewPressed() { 245 for (int i = 0; i < _sensorModel.getRowCount(); i++) { 246 _sensorModel.setValueAt(Boolean.FALSE, i, BeanTableModel.INCLUDE_COLUMN); 247 } 248 // look for name in List panel 249 String group = _sensorGroupList.getSelectedValue(); 250 if (group == null) { // not there, look in text field 251 group = _nameField.getText(); 252 } 253 _nameField.setText(group); 254 // Look for Sensor group in Route table 255 RouteManager rm = InstanceManager.getDefault(jmri.RouteManager.class); 256 String prefix = (namePrefix + group + nameDivider); 257 boolean isRoute = false; 258 int setRow = 0; 259 for (Route r : rm.getNamedBeanSet()) { 260 String name = r.getSystemName(); 261 if (name.startsWith(prefix)) { 262 isRoute = true; 263 String sensor = name.substring(prefix.length()); 264 // find and check that sensor 265 for (int j = _sensorModel.getRowCount() - 1; j >= 0; j--) { 266 if (_sensorModel.getValueAt(j, BeanTableModel.SNAME_COLUMN).equals(sensor)) { 267 _sensorModel.setValueAt(Boolean.TRUE, j, BeanTableModel.INCLUDE_COLUMN); 268 setRow = j; 269 } 270 } 271 } 272 } 273 274 // look for Sensor group in SYSTEM Logix 275 if (!isRoute) { 276 Logix logix = getSystemLogix(); 277 String cSystemName = (ConditionalSystemPrefix + group); 278 String cUserName = ConditionalUserPrefix + group; 279 for (int i = 0; i < logix.getNumConditionals(); i++) { 280 String name = logix.getConditionalByNumberOrder(i); 281 if (cSystemName.equalsIgnoreCase(name) || cUserName.equals(name)) { // Ignore case for compatibility 282 Conditional c = InstanceManager.getDefault(jmri.ConditionalManager.class).getBySystemName(name); 283 if (c == null) { 284 log.error("Conditional \"{}\" expected but NOT found in Logix {}", name, logix.getSystemName()); 285 } else { 286 List<ConditionalVariable> variableList = c.getCopyOfStateVariables(); 287 for (int k = 0; k < variableList.size(); k++) { 288 String sensor = variableList.get(k).getName(); 289 if (sensor != null) { 290 for (int j = _sensorModel.getRowCount() - 1; j >= 0; j--) { 291 if (sensor.equals(_sensorModel.getValueAt(j, BeanTableModel.UNAME_COLUMN)) 292 || sensor.equals(_sensorModel.getValueAt(j, BeanTableModel.SNAME_COLUMN))) { 293 _sensorModel.setValueAt(Boolean.TRUE, j, BeanTableModel.INCLUDE_COLUMN); 294 setRow = j; 295 } 296 } 297 } 298 } 299 } 300 } 301 } 302 } 303 _sensorModel.fireTableDataChanged(); 304 setRow -= 9; 305 if (setRow < 0) { 306 setRow = 0; 307 } 308 _sensorScrollPane.getVerticalScrollBar().setValue(setRow * rowHeight); 309 } 310 311 Logix getSystemLogix() { 312 Logix logix = InstanceManager.getDefault(jmri.LogixManager.class).getBySystemName(logixSysName); 313 if (logix == null) { 314 logix = InstanceManager.getDefault(jmri.LogixManager.class).createNewLogix(logixSysName, logixUserName); 315 } 316 return logix; 317 } 318 319 void clear() { 320 _sensorGroupList.getSelectionModel().clearSelection(); 321 _nameField.setText(""); 322 for (int i = 0; i < _sensorModel.getRowCount(); i++) { 323 _sensorModel.setValueAt(Boolean.FALSE, i, BeanTableModel.INCLUDE_COLUMN); 324 } 325 _sensorModel.fireTableDataChanged(); 326 } 327 328 void donePressed(ActionEvent e) { 329 _sensorModel.dispose(); 330 dispose(); 331 } 332 333 void deleteGroup(boolean showMsg) { 334 String group = _nameField.getText(); 335 336 if (group == null || group.isEmpty()) { 337 if (showMsg) { 338 JmriJOptionPane.showMessageDialog(this, 339 Bundle.getMessage("MessageError3"), Bundle.getMessage("ErrorTitle"), 340 JmriJOptionPane.ERROR_MESSAGE); 341 } 342 return; 343 } 344 345 // remove the old routes 346 String prefix = (namePrefix + group + nameDivider); 347 RouteManager rm = InstanceManager.getDefault(jmri.RouteManager.class); 348 for (Route r : rm.getNamedBeanSet()) { 349 String name = r.getSystemName(); 350 if (name.startsWith(prefix)) { 351 // OK, kill this one 352 r.deActivateRoute(); 353 rm.deleteRoute(r); 354 } 355 } 356 357 // remove Logix IX:SYS conditional 358 // Due to a change at 4.17.2, the system names are no longer forced to upper case. 359 // Older SYS conditionals will have an upper case name, so the user name is an alternate name. 360 Logix logix = getSystemLogix(); 361 String cSystemName = ConditionalSystemPrefix + group; 362 String cUserName = ConditionalUserPrefix + group; 363 364 for (int i = 0; i < logix.getNumConditionals(); i++) { 365 String cdlName = logix.getConditionalByNumberOrder(i); 366 Conditional cdl = logix.getConditional(cdlName); 367 if (cdl != null) { 368 if (cSystemName.equals(cdl.getSystemName()) || cUserName.equals(cdl.getUserName())) { 369 String[] msgs = logix.deleteConditional(cdlName); 370 if (msgs == null) { 371 break; 372 } 373 374 // Conditional delete failed or was vetoed 375 if (showMsg) { 376 JmriJOptionPane.showMessageDialog(this, 377 Bundle.getMessage("MessageError41") + " " + msgs[0] + " (" + msgs[1] + ") " 378 + Bundle.getMessage("MessageError42") + " " + msgs[2] + " (" + msgs[3] + "), " 379 + Bundle.getMessage("MessageError43") + " " + msgs[4] + " (" + msgs[5] + "). " 380 + Bundle.getMessage("MessageError44"), 381 Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE); 382 } 383 return; 384 } 385 } else { 386 log.error("Conditional \"{}\" expected but NOT found in Logix {}", cdlName, logix.getSystemName()); 387 return; 388 } 389 } 390 391 // remove from list 392 DefaultListModel<String> model = (DefaultListModel<String>) _sensorGroupList.getModel(); 393 model.removeElement(group); 394 } 395 396 void undoGroupPressed() { 397 deleteGroup(true); 398 clear(); 399 } 400 401 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(SensorGroupFrame.class); 402}