001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.visualweb.insync;
042:
043: import org.netbeans.modules.visualweb.api.insync.InSyncService;
044:
045: import java.lang.reflect.InvocationTargetException;
046: import java.lang.reflect.Method;
047: import java.util.ArrayList;
048: import java.util.Iterator;
049:
050: import org.openide.ErrorManager;
051: import org.openide.awt.UndoRedo;
052: import org.openide.cookies.EditorCookie; // XXX Node a NB cookie, can't use!
053: //import org.openide.cookies.UndoRedoCookie;
054: import org.openide.loaders.DataObject;
055: import org.openide.text.CloneableEditorSupport;
056:
057: /**
058: * Represents a single undoable event
059: *
060: * @author Tor Norbye
061: */
062: public class UndoEvent implements InSyncService.WriteLock {
063: private String description;
064: private ArrayList modifiedUnits;
065: private Model model;
066:
067: public Model getModel() {
068: return model;
069: }
070:
071: public UndoEvent(String description, Model model) {
072: this .description = description;
073: this .model = model;
074: }
075:
076: /**
077: * Make a note of the fact that the given source unit was updated as part of this undoable
078: * event, such that its buffer's undo event is run when this entire event is rolled back. We
079: * want to actually record units MULTIPLE times if they are actually flushed several times
080: * during an update - that way we can undo all their changes as a single event.
081: */
082: public void notifyBufferUpdated(SourceUnit unit) {
083: if (modifiedUnits == null) {
084: modifiedUnits = new ArrayList(3);
085: }
086: modifiedUnits.add(unit);
087: }
088:
089: /**
090: *
091: */
092: public void undo() {
093: if (modifiedUnits == null) {
094: return;
095: }
096:
097: Iterator it = modifiedUnits.iterator();
098: while (it.hasNext()) {
099: SourceUnit unit = (SourceUnit) it.next();
100: DataObject dobj = unit.getDataObject();
101: /*
102: This doesn't work well because the JavaEditor is NOT
103: a ClonableEditor!
104: EditorCookie ec = (EditorCookie)dobj.getCookie(EditorCookie.class);
105: if (ec instanceof CloneableEditorSupport) {
106: CloneableEditorSupport ces = (CloneableEditorSupport)ec;
107: ces.getUndoRedoPublic().undo();
108: }
109: */
110: // UndoRedoCookie urc = (UndoRedoCookie)dobj.getCookie(UndoRedoCookie.class);
111: // if (urc != null) {
112: // UndoRedo ur = urc.getUndoRedoI();
113: // if (ur != null) {
114: // ur.undo();
115: // }
116: // }
117: // RaveUndoRedoCookie urc = (RaveUndoRedoCookie)dobj.getCookie(RaveUndoRedoCookie.class);
118: // if (urc != null) {
119: // UndoRedo ur = urc.getUndoRedoI();
120: // if (ur != null) {
121: // ur.undo();
122: // }
123: // }
124: // Use CloneableEditorSupport's UndoRedo to perform undo
125: EditorCookie ec = (EditorCookie) dobj
126: .getCookie(EditorCookie.class);
127: if (ec instanceof CloneableEditorSupport) {
128: CloneableEditorSupport ces = (CloneableEditorSupport) ec;
129: UndoRedo undoRedo = getUndoRedo(ces);
130: if (undoRedo != null) {
131: undoRedo.undo();
132: }
133: }
134: }
135: }
136:
137: /** Return true iff there have been any changes to any buffers
138: * for this undo event.
139: */
140: public boolean hasChanges() {
141: return modifiedUnits != null && modifiedUnits.size() > 0;
142: }
143:
144: /**
145: *
146: */
147: public void redo() {
148: if (modifiedUnits == null) {
149: return;
150: }
151:
152: Iterator it = modifiedUnits.iterator();
153: while (it.hasNext()) {
154: SourceUnit unit = (SourceUnit) it.next();
155: DataObject dobj = unit.getDataObject();
156: /*
157: EditorCookie ec = (EditorCookie)dobj.getCookie(EditorCookie.class);
158: if (ec instanceof CloneableEditorSupport) {
159: CloneableEditorSupport ces = (CloneableEditorSupport)ec;
160: ces.getUndoRedoPublic().redo();
161: }
162: */
163: // UndoRedoCookie urc = (UndoRedoCookie)dobj.getCookie(UndoRedoCookie.class);
164: // if (urc != null) {
165: // UndoRedo ur = urc.getUndoRedoI();
166: // if (ur != null) {
167: // ur.redo();
168: // }
169: // }
170: // RaveUndoRedoCookie urc = (RaveUndoRedoCookie)dobj.getCookie(RaveUndoRedoCookie.class);
171: // if (urc != null) {
172: // UndoRedo ur = urc.getUndoRedoI();
173: // if (ur != null) {
174: // ur.redo();
175: // }
176: // }
177: // Use CloneableEditorSupport's UndoRedo to perform redo
178: EditorCookie ec = (EditorCookie) dobj
179: .getCookie(EditorCookie.class);
180: if (ec instanceof CloneableEditorSupport) {
181: CloneableEditorSupport ces = (CloneableEditorSupport) ec;
182: UndoRedo undoRedo = getUndoRedo(ces);
183: if (undoRedo != null) {
184: undoRedo.redo();
185: }
186: }
187: }
188: }
189:
190: /**
191: * @return the never-null description for this event.
192: */
193: public String getDescription() {
194: return description != null ? description : "";
195: }
196:
197: public String toString() {
198: return getDescription();
199: }
200:
201: // CloneableEditorSupport's UndoRedo is protected, so call it via reflection.
202: private static UndoRedo getUndoRedo(CloneableEditorSupport ces) {
203: try {
204: Method method = CloneableEditorSupport.class
205: .getDeclaredMethod("getUndoRedo", new Class[0]);
206: method.setAccessible(true);
207: try {
208: return (UndoRedo) method.invoke(ces, new Object[0]);
209: } catch (IllegalArgumentException ex) {
210: ErrorManager.getDefault().notify(
211: ErrorManager.INFORMATIONAL, ex);
212: } catch (InvocationTargetException ex) {
213: ErrorManager.getDefault().notify(
214: ErrorManager.INFORMATIONAL, ex);
215: } catch (IllegalAccessException ex) {
216: ErrorManager.getDefault().notify(
217: ErrorManager.INFORMATIONAL, ex);
218: }
219: } catch (SecurityException ex) {
220: ErrorManager.getDefault().notify(
221: ErrorManager.INFORMATIONAL, ex);
222: } catch (NoSuchMethodException ex) {
223: ErrorManager.getDefault().notify(
224: ErrorManager.INFORMATIONAL, ex);
225: }
226: return null;
227: }
228: }
|