All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.muntjak.tinylookandfeel.controlpanel.UndoManager Maven / Gradle / Ivy

Go to download

This is the Tiny look-and-feel packaged to be distributed with the SQuirreLSQL client. The Tiny look-and-feel is a (mostly painted) look-and-feel for Java 1.4 and higher.

The newest version!
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *	This file is part of the Tiny Look and Feel                                *
 *  Copyright 2003 - 2008  Hans Bickel                                         *
 *                                                                             *
 *  For licensing information and credits, please refer to the                 *
 *  comment in file de.muntjak.tinylookandfeel.TinyLookAndFeel                 *
 *                                                                             *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

package de.muntjak.tinylookandfeel.controlpanel;

import java.util.Iterator;
import java.util.Stack;
import java.util.Vector;

import javax.swing.plaf.ColorUIResource;

import de.muntjak.tinylookandfeel.controlpanel.ControlPanel.BooleanControl;
import de.muntjak.tinylookandfeel.controlpanel.ControlPanel.ColorizeIconCheck;
import de.muntjak.tinylookandfeel.controlpanel.ControlPanel.FontColorControl;
import de.muntjak.tinylookandfeel.controlpanel.ControlPanel.FontPanel;
import de.muntjak.tinylookandfeel.controlpanel.ControlPanel.HSBControl;
import de.muntjak.tinylookandfeel.controlpanel.IntControl;
import de.muntjak.tinylookandfeel.controlpanel.ControlPanel.SpreadControl;
import de.muntjak.tinylookandfeel.util.SBReference;
import de.muntjak.tinylookandfeel.util.ColoredFont;
import de.muntjak.tinylookandfeel.util.HSBReference;

/**
 * UndoManager
 * @author Hans Bickel
 *
 */
public class UndoManager {
	
	// stack of UndoData
	private static final Stack undoStack = new Stack();
	private static final Stack redoStack = new Stack();
	private static String undoDescription, redoDescription;
	
	// undo items which must be activated by pressing
	// 'Apply Settings' are added to delayedUndoItems
	// until they are activated at activateDelayedUndoItems(ControlPanel)
	private static final Vector delayedUndoItems = new Vector();
	
	static void clear() {
		//new Exception("UndoManager.clear()").printStackTrace();
		undoStack.clear();
		redoStack.clear();
		delayedUndoItems.clear();
	}
	
	/**
	 * Called if user clicked 'Apply Settings'. Returns
	 * true if there was at least one delayed undo item,
	 * false otherwise.
	 * @param cp
	 * @return true if there was at least one delayed undo item,
	 * false otherwise
	 */
	static boolean activateDelayedUndoItems(ControlPanel cp) {
		if(delayedUndoItems.isEmpty()) return false;
		
		if(delayedUndoItems.size() == 1) {
			undoStack.push(delayedUndoItems.get(0));
		}
		else {
			// push vector of UndoData
			undoStack.push(delayedUndoItems.clone());
//			printVector(delayedUndoItems);
		}

		undoDescription = getDescription(undoStack.peek());
		
		delayedUndoItems.clear();
		redoStack.clear();
		cp.undoItemsActivated();
		
		return true;
	}
	
	private static void printVector(Vector v) {
		System.out.println("\n" + v.size() + " items:");
		Iterator ii = v.iterator();
		while(ii.hasNext()) {
			System.out.println("  " + ii.next());
		}
	}

	private static String getDescription(Object o) {
		if(o instanceof UndoData) {
			return ((UndoData)o).description;
		}
		else if(o instanceof Vector) {
			Vector v = (Vector)o;
			String description = null;

			Iterator ii = v.iterator();
			while(ii.hasNext()) {
				UndoData data = (UndoData)ii.next();

				if(description == null) {
					description = data.description;
				}
				else if(!description.equals(data.description)) {
					if(description.startsWith("Change Inset") &&
						data.description.startsWith("Change Inset"))
					{
						description = "Change Inset";
					}
					else {
						description = "Multiple Actions";
						break;
					}
				}
			}
			
			if("Change Inset".equals(description)) {
				description = "Change multiple Insets";
			}
			else if("Change Boolean".equals(description)) {
				description = "Change multiple Booleans";
			}
			else if("Change Spread".equals(description)) {
				description = "Change multiple Spreads";
			}
			else if("Change Color".equals(description)) {
				description = "Change multiple Colors";
			}
			else if("Change Font".equals(description)) {
				description = "Change multiple Fonts";
			}
			else if(!"Multiple Actions".equals(description)) {
				description = "Multiple " + description + "s";
			}
			
			return description;
		}
		
		return null;	// Error
	}
	
