1 /*******************************************************************************
2  * Copyright (c) 2000, 2016 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.jdt.internal.ui.wizards.buildpaths.newsourcepage;
15 
16 import java.lang.reflect.InvocationTargetException;
17 import java.util.ArrayList;
18 import java.util.HashSet;
19 import java.util.List;
20 import java.util.Set;
21 
22 import org.eclipse.swt.widgets.Shell;
23 
24 import org.eclipse.core.runtime.CoreException;
25 import org.eclipse.core.runtime.IPath;
26 import org.eclipse.core.runtime.IProgressMonitor;
27 import org.eclipse.core.runtime.OperationCanceledException;
28 import org.eclipse.core.runtime.SubProgressMonitor;
29 
30 import org.eclipse.core.resources.IContainer;
31 import org.eclipse.core.resources.IFolder;
32 import org.eclipse.core.resources.IProject;
33 import org.eclipse.core.resources.IResource;
34 import org.eclipse.core.resources.IWorkspaceRoot;
35 
36 import org.eclipse.jface.dialogs.IDialogConstants;
37 import org.eclipse.jface.dialogs.MessageDialog;
38 import org.eclipse.jface.operation.IRunnableContext;
39 import org.eclipse.jface.operation.IRunnableWithProgress;
40 import org.eclipse.jface.viewers.IStructuredSelection;
41 import org.eclipse.jface.viewers.StructuredSelection;
42 
43 import org.eclipse.ui.IWorkbenchSite;
44 import org.eclipse.ui.PlatformUI;
45 import org.eclipse.ui.part.ISetSelectionTarget;
46 
47 import org.eclipse.jdt.core.IClasspathEntry;
48 import org.eclipse.jdt.core.IJavaElement;
49 import org.eclipse.jdt.core.IJavaProject;
50 import org.eclipse.jdt.core.IPackageFragment;
51 import org.eclipse.jdt.core.JavaCore;
52 
53 import org.eclipse.jdt.internal.core.manipulation.util.BasicElementLabels;
54 import org.eclipse.jdt.internal.corext.buildpath.BuildpathDelta;
55 import org.eclipse.jdt.internal.corext.buildpath.ClasspathModifier;
56 import org.eclipse.jdt.internal.corext.util.Messages;
57 
58 import org.eclipse.jdt.ui.JavaElementLabels;
59 
60 import org.eclipse.jdt.internal.ui.JavaPlugin;
61 import org.eclipse.jdt.internal.ui.JavaPluginImages;
62 import org.eclipse.jdt.internal.ui.dialogs.StatusInfo;
63 import org.eclipse.jdt.internal.ui.wizards.NewWizardMessages;
64 import org.eclipse.jdt.internal.ui.wizards.buildpaths.BuildPathBasePage;
65 import org.eclipse.jdt.internal.ui.wizards.buildpaths.BuildPathsBlock;
66 import org.eclipse.jdt.internal.ui.wizards.buildpaths.CPListElement;
67 import org.eclipse.jdt.internal.ui.wizards.buildpaths.newsourcepage.ClasspathModifierQueries.OutputFolderQuery;
68 
69 //SelectedElements iff enabled: IJavaProject || IPackageFrament || IFolder
70 public class AddFolderToBuildpathAction extends BuildpathModifierAction {
71 
72 	private final IRunnableContext fContext;
73 
AddFolderToBuildpathAction(IWorkbenchSite site)74 	public AddFolderToBuildpathAction(IWorkbenchSite site) {
75 		this(site, null, PlatformUI.getWorkbench().getProgressService());
76 	}
77 
AddFolderToBuildpathAction(IRunnableContext context, ISetSelectionTarget selectionTarget)78 	public AddFolderToBuildpathAction(IRunnableContext context, ISetSelectionTarget selectionTarget) {
79 		this(null, selectionTarget, context);
80 	}
81 
AddFolderToBuildpathAction(IWorkbenchSite site, ISetSelectionTarget selectionTarget, IRunnableContext context)82 	private AddFolderToBuildpathAction(IWorkbenchSite site, ISetSelectionTarget selectionTarget, IRunnableContext context) {
83 		super(site, selectionTarget, BuildpathModifierAction.ADD_SEL_SF_TO_BP);
84 
85 		fContext= context;
86 
87 		setText(NewWizardMessages.NewSourceContainerWorkbookPage_ToolBar_AddSelSFToCP_label);
88 		setImageDescriptor(JavaPluginImages.DESC_ELCL_ADD_AS_SOURCE_FOLDER);
89 		setToolTipText(NewWizardMessages.NewSourceContainerWorkbookPage_ToolBar_AddSelSFToCP_tooltip);
90 	}
91 
92 	@Override
getDetailedDescription()93 	public String getDetailedDescription() {
94 		if (!isEnabled())
95 			return null;
96 
97 		if (getSelectedElements().size() != 1)
98 			return NewWizardMessages.PackageExplorerActionGroup_FormText_Default_toBuildpath;
99 
100 		Object obj= getSelectedElements().get(0);
101 		String elementLabel= JavaElementLabels.getTextLabel(obj, JavaElementLabels.ALL_DEFAULT);
102 		if (obj instanceof IJavaProject) {
103 			return Messages.format(NewWizardMessages.PackageExplorerActionGroup_FormText_ProjectToBuildpath, elementLabel);
104 		} else if (obj instanceof IPackageFragment) {
105 			return Messages.format(NewWizardMessages.PackageExplorerActionGroup_FormText_PackageToBuildpath, elementLabel);
106 		} else if (obj instanceof IResource) {
107 			return Messages.format(NewWizardMessages.PackageExplorerActionGroup_FormText_FolderToBuildpath, elementLabel);
108 		}
109 
110 		return null;
111 	}
112 
113 	@Override
run()114 	public void run() {
115 
116 		try {
117 			final IJavaProject project;
118 			Object object= getSelectedElements().get(0);
119 			if (object instanceof IJavaProject) {
120 				project= (IJavaProject)object;
121 			} else if (object instanceof IPackageFragment) {
122 				project= ((IPackageFragment)object).getJavaProject();
123 			} else {
124 				IFolder folder= (IFolder)object;
125 				project= JavaCore.create(folder.getProject());
126 				if (project == null)
127 					return;
128 			}
129 
130 			final Shell shell= getShell();
131 
132 			final boolean removeProjectFromClasspath;
133 			IPath outputLocation= project.getOutputLocation();
134 			final IPath defaultOutputLocation= outputLocation.makeRelative();
135 			final IPath newDefaultOutputLocation;
136 			final boolean removeOldClassFiles;
137 			IPath projPath= project.getProject().getFullPath();
138 			if (((getSelectedElements().size() != 1) || !(getSelectedElements().get(0) instanceof IJavaProject)) && //if only the project should be added, then the query does not need to be executed
139 					(outputLocation.equals(projPath) || defaultOutputLocation.segmentCount() == 1)) {
140 
141 
142 				final OutputFolderQuery outputFolderQuery= ClasspathModifierQueries.getDefaultFolderQuery(shell, defaultOutputLocation);
143 				if (outputFolderQuery.doQuery(true, ClasspathModifier.getValidator(getSelectedElements(), project), project)) {
144 					newDefaultOutputLocation= outputFolderQuery.getOutputLocation();
145 					removeProjectFromClasspath= outputFolderQuery.removeProjectFromClasspath();
146 
147 					if (BuildPathsBlock.hasClassfiles(project.getProject()) && outputLocation.equals(projPath)) {
148 						String title= NewWizardMessages.BuildPathsBlock_RemoveBinariesDialog_title;
149 						String message= Messages.format(NewWizardMessages.BuildPathsBlock_RemoveBinariesDialog_description, BasicElementLabels.getPathLabel(projPath, false));
150 						MessageDialog dialog= new MessageDialog(shell, title, null, message, MessageDialog.QUESTION, new String[] { IDialogConstants.YES_LABEL, IDialogConstants.NO_LABEL, IDialogConstants.CANCEL_LABEL }, 0);
151 						int answer= dialog.open();
152 						switch (answer) {
153 						case 0:
154 							removeOldClassFiles= true;
155 							break;
156 						case 1:
157 							removeOldClassFiles= false;
158 							break;
159 						default:
160 							return;
161 						}
162 					} else {
163 						removeOldClassFiles= false;
164 					}
165 				} else {
166 					return;
167 				}
168 			} else {
169 				removeProjectFromClasspath= false;
170 				removeOldClassFiles= false;
171 				newDefaultOutputLocation= defaultOutputLocation;
172 			}
173 
174 			try {
175 				final IRunnableWithProgress runnable= new IRunnableWithProgress() {
176 					@Override
177 					public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
178 						try {
179 							List<IJavaElement> result= addToClasspath(getSelectedElements(), project, newDefaultOutputLocation.makeAbsolute(), removeProjectFromClasspath, removeOldClassFiles, monitor);
180 							selectAndReveal(new StructuredSelection(result));
181 						} catch (CoreException e) {
182 							throw new InvocationTargetException(e);
183 						}
184 					}
185 				};
186 				fContext.run(false, false, runnable);
187 			} catch (final InvocationTargetException e) {
188 				if (e.getCause() instanceof CoreException) {
189 					showExceptionDialog((CoreException)e.getCause(), NewWizardMessages.AddSourceFolderToBuildpathAction_ErrorTitle);
190 				} else {
191 					JavaPlugin.log(e);
192 				}
193 			} catch (final InterruptedException e) {
194 			}
195 		} catch (CoreException e) {
196 			showExceptionDialog(e, NewWizardMessages.AddSourceFolderToBuildpathAction_ErrorTitle);
197 		}
198 	}
199 
addToClasspath(List<?> elements, IJavaProject project, IPath outputLocation, boolean removeProjectFromClasspath, boolean removeOldClassFiles, IProgressMonitor monitor)200 	private List<IJavaElement> addToClasspath(List<?> elements, IJavaProject project, IPath outputLocation, boolean removeProjectFromClasspath, boolean removeOldClassFiles, IProgressMonitor monitor) throws OperationCanceledException, CoreException {
201 		if (!project.getProject().hasNature(JavaCore.NATURE_ID)) {
202 			StatusInfo rootStatus= new StatusInfo();
203 			rootStatus.setError(NewWizardMessages.ClasspathModifier_Error_NoNatures);
204 			throw new CoreException(rootStatus);
205 		}
206 
207 		try {
208 			monitor.beginTask(NewWizardMessages.ClasspathModifier_Monitor_AddToBuildpath, elements.size() + 4);
209 			IWorkspaceRoot workspaceRoot= JavaPlugin.getWorkspace().getRoot();
210 
211 			if (removeOldClassFiles) {
212 				IResource res= workspaceRoot.findMember(project.getOutputLocation());
213 				if (res instanceof IContainer && BuildPathsBlock.hasClassfiles(res)) {
214 					BuildPathsBlock.removeOldClassfiles(res);
215 				}
216 			}
217 
218 			BuildpathDelta delta= new BuildpathDelta(getToolTipText());
219 
220 			if (!project.getOutputLocation().equals(outputLocation)) {
221 				project.setOutputLocation(outputLocation, new SubProgressMonitor(monitor, 1));
222 				delta.setDefaultOutputLocation(outputLocation);
223 			} else {
224 				monitor.worked(1);
225 			}
226 
227 			List<CPListElement> existingEntries= ClasspathModifier.getExistingEntries(project);
228 			if (removeProjectFromClasspath) {
229 				ClasspathModifier.removeFromClasspath(project, existingEntries, new SubProgressMonitor(monitor, 1));
230 			} else {
231 				monitor.worked(1);
232 			}
233 
234 			List<CPListElement> newEntries= new ArrayList<>();
235 			for (Object element : elements) {
236 				CPListElement entry;
237 				if (element instanceof IResource)
238 					entry= ClasspathModifier.addToClasspath((IResource) element, existingEntries, newEntries, project, new SubProgressMonitor(monitor, 1));
239 				else
240 					entry= ClasspathModifier.addToClasspath((IJavaElement) element, existingEntries, newEntries, project, new SubProgressMonitor(monitor, 1));
241 				newEntries.add(entry);
242 			}
243 
244 			Set<CPListElement> modifiedSourceEntries= new HashSet<>();
245 			BuildPathBasePage.fixNestingConflicts(newEntries.toArray(new CPListElement[newEntries.size()]), existingEntries.toArray(new CPListElement[existingEntries.size()]), modifiedSourceEntries);
246 
247 			ClasspathModifier.setNewEntry(existingEntries, newEntries, project, new SubProgressMonitor(monitor, 1));
248 
249 			ClasspathModifier.commitClassPath(existingEntries, project, new SubProgressMonitor(monitor, 1));
250 
251 			delta.setNewEntries(existingEntries.toArray(new CPListElement[existingEntries.size()]));
252 			informListeners(delta);
253 
254 			List<IJavaElement> result= new ArrayList<>();
255 			for (CPListElement newEntrie : newEntries) {
256 				IClasspathEntry entry= newEntrie.getClasspathEntry();
257 				IJavaElement root;
258 				if (entry.getPath().equals(project.getPath()))
259 					root= project;
260 				else
261 					root= project.findPackageFragmentRoot(entry.getPath());
262 				if (root != null) {
263 					result.add(root);
264 				}
265 			}
266 
267 			return result;
268 		} finally {
269 			monitor.done();
270 		}
271 	}
272 
273 	@Override
canHandle(IStructuredSelection elements)274 	protected boolean canHandle(IStructuredSelection elements) {
275 		if (elements.size() == 0)
276 			return false;
277 		try {
278 			for (Object element : elements) {
279 				if (element instanceof IJavaProject) {
280 					if (ClasspathModifier.isSourceFolder((IJavaProject)element))
281 						return false;
282 				} else if (element instanceof IPackageFragment) {
283 					IPackageFragment fragment= (IPackageFragment)element;
284 					if (ClasspathModifier.isDefaultFragment(fragment))
285 						return false;
286 
287 					if (ClasspathModifier.isInExternalOrArchive(fragment))
288 						return false;
289 					IResource res;
290 					if ((res= fragment.getResource()) != null && res.isVirtual())
291 						return false;
292 				} else if (element instanceof IFolder) {
293 					IProject project= ((IFolder)element).getProject();
294 					IJavaProject javaProject= JavaCore.create(project);
295 					if (javaProject == null || !javaProject.exists() || ((IFolder)element).isVirtual())
296 						return false;
297 				} else {
298 					return false;
299 				}
300 			}
301 			return true;
302 		} catch (CoreException e) {
303 		}
304 		return false;
305 	}
306 }
307