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