001package jmri.jmrit.operations.automation; 002 003import java.awt.Frame; 004import java.beans.PropertyChangeEvent; 005import java.beans.PropertyChangeListener; 006import java.util.*; 007 008import javax.swing.*; 009import javax.swing.table.TableCellEditor; 010import javax.swing.table.TableColumnModel; 011 012import jmri.InstanceManager; 013import jmri.jmrit.operations.OperationsXml; 014import jmri.jmrit.operations.setup.Control; 015import jmri.util.swing.JmriJOptionPane; 016import jmri.util.table.ButtonEditor; 017import jmri.util.table.ButtonRenderer; 018 019/** 020 * Table model allowing the edit and status of an automation used by operations. 021 * 022 * @author Daniel Boudreau Copyright (C) 2016 023 */ 024public class AutomationsTableModel extends javax.swing.table.AbstractTableModel implements PropertyChangeListener { 025 026 AutomationManager automationManager; // There is only one manager 027 028 // Defines the columns 029 private static final int ID_COLUMN = 0; 030 private static final int NAME_COLUMN = ID_COLUMN + 1; 031 private static final int COMMENT_COLUMN = NAME_COLUMN + 1; 032 private static final int ACTION_COLUMN = COMMENT_COLUMN + 1; 033 private static final int STATUS_COLUMN = ACTION_COLUMN + 1; 034 private static final int RUN_COLUMN = STATUS_COLUMN + 1; 035 private static final int EDIT_COLUMN = RUN_COLUMN + 1; 036 private static final int DELETE_COLUMN = EDIT_COLUMN + 1; 037 038 private static final int HIGHEST_COLUMN = DELETE_COLUMN + 1; 039 040 public AutomationsTableModel() { 041 super(); 042 automationManager = InstanceManager.getDefault(AutomationManager.class); 043 automationManager.addPropertyChangeListener(this); 044 updateList(); 045 } 046 047 public final int SORTBYNAME = 1; 048 public final int SORTBYID = 2; 049 050 private int _sort = SORTBYNAME; 051 052 public void setSort(int sort) { 053 _sort = sort; 054 updateList(); 055 fireTableDataChanged(); 056 } 057 058 private void updateList() { 059 // first, remove listeners from the individual objects 060 removePropertyChangeAutomations(); 061 062 if (_sort == SORTBYID) { 063 _sysList = automationManager.getAutomationsByIdList(); 064 } else { 065 _sysList = automationManager.getAutomationsByNameList(); 066 } 067 // and add them back in 068 for (Automation automation : _sysList) { 069 automation.addPropertyChangeListener(this); 070 } 071 } 072 073 List<Automation> _sysList = null; 074 JTable _table; 075 076 protected void initTable(AutomationsTableFrame frame, JTable table) { 077 _table = table; 078 // Install the button handlers 079 TableColumnModel tcm = table.getColumnModel(); 080 ButtonRenderer buttonRenderer = new ButtonRenderer(); 081 TableCellEditor buttonEditor = new ButtonEditor(new javax.swing.JButton()); 082 tcm.getColumn(RUN_COLUMN).setCellRenderer(buttonRenderer); 083 tcm.getColumn(RUN_COLUMN).setCellEditor(buttonEditor); 084 tcm.getColumn(EDIT_COLUMN).setCellRenderer(buttonRenderer); 085 tcm.getColumn(EDIT_COLUMN).setCellEditor(buttonEditor); 086 tcm.getColumn(DELETE_COLUMN).setCellRenderer(buttonRenderer); 087 tcm.getColumn(DELETE_COLUMN).setCellEditor(buttonEditor); 088 table.setDefaultRenderer(JComboBox.class, new jmri.jmrit.symbolicprog.ValueRenderer()); 089 table.setDefaultEditor(JComboBox.class, new jmri.jmrit.symbolicprog.ValueEditor()); 090 091 // set column preferred widths 092 table.getColumnModel().getColumn(ID_COLUMN).setPreferredWidth(40); 093 table.getColumnModel().getColumn(NAME_COLUMN).setPreferredWidth(200); 094 table.getColumnModel().getColumn(COMMENT_COLUMN).setPreferredWidth(350); 095 table.getColumnModel().getColumn(ACTION_COLUMN).setPreferredWidth(250); 096 table.getColumnModel().getColumn(STATUS_COLUMN).setPreferredWidth(90); 097 table.getColumnModel().getColumn(RUN_COLUMN).setPreferredWidth(90); 098 table.getColumnModel().getColumn(EDIT_COLUMN).setPreferredWidth(70); 099 table.getColumnModel().getColumn(DELETE_COLUMN).setPreferredWidth(90); 100 101 frame.loadTableDetails(table); 102 } 103 104 @Override 105 public int getRowCount() { 106 return _sysList.size(); 107 } 108 109 @Override 110 public int getColumnCount() { 111 return HIGHEST_COLUMN; 112 } 113 114 @Override 115 public String getColumnName(int col) { 116 switch (col) { 117 case ID_COLUMN: 118 return Bundle.getMessage("Id"); 119 case NAME_COLUMN: 120 return Bundle.getMessage("Name"); 121 case COMMENT_COLUMN: 122 return Bundle.getMessage("Comment"); 123 case ACTION_COLUMN: 124 return Bundle.getMessage("Action"); 125 case STATUS_COLUMN: 126 return Bundle.getMessage("Status"); 127 case RUN_COLUMN: 128 return Bundle.getMessage("Run"); 129 case EDIT_COLUMN: 130 return Bundle.getMessage("ButtonEdit"); 131 case DELETE_COLUMN: 132 return Bundle.getMessage("ButtonDelete"); 133 default: 134 return "unknown"; // NOI18N 135 } 136 } 137 138 @Override 139 public Class<?> getColumnClass(int col) { 140 switch (col) { 141 case ID_COLUMN: 142 return String.class; 143 case NAME_COLUMN: 144 return String.class; 145 case COMMENT_COLUMN: 146 return String.class; 147 case STATUS_COLUMN: 148 return String.class; 149 case ACTION_COLUMN: 150 return String.class; 151 case RUN_COLUMN: 152 return JButton.class; 153 case EDIT_COLUMN: 154 return JButton.class; 155 case DELETE_COLUMN: 156 return JButton.class; 157 default: 158 return null; 159 } 160 } 161 162 @Override 163 public boolean isCellEditable(int row, int col) { 164 switch (col) { 165 case RUN_COLUMN: 166 case EDIT_COLUMN: 167 case DELETE_COLUMN: 168 return true; 169 default: 170 return false; 171 } 172 } 173 174 @Override 175 public Object getValueAt(int row, int col) { 176 if (row >= getRowCount()) { 177 return "ERROR row " + row; // NOI18N 178 } 179 Automation automation = _sysList.get(row); 180 if (automation == null) { 181 return "ERROR automation unknown " + row; // NOI18N 182 } 183 switch (col) { 184 case ID_COLUMN: 185 return automation.getId(); 186 case NAME_COLUMN: 187 return automation.getName(); 188 case COMMENT_COLUMN: 189 return automation.getComment(); 190 case ACTION_COLUMN: 191 return automation.getCurrentActionString(); 192 case STATUS_COLUMN: 193 return automation.getActionStatus(); 194 case RUN_COLUMN: 195 if (automation.isActionRunning()) 196 return Bundle.getMessage("Stop"); 197 else if (automation.isReadyToRun()) 198 return Bundle.getMessage("Run"); 199 else 200 return Bundle.getMessage("Resume"); 201 case EDIT_COLUMN: 202 return Bundle.getMessage("ButtonEdit"); 203 case DELETE_COLUMN: 204 return Bundle.getMessage("ButtonDelete"); 205 default: 206 return "unknown " + col; // NOI18N 207 } 208 } 209 210 @Override 211 public void setValueAt(Object value, int row, int col) { 212 switch (col) { 213 case RUN_COLUMN: 214 runAutomation(row); 215 break; 216 case EDIT_COLUMN: 217 editAutomation(row); 218 break; 219 case DELETE_COLUMN: 220 deleteAutomation(row); 221 break; 222 default: 223 break; 224 } 225 } 226 227 private void runAutomation(int row) { 228 Automation automation = _sysList.get(row); 229 SwingUtilities.invokeLater(() -> { 230 if (automation.isActionRunning()) 231 automation.stop(); 232 else 233 automation.resume(); 234 }); 235 } 236 237 Hashtable<String, AutomationTableFrame> automationEditFrames = new Hashtable<String, AutomationTableFrame>(); 238 239 private void editAutomation(int row) { 240 log.debug("Edit automation"); 241 Automation automation = _sysList.get(row); 242 243 // is the edit window already open? 244 if (automationEditFrames.containsKey(automation.getId())) { 245 AutomationTableFrame frame = automationEditFrames.get(automation.getId()); 246 if (frame.isVisible()) { 247 frame.toFront(); 248 frame.setExtendedState(Frame.NORMAL); 249 return; // done 250 } 251 } 252 253 // use invokeLater so new window appears on top 254 SwingUtilities.invokeLater(() -> { 255 AutomationTableFrame frame = new AutomationTableFrame(automation); 256 automationEditFrames.put(automation.getId(), frame); 257 }); 258 } 259 260 private void deleteAutomation(int row) { 261 log.debug("Delete automation"); 262 Automation automation = _sysList.get(row); 263 if (JmriJOptionPane.showConfirmDialog(null, Bundle.getMessage("DoYouWantToDeleteAutomation", 264 automation.getName()), Bundle.getMessage("DeleteAutomation?"), 265 JmriJOptionPane.YES_NO_OPTION) == JmriJOptionPane.YES_OPTION) { 266 automationManager.deregister(automation); 267 OperationsXml.save(); 268 } 269 } 270 271 private void removePropertyChangeAutomations() { 272 if (_sysList != null) { 273 for (Automation automation : _sysList) { 274 automation.removePropertyChangeListener(this); 275 } 276 } 277 } 278 279 public void dispose() { 280 Enumeration<String> en = automationEditFrames.keys(); 281 while (en.hasMoreElements()) { 282 AutomationTableFrame frame = automationEditFrames.get(en.nextElement()); 283 frame.dispose(); 284 } 285 286 automationManager.removePropertyChangeListener(this); 287 removePropertyChangeAutomations(); 288 } 289 290 // check for change in number of automations, or a change in a automation 291 @Override 292 public void propertyChange(PropertyChangeEvent e) { 293 if (Control.SHOW_PROPERTY) { 294 log.debug("Property change: ({}) old: ({}) new: ({})", e.getPropertyName(), e.getOldValue(), e 295 .getNewValue()); 296 } 297 if (e.getPropertyName().equals(AutomationManager.LISTLENGTH_CHANGED_PROPERTY)) { 298 updateList(); 299 fireTableDataChanged(); 300 } else if (e.getSource().getClass().equals(Automation.class)) { 301 Automation automation = (Automation) e.getSource(); 302 int row = _sysList.indexOf(automation); 303 if (Control.SHOW_PROPERTY) { 304 log.debug("Update automation table row: {} name: {}", row, automation.getName()); 305 } 306 if (row >= 0) { 307 fireTableRowsUpdated(row, row); 308 } 309 } 310 } 311 312 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(AutomationsTableModel.class); 313 314}