001package jmri.beans; 002 003import java.beans.PropertyChangeEvent; 004import javax.annotation.Nonnull; 005import jmri.profile.Profile; 006 007/** 008 * Bean that implements some common code for preferences objects. 009 * 010 * @author Randall Wood (C) 2017, 2020 011 */ 012public abstract class PreferencesBean extends Bean { 013 014 /** 015 * Property indicating preferences item do/do not need to be saved. 016 * 017 * {@value #DIRTY} 018 */ 019 public static final String DIRTY = "dirty"; // NOI18N 020 /** 021 * Property indicating preferences item requires restart to be applied. 022 * 023 * {@value #RESTART_REQUIRED} 024 */ 025 public static final String RESTART_REQUIRED = "restartRequired"; // NOI18N 026 private boolean restartRequired = false; 027 private boolean isDirty = false; 028 private final Profile profile; 029 030 /** 031 * Create the PreferencesBean. 032 * 033 * @param profile the Profile this PreferencesBean is associated with; if 034 * null is not associated with a Profile, but applies application wide 035 */ 036 public PreferencesBean(Profile profile) { 037 super(false); 038 this.profile = profile; 039 } 040 041 /** 042 * Get the profile associated with this PreferencesBean. 043 * 044 * @return the profile 045 */ 046 @Nonnull 047 public Profile getProfile() { 048 return this.profile; 049 } 050 051 /** 052 * Check if this preferences bean has a state that needs to be saved. 053 * 054 * @return true if unsaved; false otherwise 055 */ 056 public boolean isDirty() { 057 return this.isDirty; 058 } 059 060 /** 061 * Check if this preferences bean requires the application to be restarted 062 * to take effect. 063 * 064 * @return true if a restart is required; false otherwise 065 */ 066 public boolean isRestartRequired() { 067 return this.restartRequired; 068 } 069 070 /** 071 * Set if restart needs to be required for some preferences to take effect. 072 */ 073 protected void setRestartRequired() { 074 if (!this.restartRequired) { 075 this.restartRequired = true; 076 this.firePropertyChange(RESTART_REQUIRED, false, true); 077 } 078 } 079 080 /** 081 * Set if preferences need to be saved. 082 * 083 * @param value true to indicate need to save; false otherwise 084 */ 085 protected void setIsDirty(boolean value) { 086 boolean old = this.isDirty; 087 this.isDirty = value; 088 this.firePropertyChange(DIRTY, old, value); 089 } 090 091 /** 092 * {@inheritDoc} 093 * <p> 094 * As a side effect, calls to {@link #isDirty} will return {@code true} if 095 * oldValue and newValue differ or are null. 096 */ 097 @Override 098 public void firePropertyChange(String propertyName, Object oldValue, Object newValue) { 099 if (oldValue == null || newValue == null || !oldValue.equals(newValue)) { 100 this.propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue); 101 this.setIsDirty(true); 102 } 103 } 104 105 /** 106 * {@inheritDoc} 107 * <p> 108 * As a side effect, calls to {@link #isDirty} will return {@code true} if 109 * oldValue and newValue differ and propertyName is not {@value #DIRTY}. 110 */ 111 @Override 112 public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) { 113 if (oldValue != newValue) { 114 this.propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue); 115 // don't force dirty to true if we just changed dirty 116 if (!DIRTY.equals(propertyName)) { 117 this.setIsDirty(true); 118 } 119 } 120 } 121 122 /** 123 * {@inheritDoc} 124 * <p> 125 * As a side effect, calls to {@link #isDirty} will return {@code true} if 126 * oldValue and newValue differ. 127 */ 128 @Override 129 public void firePropertyChange(String propertyName, int oldValue, int newValue) { 130 if (oldValue != newValue) { 131 this.propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue); 132 this.setIsDirty(true); 133 } 134 } 135 136 /** 137 * {@inheritDoc} 138 * <p> 139 * As a side effect, calls to {@link #isDirty} will return {@code true}. To 140 * avoid that side effect, call 141 * {@link PropertyChangeSupport#firePropertyChange(java.beans.PropertyChangeEvent)} 142 * on {@link #propertyChangeSupport} directly. 143 */ 144 @Override 145 public void firePropertyChange(PropertyChangeEvent evt) { 146 this.propertyChangeSupport.firePropertyChange(evt); 147 if (!DIRTY.equals(evt.getPropertyName())) { 148 this.setIsDirty(true); 149 } 150 } 151}