001package jmri; 002 003import java.beans.PropertyVetoException; 004import javax.annotation.Nonnull; 005import jmri.beans.ConstrainedBean; 006 007/** 008 * Define the characteristics of a layout scale. A scale has four properties. 009 * <ul> 010 * <li>Name - A fixed string, such N or HO. 011 * <li>User name - An alternate name that can be changed. It defaults to the scale name. 012 * <li>Ratio - The ratio for the scale, such as 160 for N scale. 013 * <li>Factor - A derived value created by dividing 1 by the scale ratio. 014 * </ul> 015 * In addition to the standard scales, there is custom entry. Custom settings 016 * are retained in a local copy of ScaleData.xml. 017 * <p> 018 * Methods are provided to set/get the user name and the scale ratio. The scale 019 * factor is generated from the scale ratio and is read only, as is the scale name. 020 * <p> 021 * While changing the ratio and user names of the standard scales is not 022 * prohibited, doing so is not recommended due to potential conflicts with other 023 * applications. 024 * <p> 025 * Changes to user names and ratios send a <strong>vetoableChange</strong> event. 026 * Interested applications can add a <strong>vetoableChange</strong> listener 027 * in order to be notified when an event occurs. If the listener determines that 028 * the change cannot occur, it can throw a <strong>PropertyVetoException</strong>. 029 * <p> 030 * See {@link jmri.ScaleManager Scale Manager} for manager details. 031 * 032 * @author Dave Sand Copyright (C) 2018 033 * @since 4.13.6 034 */ 035public class Scale extends ConstrainedBean { 036 037 public Scale() { 038 super(); 039 } 040 041 public Scale(@Nonnull String name, double ratio, String userName) { 042 super(); 043 _name = name; 044 _userName = (userName == null) ? name : userName; 045 _ratio = ratio; 046 _factor = 1.0 / _ratio; 047 } 048 049 private String _name = "HO"; // NOI18N 050 private String _userName = "HO"; // NOI18N 051 private double _ratio = 87.1; 052 private double _factor = 1 / 87.1; 053 054 /** 055 * Get the Name of the Scale. 056 * @return the Scale name. 057 */ 058 public String getScaleName() { 059 return _name; 060 } 061 062 /** 063 * Get the UserName of the Scale. 064 * @return the UserName. 065 */ 066 public String getUserName() { 067 return _userName; 068 } 069 070 /** 071 * Get the Scale Ratio. 072 * @return e.g. 87.1 073 */ 074 public double getScaleRatio() { 075 return _ratio; 076 } 077 078 /** 079 * Get the Scale Factor 080 * @return e.g. 1 divided by 87.1 081 */ 082 public double getScaleFactor() { 083 return _factor; 084 } 085 086 /** 087 * Set the user name for the current scale. 088 * Registered listeners can veto the change. 089 * @param newName The name to be applied if unique. 090 * @throws IllegalArgumentException The supplied name is a duplicate. 091 * @throws PropertyVetoException The user name change was vetoed. 092 */ 093 public void setUserName(@Nonnull String newName) throws IllegalArgumentException, PropertyVetoException { 094 for (Scale scale : ScaleManager.getScales()) { 095 if ( scale.getUserName().equals(newName) 096 && !scale.getScaleName().equals(_name)) { 097 throw new IllegalArgumentException("Duplicate scale user name: " + newName); 098 } 099 } 100 101 String oldName = _userName; 102 _userName = newName; 103 104 try { 105 fireVetoableChange("ScaleUserName", oldName, newName); // NOI18N 106 } catch (PropertyVetoException ex) { 107 // Roll back change 108 log.warn("The user name change for {} scale to {} was rejected: Reason: {}", // NOI18N 109 _name, _userName, ex.getMessage()); 110 _userName = oldName; 111 throw ex; // Notify caller 112 } 113 jmri.configurexml.ScaleConfigXML.doStore(); 114 } 115 116 /** 117 * Set the new scale ratio and calculate the scale factor. 118 * Registered listeners can veto the change. 119 * @param newRatio A double value containing the ratio. 120 * @throws IllegalArgumentException The new ratio is less than 1. 121 * @throws PropertyVetoException The ratio change was vetoed. 122 */ 123 public void setScaleRatio(double newRatio) throws IllegalArgumentException, PropertyVetoException { 124 if (newRatio < 1.0) { 125 throw new IllegalArgumentException("The scale ratio is less than 1"); // NOI18N 126 } 127 128 double oldRatio = _ratio; 129 _ratio = newRatio; 130 _factor = 1.0 / _ratio; 131 132 try { 133 fireVetoableChange("ScaleRatio", oldRatio, newRatio); // NOI18N 134 } catch (PropertyVetoException ex) { 135 // Roll back change 136 log.warn("The ratio change for {} scale to {} was rejected: Reason: {}", // NOI18N 137 _name, _ratio, ex.getMessage()); 138 _ratio = oldRatio; 139 _factor = 1.0 / oldRatio; 140 throw ex; // Notify caller 141 } 142 jmri.configurexml.ScaleConfigXML.doStore(); 143 } 144 145 @Override 146 public String toString() { 147 return String.format("%s (%.1f)", getUserName(), getScaleRatio()); 148 } 149 150 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(Scale.class); 151 152}