	static String getUndoDescription() {
		return undoDescription;
	}
	
	static String getRedoDescription() {
		return redoDescription;
	}

	static void storeUndoData(ColoredFont cf) {
		UndoData data = new UndoData(cf);
		
		if(delayedUndoItems.contains(data)) {
			int index = delayedUndoItems.indexOf(data);
			UndoData old = (UndoData)delayedUndoItems.get(index);
			delayedUndoItems.remove(data);
			
			data.cfData = old.cfData;
			delayedUndoItems.add(data);
		}
		else {
			delayedUndoItems.add(data);
		}
	}
	
	static void storeUndoData(SBControl sb) {
		UndoData data = new UndoData(sb);
		
		if(sb.forceUpdate) {
			if(delayedUndoItems.contains(data)) {
				int index = delayedUndoItems.indexOf(data);
				UndoData old = (UndoData)delayedUndoItems.get(index);
				delayedUndoItems.remove(data);
				
				data.sbData = old.sbData;
				delayedUndoItems.add(data);
			}
			else {
				delayedUndoItems.add(data);
			}
		}
		else {
			undoStack.push(data);
			redoStack.clear();
			undoDescription = data.description;
		}
	}
	
	static void storeUndoData(SpreadControl sc) {
		UndoData data = new UndoData(sc);
		undoDescription = data.description;
		
		undoStack.push(data);
		redoStack.clear();
	}
	
	static void storeUndoData(BooleanControl bc) {
		UndoData data = new UndoData(bc);
		
		if(bc.forceUpdate) {
			if(delayedUndoItems.contains(data)) {
				delayedUndoItems.remove(data);
			}
			else {
				delayedUndoItems.add(data);
			}
		}
		else {
			undoStack.push(data);
			redoStack.clear();
			undoDescription = data.description;
		}
	}
	
	static void storeUndoData(HSBControl hsb, ColorizeIconCheck cc) {
		UndoData data = new UndoData(hsb, cc);
		
		if(delayedUndoItems.contains(data)) {
			int index = delayedUndoItems.indexOf(data);
			UndoData old = (UndoData)delayedUndoItems.get(index);
			delayedUndoItems.remove(data);
			
			data.hsbData = old.hsbData;
			data.cc = old.cc;
			delayedUndoItems.add(data);
		}
		else {
			delayedUndoItems.add(data);
		}
	}
	
	static void storeUndoData(ColorizeIconCheck cc) {
		UndoData data = new UndoData(cc);
		
		if(delayedUndoItems.contains(data)) {
			delayedUndoItems.remove(data);
		}
		else {
			delayedUndoItems.add(data);
		}
	}
	
	static void storeUndoData(InsetsControl ic, int icValue) {
		UndoData data = new UndoData(ic, icValue);
		
		delayedUndoItems.add(data);
	}
	
	static void storeUndoData(IntControl ic, int icValue) {
		UndoData data = new UndoData(ic, icValue);
		
		delayedUndoItems.add(data);
	}
	
	public static void storeUndoData(ParameterSet params) {
		UndoData data = new UndoData(params);
		undoDescription = data.description;
		
		undoStack.push(data);
		redoStack.clear();
	}

	/**
	 * 
	 * @return true if the undo operation succeeded, false otherwise
	 */
	static boolean doUndo(ControlPanel cp) {
		if(undoStack.isEmpty()) return false;
		
		Object o = undoStack.pop();
		redoStack.push(o);

		if(o instanceof UndoData) {
			((UndoData)o).doUndo(cp, true);
		}
		else {
			Vector v = (Vector)o;
			int top = v.size() - 1;

			for(int i = top; i >= 0; i--) {
				((UndoData)v.get(i)).doUndo(cp, false);
			}
			
			cp.setTheme();
		}
		
		if(!undoStack.isEmpty()) {
			undoDescription = getDescription(undoStack.peek());
		}
		
		redoDescription = getDescription(redoStack.peek());
		
		return true;
	}
	
