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-2006 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.form;
042:
043: import com.sun.source.tree.ClassTree;
044: import com.sun.source.tree.Tree;
045: import com.sun.source.util.TreePath;
046: import com.sun.source.util.TreePathScanner;
047: import com.sun.source.util.Trees;
048: import java.io.IOException;
049: import java.util.Iterator;
050: import java.util.List;
051: import java.util.logging.Level;
052: import java.util.logging.Logger;
053: import javax.lang.model.element.Element;
054: import org.netbeans.api.java.source.CancellableTask;
055: import org.netbeans.api.java.source.CompilationController;
056: import org.netbeans.api.java.source.CompilationInfo;
057: import org.netbeans.api.java.source.JavaSource;
058: import org.netbeans.api.java.source.JavaSource.Phase;
059: import org.netbeans.api.java.source.TreePathHandle;
060: import org.netbeans.modules.refactoring.api.Problem;
061: import org.netbeans.modules.refactoring.api.RefactoringSession;
062: import org.netbeans.modules.refactoring.api.RenameRefactoring;
063: import org.openide.util.Lookup;
064: import org.openide.util.lookup.Lookups;
065:
066: /**
067: * Class used to hook form component/variables renaming into refactoring.
068: * @author Wade Chandler
069: * @version 1.0
070: */
071: public class RADComponentRenameRefactoringSupport {
072: private String newName = "";
073: private RADComponent component = null;
074:
075: public RADComponent getComponent() {
076: return component;
077: }
078:
079: public void setComponent(RADComponent component) {
080: this .component = component;
081: }
082:
083: /**
084: * Creates a new instance of support.
085: * @param newName the new name of the field being set
086: */
087: public RADComponentRenameRefactoringSupport(String newName) {
088: this .newName = newName;
089: }
090:
091: private static class MemberVisitor extends
092: TreePathScanner<Void, Void> implements
093: CancellableTask<CompilationController> {
094:
095: private CompilationInfo info;
096: private String member = null;
097: private TreePathHandle handle = null;
098:
099: public TreePathHandle getHandle() {
100: return handle;
101: }
102:
103: public void setHandle(TreePathHandle handle) {
104: this .handle = handle;
105: }
106:
107: public MemberVisitor(CompilationInfo info, String member) {
108: this .info = info;
109: this .member = member;
110: }
111:
112: @Override
113: public Void visitClass(ClassTree t, Void v) {
114: List<? extends Tree> members = (List<? extends Tree>) t
115: .getMembers();
116: Iterator<? extends Tree> it = members.iterator();
117: while (it.hasNext()) {
118: Tree tr = it.next();
119: if (tr.getKind() == Tree.Kind.VARIABLE) {
120: Trees trees = info.getTrees();
121: TreePath path = new TreePath(getCurrentPath(), tr);
122: Element el = trees.getElement(path);
123: String sname = el.getSimpleName().toString();
124: if (sname.equals(this .member)) {
125: this .handle = TreePathHandle.create(path, info);
126: }
127: } // TODO also need to check local variables in initComponents
128: }
129: return null;
130: }
131:
132: public void cancel() {
133: }
134:
135: public void run(CompilationController parameter)
136: throws IOException {
137: this .info = parameter;
138: parameter.toPhase(Phase.ELEMENTS_RESOLVED);
139: this .scan(parameter.getCompilationUnit(), null);
140: }
141: }
142:
143: /**
144: * Method used to perform the actual refactoring. This method will use the oldName to locate the
145: * elemnent/field needing renamed. It will then setup the correct Java infrastructure path
146: * for refactoring to use. Currently no UI besides gather the user variable is used. If found at
147: * some point people are using component fields outside of the forms and this is very slow then
148: * we can add better UI support.
149: */
150: public void doRenameRefactoring() {
151: //now we need to get into the Java phase and get a TreePathHandle
152: //to the field we are renaming. We can then kick off a RenameRefactoring
153: FormDataObject dao = FormEditor
154: .getFormDataObject(this .component.getFormModel());
155: if (dao != null) {
156: //we should be able to
157: JavaSource js = JavaSource.forFileObject(dao
158: .getPrimaryFile());
159: try {
160: MemberVisitor visitor = new MemberVisitor(null,
161: component.getName());
162: js.runUserActionTask(visitor, true);
163: if (visitor.getHandle() == null) {
164: //this would only happen if setName were called without the correct component being
165: //selected some how...
166: return;
167: }
168: FormEditorSupport fes = dao.getFormEditorSupport();
169: if (fes.isModified()) {
170: fes.saveDocument();
171: }
172: //ok, so we are now ready to actually setup our RenameRefactoring...we need the element TreePathHandle
173: Lookup rnl = Lookups.singleton(visitor.getHandle());
174: RefactoringSession renameSession = RefactoringSession
175: .create("Change variable name");//NOI18N
176: RenameRefactoring refactoring = new RenameRefactoring(
177: rnl);
178: Problem pre = refactoring.preCheck();
179: if (pre != null && pre.isFatal()) {
180: Logger
181: .getLogger("global")
182: .log(Level.WARNING,
183: "There were problems trying to perform the refactoring.");
184: }
185:
186: Problem p = null;
187:
188: if ((!(pre != null && pre.isFatal()))
189: && !emptyOrWhite(newName)) {
190: refactoring.setNewName(newName);
191: p = refactoring.prepare(renameSession);
192: }
193:
194: if ((!(p != null && p.isFatal()))
195: && !emptyOrWhite(newName)) {
196: renameSession.doRefactoring(true);
197: }
198: } catch (IOException e) {
199: Logger.getLogger("global").log(Level.SEVERE,
200: e.getMessage(), e);
201: }
202: }
203: }
204:
205: private static boolean emptyOrWhite(String s) {
206: if (s == null) {
207: return true;
208: }
209: if (s.trim().length() < 0) {
210: return true;
211: }
212: return false;
213: }
214:
215: }
|