/*
* Copyright (c) 2012, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.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.eclipse.org/legal/epl-v10.html
*
* 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 com.google.dart.tools.ui.actions;
import com.google.dart.tools.core.internal.util.ResourceUtil;
import com.google.dart.tools.ui.DartToolsPlugin;
import com.google.dart.tools.ui.instrumentation.UIInstrumentationBuilder;
import com.google.dart.tools.ui.internal.projects.NewApplicationCreationPage.ProjectType;
import com.google.dart.tools.ui.internal.projects.ProjectMessages;
import com.google.dart.tools.ui.internal.projects.ProjectUtils;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbenchWindow;
import java.io.File;
import java.net.URI;
import java.util.ArrayList;
/**
* Creates projects in the workspace.
*/
public class CreateAndRevealProjectAction extends InstrumentedAction {
//TODO(pquitslund): permit/handle overwriting existing projects
private final IWorkbenchWindow window;
private final String[] directories;
private IStatus status;
private IProject project = null;
private final ProjectType type;
/**
* Create the action.
*
* @param window the workbench window
* @param type the project type
* @param directories directory paths
*/
public CreateAndRevealProjectAction(IWorkbenchWindow window, ProjectType type,
String... directories) {
this.type = type;
this.directories = directories;
this.window = window;
}
/**
* Create the action.
*
* @param window the workbench window
* @param directories directory paths
*/
public CreateAndRevealProjectAction(IWorkbenchWindow window, String... directories) {
this(window, ProjectType.NONE, directories);
}
public IProject getProject() {
return project;
}
/**
* Return {@link Status#OK_STATUS} if creation succeeded, {@link Status#CANCEL_STATUS} otherwise.
* (Returns null if the action has not been run yet.)
*/
public IStatus getStatus() {
return status;
}
protected void createAndRevealProject(String directoryPath) {
Path path = new Path(directoryPath);
String name = path.lastSegment();
IProject projectHandle = getProjectHandle(name);
if (projectHandle.exists()) {
if (projectHandle.getLocation().equals(path)) {
ProjectUtils.selectAndReveal(projectHandle);
project = projectHandle;
} else {
name = ProjectUtils.generateUniqueNameFrom(name);
projectHandle = getProjectHandle(name);
project = projectHandle;
}
}
if (!isNestedByAnExistingProject(path) && !nestsAnExistingProject(path)) {
URI location = new File(directoryPath).toURI();
IProject newProject = ProjectUtils.createNewProject(
name,
projectHandle,
type,
location,
window,
getShell());
ProjectUtils.selectAndReveal(newProject);
project = newProject;
} else {
status = Status.CANCEL_STATUS;
}
}
@Override
protected void doRun(Event event, UIInstrumentationBuilder instrumentation) {
status = Status.OK_STATUS; //will get unset if any creation fails
instrumentation.metric("Directories-Count", directories.length);
for (String d : directories) {
instrumentation.data("Directory", d);
createAndRevealProject(d);
}
}
private IProject getProjectHandle(String name) {
return ResourcesPlugin.getWorkspace().getRoot().getProject(name);
}
private Shell getShell() {
return window.getShell();
}
private boolean isNestedByAnExistingProject(IPath path) {
for (IProject project : ResourcesPlugin.getWorkspace().getRoot().getProjects()) {
IPath location = project.getLocation();
if (location.isPrefixOf(path)) {
IResource resource = ResourceUtil.getResource(path.toFile());
ProjectUtils.selectAndReveal(resource);
return true;
}
}
return false;
}
private boolean nestsAnExistingProject(IPath path) {
// Reference the set of projects in the workspace
final IProject[] projectArray = ResourcesPlugin.getWorkspace().getRoot().getProjects();
// Create a list of Strings which we will populate with project names which are sub directories
// of the passed IPath, if there aren't many projects in the workspace, no reason to create a
// large array.
ArrayList<String> violatingProjectNameList = new ArrayList<String>(Math.min(
projectArray.length,
10));
// Loop through each of the projects to populate projectArray
for (IProject project : projectArray) {
IPath location = project.getLocation();
if (path.isPrefixOf(location)) {
violatingProjectNameList.add(project.getName());
}
}
// If there are any violating projects, throw an error message.
if (!violatingProjectNameList.isEmpty()) {
// For the error message in the dialog, we need the name of the project we are trying to create.
String folderName = path.lastSegment();
// And we need the list of violating project names, the following converts the list of strings
// into a comma separated list to make it human readable.
String violatingNamesMessage = "'" + violatingProjectNameList.get(0) + "'";
for (int i = 1; i < violatingProjectNameList.size() - 1; i++) {
violatingNamesMessage += ", '" + violatingProjectNameList.get(i) + "'";
}
if (violatingProjectNameList.size() > 1) {
violatingNamesMessage += " and '"
+ violatingProjectNameList.get(violatingProjectNameList.size() - 1) + "'";
}
// Finally, open the dialog and then return true.
String message1 = NLS.bind(
ProjectMessages.OpenExistingFolderWizardAction_nesting_msg1,
folderName,
violatingNamesMessage);
String message2 = NLS.bind(
ProjectMessages.OpenExistingFolderWizardAction_nesting_msg2,
folderName,
violatingNamesMessage);
ErrorDialog.openError(
getShell(),
ProjectMessages.OpenExistingFolderWizardAction_nesting_title,
ProjectMessages.OpenExistingFolderWizardAction_nesting_title,
new MultiStatus(DartToolsPlugin.PLUGIN_ID, 1, new IStatus[] {new Status(
IStatus.ERROR,
DartToolsPlugin.PLUGIN_ID,
message2)}, message1, null),
IStatus.ERROR);
return true;
}
// Otherwise, none of the projects in the workspace are children of the new project, return false.
return false;
}
}