UndoRedo system

Asd Code 1

final TextViewUndoRedo helper = new TextViewUndoRedo(_edittext);
Asd Code 2

_undo.setOnClickListener (new View.OnClickListener() { @Override public void onClick(View v) { helper.undo(); } });
Asd Code 3

_redo.setOnClickListener (new View.OnClickListener() { @Override public void onClick(View v) { helper.redo(); } });

Asd Code 4

}
Asd Code 5


public class TextViewUndoRedo { 	 	private boolean mIsUndoOrRedo = false; 	private EditHistory mEditHistory; 	private EditTextChangeListener mChangeListener; 	private TextView mTextView; 	 	public TextViewUndoRedo(TextView textView) { 		mTextView = textView; 		mEditHistory = new EditHistory(); 		mChangeListener = new EditTextChangeListener(); 		mTextView.addTextChangedListener(mChangeListener); 	} 	public void disconnect() { 		mTextView.removeTextChangedListener(mChangeListener); 	} 	public void setMaxHistorySize(int maxHistorySize) { 		mEditHistory.setMaxHistorySize(maxHistorySize); 	} 	public void clearHistory() { 		mEditHistory.clear(); 	} 	 	public boolean getCanUndo() { 		return (mEditHistory.mmPosition > 0); 	} 	public void undo() { 		EditItem edit = mEditHistory.getPrevious(); 		if (edit == null) { 			return; 		} 		Editable text = mTextView.getEditableText(); 		int start = edit.mmStart; 		int end = start + (edit.mmAfter != null ? edit.mmAfter.length() : 0); 		mIsUndoOrRedo = true; 		text.replace(start, end, edit.mmBefore); 		mIsUndoOrRedo = false; 		for (Object o : text.getSpans(0, text.length(), android.text.style.UnderlineSpan.class)) { 			text.removeSpan(o); 		} 		Selection.setSelection(text, edit.mmBefore == null ? start 				: (start + edit.mmBefore.length())); 	} 	public boolean getCanRedo() { 		return (mEditHistory.mmPosition < mEditHistory.mmHistory.size()); 	} 	public void redo() { 		EditItem edit = mEditHistory.getNext(); 		if (edit == null) { 			return; 		} 		Editable text = mTextView.getEditableText(); 		int start = edit.mmStart; 		int end = start + (edit.mmBefore != null ? edit.mmBefore.length() : 0); 		mIsUndoOrRedo = true; 		text.replace(start, end, edit.mmAfter); 		mIsUndoOrRedo = false; 		for (Object o : text.getSpans(0, text.length(), android.text.style.UnderlineSpan.class)) { 			text.removeSpan(o); 		} 		Selection.setSelection(text, edit.mmAfter == null ? start 				: (start + edit.mmAfter.length())); 	} 	public void storePersistentState(android.content.SharedPreferences.Editor editor, String prefix) { 		editor.putString(prefix + ".hash", 				String.valueOf(mTextView.getText().toString().hashCode())); 		editor.putInt(prefix + ".maxSize", mEditHistory.mmMaxHistorySize); 		editor.putInt(prefix + ".position", mEditHistory.mmPosition); 		editor.putInt(prefix + ".size", mEditHistory.mmHistory.size()); 		int i = 0; 		for (EditItem ei : mEditHistory.mmHistory) { 			String pre = prefix + "." + i; 			editor.putInt(pre + ".start", ei.mmStart); 			editor.putString(pre + ".before", ei.mmBefore.toString()); 			editor.putString(pre + ".after", ei.mmAfter.toString()); 			i++; 		} 	} 	public boolean restorePersistentState(SharedPreferences sp, String prefix) 			throws IllegalStateException { 		boolean ok = doRestorePersistentState(sp, prefix); 		if (!ok) { 			mEditHistory.clear(); 		} 		return ok; 	} 	private boolean doRestorePersistentState(SharedPreferences sp, String prefix) { 		String hash = sp.getString(prefix + ".hash", null); 		if (hash == null) { 			return true; 		} 		if (Integer.valueOf(hash) != mTextView.getText().toString().hashCode()) { 			return false; 		} 		mEditHistory.clear(); 		mEditHistory.mmMaxHistorySize = sp.getInt(prefix + ".maxSize", -1); 		int count = sp.getInt(prefix + ".size", -1); 		if (count == -1) { 			return false; 		} 		for (int i = 0; i < count; i++) { 			String pre = prefix + "." + i; 			int start = sp.getInt(pre + ".start", -1); 			String before = sp.getString(pre + ".before", null); 			String after = sp.getString(pre + ".after", null); 			if (start == -1 || before == null || after == null) { 				return false; 			} 			mEditHistory.add(new EditItem(start, before, after)); 		} 		mEditHistory.mmPosition = sp.getInt(prefix + ".position", -1); 		if (mEditHistory.mmPosition == -1) { 			return false; 		} 		return true; 	} 	private final class EditHistory { 		private int mmPosition = 0; 		private int mmMaxHistorySize = -1; 		private final LinkedList mmHistory = new LinkedList(); 		private void clear() { 			mmPosition = 0; 			mmHistory.clear(); 		} 		private void add(EditItem item) { 			while (mmHistory.size() > mmPosition) { 				mmHistory.removeLast(); 			} 			mmHistory.add(item); 			mmPosition++; 			if (mmMaxHistorySize >= 0) { 				trimHistory(); 			} 		} 		private void setMaxHistorySize(int maxHistorySize) { 			mmMaxHistorySize = maxHistorySize; 			if (mmMaxHistorySize >= 0) { 				trimHistory(); 			} 		} 		private void trimHistory() { 			while (mmHistory.size() > mmMaxHistorySize) { 				mmHistory.removeFirst(); 				mmPosition--; 			} 			if (mmPosition < 0) { 				mmPosition = 0; 			} 		} 		private EditItem getPrevious() { 			if (mmPosition == 0) { 				return null; 			} 			mmPosition--; 			return mmHistory.get(mmPosition); 		} 		private EditItem getNext() { 			if (mmPosition >= mmHistory.size()) { 				return null; 			} 			EditItem item = mmHistory.get(mmPosition); 			mmPosition++; 			return item; 		} 	} 	private final class EditItem { 		private final int mmStart; 		private final CharSequence mmBefore; 		private final CharSequence mmAfter; 		public EditItem(int start, CharSequence before, CharSequence after) { 			mmStart = start; 			mmBefore = before; 			mmAfter = after; 		} 	} 	private final class EditTextChangeListener implements TextWatcher { 		private CharSequence mBeforeChange; 		private CharSequence mAfterChange; 		public void beforeTextChanged(CharSequence s, int start, int count, 				int after) { 			if (mIsUndoOrRedo) { 				return; 			} 			mBeforeChange = s.subSequence(start, start + count); 		} 		public void onTextChanged(CharSequence s, int start, int before, 				int count) { 			if (mIsUndoOrRedo) { 				return; 			} 			mAfterChange = s.subSequence(start, start + count); 			mEditHistory.add(new EditItem(start, mBeforeChange, mAfterChange)); 		} 		public void afterTextChanged(Editable s) { 		} 	} }

Asd Code 6

{