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 public String getScaleName() { 055 return _name; 056 } 057 058 public String getUserName() { 059 return _userName; 060 } 061 062 public double getScaleRatio() { 063 return _ratio; 064 } 065 066 public double getScaleFactor() { 067 return _factor; 068 } 069 070 /** 071 * Set the user name for the current scale. 072 * Registered listeners can veto the change. 073 * @param newName The name to be applied if unique. 074 * @throws IllegalArgumentException The supplied name is a duplicate. 075 * @throws PropertyVetoException The user name change was vetoed. 076 */ 077 public void setUserName(@Nonnull String newName) throws IllegalArgumentException, PropertyVetoException { 078 for (Scale scale : ScaleManager.getScales()) { 079 if (scale.getUserName().equals(newName)) { 080 if (!scale.getScaleName().equals(_name)) { 081 throw new IllegalArgumentException("Duplicate scale user name"); // NOI18N 082 } 083 } 084 } 085 086 String oldName = _userName; 087 _userName = newName; 088 089 try { 090 fireVetoableChange("ScaleUserName", oldName, newName); // NOI18N 091 } catch (PropertyVetoException ex) { 092 // Roll back change 093 log.warn("The user name change for {} scale to {} was rejected: Reason: {}", // NOI18N 094 _name, _userName, ex.getMessage()); 095 _userName = oldName; 096 throw ex; // Notify caller 097 } 098 jmri.configurexml.ScaleConfigXML.doStore(); 099 } 100 101 /** 102 * Set the new scale ratio and calculate the scale factor. 103 * Registered listeners can veto the change. 104 * @param newRatio A double value containing the ratio. 105 * @throws IllegalArgumentException The new ratio is less than 1. 106 * @throws PropertyVetoException The ratio change was vetoed. 107 */ 108 public void setScaleRatio(double newRatio) throws IllegalArgumentException, PropertyVetoException { 109 if (newRatio < 1.0) { 110 throw new IllegalArgumentException("The scale ratio is less than 1"); // NOI18N 111 } 112 113 double oldRatio = _ratio; 114 _ratio = newRatio; 115 _factor = 1.0 / _ratio; 116 117 try { 118 fireVetoableChange("ScaleRatio", oldRatio, newRatio); // NOI18N 119 } catch (PropertyVetoException ex) { 120 // Roll back change 121 log.warn("The ratio change for {} scale to {} was rejected: Reason: {}", // NOI18N 122 _name, _ratio, ex.getMessage()); 123 _ratio = oldRatio; 124 _factor = 1.0 / oldRatio; 125 throw ex; // Notify caller 126 } 127 jmri.configurexml.ScaleConfigXML.doStore(); 128 } 129 130 @Override 131 public String toString() { 132 return String.format("%s (%.1f)", getUserName(), getScaleRatio()); 133 } 134 135 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(Scale.class); 136 137}