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