001package jmri.jmrit.operations.automation.actions; 002 003import java.text.MessageFormat; 004import javax.swing.JComboBox; 005 006import jmri.beans.PropertyChangeSupport; 007import jmri.jmrit.operations.automation.Automation; 008import jmri.jmrit.operations.automation.AutomationItem; 009import jmri.jmrit.operations.routes.RouteLocation; 010import jmri.jmrit.operations.trains.Train; 011import jmri.jmrit.operations.trains.schedules.TrainSchedule; 012import jmri.util.swing.JmriJOptionPane; 013 014public abstract class Action extends PropertyChangeSupport { 015 016 public static final String ACTION_COMPLETE_CHANGED_PROPERTY = "actionComplete"; // NOI18N 017 public static final String ACTION_HALT_CHANGED_PROPERTY = "actionHalt"; // NOI18N 018 public static final String ACTION_RUNNING_CHANGED_PROPERTY = "actionRunning"; // NOI18N 019 public static final String ACTION_GOTO_CHANGED_PROPERTY = "actionGoto"; // NOI18N 020 021 public static final int HALT = 0; // halt is the first button 022 public static final int OKAY = 1; 023 public static final int CLOSED = JmriJOptionPane.CLOSED_OPTION; // -1 024 public static final int NO_MESSAGE_SENT = -2; 025 public static final int FINISH_FAILED = -3; 026 027 protected AutomationItem _automationItem = null; 028 029 abstract public int getCode(); 030 031 abstract public String getName(); 032 033 abstract public void doAction(); 034 035 abstract public void cancelAction(); 036 037 /** 038 * For combo boxes. 039 * <p> 040 * {@inheritDoc} 041 */ 042 @Override 043 public String toString() { 044 return getName(); 045 } 046 047 /** 048 * Mask off menu bits. 049 * 050 * @param code the integer to be modified by masking off menu bits. 051 * 052 * @return code and ActionCodes.CODE_MASK 053 */ 054 protected int getCode(int code) { 055 return code & ActionCodes.CODE_MASK; 056 } 057 058 public boolean isTrainMenuEnabled() { 059 return (getCode() & ActionCodes.ENABLE_TRAINS) == ActionCodes.ENABLE_TRAINS; 060 } 061 062 public boolean isRouteMenuEnabled() { 063 return (getCode() & ActionCodes.ENABLE_ROUTES) == ActionCodes.ENABLE_ROUTES; 064 } 065 066 public boolean isMessageOkEnabled() { 067 return (getCode() & ActionCodes.OK_MESSAGE) == ActionCodes.OK_MESSAGE; 068 } 069 070 public boolean isMessageFailEnabled() { 071 return (getCode() & ActionCodes.FAIL_MESSAGE) == ActionCodes.FAIL_MESSAGE; 072 } 073 074 public boolean isAutomationMenuEnabled() { 075 return (getCode() & ActionCodes.ENABLE_AUTOMATION) == ActionCodes.ENABLE_AUTOMATION; 076 } 077 078 public boolean isGotoMenuEnabled() { 079 return (getCode() & ActionCodes.ENABLE_GOTO) == ActionCodes.ENABLE_GOTO; 080 } 081 082 /** 083 * Used to determine if this action can run concurrently with other actions. 084 * 085 * @return true if a concurrent action 086 */ 087 public boolean isConcurrentAction() { 088 return false; // override if concurrent action 089 } 090 091 public void setAutomationItem(AutomationItem item) { 092 _automationItem = item; 093 } 094 095 public AutomationItem getAutomationItem() { 096 return _automationItem; 097 } 098 099 public String getActionString() { 100 return getFormatedMessage("{0}{1}{2}{3}{4}{5}"); // NOI18N 101 } 102 103 public String getStatus() { 104 if (getAutomationItem() != null) { 105 if (getAutomationItem().isActionRunning()) { 106 return Bundle.getMessage("Running"); 107 } 108 if (!getAutomationItem().isActionRan()) { 109 return AutomationItem.NONE; 110 } 111 return getAutomationItem().isActionSuccessful() ? getActionSuccessfulString() : getActionFailedString(); 112 } 113 return "unknown"; // NOI18N 114 } 115 116 public String getActionSuccessfulString() { 117 return Bundle.getMessage("ButtonOK"); 118 } 119 120 public String getActionFailedString() { 121 return Bundle.getMessage("FAILED"); 122 } 123 124 public void setRunning(boolean running) { 125 if (getAutomationItem() != null) { 126 boolean old = getAutomationItem().isActionRunning(); 127 getAutomationItem().setActionRunning(running); 128 if (old != running) { 129 firePropertyChange(ACTION_RUNNING_CHANGED_PROPERTY, old, running); 130 } 131 } 132 } 133 134 /** 135 * Completes the action by displaying the correct message if there's one. 136 * Will halt if the option to halt the automation is enabled or the user 137 * requested the automation to halt. 138 * 139 * @param success true if action succeeded 140 * @return OKAY, HALT, CLOSED, NO_MESSAGE_SENT, FINISH_FAILED 141 */ 142 public int finishAction(boolean success) { 143 return finishAction(success, new Object[]{Bundle.getMessage("HALT"), Bundle.getMessage("ButtonOK")}); 144 } 145 146 /** 147 * Completes the action by displaying the correct message if there's one. 148 * Will halt if the option to halt the automation is enabled or the user 149 * requested the automation to halt. 150 * 151 * @param success true if action succeeded 152 * @param buttons buttons to display in message 153 * @return OKAY, HALT, CLOSED, NO_MESSAGE_SENT, FINISH_FAILED 154 */ 155 public int finishAction(boolean success, Object[] buttons) { 156 int response = FINISH_FAILED; 157 if (getAutomationItem() != null) { 158 setRunning(true); 159 getAutomationItem().setActionSuccessful(success); 160 setRunning(false); 161 String message = getAutomationItem().getMessage(); 162 if (!success) { 163 message = getAutomationItem().getMessageFail(); 164 if (getAutomationItem().isHaltFailureEnabled()) { 165 buttons = new Object[]{Bundle.getMessage("HALT")}; // Must halt, only the HALT button shown 166 } 167 } 168 response = sendMessage(message, buttons, success); 169 if (response == HALT && buttons[0].equals(Bundle.getMessage("HALT")) 170 || (!success && getAutomationItem().isHaltFailureEnabled())) { 171 firePropertyChange(ACTION_HALT_CHANGED_PROPERTY, !success, success); 172 } else { 173 firePropertyChange(ACTION_COMPLETE_CHANGED_PROPERTY, !success, success); 174 } 175 } 176 return response; 177 } 178 179 /** 180 * Displays message if there's one. 181 * 182 * @param buttons the buttons to display, if success and two or more 183 * buttons, the second button becomes the default 184 * @param success true if action succeeded 185 * @param message the text to be displayed 186 * @return array number for which button was pressed, NO_MESSAGE_SENT, CLOSED 187 */ 188 public int sendMessage(String message, Object[] buttons, boolean success) { 189 int response = NO_MESSAGE_SENT; 190 if (getAutomationItem() != null && !message.equals(AutomationItem.NONE)) { 191 String title = getAutomationItem().getId() + " " 192 + (success ? "" : Bundle.getMessage("Failed")) + " " + getActionString(); 193 Object intialValue = buttons[0]; // normally HALT 194 if (buttons.length > 1 && success) { 195 intialValue = buttons[1]; // normally OK 196 } 197 response = JmriJOptionPane.showOptionDialog(null, getFormatedMessage(message), title, 198 JmriJOptionPane.DEFAULT_OPTION, JmriJOptionPane.INFORMATION_MESSAGE, null, buttons, 199 intialValue); 200 } 201 return response; 202 } 203 204 /** 205 * Formats a message using fixed arguments in the following order: 206 * <p> 207 * action name, train name, route location name, automation name, goto item 208 * id, train schedule day. 209 * 210 * @param message the string to be formated 211 * 212 * @return formated message 213 */ 214 public String getFormatedMessage(String message) { 215 String trainName = ""; 216 Train train = getAutomationItem().getTrain(); 217 if (train != null) { 218 trainName = " " + train.getName(); 219 } 220 String routeLocationName = ""; 221 RouteLocation rl = getAutomationItem().getRouteLocation(); 222 if (rl != null) { 223 routeLocationName = " " + rl.getName(); 224 } 225 String automationName = ""; 226 Automation automation = getAutomationItem().getAutomationToRun(); 227 if (automation != null) { 228 automationName = " " + automation.getName(); 229 } 230 String itemId = ""; 231 AutomationItem item = getAutomationItem().getGotoAutomationItem(); 232 if (item != null) { 233 itemId = " " + item.getId(); 234 } 235 String day = ""; 236 TrainSchedule trainSchedule = getAutomationItem().getTrainSchedule(); 237 if (trainSchedule != null) { 238 day = " " + trainSchedule.getName(); 239 } 240 return MessageFormat.format(message, new Object[]{getName(), trainName, routeLocationName, automationName, itemId, day}); 241 } 242 243 // to be overridden if action needs a ComboBox 244 public JComboBox<?> getComboBox() { 245 JComboBox<?> cb = new JComboBox<>(); 246 cb.setEnabled(false); 247 return cb; 248 } 249 250}