	/**
	 * 
	 * @return true if the redo operation succeeded, false otherwise
	 */
	static boolean doRedo(ControlPanel cp) {
		if(redoStack.isEmpty()) return false;

		Object o = redoStack.pop();
		
		undoStack.push(o);
		
		if(o instanceof UndoData) {
			((UndoData)o).doUndo(cp, true);
		}
		else {
			Vector v = (Vector)o;
			int top = v.size() - 1;

			for(int i = top; i >= 0; i--) {
				((UndoData)v.get(i)).doUndo(cp, false);
			}
			
			cp.setTheme();
		}

		if(!redoStack.isEmpty()) {
			redoDescription = getDescription(redoStack.peek());
		}
		
		undoDescription = getDescription(undoStack.peek());
		
		return true;
	}
	
	static boolean canUndo() {
		return !undoStack.isEmpty();
	}
	
	static boolean canRedo() {
		return !redoStack.isEmpty();
	}

	/**
	 * Overrides equals(Object). Two UndoData are supposed
	 * to be equal if their controls are equal.
	 */
	private static class UndoData {
		
		String description;
		SBControl sb;
		SBReference sbData;
		
		ColoredFont cf;
		ColoredFont cfData;
		
		BooleanControl bc;
		boolean bcValue;
		
		HSBControl hsb;
		HSBReference hsbData;
		
		SpreadControl sc;
		int spread;
		
		ColorizeIconCheck cc;
		boolean ccValue;
		
		IntControl intControl;
		int intControlValue;
		
		InsetsControl insetsControl;
		int insetsControlValue;
		
		ParameterSet params;
		ParameterSet paramData;

		UndoData(SBControl sb) {
			this.sb = sb;
			// copy current values
			sbData = new SBReference(sb.getSBReference());
			description = "Change Color";
//			System.out.println("Stored: " + sb + " / " + sbData);
		}
		
		UndoData(ColoredFont cf) {
			this.cf = cf;
			// copy current values
			cfData = new ColoredFont(cf);
			description = "Change Font";
		}
		
		UndoData(BooleanControl bc) {
			this.bc = bc;
			// Note: Because with BooleanControl undo data is
			// stored *after* value changed, the next undo value
			// is equal to current value
			bcValue = bc.ref.getValue();
			description = "Change Boolean";
		}
		
		UndoData(SpreadControl sc) {
			this.sc = sc;
			// copy current value
			spread = sc.spread;
			description = "Change Spread";
		}

		UndoData(HSBControl hsb, ColorizeIconCheck cc) {
			this.hsb = hsb;
			hsbData = new HSBReference(hsb.getUndoReference());
			description = "Colorize Icon Action";
			
			if(!cc.isSelected()) {
				this.cc = cc;
				// copy current value (before change)
				ccValue = cc.isSelected();
			}
		}
		
		UndoData(ColorizeIconCheck cc) {
			this.cc = cc;
			// Note: Because with ColorizeIconCheck undo data is
			// stored *after* value changed, the next undo value
			// is the reversed current value
			ccValue = !cc.isSelected();
			description = "Colorize Icon Action";
		}
		
		UndoData(InsetsControl insetsControl, int value) {
			this.insetsControl = insetsControl;
			this.insetsControlValue = value;
			description = "Change Insets." + insetsControl.getPositionString();
		}

		UndoData(IntControl intControl, int value) {
			this.intControl = intControl;
			this.intControlValue = value;
			description = "Change " + intControl.getDescription();
		}
		
		UndoData(ParameterSet params) {
			this.params = params;
			paramData = params.getGenerator().getParameterSet();
//			System.out.println("UndoManager.paramData: " + paramData);
			description = params.getUndoString();
		}
		
		public boolean equals(Object o) {
			if(o == null || !(o instanceof UndoData)) return false;
			
			UndoData other = (UndoData)o;
			
			if(cf != null) {
				return cf.equals(other.cf);
			}
			else if(sb != null) {
				return sb.equals(other.sb);
			}
			else if(sc != null) {
				return sc.equals(other.sc);
			}
			else if(bc != null) {
				return bc.equals(other.bc);
			}
			else if(hsb != null) {
				return hsb.equals(other.hsb);
			}
			else if(cc != null) {
				return cc.equals(other.cc);
			}
			else if(insetsControl != null) {
				return insetsControl.equals(other.insetsControl);
			}
			else if(intControl != null) {
				return intControl.equals(other.intControl);
			}
			else if(params != null) {
				return insetsControl.equals(other.params);
			}
			
			return false;
		}
		
