001package jmri.jmrit.throttle; 002 003import java.awt.Dimension; 004import java.beans.PropertyChangeEvent; 005import java.beans.PropertyChangeListener; 006import java.io.File; 007import java.util.ArrayList; 008 009import jmri.jmrit.XmlFile; 010import jmri.util.FileUtil; 011 012import org.jdom2.Document; 013import org.jdom2.Element; 014import org.slf4j.Logger; 015import org.slf4j.LoggerFactory; 016 017/** 018 * A class to store JMRI throttles preferences. 019 * <p> 020 * A singleton instance is provided by a call to 021 * <code>jmri.InstanceManager.getDefault(ThrottlesPreferences.class);</code> or 022 * <code>jmri.InstanceManager.getNullableDefault(ThrottlesPreferences.class)</code>; 023 * @author Lionel Jeanson - 2009-2021 024 * 025 */ 026public class ThrottlesPreferences implements jmri.InstanceManagerAutoDefault { 027 028 private boolean _useExThrottle = true; 029 private boolean _useToolBar = true; 030 private boolean _useFunctionIcon = true; 031 private boolean _useLargeSpeedSlider = true; 032 private boolean _resizeWinImg = false; 033 private boolean _useRosterImage = true; 034 private boolean _enableRosterSearch = true; 035 private boolean _enableAutoLoad = true; 036 private boolean _hideUndefinedFunButton = false; 037 private boolean _ignoreThrottlePosition = true; 038 private boolean _saveThrottleOnLayoutSave = true; 039 private boolean _isSilentSteal = false; 040 private boolean _isSilentShare = false; 041 private String _defaultThrottleFilePath = null; 042 private ThrottlesPreferencesWindowKeyboardControls _tpwkc = new ThrottlesPreferencesWindowKeyboardControls(); 043 protected boolean dirty = false; 044 045 private Dimension _winDim = new Dimension(800, 600); 046 private String prefFile; 047 private ArrayList<PropertyChangeListener> listeners; 048 049 public ThrottlesPreferences() { 050 String dirname = FileUtil.getUserFilesPath() + "throttle" + File.separator; 051 FileUtil.createDirectory(dirname); 052 prefFile = dirname + "ThrottlesPreferences.xml"; 053 ThrottlesPrefsXml prefs = new ThrottlesPrefsXml(); 054 File file = new File(prefFile); 055 Element root; 056 try { 057 root = prefs.rootFromFile(file); 058 } catch (java.io.FileNotFoundException e2) { 059 log.info("Did not find throttle preferences file. This is normal if you haven't save the preferences before"); 060 root = null; 061 } catch (Exception e) { 062 log.error("Exception while loading throttles preferences", e); 063 root = null; 064 } 065 if (root != null) { 066 load(root.getChild("throttlesPreferences")); 067 } 068 } 069 070 public void load(org.jdom2.Element e) { 071 if (e == null) { 072 return; 073 } 074 org.jdom2.Attribute a; 075 org.jdom2.Attribute b; 076 if ((a = e.getAttribute("isUsingExThrottle")) != null) { 077 setUseExThrottle(a.getValue().compareTo("true") == 0); 078 } 079 if ((a = e.getAttribute("isUsingToolBar")) != null) { 080 setUsingToolBar(a.getValue().compareTo("true") == 0); 081 } 082 if ((a = e.getAttribute("isResizingWindow")) != null) { 083 setResizeWindow(a.getValue().compareTo("true") == 0); 084 } 085 if ((a = e.getAttribute("isUsingFunctionIcon")) != null) { 086 setUsingFunctionIcon(a.getValue().compareTo("true") == 0); 087 } 088 if (((a = e.getAttribute("windowDimensionWidth")) != null) && ((b = e.getAttribute("windowDimensionHeight")) != null)) { 089 setWindowDimension(new Dimension(Integer.parseInt(a.getValue()), Integer.parseInt(b.getValue()))); 090 } 091 if ((a = e.getAttribute("isSavingThrottleOnLayoutSave")) != null) { 092 setSaveThrottleOnLayoutSave(a.getValue().compareTo("true") == 0); 093 } 094 if ((a = e.getAttribute("isUsingRosterImage")) != null) { 095 setUseRosterImage(a.getValue().compareTo("true") == 0); 096 } 097 if ((a = e.getAttribute("isEnablingRosterSearch")) != null) { 098 setEnableRosterSearch(a.getValue().compareTo("true") == 0); 099 } 100 if ((a = e.getAttribute("isAutoLoading")) != null) { 101 setAutoLoad(a.getValue().compareTo("true") == 0); 102 } 103 if ((a = e.getAttribute("isHidingUndefinedFunctionButtons")) != null) { 104 setHideUndefinedFuncButt(a.getValue().compareTo("true") == 0); 105 } 106 if ((a = e.getAttribute("isIgnoringThrottlePosition")) != null) { 107 setIgnoreThrottlePosition(a.getValue().compareTo("true") == 0); 108 } 109 if ((a = e.getAttribute("isSilentSteal")) != null) { 110 setSilentSteal(a.getValue().compareTo("true") == 0); 111 } 112 if ((a = e.getAttribute("isSilentShare")) != null) { 113 setSilentShare(a.getValue().compareTo("true") == 0); 114 } 115 if ((a = e.getAttribute("isUsingLargeSpeedSlider")) != null) { 116 setUseLargeSpeedSlider(a.getValue().compareTo("true") == 0); 117 } 118 if (e.getChild("throttlesControls") != null) { 119 this._tpwkc.load(e.getChild("throttlesControls")); 120 } 121 if ((a = e.getAttribute("defaultThrottleFilePath")) != null) { 122 setDefaultThrottleFilePath(a.getValue()); 123 } 124 125 this.dirty = false; 126 } 127 128 /** 129 * @return true if preferences need to be saved 130 */ 131 public boolean isDirty() { 132 return dirty; 133 } 134 135 /** 136 * An extension of the abstract XmlFile. No changes made to that class. 137 * 138 */ 139 static class ThrottlesPrefsXml extends XmlFile { 140 } 141 142 public Element store() { 143 org.jdom2.Element e = new org.jdom2.Element("throttlesPreferences"); 144 e.setAttribute("isUsingExThrottle", "" + isUsingExThrottle()); 145 e.setAttribute("isUsingToolBar", "" + isUsingToolBar()); 146 e.setAttribute("isUsingFunctionIcon", "" + isUsingFunctionIcon()); 147 e.setAttribute("isResizingWindow", "" + isResizingWindow()); 148 e.setAttribute("windowDimensionWidth", "" + (int) getWindowDimension().getWidth()); 149 e.setAttribute("windowDimensionHeight", "" + (int) getWindowDimension().getHeight()); 150 e.setAttribute("isSavingThrottleOnLayoutSave", "" + isSavingThrottleOnLayoutSave()); 151 e.setAttribute("isUsingRosterImage", "" + isUsingRosterImage()); 152 e.setAttribute("isEnablingRosterSearch", "" + isEnablingRosterSearch()); 153 e.setAttribute("isAutoLoading", "" + isAutoLoading()); 154 e.setAttribute("isHidingUndefinedFunctionButtons", "" + isHidingUndefinedFuncButt()); 155 e.setAttribute("isIgnoringThrottlePosition", "" + isIgnoringThrottlePosition()); 156 e.setAttribute("isSilentSteal", "" + isSilentSteal()); 157 e.setAttribute("isSilentShare", "" + isSilentShare()); 158 e.setAttribute("isUsingLargeSpeedSlider", "" + isUsingLargeSpeedSlider()); 159 e.setAttribute("defaultThrottleFilePath", "" + getDefaultThrottleFilePath()); 160 java.util.ArrayList<Element> children = new java.util.ArrayList<>(1); 161 children.add(this._tpwkc.store()); 162 e.setContent(children); 163 return e; 164 } 165 166 public void set(ThrottlesPreferences tp) { 167 setWindowDimension(tp.getWindowDimension()); 168 setUseExThrottle(tp.isUsingExThrottle()); 169 setUsingToolBar(tp.isUsingToolBar()); 170 setUsingFunctionIcon(tp.isUsingFunctionIcon()); 171 setResizeWindow(tp.isResizingWindow()); 172 setSaveThrottleOnLayoutSave(tp.isSavingThrottleOnLayoutSave()); 173 setUseRosterImage(tp.isUsingRosterImage()); 174 setEnableRosterSearch(tp.isEnablingRosterSearch()); 175 setAutoLoad(tp.isAutoLoading()); 176 setHideUndefinedFuncButt(tp.isHidingUndefinedFuncButt()); 177 setIgnoreThrottlePosition(tp.isIgnoringThrottlePosition()); 178 setSilentSteal(tp.isSilentSteal()); 179 setSilentShare(tp.isSilentShare()); 180 setUseLargeSpeedSlider(tp.isUsingLargeSpeedSlider()); 181 setThrottlesKeyboardControls(tp.getThrottlesKeyboardControls()); 182 setDefaultThrottleFilePath(tp.getDefaultThrottleFilePath()); 183 184 if (listeners != null) { 185 for (int i = 0; i < listeners.size(); i++) { 186 PropertyChangeListener l = listeners.get(i); 187 PropertyChangeEvent e = new PropertyChangeEvent(this, "ThrottlePreferences", null, this); 188 l.propertyChange(e); 189 } 190 } 191 } 192 193 public void save() { 194 if (prefFile == null) { 195 return; 196 } 197 XmlFile xf = new XmlFile() { 198 }; // odd syntax is due to XmlFile being abstract 199 xf.makeBackupFile(prefFile); 200 File file = new File(prefFile); 201 try { 202 //The file does not exist, create it before writing 203 File parentDir = file.getParentFile(); 204 if (!parentDir.exists()) { 205 if (!parentDir.mkdir()) // make directory, check result 206 { 207 log.error("failed to make parent directory"); 208 } 209 } 210 if (!file.createNewFile()) // create file, check result 211 { 212 log.error("createNewFile failed"); 213 } 214 } catch (Exception exp) { 215 log.error("Exception while writing the new throttles preferences file, may not be complete", exp); 216 } 217 218 try { 219 Element root = new Element("throttles-preferences"); 220 Document doc = XmlFile.newDocument(root, XmlFile.getDefaultDtdLocation() + "throttles-preferences.dtd"); 221 // add XSLT processing instruction 222 // <?xml-stylesheet type="text/xsl" href="XSLT/throttle.xsl"?> 223/*TODO java.util.Map<String,String> m = new java.util.HashMap<String,String>(); 224 m.put("type", "text/xsl"); 225 m.put("href", jmri.jmrit.XmlFile.xsltLocation+"throttles-preferences.xsl"); 226 ProcessingInstruction p = new ProcessingInstruction("xml-stylesheet", m); 227 doc.addContent(0,p);*/ 228 root.setContent(store()); 229 xf.writeXML(file, doc); 230 } catch (java.io.IOException ex) { 231 log.warn("Exception in storing throttles preferences xml", ex); 232 } 233 this.dirty = false; 234 } 235 236 public Dimension getWindowDimension() { 237 return _winDim; 238 } 239 240 public void setWindowDimension(Dimension d) { 241 _winDim = d; 242 this.dirty = true; 243 } 244 245 public boolean isUsingExThrottle() { 246 return _useExThrottle; 247 } 248 249 public void setUseExThrottle(boolean exThrottle) { 250 _useExThrottle = exThrottle; 251 this.dirty = true; 252 } 253 254 public boolean isUsingToolBar() { 255 return _useToolBar; 256 } 257 258 public void setUsingToolBar(boolean win4all) { 259 _useToolBar = win4all; 260 this.dirty = true; 261 } 262 263 /** 264 * Check if function icons are in use. 265 * 266 * @return user preference to use function icons. 267 */ 268 public boolean isUsingFunctionIcon() { 269 return _useFunctionIcon; 270 } 271 272 public void setUsingFunctionIcon(boolean useFunctionIcon) { 273 _useFunctionIcon = useFunctionIcon; 274 this.dirty = true; 275 } 276 277 public boolean isResizingWindow() { 278 return _resizeWinImg; 279 } 280 281 public void setResizeWindow(boolean winImg) { 282 _resizeWinImg = winImg; 283 this.dirty = true; 284 } 285 286 public boolean isUsingRosterImage() { 287 return _useRosterImage; 288 } 289 290 public void setUseRosterImage(boolean rosterImage) { 291 _useRosterImage = rosterImage; 292 this.dirty = true; 293 } 294 295 public boolean isEnablingRosterSearch() { 296 return _enableRosterSearch; 297 } 298 299 public void setEnableRosterSearch(boolean b) { 300 _enableRosterSearch = b; 301 this.dirty = true; 302 } 303 304 public void setAutoLoad(boolean b) { 305 _enableAutoLoad = b; 306 this.dirty = true; 307 } 308 309 public boolean isAutoLoading() { 310 return _enableAutoLoad; 311 } 312 313 public void setHideUndefinedFuncButt(boolean b) { 314 _hideUndefinedFunButton = b; 315 this.dirty = true; 316 } 317 318 public boolean isHidingUndefinedFuncButt() { 319 return _hideUndefinedFunButton; 320 } 321 322 public void setIgnoreThrottlePosition(boolean b) { 323 _ignoreThrottlePosition = b; 324 this.dirty = true; 325 } 326 327 public boolean isIgnoringThrottlePosition() { 328 return _ignoreThrottlePosition; 329 } 330 331 public void setSaveThrottleOnLayoutSave(boolean b) { 332 _saveThrottleOnLayoutSave = b; 333 this.dirty = true; 334 } 335 336 public boolean isSavingThrottleOnLayoutSave() { 337 return _saveThrottleOnLayoutSave; 338 } 339 340 public boolean isSilentSteal() { 341 return _isSilentSteal; 342 } 343 344 public boolean isSilentShare() { 345 return _isSilentShare; 346 } 347 348 public void setSilentSteal(boolean b) { 349 _isSilentSteal = b; 350 this.dirty = true; 351 } 352 353 public void setSilentShare(boolean b) { 354 _isSilentShare = b; 355 this.dirty = true; 356 } 357 358 359 public void setUseLargeSpeedSlider(boolean b) { 360 _useLargeSpeedSlider = b; 361 this.dirty = true; 362 } 363 364 public boolean isUsingLargeSpeedSlider() { 365 return _useLargeSpeedSlider; 366 } 367 368 public void setDefaultThrottleFilePath(String p) { 369 _defaultThrottleFilePath = p; 370 this.dirty = true; 371 } 372 373 public String getDefaultThrottleFilePath() { 374 return _defaultThrottleFilePath; 375 } 376 377 /** 378 * @return the throttles keyboard controls preferences 379 */ 380 public ThrottlesPreferencesWindowKeyboardControls getThrottlesKeyboardControls() { 381 return _tpwkc; 382 } 383 384 /** 385 * Set the throttles keyboard controls preferences 386 * @param tpwkc the new keyboard preferences 387 */ 388 public void setThrottlesKeyboardControls(ThrottlesPreferencesWindowKeyboardControls tpwkc) { 389 _tpwkc = tpwkc; 390 } 391 392 /** 393 * Add an AddressListener. 394 * AddressListeners are notified when the user 395 * selects a new address and when a Throttle is acquired for that address. 396 * @param l listener to add. 397 * 398 */ 399 public void addPropertyChangeListener(PropertyChangeListener l) { 400 if (listeners == null) { 401 listeners = new ArrayList<>(2); 402 } 403 if (!listeners.contains(l)) { 404 listeners.add(l); 405 } 406 } 407 408 /** 409 * Remove an AddressListener. 410 * @param l listener to remove. 411 */ 412 public void removePropertyChangeListener(PropertyChangeListener l) { 413 if (listeners == null) { 414 return; 415 } 416 listeners.remove(l); 417 } 418 419 private final static Logger log = LoggerFactory.getLogger(ThrottlesPreferences.class); 420}