Added
Link Here
|
1 |
/******************************************************************************* |
2 |
* Copyright (c) 2000, 2015 IBM Corporation and others. |
3 |
* All rights reserved. This program and the accompanying materials |
4 |
* are made available under the terms of the Eclipse Public License v1.0 |
5 |
* which accompanies this distribution, and is available at |
6 |
* http://www.eclipse.org/legal/epl-v10.html |
7 |
* |
8 |
* Contributors: |
9 |
* Frits Jalvingh <jal@etc.to> - Contribution for Bug 459831 - [launching] Support attaching external annotations to a JRE container |
10 |
*******************************************************************************/ |
11 |
package org.eclipse.jdt.internal.ui.wizards.buildpaths; |
12 |
|
13 |
import java.io.File; |
14 |
import java.lang.reflect.InvocationTargetException; |
15 |
import java.util.List; |
16 |
|
17 |
import org.eclipse.swt.SWT; |
18 |
import org.eclipse.swt.layout.GridData; |
19 |
import org.eclipse.swt.layout.GridLayout; |
20 |
import org.eclipse.swt.widgets.Composite; |
21 |
import org.eclipse.swt.widgets.Control; |
22 |
import org.eclipse.swt.widgets.DirectoryDialog; |
23 |
import org.eclipse.swt.widgets.FileDialog; |
24 |
import org.eclipse.swt.widgets.Label; |
25 |
import org.eclipse.swt.widgets.Shell; |
26 |
|
27 |
import org.eclipse.core.runtime.CoreException; |
28 |
import org.eclipse.core.runtime.IPath; |
29 |
import org.eclipse.core.runtime.IProgressMonitor; |
30 |
import org.eclipse.core.runtime.IStatus; |
31 |
import org.eclipse.core.runtime.Path; |
32 |
|
33 |
import org.eclipse.core.resources.IResource; |
34 |
import org.eclipse.core.resources.IWorkspace; |
35 |
import org.eclipse.core.resources.IWorkspaceRoot; |
36 |
import org.eclipse.core.resources.ResourcesPlugin; |
37 |
|
38 |
import org.eclipse.jface.dialogs.Dialog; |
39 |
import org.eclipse.jface.layout.PixelConverter; |
40 |
import org.eclipse.jface.operation.IRunnableWithProgress; |
41 |
import org.eclipse.jface.viewers.ILabelProvider; |
42 |
import org.eclipse.jface.viewers.ITreeContentProvider; |
43 |
import org.eclipse.jface.viewers.ViewerFilter; |
44 |
import org.eclipse.jface.window.Window; |
45 |
|
46 |
import org.eclipse.ui.PlatformUI; |
47 |
import org.eclipse.ui.model.WorkbenchContentProvider; |
48 |
import org.eclipse.ui.model.WorkbenchLabelProvider; |
49 |
|
50 |
import org.eclipse.jdt.core.IClasspathAttribute; |
51 |
import org.eclipse.jdt.core.IClasspathEntry; |
52 |
import org.eclipse.jdt.core.IJavaProject; |
53 |
import org.eclipse.jdt.core.JavaCore; |
54 |
|
55 |
import org.eclipse.jdt.internal.corext.util.Messages; |
56 |
|
57 |
import org.eclipse.jdt.internal.ui.IJavaHelpContextIds; |
58 |
import org.eclipse.jdt.internal.ui.JavaPlugin; |
59 |
import org.eclipse.jdt.internal.ui.dialogs.StatusInfo; |
60 |
import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels; |
61 |
import org.eclipse.jdt.internal.ui.wizards.IStatusChangeListener; |
62 |
import org.eclipse.jdt.internal.ui.wizards.NewWizardMessages; |
63 |
import org.eclipse.jdt.internal.ui.wizards.dialogfields.DialogField; |
64 |
import org.eclipse.jdt.internal.ui.wizards.dialogfields.IDialogFieldListener; |
65 |
import org.eclipse.jdt.internal.ui.wizards.dialogfields.IStringButtonAdapter; |
66 |
import org.eclipse.jdt.internal.ui.wizards.dialogfields.LayoutUtil; |
67 |
import org.eclipse.jdt.internal.ui.wizards.dialogfields.SelectionButtonDialogField; |
68 |
import org.eclipse.jdt.internal.ui.wizards.dialogfields.StringButtonDialogField; |
69 |
|
70 |
|
71 |
/** |
72 |
* UI to set the External Annotations path. Same implementation for both setting attachments for |
73 |
* libraries from variable entries and for normal (internal or external) jar. |
74 |
*/ |
75 |
public class ExternalAnnotationsAttachmentBlock { |
76 |
|
77 |
private final IStatusChangeListener fContext; |
78 |
|
79 |
private StringButtonDialogField fWorkspaceFileNameField; |
80 |
private StringButtonDialogField fExternalFileNameField; |
81 |
private SelectionButtonDialogField fExternalFolderButton; |
82 |
private SelectionButtonDialogField fExternalRadio, fWorkspaceRadio; |
83 |
|
84 |
private IStatus fWorkspaceNameStatus; |
85 |
private IStatus fExternalNameStatus; |
86 |
|
87 |
private final IWorkspaceRoot fWorkspaceRoot; |
88 |
|
89 |
private Control fSWTWidget; |
90 |
|
91 |
private final IPath fEntry; |
92 |
|
93 |
/** |
94 |
* @param context listeners for status updates |
95 |
* @param entry The entry to edit |
96 |
*/ |
97 |
public ExternalAnnotationsAttachmentBlock(IStatusChangeListener context, IPath entry) { |
98 |
fContext= context; |
99 |
fEntry= entry == null ? Path.EMPTY : entry; |
100 |
|
101 |
fWorkspaceRoot= ResourcesPlugin.getWorkspace().getRoot(); |
102 |
|
103 |
fWorkspaceNameStatus= new StatusInfo(); |
104 |
fExternalNameStatus= new StatusInfo(); |
105 |
|
106 |
AnnotationsAttachmentAdapter adapter= new AnnotationsAttachmentAdapter(); |
107 |
|
108 |
// create the dialog fields (no widgets yet) |
109 |
fWorkspaceRadio= new SelectionButtonDialogField(SWT.RADIO); |
110 |
fWorkspaceRadio.setDialogFieldListener(adapter); |
111 |
fWorkspaceRadio.setLabelText(NewWizardMessages.AnnotationsAttachmentBlock_workspace_radiolabel); |
112 |
|
113 |
fWorkspaceFileNameField= new StringButtonDialogField(adapter); |
114 |
fWorkspaceFileNameField.setDialogFieldListener(adapter); |
115 |
fWorkspaceFileNameField.setLabelText(NewWizardMessages.AnnotationsAttachmentBlock_filename_workspace_label); |
116 |
fWorkspaceFileNameField.setButtonLabel(NewWizardMessages.AnnotationsAttachmentBlock_filename_workspace_browse); |
117 |
|
118 |
fExternalRadio= new SelectionButtonDialogField(SWT.RADIO); |
119 |
fExternalRadio.setDialogFieldListener(adapter); |
120 |
fExternalRadio.setLabelText(NewWizardMessages.AnnotationsAttachmentBlock_external_radiolabel); |
121 |
|
122 |
fExternalFileNameField= new StringButtonDialogField(adapter); |
123 |
fExternalFileNameField.setDialogFieldListener(adapter); |
124 |
fExternalFileNameField.setLabelText(NewWizardMessages.AnnotationsAttachmentBlock_filename_external_label); |
125 |
fExternalFileNameField.setButtonLabel(NewWizardMessages.AnnotationsAttachmentBlock_filename_externalfile_button); |
126 |
|
127 |
fExternalFolderButton= new SelectionButtonDialogField(SWT.PUSH); |
128 |
fExternalFolderButton.setDialogFieldListener(adapter); |
129 |
fExternalFolderButton.setLabelText(NewWizardMessages.AnnotationsAttachmentBlock_filename_externalfolder_button); |
130 |
|
131 |
setDefaults(); |
132 |
} |
133 |
|
134 |
public void setDefaults() { |
135 |
IPath annotationsAttachmentPath= fEntry; |
136 |
String path= annotationsAttachmentPath == null ? null : annotationsAttachmentPath.toPortableString(); |
137 |
|
138 |
if (isWorkspacePath(annotationsAttachmentPath)) { |
139 |
fWorkspaceRadio.setSelection(true); |
140 |
fWorkspaceFileNameField.setText(path); |
141 |
} else if (path != null && path.length() != 0) { |
142 |
fExternalRadio.setSelection(true); |
143 |
fExternalFileNameField.setText(path); |
144 |
} else { |
145 |
fWorkspaceRadio.setSelection(true); |
146 |
fExternalRadio.setSelection(false); |
147 |
} |
148 |
} |
149 |
|
150 |
private boolean isWorkspacePath(IPath path) { |
151 |
if (path == null || path.getDevice() != null) |
152 |
return false; |
153 |
IWorkspace workspace= ResourcesPlugin.getWorkspace(); |
154 |
if (workspace == null) |
155 |
return false; |
156 |
return workspace.getRoot().findMember(path) != null; |
157 |
} |
158 |
|
159 |
/** |
160 |
* Gets the source attachment path chosen by the user |
161 |
* @return the source attachment path |
162 |
*/ |
163 |
public IPath getAnnotationsPath() { |
164 |
return (getFilePath().segmentCount() == 0) ? null : getFilePath(); |
165 |
} |
166 |
|
167 |
/** |
168 |
* Creates the control |
169 |
* @param parent the parent |
170 |
* @return the created control |
171 |
*/ |
172 |
public Control createControl(Composite parent) { |
173 |
PixelConverter converter= new PixelConverter(parent); |
174 |
|
175 |
fSWTWidget= parent; |
176 |
|
177 |
Composite composite= new Composite(parent, SWT.NONE); |
178 |
|
179 |
GridLayout layout= new GridLayout(); |
180 |
layout.marginHeight= 0; |
181 |
layout.marginWidth= 0; |
182 |
layout.numColumns= 4; |
183 |
composite.setLayout(layout); |
184 |
|
185 |
|
186 |
int widthHint= converter.convertWidthInCharsToPixels(60); |
187 |
|
188 |
GridData gd= new GridData(GridData.FILL, GridData.BEGINNING, false, false, 3, 1); |
189 |
gd.widthHint= converter.convertWidthInCharsToPixels(50); |
190 |
|
191 |
Label message= new Label(composite, SWT.LEFT + SWT.WRAP); |
192 |
message.setLayoutData(gd); |
193 |
message.setText(NewWizardMessages.AnnotationsAttachmentBlock_message); |
194 |
|
195 |
fWorkspaceRadio.doFillIntoGrid(composite, 4); |
196 |
|
197 |
fWorkspaceFileNameField.doFillIntoGrid(composite, 4); |
198 |
LayoutUtil.setWidthHint(fWorkspaceFileNameField.getTextControl(null), widthHint); |
199 |
LayoutUtil.setHorizontalGrabbing(fWorkspaceFileNameField.getTextControl(null)); |
200 |
|
201 |
DialogField.createEmptySpace(composite, 4); |
202 |
|
203 |
fExternalRadio.doFillIntoGrid(composite, 4); |
204 |
fExternalFileNameField.doFillIntoGrid(composite, 4); |
205 |
LayoutUtil.setWidthHint(fExternalFileNameField.getTextControl(null), widthHint); |
206 |
LayoutUtil.setHorizontalGrabbing(fExternalFileNameField.getTextControl(null)); |
207 |
|
208 |
DialogField.createEmptySpace(composite, 1); |
209 |
|
210 |
fExternalFolderButton.doFillIntoGrid(composite, 1); |
211 |
|
212 |
LayoutUtil.setHorizontalIndent(fWorkspaceFileNameField.getLabelControl(null)); |
213 |
LayoutUtil.setHorizontalIndent(fExternalFileNameField.getLabelControl(null)); |
214 |
|
215 |
fWorkspaceRadio.attachDialogField(fWorkspaceFileNameField); |
216 |
fExternalRadio.attachDialogFields(new DialogField[] { fExternalFileNameField, fExternalFolderButton }); |
217 |
|
218 |
Dialog.applyDialogFont(composite); |
219 |
|
220 |
PlatformUI.getWorkbench().getHelpSystem().setHelp(composite, IJavaHelpContextIds.EXTERNAL_ANNOTATIONS_ATTACHMENT_DIALOG); |
221 |
return composite; |
222 |
} |
223 |
|
224 |
|
225 |
private class AnnotationsAttachmentAdapter implements IStringButtonAdapter, IDialogFieldListener { |
226 |
|
227 |
// -------- IStringButtonAdapter -------- |
228 |
public void changeControlPressed(DialogField field) { |
229 |
attachmentChangeControlPressed(field); |
230 |
} |
231 |
|
232 |
// ---------- IDialogFieldListener -------- |
233 |
public void dialogFieldChanged(DialogField field) { |
234 |
attachmentDialogFieldChanged(field); |
235 |
} |
236 |
} |
237 |
|
238 |
private void attachmentChangeControlPressed(DialogField field) { |
239 |
if (field == fWorkspaceFileNameField) { |
240 |
IPath jarFilePath= chooseInternal(); |
241 |
if (jarFilePath != null) { |
242 |
fWorkspaceFileNameField.setText(jarFilePath.toString()); |
243 |
} |
244 |
} else if (field == fExternalFileNameField) { |
245 |
IPath jarFilePath= chooseExtJarFile(); |
246 |
if (jarFilePath != null) { |
247 |
fExternalFileNameField.setText(jarFilePath.toString()); |
248 |
} |
249 |
} |
250 |
} |
251 |
|
252 |
// ---------- IDialogFieldListener -------- |
253 |
|
254 |
private void attachmentDialogFieldChanged(DialogField field) { |
255 |
if (field == fWorkspaceFileNameField) { |
256 |
fWorkspaceNameStatus= updateFileNameStatus(fWorkspaceFileNameField); |
257 |
} else if (field == fExternalFileNameField) { |
258 |
fExternalNameStatus= updateFileNameStatus(fExternalFileNameField); |
259 |
} else if (field == fExternalFolderButton) { |
260 |
IPath folderPath= chooseExtFolder(); |
261 |
if (folderPath != null) { |
262 |
fExternalFileNameField.setText(folderPath.toString()); |
263 |
} |
264 |
return; |
265 |
} |
266 |
doStatusLineUpdate(); |
267 |
} |
268 |
|
269 |
private void doStatusLineUpdate() { |
270 |
IStatus status; |
271 |
boolean isWorkSpace= fWorkspaceRadio.isSelected(); |
272 |
if (isWorkSpace) { |
273 |
fWorkspaceFileNameField.enableButton(canBrowseFileName()); |
274 |
status= fWorkspaceNameStatus; |
275 |
} else { |
276 |
fExternalFileNameField.enableButton(canBrowseFileName()); |
277 |
status= fExternalNameStatus; |
278 |
} |
279 |
fContext.statusChanged(status); |
280 |
} |
281 |
|
282 |
private boolean canBrowseFileName() { // FIXME remove |
283 |
return true; |
284 |
} |
285 |
|
286 |
private IStatus updateFileNameStatus(StringButtonDialogField field) { |
287 |
StatusInfo status= new StatusInfo(); |
288 |
|
289 |
String fileName= field.getText(); |
290 |
if (fileName.length() == 0) { |
291 |
// no external annotations file defined |
292 |
return status; |
293 |
} else { |
294 |
if (!Path.EMPTY.isValidPath(fileName)) { |
295 |
status.setError(NewWizardMessages.AnnotationsAttachmentBlock_filename_error_notvalid); |
296 |
return status; |
297 |
} |
298 |
IPath filePath= Path.fromOSString(fileName); |
299 |
IPath resolvedPath; |
300 |
File file= filePath.toFile(); |
301 |
IResource res= fWorkspaceRoot.findMember(filePath); |
302 |
boolean exists; |
303 |
if (res != null) { |
304 |
IPath location= res.getLocation(); |
305 |
if (location != null) { |
306 |
exists= location.toFile().exists(); |
307 |
} else { |
308 |
exists= res.exists(); |
309 |
} |
310 |
} else { |
311 |
exists= file.exists(); |
312 |
} |
313 |
if (!exists) { |
314 |
String message= Messages.format(NewWizardMessages.AnnotationsAttachmentBlock_filename_error_filenotexists, BasicElementLabels.getPathLabel(filePath, false)); |
315 |
status.setError(message); |
316 |
return status; |
317 |
} |
318 |
if (!filePath.isAbsolute()) { |
319 |
String message= Messages.format(NewWizardMessages.AnnotationsAttachmentBlock_filename_error_notabsolute, BasicElementLabels.getPathLabel(filePath, false)); |
320 |
status.setError(message); |
321 |
return status; |
322 |
} |
323 |
} |
324 |
return status; |
325 |
} |
326 |
|
327 |
private IPath getFilePath() { |
328 |
String filePath= fWorkspaceRadio.isSelected() ? fWorkspaceFileNameField.getText() : fExternalFileNameField.getText(); |
329 |
return Path.fromOSString(filePath).makeAbsolute(); |
330 |
} |
331 |
|
332 |
/* |
333 |
* Opens a dialog to choose a jar from the file system. |
334 |
*/ |
335 |
private IPath chooseExtJarFile() { |
336 |
IPath currPath= getFilePath(); |
337 |
if (currPath.segmentCount() == 0) { |
338 |
currPath= fEntry; |
339 |
} |
340 |
|
341 |
if (ArchiveFileFilter.isArchivePath(currPath, true)) { |
342 |
currPath= currPath.removeLastSegments(1); |
343 |
} |
344 |
|
345 |
FileDialog dialog= new FileDialog(getShell()); |
346 |
dialog.setText(NewWizardMessages.AnnotationsAttachmentBlock_extjardialog_text); |
347 |
dialog.setFilterExtensions(ArchiveFileFilter.JAR_ZIP_FILTER_EXTENSIONS); |
348 |
dialog.setFilterPath(currPath.toOSString()); |
349 |
String res= dialog.open(); |
350 |
if (res != null) { |
351 |
return Path.fromOSString(res).makeAbsolute(); |
352 |
} |
353 |
return null; |
354 |
} |
355 |
|
356 |
private IPath chooseExtFolder() { |
357 |
IPath currPath= getFilePath(); |
358 |
if (currPath.segmentCount() == 0) { |
359 |
currPath= fEntry; |
360 |
} |
361 |
if (ArchiveFileFilter.isArchivePath(currPath, true)) { |
362 |
currPath= currPath.removeLastSegments(1); |
363 |
} |
364 |
|
365 |
DirectoryDialog dialog= new DirectoryDialog(getShell()); |
366 |
dialog.setMessage(NewWizardMessages.AnnotationsAttachmentBlock_extfolderdialog_message); |
367 |
dialog.setText(NewWizardMessages.AnnotationsAttachmentBlock_extfolderdialog_text); |
368 |
dialog.setFilterPath(currPath.toOSString()); |
369 |
String res= dialog.open(); |
370 |
if (res != null) { |
371 |
return Path.fromOSString(res).makeAbsolute(); |
372 |
} |
373 |
return null; |
374 |
} |
375 |
|
376 |
/* |
377 |
* Opens a dialog to choose an internal jar. |
378 |
*/ |
379 |
private IPath chooseInternal() { |
380 |
String initSelection= fWorkspaceFileNameField.getText(); |
381 |
|
382 |
ViewerFilter filter= new ArchiveFileFilter((List<IResource>) null, false, false); |
383 |
|
384 |
ILabelProvider lp= new WorkbenchLabelProvider(); |
385 |
ITreeContentProvider cp= new WorkbenchContentProvider(); |
386 |
|
387 |
IResource initSel= null; |
388 |
if (initSelection.length() > 0) { |
389 |
initSel= fWorkspaceRoot.findMember(new Path(initSelection)); |
390 |
} |
391 |
if (initSel == null) { |
392 |
initSel= fWorkspaceRoot.findMember(fEntry); |
393 |
} |
394 |
|
395 |
FolderSelectionDialog dialog= new FolderSelectionDialog(getShell(), lp, cp); |
396 |
dialog.setAllowMultiple(false); |
397 |
dialog.addFilter(filter); |
398 |
dialog.setTitle(NewWizardMessages.AnnotationsAttachmentBlock_intjardialog_title); |
399 |
dialog.setMessage(NewWizardMessages.AnnotationsAttachmentBlock_intjardialog_message); |
400 |
dialog.setInput(fWorkspaceRoot); |
401 |
dialog.setInitialSelection(initSel); |
402 |
if (dialog.open() == Window.OK) { |
403 |
IResource res= (IResource) dialog.getFirstResult(); |
404 |
return res.getFullPath(); |
405 |
} |
406 |
return null; |
407 |
} |
408 |
|
409 |
private Shell getShell() { |
410 |
if (fSWTWidget != null) { |
411 |
return fSWTWidget.getShell(); |
412 |
} |
413 |
return JavaPlugin.getActiveWorkbenchShell(); |
414 |
} |
415 |
|
416 |
/** |
417 |
* Takes a path and replaces the beginning with a variable name |
418 |
* (if the beginning matches with the variables value) |
419 |
* @param path the path |
420 |
* @param varName the variable |
421 |
* @return the modified path |
422 |
*/ |
423 |
private IPath modifyPath(IPath path, String varName) { |
424 |
if (varName == null || path == null) { |
425 |
return null; |
426 |
} |
427 |
if (path.isEmpty()) { |
428 |
return new Path(varName); |
429 |
} |
430 |
|
431 |
IPath varPath= JavaCore.getClasspathVariable(varName); |
432 |
if (varPath != null) { |
433 |
if (varPath.isPrefixOf(path)) { |
434 |
path= path.removeFirstSegments(varPath.segmentCount()); |
435 |
} else { |
436 |
path= new Path(path.lastSegment()); |
437 |
} |
438 |
} else { |
439 |
path= new Path(path.lastSegment()); |
440 |
} |
441 |
return new Path(varName).append(path); |
442 |
} |
443 |
|
444 |
|
445 |
/** |
446 |
* Creates a runnable that sets the annotations attachment by modifying the project's classpath. |
447 |
* @param shell the shell |
448 |
* @param newEntry the new entry |
449 |
* @param jproject the Java project |
450 |
* @param containerPath the path of the parent container or <code>null</code> if the element is not in a container |
451 |
* @param isReferencedEntry <code>true</code> iff the entry has a {@link IClasspathEntry#getReferencingEntry() referencing entry} |
452 |
* @return return the runnable |
453 |
*/ |
454 |
public static IRunnableWithProgress getRunnable(final Shell shell, final IClasspathEntry newEntry, final IJavaProject jproject, final IPath containerPath, final boolean isReferencedEntry) { |
455 |
return new IRunnableWithProgress() { |
456 |
public void run(IProgressMonitor monitor) throws InvocationTargetException { |
457 |
try { |
458 |
String[] changedAttributes= { IClasspathAttribute.EXTERNAL_ANNOTATION_PATH }; |
459 |
BuildPathSupport.modifyClasspathEntry(shell, newEntry, changedAttributes, jproject, containerPath, isReferencedEntry, monitor); |
460 |
} catch (CoreException e) { |
461 |
throw new InvocationTargetException(e); |
462 |
} |
463 |
} |
464 |
}; |
465 |
} |
466 |
} |