		public String toString() {
			if(sb != null) {
				return "Current Cr:" + sb.getSBReference() +
					" Undo Cr:" + sbData;
			}
			
			return super.toString();
		}

		void doUndo(ControlPanel cp, boolean setTheme) {
//			System.out.println("doUndo: " + this);
			if(sb != null) {
				int bri = sbData.getBrightness();
				ColorUIResource c = sbData.getColor();
				int ref = sbData.getReference();
				int sat = sbData.getSaturation();
				
				// for redo
				SBReference colorRef = sb.getSBReference();
				sbData.setBrightness(colorRef.getBrightness());
				sbData.setReference(colorRef.getReference());
				sbData.setSaturation(colorRef.getSaturation());
				sbData.setColor(colorRef.getColor());
				// end for redo
				
				colorRef.setBrightness(bri);
				colorRef.setReference(ref);
				colorRef.setSaturation(sat);
				colorRef.setColor(c);
				sb.update();
				
				if(setTheme) {
					sb.updateTargets(false);
				}
			}
			else if(sc != null) {
				int mem = sc.spread;
				
				if(setTheme) {
					sc.update(spread, false);	// also updates targets
				}
				
				// for redo
				spread = mem;
			}
			else if(bc != null) {
				bc.ref.setValue(bcValue);
				bc.setSelected(bcValue);

				if(setTheme) {
					bc.updateTargets(false);
				}

				// for redo
				bcValue = !bcValue;
			}
			else if(hsb != null) {
				int bri = hsbData.getBrightness();
				int hue = hsbData.getHue();
				boolean preserveGrey = hsbData.isPreserveGrey();
				int ref = hsbData.getReference();
				int sat = hsbData.getSaturation();
				
				// for redo
				HSBReference r = hsb.getHSBReference();
				hsbData.setBrightness(r.getBrightness());
				hsbData.setHue(r.getHue());
				hsbData.setPreserveGrey(r.isPreserveGrey());
				hsbData.setReference(r.getReference());
				hsbData.setSaturation(r.getSaturation());
				// end for redo
				
				r.setBrightness(bri);
				r.setHue(hue);
				r.setPreserveGrey(preserveGrey);
				r.setReference(ref);
				r.setSaturation(sat);

				if(cc != null) {
					cc.setSelected(ccValue);
					cc.ref.setValue(ccValue);
					
					if(setTheme) {
						hsb.update();
						cp.colorizeIcon(hsb, ccValue);
					}
					
					// for redo
					ccValue = !ccValue;
				}
				else {
					if(setTheme) {
						hsb.update();
						cp.colorizeIcon(hsb, true);
					}
				}
				
				if(setTheme) cp.setTheme();
			}
			else if(cc != null) {
				cc.setSelected(ccValue);
				cc.ref.setValue(ccValue);
				
				if(setTheme) {
					cp.colorizeIcon(cc.hsb, ccValue);
					cp.setTheme();
				}
				
				// for redo
				ccValue = !ccValue;
			}
			else if(insetsControl != null) {
				int mem = ((Integer)insetsControl.getValue()).intValue();
				insetsControl.commitValue(insetsControlValue);
				
				if(setTheme) cp.setTheme();
				
				// for redo
				insetsControlValue = mem;
			}
			else if(intControl != null) {
				int mem = ((Integer)intControl.getValue()).intValue();
				intControl.commitValue(intControlValue);
				
				if(setTheme) cp.setTheme();
				
				// for redo
				intControlValue = mem;
			}
			else if(cf != null) {
				ColoredFont temp = new ColoredFont(cfData);
				// for redo
				cfData = new ColoredFont(cf);

				cf.update(temp);
				cp.initFonts();

				if(setTheme) cp.setTheme();
			}
			else if(params != null) {
				params.updateValues(paramData);
				
				// store current parameters for redo
				paramData.updateValues();
				
				params.pasteParameters(false);	// triggers setTheme()
				params.updateReferenceColors();
//				System.out.println("UndoManager.doUndo: " + params);
			}
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy