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