001package jmri.jmrit.throttle; 002 003import java.util.*; 004 005import javax.annotation.CheckForNull; 006import javax.swing.JFrame; 007 008import jmri.DccLocoAddress; 009import jmri.InstanceManagerAutoDefault; 010import jmri.util.JmriJFrame; 011 012import org.jdom2.Element; 013 014/** 015 * Interface for allocating and deallocating throttles frames. Not to be 016 * confused with ThrottleManager. 017 * 018 * @author Glen Oberhauser 019 */ 020public class ThrottleFrameManager implements InstanceManagerAutoDefault, ThrottleControllersUIContainersManager { 021 022 private int activeFrame; 023 private int frameCounterID = 0; // to generate unique names for each card 024 025 private ArrayList<ThrottleControllersUIContainer> throttleWindows; // synchronized access 026 027 private ThrottlesPreferencesWindow throttlePreferencesFrame; 028 private JmriJFrame throttlesListFrame; 029 private ThrottlesListPanel throttlesListPanel; 030 031 /** 032 * Constructor for the ThrottleFrameManager object. 033 */ 034 public ThrottleFrameManager() { 035 throttleWindows = new ArrayList<>(0); 036 } 037 038 /** 039 * Tell this manager that a new ThrottleWindow was created. 040 * 041 * @return The newly created ThrottleWindow 042 */ 043 public ThrottleWindow createThrottleWindow() { 044 return createThrottleWindow((jmri.jmrix.ConnectionConfig) null); 045 } 046 047 /** 048 * Tell this manager that a new ThrottleWindow was created. 049 * 050 * @param connectionConfig the connection config 051 * @return The newly created ThrottleWindow 052 */ 053 public ThrottleWindow createThrottleWindow(jmri.jmrix.ConnectionConfig connectionConfig) { 054 ThrottleWindow tw = new ThrottleWindow(connectionConfig); 055 tw.pack(); 056 synchronized (this) { 057 throttleWindows.add(tw); 058 activeFrame = throttleWindows.indexOf(tw); 059 } 060 getThrottlesListPanel().getTableModel().fireTableStructureChanged(); 061 return tw; 062 } 063 064 /** 065 * Tell this manager that a new ThrottleWindow was created. 066 * 067 * @param e the xml element for the throttle window 068 * @return The newly created ThrottleWindow 069 */ 070 public ThrottleWindow createThrottleWindow(Element e) { 071 ThrottleWindow tw = ThrottleWindow.createThrottleWindow(e); 072 tw.pack(); 073 synchronized (this) { 074 throttleWindows.add(tw); 075 activeFrame = throttleWindows.indexOf(tw); 076 } 077 getThrottlesListPanel().getTableModel().fireTableStructureChanged(); 078 return tw; 079 } 080 081 /** 082 * Tell this manager that a new ThrottleFrame was created. 083 * 084 * @return The newly created ThrottleFrame 085 */ 086 public ThrottleFrame createThrottleFrame() { 087 return createThrottleFrame(null); 088 } 089 090 @Override 091 public ThrottleControllerUI createThrottleController() { 092 return createThrottleFrame(); 093 } 094 095 /** 096 * Tell this manager that a new ThrottleFrame was created. 097 * 098 * @param connectionConfig the connection config 099 * @return The newly created ThrottleFrame 100 */ 101 public ThrottleFrame createThrottleFrame(jmri.jmrix.ConnectionConfig connectionConfig) { 102 return createThrottleWindow(connectionConfig).getCurrentThrottleFrame(); 103 } 104 105 /** 106 * Request that this manager destroy a throttle frame. 107 * 108 * @param frame The to-be-destroyed ThrottleFrame 109 */ 110 public void requestThrottleWindowDestruction(ThrottleWindow frame) { 111 if (frame != null) { 112 destroyThrottleWindow(frame); 113 synchronized (this) { 114 throttleWindows.remove(frame); 115 if (!throttleWindows.isEmpty()) { 116 requestFocusForNextThrottleWindow(); 117 } 118 } 119 } 120 getThrottlesListPanel().getTableModel().fireTableStructureChanged(); 121 } 122 123 public synchronized void requestAllThrottleWindowsDestroyed() { 124 for (ThrottleControllersUIContainer frame : throttleWindows) { 125 destroyThrottleWindow((ThrottleWindow)frame); 126 } 127 throttleWindows = new ArrayList<>(0); 128 getThrottlesListPanel().getTableModel().fireTableStructureChanged(); 129 } 130 131 public int generateUniqueFrameID() { 132 return frameCounterID++; 133 } 134 135 /** 136 * Perform the destruction of a ThrottleFrame. This method will not affect 137 * the throttleFrames list, thus ensuring no synchronozation problems. 138 * 139 * @param window The ThrottleFrame to be destroyed. 140 */ 141 private void destroyThrottleWindow(ThrottleWindow window) { 142 throttleWindows.remove(window); 143 window.dispose(); 144 getThrottlesListPanel().getTableModel().fireTableStructureChanged(); 145 } 146 147 @Override 148 public Iterator<ThrottleControllersUIContainer> iterator() { 149 return throttleWindows.iterator(); 150 } 151 152 /** 153 * Return the number of active thottle windows. 154 * 155 * @return the number of active thottle window. 156 */ 157 @Override 158 public synchronized int getNbThrottleControllersContainers() { 159 return throttleWindows.size(); 160 } 161 162 @Override 163 public synchronized ThrottleControllersUIContainer getThrottleControllersContainerAt(int n) { 164 if (! (n < throttleWindows.size())) { 165 return null; 166 } 167 return throttleWindows.get(n); 168 } 169 170 public synchronized void requestFocusForNextThrottleWindow() { 171 activeFrame = (activeFrame + 1) % throttleWindows.size(); 172 ThrottleWindow tw = (ThrottleWindow) throttleWindows.get(activeFrame); 173 tw.requestFocus(); 174 tw.toFront(); 175 } 176 177 public synchronized void requestFocusForPreviousThrottleWindow() { 178 activeFrame--; 179 if (activeFrame < 0) { 180 activeFrame = throttleWindows.size() - 1; 181 } 182 ThrottleWindow tw =(ThrottleWindow) throttleWindows.get(activeFrame); 183 tw.requestFocus(); 184 tw.toFront(); 185 } 186 187 public synchronized ThrottleWindow getCurrentThrottleFrame() { 188 if (throttleWindows == null) { 189 return null; 190 } 191 if (throttleWindows.isEmpty()) { 192 return null; 193 } 194 return (ThrottleWindow) throttleWindows.get(activeFrame); 195 } 196 197 public ThrottlesListPanel getThrottlesListPanel() { 198 if (throttlesListPanel == null) { 199 throttlesListPanel = new ThrottlesListPanel(); 200 } 201 return throttlesListPanel; 202 } 203 204 /* 205 * Show JMRI native throttle list window 206 * 207 */ 208 public void showThrottlesList() { 209 if (throttlesListFrame == null) { 210 throttlesListFrame = new JmriJFrame(Bundle.getMessage("ThrottleListFrameTile")); 211 throttlesListFrame.setContentPane(getThrottlesListPanel()); 212 throttlesListFrame.pack(); 213 } 214 throttlesListFrame.setVisible(true); 215 } 216 217 /* 218 * Show throttle preferences window 219 * 220 */ 221 public void showThrottlesPreferences() { 222 if (throttlePreferencesFrame == null) { 223 throttlePreferencesFrame = new ThrottlesPreferencesWindow(Bundle.getMessage("ThrottlePreferencesFrameTitle")); 224 throttlePreferencesFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 225 throttlePreferencesFrame.pack(); 226 } else { 227 throttlePreferencesFrame.resetComponents(); 228 throttlePreferencesFrame.revalidate(); 229 } 230 throttlePreferencesFrame.setVisible(true); 231 throttlePreferencesFrame.requestFocus(); 232 } 233 234 /* 235 * Apply curent throttle preferences to all throttle windows 236 * 237 */ 238 public void applyPreferences() { 239 throttleWindows.forEach(tw -> { 240 ((ThrottleWindow)tw).applyPreferences(); 241 }); 242 getThrottlesListPanel().applyPreferences(); 243 } 244 245 /** 246 * Force emergency stop of all managed throttles windows 247 * 248 */ 249 public void emergencyStopAll() { 250 throttleWindows.forEach(tw -> { 251 tw.emergencyStopAll(); 252 }); 253 } 254 255 /** 256 * Get the number of usages of a particular Loco Address. 257 * @param la the Loco Address, can be null. 258 * @return 0 if no usages, else number of AddressPanel usages. 259 */ 260 @Override 261 public int getNumberOfEntriesFor(@CheckForNull DccLocoAddress la) { 262 if (la == null) { 263 return 0; 264 } 265 int ret = 0; 266 for (ThrottleControllersUIContainer tw : throttleWindows) { 267 ret += tw.getNumberOfEntriesFor(la); 268 } 269 return ret; 270 } 271 272 // private final static Logger log = LoggerFactory.getLogger(ThrottleFrameManager.class); 273}