0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * The Original Software is NetBeans. The Initial Developer of the Original
0027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
0028: * Microsystems, Inc. All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: */
0041:
0042: package org.netbeans.modules.refactoring.java.ui;
0043:
0044: import com.sun.source.tree.CompilationUnitTree;
0045: import com.sun.source.tree.Tree;
0046: import com.sun.source.util.TreePath;
0047: import java.awt.datatransfer.Transferable;
0048: import java.io.IOException;
0049: import java.lang.ref.WeakReference;
0050: import java.util.ArrayList;
0051: import java.util.Arrays;
0052: import java.util.Collection;
0053: import java.util.Collections;
0054: import java.util.Enumeration;
0055: import java.util.HashSet;
0056: import java.util.List;
0057: import java.util.Set;
0058: import javax.lang.model.element.Element;
0059: import javax.lang.model.element.ElementKind;
0060: import javax.lang.model.element.Modifier;
0061: import javax.lang.model.element.TypeElement;
0062: import javax.swing.Action;
0063: import javax.swing.JOptionPane;
0064: import javax.swing.text.JTextComponent;
0065: import org.netbeans.api.fileinfo.NonRecursiveFolder;
0066: import org.netbeans.api.java.source.CancellableTask;
0067: import org.netbeans.api.java.source.CompilationController;
0068: import org.netbeans.api.java.source.CompilationInfo;
0069: import org.netbeans.api.java.source.JavaSource;
0070: import org.netbeans.api.java.source.JavaSource.Phase;
0071: import org.netbeans.api.java.source.SourceUtils;
0072: import org.netbeans.api.java.source.TreePathHandle;
0073: import org.netbeans.modules.refactoring.api.ui.ExplorerContext;
0074: import org.netbeans.modules.refactoring.api.ui.RefactoringActionsFactory;
0075: import org.netbeans.modules.refactoring.java.RetoucheUtils;
0076: import org.netbeans.modules.refactoring.java.RetoucheUtils;
0077: import org.netbeans.modules.refactoring.spi.ui.UI;
0078: import org.netbeans.modules.refactoring.spi.ui.ActionsImplementationProvider;
0079: import org.netbeans.modules.refactoring.spi.ui.RefactoringUI;
0080: import org.openide.ErrorManager;
0081: import org.openide.cookies.EditorCookie;
0082: import org.openide.filesystems.FileObject;
0083: import org.openide.filesystems.FileUtil;
0084: import org.openide.loaders.DataFolder;
0085: import org.openide.loaders.DataObject;
0086: import org.openide.loaders.DataObjectNotFoundException;
0087: import org.openide.nodes.Node;
0088: import org.openide.text.CloneableEditorSupport;
0089: import org.openide.util.Exceptions;
0090: import org.openide.util.Lookup;
0091: import org.openide.util.NbBundle;
0092: import org.openide.util.datatransfer.PasteType;
0093: import org.openide.windows.TopComponent;
0094:
0095: /**
0096: *
0097: * @author Jan Becicka
0098: */
0099: public class RefactoringActionsProvider extends
0100: ActionsImplementationProvider {
0101:
0102: /** Creates a new instance of RefactoringActionsProvider */
0103: public RefactoringActionsProvider() {
0104: }
0105:
0106: @Override
0107: public void doRename(final Lookup lookup) {
0108: Runnable task;
0109: EditorCookie ec = lookup.lookup(EditorCookie.class);
0110: if (isFromEditor(ec)) {
0111: task = new TextComponentTask(ec) {
0112: @Override
0113: protected RefactoringUI createRefactoringUI(
0114: TreePathHandle selectedElement,
0115: int startOffset, int endOffset,
0116: final CompilationInfo info) {
0117: Element selected = selectedElement
0118: .resolveElement(info);
0119: if (selected == null)
0120: return null;
0121: if (selected.getKind() == ElementKind.CONSTRUCTOR) {
0122: selected = selected.getEnclosingElement();
0123: selectedElement = TreePathHandle.create(info
0124: .getTrees().getPath(selected), info);
0125: }
0126: if (selected.getKind() == ElementKind.PACKAGE) {
0127: NonRecursiveFolder folder = new NonRecursiveFolder() {
0128: public FileObject getFolder() {
0129: return info.getFileObject().getParent();
0130: }
0131: };
0132: return new RenameRefactoringUI(folder);
0133: } else if (selected instanceof TypeElement
0134: && !((TypeElement) selected)
0135: .getNestingKind().isNested()) {
0136: FileObject f = SourceUtils.getFile(selected,
0137: info.getClasspathInfo());
0138: if (f != null
0139: && selected.getSimpleName().toString()
0140: .equals(f.getName())) {
0141: return new RenameRefactoringUI(
0142: f == null ? info.getFileObject()
0143: : f, selectedElement, info);
0144: } else {
0145: return new RenameRefactoringUI(
0146: selectedElement, info);
0147: }
0148: } else {
0149: return new RenameRefactoringUI(selectedElement,
0150: info);
0151: }
0152: }
0153: };
0154: } else if (nodeHandle(lookup)) {
0155: task = new TreePathHandleTask(new HashSet(lookup
0156: .lookupAll(Node.class))) {
0157:
0158: @Override
0159: protected RefactoringUI createRefactoringUI(
0160: Collection<TreePathHandle> handles,
0161: CompilationInfo cinfo) {
0162: if (renameFile) {
0163: return new RenameRefactoringUI(handles
0164: .iterator().next().getFileObject(),
0165: handles.iterator().next(), cinfo);
0166: } else {
0167: return new RenameRefactoringUI(handles
0168: .iterator().next(), cinfo);
0169: }
0170: }
0171:
0172: };
0173: } else {
0174: task = new NodeToFileObjectTask(new HashSet(lookup
0175: .lookupAll(Node.class))) {
0176: @Override
0177: protected RefactoringUI createRefactoringUI(
0178: FileObject[] selectedElements,
0179: Collection<TreePathHandle> handles) {
0180: String newName = getName(lookup);
0181: if (newName != null) {
0182: if (pkg[0] != null)
0183: return new RenameRefactoringUI(pkg[0],
0184: newName);
0185: else
0186: return new RenameRefactoringUI(
0187: selectedElements[0],
0188: newName,
0189: handles == null
0190: || handles.isEmpty() ? null
0191: : handles.iterator().next(),
0192: cinfo == null ? null : cinfo.get());
0193: } else if (pkg[0] != null)
0194: return new RenameRefactoringUI(pkg[0]);
0195: else
0196: return new RenameRefactoringUI(
0197: selectedElements[0], handles == null
0198: || handles.isEmpty() ? null
0199: : handles.iterator().next(),
0200: cinfo == null ? null : cinfo.get());
0201: }
0202: };
0203: }
0204: RetoucheUtils
0205: .invokeAfterScanFinished(task,
0206: getActionName(RefactoringActionsFactory
0207: .renameAction()));
0208: }
0209:
0210: static String getActionName(Action action) {
0211: String arg = (String) action.getValue(Action.NAME);
0212: arg = org.openide.util.Utilities.replaceString(arg, "&", ""); // NOI18N
0213: return org.openide.util.Utilities.replaceString(arg, "...", ""); // NOI18N
0214: }
0215:
0216: /**
0217: * returns true if exactly one refactorable file is selected
0218: */
0219: @Override
0220: public boolean canRename(Lookup lookup) {
0221: Collection<? extends Node> nodes = new HashSet(lookup
0222: .lookupAll(Node.class));
0223: if (nodes.size() != 1) {
0224: return false;
0225: }
0226: Node n = nodes.iterator().next();
0227: if (n.getLookup().lookup(TreePathHandle.class) != null) {
0228: return true;
0229: }
0230: DataObject dob = n.getCookie(DataObject.class);
0231: if (dob == null) {
0232: return false;
0233: }
0234: FileObject fo = dob.getPrimaryFile();
0235: if (RetoucheUtils.isRefactorable(fo)) { //NOI18N
0236: return true;
0237: }
0238: if ((dob instanceof DataFolder)
0239: && RetoucheUtils.isFileInOpenProject(fo)
0240: && RetoucheUtils.isOnSourceClasspath(fo)
0241: && !RetoucheUtils.isClasspathRoot(fo))
0242: return true;
0243: return false;
0244: }
0245:
0246: @Override
0247: public void doCopy(final Lookup lookup) {
0248: Runnable task;
0249: EditorCookie ec = lookup.lookup(EditorCookie.class);
0250: // if (isFromEditor(ec)) {
0251: // return new TextComponentRunnable(ec) {
0252: // @Override
0253: // protected RefactoringUI createRefactoringUI(TreePathHandle selectedElement,int startOffset,int endOffset, CompilationInfo info) {
0254: // Element selected = selectedElement.resolveElement(info);
0255: // if (selected.getKind() == ElementKind.PACKAGE || selected.getEnclosingElement().getKind() == ElementKind.PACKAGE) {
0256: // FileObject f = SourceUtils.getFile(selected, info.getClasspathInfo());
0257: // return new RenameRefactoringUI(f==null?info.getFileObject():f);
0258: // } else {
0259: // return new RenameRefactoringUI(selectedElement, info);
0260: // }
0261: // }
0262: // };
0263: // } else {
0264: task = new NodeToFileObjectTask(new HashSet(lookup
0265: .lookupAll(Node.class))) {
0266: @Override
0267: protected RefactoringUI createRefactoringUI(
0268: FileObject[] selectedElements,
0269: Collection<TreePathHandle> handle) {
0270: return new CopyClassRefactoringUI(selectedElements[0],
0271: getTarget(lookup), getPaste(lookup));
0272: }
0273: };
0274: // }
0275: RetoucheUtils.invokeAfterScanFinished(task,
0276: getActionName(RefactoringActionsFactory.copyAction()));
0277: }
0278:
0279: /**
0280: * returns true if exactly one refactorable file is selected
0281: */
0282: @Override
0283: public boolean canCopy(Lookup lookup) {
0284: Collection<? extends Node> nodes = new HashSet(lookup
0285: .lookupAll(Node.class));
0286: if (nodes.size() != 1) {
0287: return false;
0288: }
0289: Node n = nodes.iterator().next();
0290: DataObject dob = n.getCookie(DataObject.class);
0291: if (dob == null) {
0292: return false;
0293: }
0294:
0295: ExplorerContext dict = lookup.lookup(ExplorerContext.class);
0296: FileObject fob = getTarget(lookup);
0297: if (dict != null && dict.getTargetNode() != null && fob == null) { //NOI18N
0298: //unknown target
0299: return false;
0300: }
0301: if (fob != null) {
0302: if (!fob.isFolder())
0303: return false;
0304: if (!RetoucheUtils.isOnSourceClasspath(fob))
0305: return false;
0306:
0307: FileObject fo = dob.getPrimaryFile();
0308: if (RetoucheUtils.isRefactorable(fo)) { //NOI18N
0309: return true;
0310: }
0311:
0312: } else {
0313: FileObject fo = dob.getPrimaryFile();
0314: if (RetoucheUtils.isRefactorable(fo)) { //NOI18N
0315: return true;
0316: }
0317: }
0318:
0319: return false;
0320: }
0321:
0322: @Override
0323: public boolean canFindUsages(Lookup lookup) {
0324: Collection<? extends Node> nodes = new HashSet(lookup
0325: .lookupAll(Node.class));
0326: if (nodes.size() != 1) {
0327: return false;
0328: }
0329: Node n = nodes.iterator().next();
0330: if (n.getLookup().lookup(TreePathHandle.class) != null) {
0331: return true;
0332: }
0333: DataObject dob = n.getCookie(DataObject.class);
0334: if ((dob != null)
0335: && RetoucheUtils.isJavaFile(dob.getPrimaryFile())
0336: && !"package-info".equals(dob.getName())) { //NOI18N
0337: return true;
0338: }
0339: return false;
0340: }
0341:
0342: @Override
0343: public void doFindUsages(Lookup lookup) {
0344: Runnable task;
0345: EditorCookie ec = lookup.lookup(EditorCookie.class);
0346: if (isFromEditor(ec)) {
0347: task = new TextComponentTask(ec) {
0348: @Override
0349: protected RefactoringUI createRefactoringUI(
0350: TreePathHandle selectedElement,
0351: int startOffset, int endOffset,
0352: CompilationInfo info) {
0353: return new WhereUsedQueryUI(selectedElement, info);
0354: }
0355: };
0356: } else if (nodeHandle(lookup)) {
0357: task = new TreePathHandleTask(new HashSet(lookup
0358: .lookupAll(Node.class))) {
0359:
0360: @Override
0361: protected RefactoringUI createRefactoringUI(
0362: Collection<TreePathHandle> handles,
0363: CompilationInfo cinfo) {
0364: return new WhereUsedQueryUI(handles.iterator()
0365: .next(), cinfo);
0366: }
0367:
0368: };
0369: } else {
0370: task = new NodeToElementTask(new HashSet(lookup
0371: .lookupAll(Node.class))) {
0372: protected RefactoringUI createRefactoringUI(
0373: TreePathHandle selectedElement,
0374: CompilationInfo info) {
0375: if (selectedElement == null)
0376: return null;
0377: return new WhereUsedQueryUI(selectedElement, info);
0378: }
0379: };
0380: }
0381: RetoucheUtils.invokeAfterScanFinished(task,
0382: getActionName(RefactoringActionsFactory
0383: .whereUsedAction()));
0384: }
0385:
0386: /**
0387: * returns true iff all selected file are refactorable java files
0388: **/
0389:
0390: @Override
0391: public boolean canDelete(Lookup lookup) {
0392: Collection<? extends Node> nodes = new HashSet(lookup
0393: .lookupAll(Node.class));
0394: //We live with a 2 pass validation of the selected nodes for now since
0395: //the code will become unreadable if we attempt to implement all checks
0396: //in one pass.
0397: if (multiplePkgsSelected(nodes)) {
0398: return false;
0399: }
0400: for (Node n : nodes) {
0401: if (n.getLookup().lookup(TreePathHandle.class) != null) {
0402: return true;
0403: }
0404: DataObject dataObject = n.getCookie(DataObject.class);
0405: if (dataObject == null) {
0406: return false;
0407: }
0408: FileObject fileObject = dataObject.getPrimaryFile();
0409: if (isRefactorableFolder(dataObject)
0410: && containsJavaFile(fileObject)) {
0411: return true;
0412: }
0413: if (!RetoucheUtils.isRefactorable(fileObject)) {
0414: return false;
0415: }
0416: }
0417: return !nodes.isEmpty();
0418: }
0419:
0420: @Override
0421: public void doDelete(final Lookup lookup) {
0422: Runnable task;
0423: EditorCookie ec = lookup.lookup(EditorCookie.class);
0424: final boolean b = lookup.lookup(ExplorerContext.class) != null;
0425: if (isFromEditor(ec)) {
0426: task = new TextComponentTask(ec) {
0427: @Override
0428: protected RefactoringUI createRefactoringUI(
0429: TreePathHandle selectedElement,
0430: int startOffset, int endOffset,
0431: CompilationInfo info) {
0432: Element selected = selectedElement
0433: .resolveElement(info);
0434: if (selected.getKind() == ElementKind.PACKAGE
0435: || selected.getEnclosingElement().getKind() == ElementKind.PACKAGE) {
0436: FileObject file = SourceUtils.getFile(selected,
0437: info.getClasspathInfo());
0438: if (file == null) {
0439: return null;
0440: }
0441: if (file.getName().equals(
0442: selected.getSimpleName().toString())) {
0443: return new SafeDeleteUI(
0444: new FileObject[] { file },
0445: Collections
0446: .singleton(selectedElement),
0447: b);
0448: }
0449: }
0450: return new SafeDeleteUI(
0451: new TreePathHandle[] { selectedElement },
0452: info);
0453: }
0454: };
0455: } else if (nodeHandle(lookup)) {
0456: task = new TreePathHandleTask(new HashSet(lookup
0457: .lookupAll(Node.class))) {
0458:
0459: @Override
0460: protected RefactoringUI createRefactoringUI(
0461: Collection<TreePathHandle> handles,
0462: CompilationInfo cinfo) {
0463: if (renameFile) {
0464: FileObject[] files = new FileObject[handles
0465: .size()];
0466: int i = 0;
0467: for (TreePathHandle handle : handles) {
0468: files[i++] = handle.getFileObject();
0469: }
0470: return new SafeDeleteUI(files, handles, b);
0471: } else {
0472: return new SafeDeleteUI(handles
0473: .toArray(new TreePathHandle[handles
0474: .size()]), cinfo);
0475: }
0476: }
0477:
0478: };
0479: } else if (isPackageSelected(lookup)) {
0480: task = new PackagetoTreePathHandleTask(lookup
0481: .lookupAll(Node.class)) {
0482: @Override
0483: protected RefactoringUI createRefactoringUI(
0484: Collection<TreePathHandle> handles,
0485: CompilationInfo cinfo) {
0486: if (handles.isEmpty()) {
0487: return new SafeDeleteUI(getFileHandles(),
0488: handles, true);
0489: } else {
0490: return new SafeDeleteUI(getFileHandles(),
0491: handles, b);
0492: }
0493: }
0494: };
0495: } else {
0496: task = new NodeToFileObjectTask(new HashSet(lookup
0497: .lookupAll(Node.class))) {
0498: @Override
0499: protected RefactoringUI createRefactoringUI(
0500: FileObject[] selectedElements,
0501: Collection<TreePathHandle> handles) {
0502: return new SafeDeleteUI(selectedElements, handles,
0503: b);
0504: }
0505:
0506: };
0507: }
0508: RetoucheUtils.invokeAfterScanFinished(task,
0509: getActionName(RefactoringActionsFactory
0510: .safeDeleteAction()));
0511: }
0512:
0513: private FileObject getTarget(Lookup look) {
0514: ExplorerContext drop = look.lookup(ExplorerContext.class);
0515: if (drop == null)
0516: return null;
0517: Node n = (Node) drop.getTargetNode();
0518: if (n == null)
0519: return null;
0520: DataObject dob = n.getCookie(DataObject.class);
0521: if (dob != null)
0522: return dob.getPrimaryFile();
0523: return null;
0524: }
0525:
0526: private PasteType getPaste(Lookup look) {
0527: ExplorerContext drop = look.lookup(ExplorerContext.class);
0528: if (drop == null)
0529: return null;
0530: Transferable orig = drop.getTransferable();
0531: if (orig == null)
0532: return null;
0533: Node n = drop.getTargetNode();
0534: if (n == null)
0535: return null;
0536: PasteType[] pt = n.getPasteTypes(orig);
0537: if (pt.length == 1) {
0538: return null;
0539: }
0540: return pt[1];
0541: }
0542:
0543: static String getName(Lookup look) {
0544: ExplorerContext ren = look.lookup(ExplorerContext.class);
0545: if (ren == null)
0546: return null;
0547: return ren.getNewName(); //NOI18N
0548: }
0549:
0550: /**
0551: * returns true if there is at least one java file in the selection
0552: * and all java files are refactorable
0553: */
0554: @Override
0555: public boolean canMove(Lookup lookup) {
0556: Collection<? extends Node> nodes = new HashSet(lookup
0557: .lookupAll(Node.class));
0558: ExplorerContext drop = lookup.lookup(ExplorerContext.class);
0559: FileObject fo = getTarget(lookup);
0560: if (fo != null) {
0561: if (!fo.isFolder())
0562: return false;
0563: if (!RetoucheUtils.isOnSourceClasspath(fo))
0564: return false;
0565:
0566: //it is drag and drop
0567: Set<DataFolder> folders = new HashSet<DataFolder>();
0568: boolean jdoFound = false;
0569: for (Node n : nodes) {
0570: DataObject dob = n.getCookie(DataObject.class);
0571: if (dob == null) {
0572: return false;
0573: }
0574: if (!RetoucheUtils.isOnSourceClasspath(dob
0575: .getPrimaryFile())) {
0576: return false;
0577: }
0578: if (dob instanceof DataFolder) {
0579: if (FileUtil.getRelativePath(dob.getPrimaryFile(),
0580: fo) != null)
0581: return false;
0582: folders.add((DataFolder) dob);
0583: } else if (RetoucheUtils.isJavaFile(dob
0584: .getPrimaryFile())) {
0585: jdoFound = true;
0586: }
0587: }
0588: if (jdoFound)
0589: return true;
0590: for (DataFolder fold : folders) {
0591: for (Enumeration<DataObject> e = (fold).children(true); e
0592: .hasMoreElements();) {
0593: if (RetoucheUtils.isJavaFile(e.nextElement()
0594: .getPrimaryFile())) {
0595: return true;
0596: }
0597: }
0598: }
0599: return false;
0600: } else {
0601: //regular invokation
0602: boolean result = false;
0603: for (Node n : nodes) {
0604: DataObject dob = n.getCookie(DataObject.class);
0605: if (dob == null) {
0606: return false;
0607: }
0608: if (dob instanceof DataFolder) {
0609: return drop != null;
0610: }
0611: if (!RetoucheUtils.isOnSourceClasspath(dob
0612: .getPrimaryFile())) {
0613: return false;
0614: }
0615: if (RetoucheUtils.isJavaFile(dob.getPrimaryFile())) {
0616: result = true;
0617: }
0618: }
0619: return result;
0620: }
0621: }
0622:
0623: @Override
0624: public void doMove(final Lookup lookup) {
0625: Runnable task;
0626: EditorCookie ec = lookup.lookup(EditorCookie.class);
0627: if (isFromEditor(ec)) {
0628: task = new TextComponentTask(ec) {
0629: @Override
0630: protected RefactoringUI createRefactoringUI(
0631: TreePathHandle selectedElement,
0632: int startOffset, int endOffset,
0633: CompilationInfo info) {
0634: Element e = selectedElement.resolveElement(info);
0635: if ((e.getKind().isClass() || e.getKind()
0636: .isInterface())
0637: && SourceUtils
0638: .getOutermostEnclosingTypeElement(e) == e) {
0639: try {
0640: FileObject fo = SourceUtils.getFile(e, info
0641: .getClasspathInfo());
0642: if (fo != null) {
0643: DataObject d = DataObject
0644: .find(SourceUtils
0645: .getFile(
0646: e,
0647: info
0648: .getClasspathInfo()));
0649: if (d.getName().equals(
0650: e.getSimpleName().toString())) {
0651: return new MoveClassUI(d);
0652: }
0653: }
0654: } catch (DataObjectNotFoundException ex) {
0655: throw (RuntimeException) new RuntimeException()
0656: .initCause(ex);
0657: }
0658: }
0659: if (selectedElement.resolve(info).getLeaf()
0660: .getKind() == Tree.Kind.COMPILATION_UNIT) {
0661: try {
0662: return new MoveClassUI(DataObject.find(info
0663: .getFileObject()));
0664: } catch (DataObjectNotFoundException ex) {
0665: throw (RuntimeException) new RuntimeException()
0666: .initCause(ex);
0667: }
0668: } else {
0669: try {
0670: return new MoveClassUI(DataObject.find(info
0671: .getFileObject()));
0672: } catch (DataObjectNotFoundException ex) {
0673: throw (RuntimeException) new RuntimeException()
0674: .initCause(ex);
0675: }
0676: }
0677: }
0678: };
0679: } else {
0680: task = new NodeToFileObjectTask(new HashSet(lookup
0681: .lookupAll(Node.class))) {
0682: @Override
0683: protected RefactoringUI createRefactoringUI(
0684: FileObject[] selectedElements,
0685: Collection<TreePathHandle> handles) {
0686: PasteType paste = getPaste(lookup);
0687: FileObject tar = getTarget(lookup);
0688: if (selectedElements.length == 1) {
0689: if (!selectedElements[0].isFolder()) {
0690: try {
0691: return new MoveClassUI(DataObject
0692: .find(selectedElements[0]),
0693: tar, paste, handles);
0694: } catch (DataObjectNotFoundException ex) {
0695: throw (RuntimeException) new RuntimeException()
0696: .initCause(ex);
0697: }
0698: } else {
0699: Set s = new HashSet();
0700: s.addAll(Arrays.asList(selectedElements));
0701: return new MoveClassesUI(s, tar, paste);
0702: }
0703: } else {
0704: Set s = new HashSet();
0705: s.addAll(Arrays.asList(selectedElements));
0706: return new MoveClassesUI(s, tar, paste);
0707: }
0708: }
0709:
0710: };
0711: }
0712: RetoucheUtils
0713: .invokeAfterScanFinished(task,
0714: getActionName(RefactoringActionsFactory
0715: .renameAction()));
0716: }
0717:
0718: public static abstract class TreePathHandleTask implements
0719: Runnable, CancellableTask<CompilationController> {
0720: public CompilationInfo cinfo;
0721: private Collection<TreePathHandle> handles = new ArrayList<TreePathHandle>();
0722: private TreePathHandle current;
0723: boolean renameFile;
0724:
0725: public TreePathHandleTask(Collection<? extends Node> nodes) {
0726: for (Node n : nodes) {
0727: TreePathHandle temp = n.getLookup().lookup(
0728: TreePathHandle.class);
0729: if (temp != null) {
0730: handles.add(temp);
0731: }
0732: }
0733: }
0734:
0735: public void cancel() {
0736: }
0737:
0738: public void run(CompilationController info) throws Exception {
0739: cinfo = info;
0740: Element el = current.resolveElement(cinfo);
0741: if (el != null && el instanceof TypeElement
0742: && !((TypeElement) el).getNestingKind().isNested()) {
0743: if (info.getFileObject().getName().equals(
0744: el.getSimpleName().toString())) {
0745: renameFile = true;
0746: }
0747: }
0748: }
0749:
0750: public void run() {
0751: for (TreePathHandle handle : handles) {
0752: FileObject f = handle.getFileObject();
0753: current = handle;
0754: JavaSource source = JavaSource.forFileObject(f);
0755: assert source != null;
0756: try {
0757: source.runUserActionTask(this , false);
0758: } catch (IllegalArgumentException ex) {
0759: ex.printStackTrace();
0760: } catch (IOException ex) {
0761: ex.printStackTrace();
0762: }
0763: }
0764:
0765: TopComponent activetc = TopComponent.getRegistry()
0766: .getActivated();
0767:
0768: RefactoringUI ui = createRefactoringUI(handles, cinfo);
0769: if (ui != null) {
0770: UI.openRefactoringUI(ui, activetc);
0771: } else {
0772: JOptionPane.showMessageDialog(null, NbBundle
0773: .getMessage(RefactoringActionsProvider.class,
0774: "ERR_CannotRenameKeyword"));
0775: }
0776: }
0777:
0778: protected abstract RefactoringUI createRefactoringUI(
0779: Collection<TreePathHandle> handles, CompilationInfo info);
0780: }
0781:
0782: public static abstract class TextComponentTask implements Runnable,
0783: CancellableTask<CompilationController> {
0784: private JTextComponent textC;
0785: private int caret;
0786: private int start;
0787: private int end;
0788: private RefactoringUI ui;
0789:
0790: public TextComponentTask(EditorCookie ec) {
0791: this .textC = ec.getOpenedPanes()[0];
0792: this .caret = textC.getCaretPosition();
0793: this .start = textC.getSelectionStart();
0794: this .end = textC.getSelectionEnd();
0795: assert caret != -1;
0796: assert start != -1;
0797: assert end != -1;
0798: }
0799:
0800: public void cancel() {
0801: }
0802:
0803: public void run(CompilationController cc) throws Exception {
0804: TreePath selectedElement = null;
0805: cc.toPhase(Phase.RESOLVED);
0806: selectedElement = cc.getTreeUtilities().pathFor(caret);
0807: //workaround for issue 89064
0808: if (selectedElement.getLeaf().getKind() == Tree.Kind.COMPILATION_UNIT) {
0809: List<? extends Tree> decls = cc.getCompilationUnit()
0810: .getTypeDecls();
0811: if (!decls.isEmpty()) {
0812: selectedElement = TreePath.getPath(cc
0813: .getCompilationUnit(), decls.get(0));
0814: }
0815: }
0816: ui = createRefactoringUI(TreePathHandle.create(
0817: selectedElement, cc), start, end, cc);
0818: }
0819:
0820: public final void run() {
0821: try {
0822: JavaSource source = JavaSource.forDocument(textC
0823: .getDocument());
0824: source.runUserActionTask(this , false);
0825: } catch (IOException ioe) {
0826: ErrorManager.getDefault().notify(ioe);
0827: return;
0828: }
0829: TopComponent activetc = TopComponent.getRegistry()
0830: .getActivated();
0831:
0832: if (ui != null) {
0833: UI.openRefactoringUI(ui, activetc);
0834: } else {
0835: JOptionPane.showMessageDialog(null, NbBundle
0836: .getMessage(RefactoringActionsProvider.class,
0837: "ERR_CannotRenameKeyword"));
0838: }
0839: }
0840:
0841: protected abstract RefactoringUI createRefactoringUI(
0842: TreePathHandle selectedElement, int startOffset,
0843: int endOffset, CompilationInfo info);
0844: }
0845:
0846: public static abstract class NodeToElementTask implements Runnable,
0847: CancellableTask<CompilationController> {
0848: private Node node;
0849: private RefactoringUI ui;
0850:
0851: public NodeToElementTask(Collection<? extends Node> nodes) {
0852: assert nodes.size() == 1;
0853: this .node = nodes.iterator().next();
0854: }
0855:
0856: public void cancel() {
0857: }
0858:
0859: public void run(CompilationController info) throws Exception {
0860: info.toPhase(Phase.ELEMENTS_RESOLVED);
0861: CompilationUnitTree unit = info.getCompilationUnit();
0862: if (unit.getTypeDecls().isEmpty()) {
0863: ui = createRefactoringUI(null, info);
0864: } else {
0865: TreePathHandle representedObject = TreePathHandle
0866: .create(TreePath.getPath(unit, unit
0867: .getTypeDecls().get(0)), info);
0868: ui = createRefactoringUI(representedObject, info);
0869: }
0870: }
0871:
0872: public final void run() {
0873: DataObject o = node.getCookie(DataObject.class);
0874: JavaSource source = JavaSource.forFileObject(o
0875: .getPrimaryFile());
0876: assert source != null;
0877: try {
0878: source.runUserActionTask(this , false);
0879: } catch (IllegalArgumentException ex) {
0880: ex.printStackTrace();
0881: } catch (IOException ex) {
0882: ex.printStackTrace();
0883: }
0884: if (ui != null) {
0885: UI.openRefactoringUI(ui);
0886: } else {
0887: JOptionPane.showMessageDialog(null, NbBundle
0888: .getMessage(RefactoringActionsProvider.class,
0889: "ERR_NoTypeDecls"));
0890: }
0891: }
0892:
0893: protected abstract RefactoringUI createRefactoringUI(
0894: TreePathHandle selectedElement, CompilationInfo info);
0895: }
0896:
0897: public static abstract class NodeToFileObjectTask implements
0898: Runnable, CancellableTask<CompilationController> {
0899: private Collection<? extends Node> nodes;
0900: public NonRecursiveFolder pkg[];
0901: public WeakReference<CompilationInfo> cinfo;
0902: Collection<TreePathHandle> handles = new ArrayList<TreePathHandle>();
0903:
0904: public NodeToFileObjectTask(Collection<? extends Node> nodes) {
0905: this .nodes = nodes;
0906: }
0907:
0908: public void cancel() {
0909: }
0910:
0911: public void run(CompilationController info) throws Exception {
0912: info.toPhase(Phase.ELEMENTS_RESOLVED);
0913: CompilationUnitTree unit = info.getCompilationUnit();
0914: Collection<TreePathHandle> publicHandles = new ArrayList<TreePathHandle>();
0915: Collection<TreePathHandle> sameNameHandles = new ArrayList<TreePathHandle>();
0916: for (Tree t : unit.getTypeDecls()) {
0917: Element e = info.getTrees().getElement(
0918: TreePath.getPath(unit, t));
0919: if (e == null
0920: || !(e.getKind().isClass() || e.getKind()
0921: .isInterface())) {
0922: // syntax errors #111195
0923: continue;
0924: }
0925: if (e.getSimpleName().toString().equals(
0926: info.getFileObject().getName())) {
0927: TreePathHandle representedObject = TreePathHandle
0928: .create(TreePath.getPath(unit, t), info);
0929: sameNameHandles.add(representedObject);
0930: }
0931: if (e.getModifiers().contains(Modifier.PUBLIC)) {
0932: TreePathHandle representedObject = TreePathHandle
0933: .create(TreePath.getPath(unit, t), info);
0934: publicHandles.add(representedObject);
0935: }
0936: }
0937: if (!publicHandles.isEmpty()) {
0938: handles.addAll(publicHandles);
0939: } else {
0940: handles.addAll(sameNameHandles);
0941: }
0942: cinfo = new WeakReference<CompilationInfo>(info);
0943: }
0944:
0945: public void run() {
0946: FileObject[] fobs = new FileObject[nodes.size()];
0947: pkg = new NonRecursiveFolder[fobs.length];
0948: int i = 0;
0949: for (Node node : nodes) {
0950: DataObject dob = node.getCookie(DataObject.class);
0951: if (dob != null) {
0952: fobs[i] = dob.getPrimaryFile();
0953: if (RetoucheUtils.isJavaFile(fobs[i])) {
0954: JavaSource source = JavaSource
0955: .forFileObject(fobs[i]);
0956: assert source != null;
0957: try {
0958: source.runUserActionTask(this , false);
0959: } catch (IllegalArgumentException ex) {
0960: ex.printStackTrace();
0961: } catch (IOException ex) {
0962: ex.printStackTrace();
0963: }
0964: }
0965:
0966: pkg[i++] = node.getLookup().lookup(
0967: NonRecursiveFolder.class);
0968: }
0969: }
0970: RefactoringUI ui = createRefactoringUI(fobs, handles);
0971: if (ui != null) {
0972: UI.openRefactoringUI(ui);
0973: } else {
0974: JOptionPane.showMessageDialog(null, NbBundle
0975: .getMessage(RefactoringActionsProvider.class,
0976: "ERR_NoTypeDecls"));
0977: }
0978: }
0979:
0980: protected abstract RefactoringUI createRefactoringUI(
0981: FileObject[] selectedElement,
0982: Collection<TreePathHandle> handles);
0983: }
0984:
0985: private static boolean isPackageSelected(Lookup lookup) {
0986: Node node = lookup.lookup(Node.class);
0987: if (node != null) {
0988: DataObject dataObject = node.getLookup().lookup(
0989: DataObject.class);
0990: if (dataObject == null) {
0991: return false;
0992: }
0993:
0994: FileObject fileObject = dataObject.getPrimaryFile();
0995: if ((dataObject instanceof DataFolder)
0996: && RetoucheUtils.isFileInOpenProject(fileObject)
0997: && RetoucheUtils.isOnSourceClasspath(fileObject)
0998: && !RetoucheUtils.isClasspathRoot(fileObject)) {
0999: return true;
1000: }
1001: }
1002: return false;
1003: }
1004:
1005: private static boolean multiplePkgsSelected(
1006: Collection<? extends Node> nodes) {
1007: boolean pkgSelected = false;
1008: for (Node node : nodes) {
1009: DataObject dataObject = node.getCookie(DataObject.class);
1010: if (dataObject == null) {
1011: continue;
1012: }
1013: if (isRefactorableFolder(dataObject)) {
1014: if (pkgSelected) {
1015: return true;
1016: } else {
1017: pkgSelected = true;
1018: }
1019: }
1020: }
1021:
1022: return false;
1023: }
1024:
1025: static boolean isFromEditor(EditorCookie ec) {
1026: if (ec != null && ec.getOpenedPanes() != null) {
1027: TopComponent activetc = TopComponent.getRegistry()
1028: .getActivated();
1029: if (activetc instanceof CloneableEditorSupport.Pane) {
1030: return true;
1031: }
1032: }
1033: return false;
1034: }
1035:
1036: static boolean nodeHandle(Lookup lookup) {
1037: Node n = lookup.lookup(Node.class);
1038: if (n != null) {
1039: if (n.getLookup().lookup(TreePathHandle.class) != null)
1040: return true;
1041: }
1042: return false;
1043: }
1044:
1045: private static boolean isRefactorableFolder(DataObject dataObject) {
1046: FileObject fileObject = dataObject.getPrimaryFile();
1047: FileObject[] children = fileObject.getChildren();
1048: if (children == null || children.length <= 0) {
1049: return false;
1050: }
1051:
1052: return (dataObject instanceof DataFolder)
1053: && RetoucheUtils.isFileInOpenProject(fileObject)
1054: && RetoucheUtils.isOnSourceClasspath(fileObject)
1055: && !RetoucheUtils.isClasspathRoot(fileObject);
1056: }
1057:
1058: private static boolean containsJavaFile(FileObject fileObject) {
1059: FileObject[] children = fileObject.getChildren();
1060: if (children == null) {
1061: return false;
1062: }
1063: for (int x = 0; x < children.length; x++) {
1064: try {
1065: DataObject dobj = DataObject.find(children[x]);
1066: FileObject fobj = dobj.getPrimaryFile();
1067: // if (dobj instanceof DataFolder) {
1068: // if (containsJavaFile(fobj)) {
1069: // return true;
1070: // }
1071: // } else {
1072: if (RetoucheUtils.isJavaFile(fobj)) {
1073: return true;
1074: }
1075: } catch (DataObjectNotFoundException ex) {
1076: }
1077: }
1078: return false;
1079: }
1080:
1081: }
|