blob: f5177f9be7cddcb0bcdfd52f46aee21969cbb7a0 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.refactoring.java.plugins;
import java.awt.event.ActionEvent;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.Action;
import javax.swing.SwingUtilities;
import org.netbeans.api.fileinfo.NonRecursiveFolder;
import org.netbeans.api.java.classpath.ClassPath;
import org.netbeans.api.queries.VersioningQuery;
import org.netbeans.api.queries.VisibilityQuery;
import org.netbeans.modules.refactoring.api.AbstractRefactoring;
import org.netbeans.modules.refactoring.api.Problem;
import org.netbeans.modules.refactoring.api.RenameRefactoring;
import org.netbeans.modules.refactoring.java.RefactoringUtils;
import org.netbeans.modules.refactoring.spi.RefactoringElementsBag;
import org.netbeans.modules.refactoring.spi.RefactoringPlugin;
import org.netbeans.modules.refactoring.spi.RefactoringPluginFactory;
import org.netbeans.modules.refactoring.spi.SimpleRefactoringElementImplementation;
import org.openide.ErrorManager;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileSystem.AtomicAction;
import org.openide.filesystems.FileUtil;
import org.openide.loaders.DataFolder;
import org.openide.loaders.DataObject;
import org.openide.text.PositionBounds;
import org.openide.util.ContextAwareAction;
import org.openide.util.Exceptions;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.openide.util.lookup.Lookups;
/**
*
* @author Jan Becicka
*/
@org.openide.util.lookup.ServiceProvider(service=org.netbeans.modules.refactoring.spi.RefactoringPluginFactory.class, position=200)
public class PackageRename implements RefactoringPluginFactory {
private static final Logger LOG = Logger.getLogger(PackageRename.class.getName());
/** Creates a new instance of PackageRename */
public PackageRename() {
}
@Override
public RefactoringPlugin createInstance(AbstractRefactoring refactoring) {
if (refactoring instanceof RenameRefactoring) {
NonRecursiveFolder folder = refactoring.getRefactoringSource().lookup(NonRecursiveFolder.class);
if (folder !=null) {
return new PackageRenamePlugin((RenameRefactoring) refactoring, folder);
}
}
return null;
}
public class PackageRenamePlugin implements RefactoringPlugin {
private final RenameRefactoring refactoring;
private final NonRecursiveFolder nonRecursiveFolder;
/** Creates a new instance of PackageRenamePlugin */
public PackageRenamePlugin(RenameRefactoring refactoring, NonRecursiveFolder nonRecursiveFolder) {
this.refactoring = refactoring;
this.nonRecursiveFolder = nonRecursiveFolder;
}
@Override
public Problem preCheck() {
return null;
}
@Override
public Problem prepare(RefactoringElementsBag elements) {
elements.addFileChange(refactoring, new RenameNonRecursiveFolder(refactoring.getRefactoringSource().lookup(NonRecursiveFolder.class), elements));
return null;
}
@Override
public Problem fastCheckParameters() {
String newName = refactoring.getNewName();
if (!RefactoringUtils.isValidPackageName(newName)) {
String msg = new MessageFormat(NbBundle.getMessage(RenameRefactoringPlugin.class, "ERR_InvalidPackage")).format(
new Object[] {newName}
);
return new Problem(true, msg);
}
FileObject folder = nonRecursiveFolder.getFolder();
ClassPath projectClassPath = ClassPath.getClassPath(folder, ClassPath.SOURCE);
FileObject fo;
if ((fo = projectClassPath.findResource(newName.replace('.','/')))!=null) {
FileObject ownerRoot = projectClassPath.findOwnerRoot(folder);
if(ownerRoot != null && ownerRoot.equals(projectClassPath.findOwnerRoot(fo))) {
if (fo.isFolder() && fo.getChildren().length == 1) {
FileObject parent = fo.getChildren()[0];
String relativePath = FileUtil.getRelativePath(parent, nonRecursiveFolder.getFolder());
if (relativePath != null) {
return null;
}
}
String msg = new MessageFormat(NbBundle.getMessage(RenameRefactoringPlugin.class,"ERR_PackageExists")).format(
new Object[] {newName}
);
return new Problem(true, msg);
}
}
return null;
}
@Override
public Problem checkParameters() {
return null;
}
@Override
public void cancelRequest() {
}
private class RenameNonRecursiveFolder extends SimpleRefactoringElementImplementation {
private FileObject folder;
private RefactoringElementsBag session;
private String oldName;
private FileObject root;
private String currentName;
public RenameNonRecursiveFolder(NonRecursiveFolder nrfo, RefactoringElementsBag session) {
this.folder = nrfo.getFolder();
this.session = session;
ClassPath cp = ClassPath.getClassPath(
folder, ClassPath.SOURCE);
this.currentName = cp.getResourceName(folder, '.', false);
this.oldName = this.currentName;
this.root = cp.findOwnerRoot(folder);
}
@Override
public String getText() {
return NbBundle.getMessage(PackageRename.class, "TXT_RenamePackage") + folder.getNameExt();
}
@Override
public String getDisplayText() {
return getText();
}
@Override
public void performChange() {
atomicSetName(refactoring.getNewName());
}
@Override
public void undoChange() {
atomicSetName(oldName);
}
private void atomicSetName(final String name) {
try {
folder.getFileSystem().runAtomicAction(new AtomicAction() {
@Override
public void run() throws IOException {
setName(name);
}
});
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
}
@Override
public Lookup getLookup() {
return Lookups.singleton(folder.getParent());
}
@Override
public FileObject getParentFile() {
return folder.getParent();
}
@Override
public PositionBounds getPosition() {
return null;
}
/**
*copy paste from PackageViewChildren
*/
public void setName(String name) {
if (currentName.equals(name)) {
return;
}
// if (!isValidPackageName (name)) {
// DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message (
// NbBundle.getMessage(PackageViewChildren.class,"MSG_InvalidPackageName"), NotifyDescriptor.INFORMATION_MESSAGE));
// return;
// }
name = name.replace('.','/')+'/'; //NOI18N
currentName = currentName.replace('.','/')+'/'; //NOI18N
int i;
for (i=0; i<currentName.length() && i< name.length(); i++) {
if (currentName.charAt(i) != name.charAt(i)) {
break;
}
}
i--;
int index = currentName.lastIndexOf('/',i); //NOI18N
String commonPrefix = index == -1 ? null : currentName.substring(0,index);
String toCreate = (index+1 == name.length()) ? "" : name.substring(index+1); //NOI18N
try {
FileObject commonFolder = commonPrefix == null ? this.root : this.root.getFileObject(commonPrefix);
FileObject destination = commonFolder;
StringTokenizer dtk = new StringTokenizer(toCreate,"/"); //NOI18N
while (dtk.hasMoreTokens()) {
String pathElement = dtk.nextToken();
FileObject tmp = destination.getFileObject(pathElement);
if (tmp == null) {
tmp = destination.createFolder(pathElement);
}
destination = tmp;
}
if (!this.folder.isValid()) {
FileObject toFileObject = FileUtil.toFileObject(new java.io.File(this.folder.getPath()));
if(toFileObject == null) {
LOG.log(Level.INFO, "Invalid folder: {0}", this.folder.getPath());
return; // File changed?
}
this.folder = toFileObject;
}
FileObject folder = this.folder;
FileUtil.toFileObject(new java.io.File(this.folder.getPath()));
DataFolder sourceFolder = DataFolder.findFolder(folder);
DataFolder destinationFolder = DataFolder.findFolder(destination);
DataObject[] children = sourceFolder.getChildren();
for (int j=0; j<children.length; j++) {
if (children[j].getPrimaryFile().isData()) {
children[j].move(destinationFolder);
}
}
while (!commonFolder.equals(folder)) {
if (isEmpty(folder)) {
FileObject tmp = folder;
folder = folder.getParent();
tmp.delete();
} else {
break;
}
}
this.folder = destinationFolder.getPrimaryFile();
selectInProjectsView(destinationFolder);
} catch (IOException ioe) {
ErrorManager.getDefault().notify(ioe);
}
this.currentName = name;
}
private boolean isEmpty(FileObject folder) {
boolean isVersioned = VersioningQuery.isManaged(folder.toURI());
if (isVersioned) {
for (FileObject child:folder.getChildren()) {
if (VisibilityQuery.getDefault().isVisible(child)) {
return false;
}
}
return true;
} else {
return folder.getChildren().length==0;
}
}
private void selectInProjectsView(final DataFolder destinationFolder) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
ContextAwareAction action = FileUtil.getConfigObject("Actions/Window/SelectDocumentNode/org-netbeans-modules-project-ui-SelectInProjects.instance", ContextAwareAction.class); //NOI18N
if(action != null) {
Action contextAction = action.createContextAwareInstance(Lookups.fixed(destinationFolder));
contextAction.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, null));
}
}
});
}
}
}
}