summaryrefslogblamecommitdiffstats
path: root/dozentenmodul/src/main/java/org/openslx/dozmod/gui/changemonitor/DialogChangeMonitor.java
blob: 4651bdad15e3683ead34fd345e7622ee158fc08d (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

















                                                    



















                                                                                         



                                              
                                                                                   




                                        

                                                                             

         

                                                                                                             

         


                                                                                     

         

                                                                         

         

                                                                                

         

                                                                           

         

                                                                       

         

                                                                     

         

                                                                           

         

                                                                                  


































                                                                        
                                                                                                    
                                                
                                              
                                             
                                                




                                                                      
                                                             
                                                             
                                                               












































                                                                                                            







                                                                                        

         

                                                                
           

                                                                                            
 

                                                                    
                 








                                                                 


















                                                                                     



                             










                                                                 
package org.openslx.dozmod.gui.changemonitor;

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

import javax.swing.ButtonGroup;
import javax.swing.ButtonModel;
import javax.swing.JCheckBox;
import javax.swing.JSpinner;
import javax.swing.JTable;
import javax.swing.text.JTextComponent;
import javax.swing.tree.TreePath;

import org.apache.log4j.Logger;
import org.jdatepicker.JDatePicker;
import org.openslx.dozmod.gui.control.ComboBox;
import org.openslx.dozmod.gui.control.JCheckBoxTree;
import org.openslx.util.Util;

public class DialogChangeMonitor {

	private static final Logger LOGGER = Logger.getLogger(DialogChangeMonitor.class);

	private final Callback callback;

	private final List<AbstractControlWrapper<?>> controls = new ArrayList<>();

	private boolean isCurrentlyModified;

	private boolean wasEverModified;

	private boolean isValid = true;

	public DialogChangeMonitor(Callback cb) {
		this.callback = cb;
	}

	/*
	 * Methods for adding various controls
	 */

	private <T> AbstractControlWrapper<T> add(AbstractControlWrapper<T> elem) {
		controls.add(elem);
		elem.resetChangeState();
		return elem;
	}

	public AbstractControlWrapper<String> add(JTextComponent component) {
		return add(new TextControlWrapper(this, component));
	}

	public <T> AbstractControlWrapper<T> addFixedCombo(ComboBox<T> component, Comparator<T> comparator) {
		return add(new FixedComboBoxWrapper<T>(this, component, comparator));
	}

	public AbstractControlWrapper<Object> addEditableCombo(ComboBox<?> component,
			Comparator<Object> comparator) {
		return add(new EditableComboBoxWrapper(this, component, comparator));
	}

	public AbstractControlWrapper<Boolean> add(JCheckBox component) {
		return add(new CheckBoxWrapper(this, component));
	}

	public AbstractControlWrapper<TreePath[]> add(JCheckBoxTree component) {
		return add(new CheckBoxTreeWrapper(this, component));
	}

	public AbstractControlWrapper<ButtonModel> add(ButtonGroup group) {
		return add(new ButtonGroupWrapper(this, group));
	}

	public AbstractControlWrapper<Object> add(JDatePicker picker) {
		return add(new DatePickerWrapper(this, picker));
	}

	public AbstractControlWrapper<Object> add(JSpinner spinner) {
		return add(new TimeSpinnerWrapper(this, spinner));
	}

	public AbstractControlWrapper<ClonedTableModel> add(JTable table) {
		return add(new TableWrapper(this, table));
	}

	public <T> AbstractControlWrapper<T> add(GenericControlWindow<T> editor) {
		return add(new GenericControlWrapper<T>(this, editor));
	}

	/*
	 * public methods for controlling the monitor
	 */

	public boolean wasEverModified() {
		return wasEverModified;
	}

	public boolean isCurrentlyModified() {
		return isCurrentlyModified;
	}

	public boolean isValid() {
		return isValid;
	}

	public void reset() {
		boolean oldState = wasEverModified;
		this.wasEverModified = this.isCurrentlyModified = false;
		for (AbstractControlWrapper<?> cw : controls) {
			cw.resetChangeState();
		}
		if (callback != null && oldState) {
			callback.modificationChanged();
		}
	}

	/*
	 * 
	 */

	void validityChanged(AbstractControlWrapper<?> cw) {
		String error = null;
		//LOGGER.info(cw.getClass().getSimpleName() + " changed validity to " + cw.isValid);
		boolean oldValid = this.isValid;
		if (cw.currentError != null) {
			this.isValid = false;
			error = cw.currentError;
		} else {
			this.isValid = true;
		}
		if (error == null) {
			for (AbstractControlWrapper<?> c : controls) {
				if (c.currentError != null) {
					this.isValid = false;
					error = c.currentError;
					break;
				}
			}
		}
		/*
		 * Trigger callback, either when
		 * a) global state changing from invalid to valid, so the error message can get cleared
		 * b) some control changed from valid to invalid, and we have an error message
		 */
		if (callback != null && ((isValid && !oldValid) || error != null)) {
			callback.validityChanged(error);
		}
	}

	/**
	 * Called from one of the inner "ControlWrapper" classes to trigger
	 * the callback for the according window/control.
	 * 
	 * @param cw The ControlWrapper where the changed state changed.
	 */
	void contentChanged(AbstractControlWrapper<?> cw) {
		LOGGER.info(cw.getClass().getSimpleName() + " is changed: " + cw.isCurrentlyChanged);
		final boolean oldEver = this.wasEverModified;
		final boolean oldCurrent = this.isCurrentlyModified;
		this.wasEverModified = false;
		this.isCurrentlyModified = false;
		for (AbstractControlWrapper<?> c : controls) {
			if (c.isCurrentlyChanged) {
				this.isCurrentlyModified = true;
				c.wasEverChanged = true;
			}
			if (c.wasEverChanged) {
				this.wasEverModified = true;
			}
		}
		if (callback != null && (oldCurrent != isCurrentlyModified || oldEver != wasEverModified)) {
			callback.modificationChanged();
		}
	}

	/*
	 * Validators
	 */

	public static interface ValidationConstraint<T> {
		/**
		 * Method should return <code>null</code> if the input is valid, an
		 * error message otherwise.
		 * 
		 * @param userInput Current content/state of the control being monitored
		 * @return error message if invalid, <code>null</code> otherwise
		 */
		String checkStateValid(T userInput);
	}

	/**
	 * Simple validator that checks for text not being empty
	 */
	public static class TextNotEmptyConstraint implements ValidationConstraint<String> {
		private final String errorMsg;

		public TextNotEmptyConstraint(String errorMessage) {
			this.errorMsg = errorMessage;
		}

		@Override
		public String checkStateValid(String userInput) {
			if (Util.isEmptyString(userInput))
				return errorMsg;
			return null;
		}

	}
	
	/**
	 * Simple validator that checks if object is not <code>null</code>
	 */
	public static class NotNullConstraint<T> implements ValidationConstraint<T> {
		private final String errorMsg;

		public NotNullConstraint(String errorMessage) {
			this.errorMsg = errorMessage;
		}

		@Override
		public String checkStateValid(T userInput) {
			if (userInput == null)
				return errorMsg;
			return null;
		}

	}

	/*
	 * Default validators
	 */

	/**
	 * Callback for class using the monitor
	 */
	public static interface Callback {
		public void validityChanged(String errorMessage);

		public void modificationChanged();
	}

}