summaryrefslogblamecommitdiffstats
path: root/dozentenmodul/src/main/java/org/openslx/dozmod/gui/changemonitor/AbstractControlWrapper.java
blob: 9b475bcbcc97d78c68631f01200d9188ce951a2b (plain) (tree)
1
2
3
4
5
6
7
8
9

                                             
                           
                            
                            
                      
                     

                                                                                     







                                                 
                                  
                                                          
                                        
                                             





                                                                             
                                                                                       
                               
                                










                                              

















                                                                                            










                                                                             
        





































                                                                                 











                                                                                                                     
                        
                                                   








                                                                                
                                                                          
                               





                                                               

                                                                                                      
                                             


                                                  
 
 
package org.openslx.dozmod.gui.changemonitor;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

import org.openslx.dozmod.gui.changemonitor.DialogChangeMonitor.ValidationConstraint;

/**
 * Control/element wrapper
 */
public abstract class AbstractControlWrapper<T> {
	private final DialogChangeMonitor dcm;
	protected boolean wasEverChanged;
	protected boolean isCurrentlyChanged;
	private T originalContent;
	private List<ValidationConstraint<T>> constraints;
	private final Comparator<T> cmp;
	protected String currentError = null;
	/**
	 * If muted, this wrapper will not react to changes of the underlying
	 * control.
	 */
	private boolean muted = false;

	protected AbstractControlWrapper(DialogChangeMonitor dcm, Comparator<T> comp) {
		this.dcm = dcm;
		this.cmp = comp;
	}

	public boolean hasChangedSinceInit() {
		return wasEverChanged;
	}

	public boolean isCurrentlyChanged() {
		return isCurrentlyChanged;
	}

	/**
	 * Returns the current error message for the first failed constraint. If no
	 * constraint currently yields invalid, null is returned.
	 * 
	 * @return
	 */
	public String currentConstraintError() {
		return currentError;
	}
	
	public AbstractControlWrapper<T> addConstraint(ValidationConstraint<T> constraint) {
		if (constraints == null) {
			constraints = new ArrayList<>();
		}
		constraints.add(constraint);
		return this;
	}

	/**
	 * Resets the change state of this control
	 * and removes the "muted" flag, if set.
	 */
	public void reset() {
		boolean wasChanged = wasEverChanged;
		resetChangeState();
		if (wasChanged) {
			// It's possible that the global change state changed
			dcm.contentChanged(this);
		}
	}
	
	protected final void resetChangeState() {
		muted = false;
		isCurrentlyChanged = wasEverChanged = false;
		originalContent = getCurrentValue();
		checkValid(originalContent);
	}

	/**
	 * To be called by the implementation whenever the content of the control
	 * changed and according checks should be triggered.
	 */
	protected final void contentChanged() {
		T text = getCurrentValue();
		checkChanged(text);
		checkValid(text);
	}

	/**
	 * Ignore any changes, don't trigger callbacks regarding
	 * this component. This flag can be removed by calling
	 * reset() on this ControlWrapper or the enclosing
	 * DialogChangeMonitor.
	 */
	public void mute() {
		muted = true;
	}

	/**
	 * Method MUST return the current value of the monitored component, so
	 * that the current state can be considered as the original unmodified
	 * state.
	 */
	abstract T getCurrentValue();

	protected void checkChanged(T newContent) {
		if (muted)
			return;
		final boolean changed;
		if (newContent == originalContent) {
			changed = false; // This also covers null == null
		} else if (newContent == null || originalContent == null) {
			changed = true; // So here we know either/or is null, not both
		} else if (newContent instanceof Collection
				&& ((Collection<?>) newContent).size() != ((Collection<?>) originalContent).size()) {
			changed = true;
		} else if (newContent instanceof Map
				&& ((Map<?, ?>) newContent).size() != ((Map<?, ?>) originalContent).size()) {
			changed = true;
		} else if (cmp == null) {
			changed = !originalContent.equals(newContent);
		} else {
			// User supplied comparator
			changed = cmp.compare(originalContent, newContent) != 0;
		}
		if (isCurrentlyChanged != changed) {
			isCurrentlyChanged = changed;
			dcm.contentChanged(this);
		}
	}

	protected void checkValid(T text) {
		if (muted || constraints == null || constraints.isEmpty())
			return;
		String error = null;
		for (ValidationConstraint<T> i : constraints) {
			error = i.checkStateValid(text);
			if (error != null)
				break;
		}
		if ((error == null && currentError != null) || (error != null && currentError == null)
				|| (error != null && !error.equals(currentError))) {
			currentError = error;
			dcm.validityChanged(this);
		}
	}

}