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.refactoring.java.ui;
042:
043: import java.io.IOException;
044: import java.text.MessageFormat;
045: import java.util.StringTokenizer;
046: import javax.lang.model.element.Element;
047: import javax.lang.model.element.ElementKind;
048: import javax.lang.model.element.Modifier;
049: import javax.swing.event.ChangeListener;
050: import org.netbeans.api.fileinfo.NonRecursiveFolder;
051: import org.netbeans.api.java.classpath.ClassPath;
052: import org.netbeans.api.java.source.ClasspathInfo;
053: import org.netbeans.api.java.source.CompilationInfo;
054: import org.netbeans.api.java.source.TreePathHandle;
055: import org.netbeans.modules.refactoring.api.AbstractRefactoring;
056: import org.netbeans.modules.refactoring.api.RenameRefactoring;
057: import org.netbeans.modules.refactoring.java.RetoucheUtils;
058: import org.netbeans.modules.refactoring.spi.ui.CustomRefactoringPanel;
059: import org.netbeans.modules.refactoring.spi.ui.RefactoringUI;
060: import org.netbeans.modules.refactoring.spi.ui.RefactoringUIBypass;
061: import org.openide.ErrorManager;
062: import org.openide.filesystems.FileObject;
063: import org.openide.loaders.DataFolder;
064: import org.openide.loaders.DataObject;
065: import org.openide.util.HelpCtx;
066: import org.openide.util.NbBundle;
067: import org.openide.util.lookup.Lookups;
068:
069: /**
070: *
071: * @author Martin Matula
072: * @author Jan Becicka
073: */
074: public class RenameRefactoringUI implements RefactoringUI,
075: RefactoringUIBypass {
076: private final AbstractRefactoring refactoring;
077: private String oldName = null;
078: private String dispOldName;
079: private String newName;
080: private RenamePanel panel;
081: private boolean fromListener = false;
082: private TreePathHandle handle;
083: private FileObject byPassFolder;
084: private boolean byPassPakageRename;
085: private boolean pkgRename = true;
086:
087: // RenameRefactoringUI(ElementHandle jmiObject, FileObject folder, boolean packageRename) {
088: // this.jmiObject = jmiObject;
089: // pkgRename = packageRename;
090: // if (jmiObject == null || jmiObject instanceof JavaPackage) {
091: // if (folder == null) {
092: // folder = JavaMetamodel.getManager().getClassPath().findResource(((JavaPackage) jmiObject).getName().replace('.','/'));
093: // if (folder == null) {
094: // //package declaration is invalid
095: // Node[] nodes = TopComponent.getRegistry().getActivatedNodes();
096: // DataObject dob = (DataObject) nodes[0].getCookie(DataObject.class);
097: // folder = dob.getFolder().getPrimaryFile();
098: // }
099: // }
100: // this.refactoring = createMoveClassRefactoring(folder, packageRename);
101: // String packageName = jmiObject != null ? ((JavaPackage) jmiObject).getName():null;
102: // if (!packageRename) {
103: // oldName = folder.getName();
104: // } else {
105: // if (packageName != null) {
106: // oldName = "".equals(packageName) ? NbBundle.getBundle("org.netbeans.modules.java.project.Bundle").getString("LBL_DefaultPackage") : packageName;
107: // } else {
108: // oldName = ClassPath.getClassPath(folder, ClassPath.SOURCE).getResourceName(folder).replace('/','.');
109: // }
110: // }
111: // } else if (jmiObject instanceof JavaClass) {
112: // this.refactoring = new RenameRefactoring(jmiObject);
113: // Object comp = jmiObject.refImmediateComposite();
114: // if (comp instanceof Resource) {
115: // FileObject fo = JavaModel.getFileObject((Resource)comp);
116: // String name = fo.getName();
117: // for (Iterator iter = ((Resource)comp).getClassifiers().iterator(); iter.hasNext(); ) {
118: // Object obj = iter.next();
119: // if (obj instanceof JavaClass) {
120: // String sName = ((JavaClass) obj).getSimpleName();
121: // if (name.equals(sName)) {
122: // name = ((JavaClass) jmiObject).getSimpleName();
123: // break;
124: // }
125: // } // if
126: // } // for
127: // oldName = name;
128: // } else {
129: // oldName = ((JavaClass) jmiObject).getSimpleName();
130: // }
131: // } else {
132: // this.refactoring = new RenameRefactoring(jmiObject);
133: // if (jmiObject instanceof NamedElement) {
134: // if (jmiObject instanceof Resource) {
135: // oldName = JavaMetamodel.getManager().getDataObject((Resource)jmiObject).getName();
136: // } else
137: // oldName = ((NamedElement) jmiObject).getName();
138: // } else {
139: // oldName = "";
140: // }
141: // }
142: // dispOldName = oldName;
143: // }
144:
145: public RenameRefactoringUI(TreePathHandle handle,
146: CompilationInfo info) {
147: this .handle = handle;
148: this .refactoring = new RenameRefactoring(Lookups
149: .singleton(handle));
150: Element element = handle.resolveElement(info);
151: oldName = element.getSimpleName().toString();
152: if (element.getModifiers().contains(Modifier.PRIVATE)) {
153: refactoring.getContext().add(
154: RetoucheUtils.getClasspathInfoFor(false, handle
155: .getFileObject()));
156: } else {
157: refactoring.getContext().add(
158: RetoucheUtils.getClasspathInfoFor(true, true,
159: RetoucheUtils.getFileObject(handle)));
160: }
161: dispOldName = oldName;
162:
163: //this(jmiObject, (FileObject) null, true);
164: }
165:
166: public RenameRefactoringUI(FileObject file, TreePathHandle handle,
167: CompilationInfo info) {
168: if (handle != null) {
169: this .handle = handle;
170: this .refactoring = new RenameRefactoring(Lookups.fixed(
171: file, handle));
172: oldName = handle.resolveElement(info).getSimpleName()
173: .toString();
174: } else {
175: this .refactoring = new RenameRefactoring(Lookups
176: .fixed(file));
177: oldName = file.getName();
178: }
179: dispOldName = oldName;
180: ClasspathInfo cpInfo = handle == null ? RetoucheUtils
181: .getClasspathInfoFor(file) : RetoucheUtils
182: .getClasspathInfoFor(handle);
183: refactoring.getContext().add(cpInfo);
184: //this(jmiObject, (FileObject) null, true);
185: }
186:
187: public RenameRefactoringUI(NonRecursiveFolder file) {
188: this .refactoring = new RenameRefactoring(Lookups
189: .singleton(file));
190: oldName = RetoucheUtils.getPackageName(file.getFolder());
191: refactoring.getContext().add(
192: RetoucheUtils.getClasspathInfoFor(file.getFolder()));
193: dispOldName = oldName;
194: pkgRename = true;
195: //this(jmiObject, (FileObject) null, true);
196: }
197:
198: // private MoveClassRefactoring createMoveClassRefactoring(FileObject folder, boolean packageRename) {
199: // return new MoveClassRefactoring(folder, packageRename);
200: // }
201:
202: RenameRefactoringUI(FileObject jmiObject, String newName,
203: TreePathHandle handle, CompilationInfo info) {
204: if (handle != null) {
205: this .refactoring = new RenameRefactoring(Lookups.fixed(
206: jmiObject, handle));
207: } else {
208: this .refactoring = new RenameRefactoring(Lookups
209: .fixed(jmiObject));
210: }
211: //this.jmiObject = jmiObject;
212: oldName = newName;
213: //[FIXME] this should be oldName of refactored object
214: this .dispOldName = newName;
215: ClasspathInfo cpInfo = handle == null ? RetoucheUtils
216: .getClasspathInfoFor(jmiObject) : RetoucheUtils
217: .getClasspathInfoFor(handle);
218: refactoring.getContext().add(cpInfo);
219: fromListener = true;
220: }
221:
222: RenameRefactoringUI(NonRecursiveFolder jmiObject, String newName) {
223: this .refactoring = new RenameRefactoring(Lookups
224: .singleton(jmiObject));
225: refactoring.getContext().add(
226: RetoucheUtils
227: .getClasspathInfoFor(jmiObject.getFolder()));
228: //this.jmiObject = jmiObject;
229: oldName = newName;
230: this .dispOldName = RetoucheUtils.getPackageName(jmiObject
231: .getFolder());
232: fromListener = true;
233: pkgRename = true;
234: }
235:
236: // RenameRefactoringUI(FileObject folder, String newName, boolean packageRename) {
237: // this.refactoring = createMoveClassRefactoring(folder, packageRename);
238: // pkgRename = packageRename;
239: // oldName = newName;
240: // //[FIXME] this should be oldName of refactored object
241: // this.dispOldName = newName;
242: // fromListener = true;
243: // this.byPassFolder = folder;
244: // this.byPassPakageRename = packageRename;
245: //
246: // }
247:
248: public boolean isQuery() {
249: return false;
250: }
251:
252: public CustomRefactoringPanel getPanel(ChangeListener parent) {
253: if (panel == null) {
254: String name = oldName;
255: String suffix = "";
256: if (handle != null) {
257: ElementKind kind = RetoucheUtils.getElementKind(handle);
258: if (kind.isClass() || kind.isInterface()) {
259: suffix = kind.isInterface() ? getString("LBL_Interface")
260: : getString("LBL_Class");
261: } else if (kind == ElementKind.METHOD) {
262: suffix = getString("LBL_Method");
263: } else if (kind == ElementKind.FIELD) {
264: suffix = getString("LBL_Field");
265: } else if (kind == ElementKind.LOCAL_VARIABLE) {
266: suffix = getString("LBL_LocalVar");
267: } else if (kind == ElementKind.PACKAGE
268: || (handle == null && fromListener)) {
269: suffix = pkgRename ? getString("LBL_Package")
270: : getString("LBL_Folder");
271: } else if (kind == ElementKind.PARAMETER) {
272: suffix = getString("LBL_Parameter");
273: }
274: }
275: suffix = suffix + " " + name; // NOI18N
276: panel = new RenamePanel(name, parent, NbBundle.getMessage(
277: RenamePanel.class, "LBL_Rename")
278: + " " + suffix, !fromListener, fromListener
279: && !byPassPakageRename);
280: }
281: return panel;
282: }
283:
284: private static String getString(String key) {
285: return NbBundle.getMessage(RenameRefactoringUI.class, key);
286: }
287:
288: public org.netbeans.modules.refactoring.api.Problem setParameters() {
289: newName = panel.getNameValue();
290: if (refactoring instanceof RenameRefactoring) {
291: ((RenameRefactoring) refactoring).setNewName(newName);
292: ((RenameRefactoring) refactoring).setSearchInComments(panel
293: .searchJavadoc());
294: }// else {
295: // ((MoveClassRefactoring) refactoring).setTargetPackageName(newName);
296: // }
297: return refactoring.checkParameters();
298: }
299:
300: public org.netbeans.modules.refactoring.api.Problem checkParameters() {
301: if (!panel.isUpdateReferences())
302: return null;
303: newName = panel.getNameValue();
304: if (refactoring instanceof RenameRefactoring) {
305: ((RenameRefactoring) refactoring).setNewName(newName);
306: }// else {
307: // ((MoveClassRefactoring) refactoring).setTargetPackageName(newName);
308: // }
309: return refactoring.fastCheckParameters();
310: }
311:
312: public org.netbeans.modules.refactoring.api.AbstractRefactoring getRefactoring() {
313: return refactoring;
314: }
315:
316: public String getDescription() {
317: return new MessageFormat(NbBundle.getMessage(RenamePanel.class,
318: "DSC_Rename")).format(new Object[] { dispOldName,
319: newName });
320: }
321:
322: public String getName() {
323: return NbBundle.getMessage(RenamePanel.class, "LBL_Rename");
324: }
325:
326: public boolean hasParameters() {
327: return true;
328: }
329:
330: public HelpCtx getHelpCtx() {
331: String postfix;
332: if (handle == null) {
333: postfix = ".JavaPackage";//NOI18N
334: } else {
335: ElementKind k = RetoucheUtils.getElementKind(handle);
336:
337: if (k.isClass() || k.isInterface())
338: postfix = ".JavaClass";//NOI18N
339: else if (k == ElementKind.METHOD)
340: postfix = ".Method";//NOI18N
341: else if (k.isField())
342: postfix = ".Field";//NOI18N
343: else
344: postfix = "";
345: }
346:
347: return new HelpCtx(RenameRefactoringUI.class.getName()
348: + postfix);
349: }
350:
351: public boolean isRefactoringBypassRequired() {
352: return !panel.isUpdateReferences();
353: }
354:
355: public void doRefactoringBypass() throws IOException {
356: DataObject dob = null;
357: if (byPassFolder != null) {
358: dob = DataFolder.findFolder(byPassFolder);
359: } else {
360: FileObject fob = refactoring.getRefactoringSource().lookup(
361: FileObject.class);
362: if (fob != null) {
363: dob = DataObject.find(refactoring
364: .getRefactoringSource()
365: .lookup(FileObject.class));
366: }
367: }
368: if (dob != null) {
369: dob.rename(panel.getNameValue());
370: } else {
371: NonRecursiveFolder pack = refactoring
372: .getRefactoringSource().lookup(
373: NonRecursiveFolder.class);
374: if (pack != null) {
375: renamePackage(pack.getFolder(), panel.getNameValue());
376: }
377: }
378: }
379:
380: private void renamePackage(FileObject source, String name) {
381: //copy/paste from PackageNode.setName()
382: FileObject root = ClassPath.getClassPath(source,
383: ClassPath.SOURCE).findOwnerRoot(source);
384:
385: name = name.replace('.', '/') + '/'; //NOI18N
386: String oldName = dispOldName.replace('.', '/') + '/'; //NOI18N
387: int i;
388: for (i = 0; i < oldName.length() && i < name.length(); i++) {
389: if (oldName.charAt(i) != name.charAt(i)) {
390: break;
391: }
392: }
393: i--;
394: int index = oldName.lastIndexOf('/', i); //NOI18N
395: String commonPrefix = index == -1 ? null : oldName.substring(0,
396: index);
397: String toCreate = (index + 1 == name.length()) ? "" : name
398: .substring(index + 1); //NOI18N
399: try {
400: FileObject commonFolder = commonPrefix == null ? root
401: : root.getFileObject(commonPrefix);
402: FileObject destination = commonFolder;
403: StringTokenizer dtk = new StringTokenizer(toCreate, "/"); //NOI18N
404: while (dtk.hasMoreTokens()) {
405: String pathElement = dtk.nextToken();
406: FileObject tmp = destination.getFileObject(pathElement);
407: if (tmp == null) {
408: tmp = destination.createFolder(pathElement);
409: }
410: destination = tmp;
411: }
412: DataFolder sourceFolder = DataFolder.findFolder(source);
413: DataFolder destinationFolder = DataFolder
414: .findFolder(destination);
415: DataObject[] children = sourceFolder.getChildren();
416: for (int j = 0; j < children.length; j++) {
417: if (children[j].getPrimaryFile().isData()) {
418: children[j].move(destinationFolder);
419: }
420: }
421: while (!commonFolder.equals(source)) {
422: if (source.getChildren().length == 0) {
423: FileObject tmp = source;
424: source = source.getParent();
425: tmp.delete();
426: } else {
427: break;
428: }
429: }
430: } catch (IOException ioe) {
431: ErrorManager.getDefault().notify(ioe);
432: }
433: }
434: }
|