001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.ui.wizards.buildpaths;
011:
012: import java.io.File;
013: import java.lang.reflect.InvocationTargetException;
014: import java.util.List;
015:
016: import org.eclipse.core.runtime.Assert;
017: import org.eclipse.core.runtime.CoreException;
018: import org.eclipse.core.runtime.IPath;
019: import org.eclipse.core.runtime.IProgressMonitor;
020: import org.eclipse.core.runtime.IStatus;
021: import org.eclipse.core.runtime.Path;
022:
023: import org.eclipse.core.resources.IResource;
024: import org.eclipse.core.resources.IWorkspaceRoot;
025: import org.eclipse.core.resources.ResourcesPlugin;
026:
027: import org.eclipse.swt.SWT;
028: import org.eclipse.swt.layout.GridData;
029: import org.eclipse.swt.layout.GridLayout;
030: import org.eclipse.swt.widgets.Composite;
031: import org.eclipse.swt.widgets.Control;
032: import org.eclipse.swt.widgets.DirectoryDialog;
033: import org.eclipse.swt.widgets.FileDialog;
034: import org.eclipse.swt.widgets.Label;
035: import org.eclipse.swt.widgets.Shell;
036:
037: import org.eclipse.jface.dialogs.Dialog;
038: import org.eclipse.jface.operation.IRunnableWithProgress;
039: import org.eclipse.jface.viewers.ILabelProvider;
040: import org.eclipse.jface.viewers.ITreeContentProvider;
041: import org.eclipse.jface.viewers.ViewerFilter;
042: import org.eclipse.jface.window.Window;
043:
044: import org.eclipse.ui.PlatformUI;
045: import org.eclipse.ui.model.WorkbenchContentProvider;
046: import org.eclipse.ui.model.WorkbenchLabelProvider;
047:
048: import org.eclipse.jdt.core.IClasspathEntry;
049: import org.eclipse.jdt.core.IJavaProject;
050: import org.eclipse.jdt.core.JavaCore;
051:
052: import org.eclipse.jdt.internal.corext.util.Messages;
053:
054: import org.eclipse.jdt.internal.ui.IJavaHelpContextIds;
055: import org.eclipse.jdt.internal.ui.JavaPlugin;
056: import org.eclipse.jdt.internal.ui.dialogs.StatusInfo;
057: import org.eclipse.jdt.internal.ui.dialogs.StatusUtil;
058: import org.eclipse.jdt.internal.ui.util.PixelConverter;
059: import org.eclipse.jdt.internal.ui.wizards.IStatusChangeListener;
060: import org.eclipse.jdt.internal.ui.wizards.NewWizardMessages;
061: import org.eclipse.jdt.internal.ui.wizards.dialogfields.DialogField;
062: import org.eclipse.jdt.internal.ui.wizards.dialogfields.IDialogFieldListener;
063: import org.eclipse.jdt.internal.ui.wizards.dialogfields.IStringButtonAdapter;
064: import org.eclipse.jdt.internal.ui.wizards.dialogfields.LayoutUtil;
065: import org.eclipse.jdt.internal.ui.wizards.dialogfields.SelectionButtonDialogField;
066: import org.eclipse.jdt.internal.ui.wizards.dialogfields.StringButtonDialogField;
067:
068: /**
069: * UI to set the source attachment archive and root.
070: * Same implementation for both setting attachments for libraries from
071: * variable entries and for normal (internal or external) jar.
072: */
073: public class SourceAttachmentBlock {
074:
075: private IStatusChangeListener fContext;
076:
077: private StringButtonDialogField fFileNameField;
078: private SelectionButtonDialogField fWorkspaceButton;
079: private SelectionButtonDialogField fExternalFolderButton;
080:
081: private IStatus fNameStatus;
082:
083: /**
084: * The path to which the archive variable points.
085: * Null if invalid path or not resolvable. Must not exist.
086: */
087: private IPath fFileVariablePath;
088:
089: private IWorkspaceRoot fWorkspaceRoot;
090:
091: private Control fSWTWidget;
092: private Label fFullPathResolvedLabel;
093:
094: private IJavaProject fProject;
095: private IClasspathEntry fEntry;
096: private IPath fContainerPath;
097:
098: /**
099: * @param context listeners for status updates
100: * @param entry The entry to edit
101: */
102: public SourceAttachmentBlock(IStatusChangeListener context,
103: IClasspathEntry entry) {
104: Assert.isNotNull(entry);
105:
106: fContext = context;
107: fEntry = entry;
108:
109: int kind = entry.getEntryKind();
110: Assert.isTrue(kind == IClasspathEntry.CPE_LIBRARY
111: || kind == IClasspathEntry.CPE_VARIABLE);
112:
113: fWorkspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
114:
115: fNameStatus = new StatusInfo();
116:
117: SourceAttachmentAdapter adapter = new SourceAttachmentAdapter();
118:
119: // create the dialog fields (no widgets yet)
120: if (isVariableEntry()) {
121: fFileNameField = new VariablePathDialogField(adapter);
122: fFileNameField.setDialogFieldListener(adapter);
123: fFileNameField
124: .setLabelText(NewWizardMessages.SourceAttachmentBlock_filename_varlabel);
125: fFileNameField
126: .setButtonLabel(NewWizardMessages.SourceAttachmentBlock_filename_external_varbutton);
127: ((VariablePathDialogField) fFileNameField)
128: .setVariableButtonLabel(NewWizardMessages.SourceAttachmentBlock_filename_variable_button);
129:
130: } else {
131: fFileNameField = new StringButtonDialogField(adapter);
132: fFileNameField.setDialogFieldListener(adapter);
133: fFileNameField
134: .setLabelText(NewWizardMessages.SourceAttachmentBlock_filename_label);
135: fFileNameField
136: .setButtonLabel(NewWizardMessages.SourceAttachmentBlock_filename_externalfile_button);
137:
138: fWorkspaceButton = new SelectionButtonDialogField(SWT.PUSH);
139: fWorkspaceButton.setDialogFieldListener(adapter);
140: fWorkspaceButton
141: .setLabelText(NewWizardMessages.SourceAttachmentBlock_filename_internal_button);
142:
143: fExternalFolderButton = new SelectionButtonDialogField(
144: SWT.PUSH);
145: fExternalFolderButton.setDialogFieldListener(adapter);
146: fExternalFolderButton
147: .setLabelText(NewWizardMessages.SourceAttachmentBlock_filename_externalfolder_button);
148: }
149:
150: // set the old settings
151: setDefaults();
152: }
153:
154: /**
155: * @deprecated Use API {@link org.eclipse.jdt.ui.wizards.BuildPathDialogAccess#configureSourceAttachment(Shell, IClasspathEntry)}
156: */
157: public SourceAttachmentBlock(IStatusChangeListener context,
158: IClasspathEntry entry, IPath containerPath,
159: IJavaProject project) {
160: this (context, entry);
161: fContainerPath = containerPath;
162: fProject = project;
163: }
164:
165: public void setDefaults() {
166: if (fEntry.getSourceAttachmentPath() != null) {
167: fFileNameField.setText(fEntry.getSourceAttachmentPath()
168: .toString());
169: } else {
170: fFileNameField.setText(""); //$NON-NLS-1$
171: }
172: }
173:
174: private boolean isVariableEntry() {
175: return fEntry.getEntryKind() == IClasspathEntry.CPE_VARIABLE;
176: }
177:
178: /**
179: * Gets the source attachment path chosen by the user
180: */
181: public IPath getSourceAttachmentPath() {
182: if (fFileNameField.getText().length() == 0) {
183: return null;
184: }
185: return getFilePath();
186: }
187:
188: /**
189: * Gets the source attachment root chosen by the user
190: * Returns null to let JCore automatically detect the root.
191: */
192: public IPath getSourceAttachmentRootPath() {
193: return null;
194: }
195:
196: public IClasspathEntry getNewEntry() {
197: CPListElement elem = CPListElement.createFromExisting(fEntry,
198: fProject);
199: elem.setAttribute(CPListElement.SOURCEATTACHMENT,
200: getSourceAttachmentPath());
201: return elem.getClasspathEntry();
202: }
203:
204: /**
205: * Creates the control
206: */
207: public Control createControl(Composite parent) {
208: PixelConverter converter = new PixelConverter(parent);
209:
210: fSWTWidget = parent;
211:
212: Composite composite = new Composite(parent, SWT.NONE);
213:
214: GridLayout layout = new GridLayout();
215: layout.marginHeight = 0;
216: layout.marginWidth = 0;
217: layout.numColumns = 4;
218: composite.setLayout(layout);
219:
220: if (isVariableEntry()) {
221: int widthHint = converter.convertWidthInCharsToPixels(40);
222: int labelWidthHint = widthHint * 2;
223:
224: Label message = new Label(composite, SWT.WRAP);
225: GridData gd = new GridData(GridData.FILL,
226: GridData.BEGINNING, false, false, 4, 1);
227: message.setLayoutData(gd);
228: message.setText(Messages.format(
229: NewWizardMessages.SourceAttachmentBlock_message,
230: fEntry.getPath().lastSegment()));
231:
232: //DialogField.createEmptySpace(composite, 1);
233:
234: Label desc = new Label(composite, SWT.WRAP);
235: gd = new GridData(GridData.FILL, GridData.BEGINNING, false,
236: false, 4, 1);
237: gd.widthHint = labelWidthHint;
238: desc.setLayoutData(gd);
239: desc
240: .setText(NewWizardMessages.SourceAttachmentBlock_filename_description);
241:
242: fFileNameField.doFillIntoGrid(composite, 4);
243: LayoutUtil.setWidthHint(
244: fFileNameField.getTextControl(null), widthHint);
245:
246: // label that shows the resolved path for variable jars
247: //DialogField.createEmptySpace(composite, 1);
248: fFullPathResolvedLabel = new Label(composite, SWT.WRAP);
249: fFullPathResolvedLabel.setText(getResolvedLabelString());
250: gd = new GridData(GridData.FILL, GridData.BEGINNING, false,
251: false, 4, 1);
252: gd.widthHint = labelWidthHint;
253: fFullPathResolvedLabel.setLayoutData(gd);
254:
255: LayoutUtil.setHorizontalGrabbing(fFileNameField
256: .getTextControl(null));
257: } else {
258: int widthHint = converter.convertWidthInCharsToPixels(60);
259:
260: GridData gd = new GridData(GridData.FILL,
261: GridData.BEGINNING, false, false, 3, 1);
262: gd.widthHint = converter.convertWidthInCharsToPixels(50);
263:
264: Label message = new Label(composite, SWT.LEFT + SWT.WRAP);
265: message.setLayoutData(gd);
266: message.setText(Messages.format(
267: NewWizardMessages.SourceAttachmentBlock_message,
268: fEntry.getPath().lastSegment()));
269:
270: fWorkspaceButton.doFillIntoGrid(composite, 1);
271: ((GridData) fWorkspaceButton.getSelectionButton(null)
272: .getLayoutData()).verticalAlignment = SWT.END;
273:
274: // archive name field
275: fFileNameField.doFillIntoGrid(composite, 4);
276: LayoutUtil.setWidthHint(
277: fFileNameField.getTextControl(null), widthHint);
278: LayoutUtil.setHorizontalGrabbing(fFileNameField
279: .getTextControl(null));
280:
281: // Additional 'browse workspace' button for normal jars
282: DialogField.createEmptySpace(composite, 3);
283:
284: fExternalFolderButton.doFillIntoGrid(composite, 1);
285: }
286:
287: fFileNameField.postSetFocusOnDialogField(parent.getDisplay());
288:
289: Dialog.applyDialogFont(composite);
290:
291: PlatformUI.getWorkbench().getHelpSystem().setHelp(composite,
292: IJavaHelpContextIds.SOURCE_ATTACHMENT_BLOCK);
293: return composite;
294: }
295:
296: private class SourceAttachmentAdapter implements
297: IStringButtonAdapter, IDialogFieldListener {
298:
299: // -------- IStringButtonAdapter --------
300: public void changeControlPressed(DialogField field) {
301: attachmentChangeControlPressed(field);
302: }
303:
304: // ---------- IDialogFieldListener --------
305: public void dialogFieldChanged(DialogField field) {
306: attachmentDialogFieldChanged(field);
307: }
308: }
309:
310: private void attachmentChangeControlPressed(DialogField field) {
311: if (field == fFileNameField) {
312: IPath jarFilePath = isVariableEntry() ? chooseExtension()
313: : chooseExtJarFile();
314: if (jarFilePath != null) {
315: fFileNameField.setText(jarFilePath.toString());
316: }
317: }
318: }
319:
320: // ---------- IDialogFieldListener --------
321:
322: private void attachmentDialogFieldChanged(DialogField field) {
323: if (field == fFileNameField) {
324: fNameStatus = updateFileNameStatus();
325: } else if (field == fWorkspaceButton) {
326: IPath jarFilePath = chooseInternal();
327: if (jarFilePath != null) {
328: fFileNameField.setText(jarFilePath.toString());
329: }
330: return;
331: } else if (field == fExternalFolderButton) {
332: IPath folderPath = chooseExtFolder();
333: if (folderPath != null) {
334: fFileNameField.setText(folderPath.toString());
335: }
336: return;
337: }
338: doStatusLineUpdate();
339: }
340:
341: private void doStatusLineUpdate() {
342: fFileNameField.enableButton(canBrowseFileName());
343:
344: // set the resolved path for variable jars
345: if (fFullPathResolvedLabel != null) {
346: fFullPathResolvedLabel.setText(getResolvedLabelString());
347: }
348:
349: IStatus status = StatusUtil
350: .getMostSevere(new IStatus[] { fNameStatus });
351: fContext.statusChanged(status);
352: }
353:
354: private boolean canBrowseFileName() {
355: if (!isVariableEntry()) {
356: return true;
357: }
358: // to browse with a variable JAR, the variable name must point to a directory
359: if (fFileVariablePath != null) {
360: return fFileVariablePath.toFile().isDirectory();
361: }
362: return false;
363: }
364:
365: private String getResolvedLabelString() {
366: IPath resolvedPath = getResolvedPath(getFilePath());
367: if (resolvedPath != null) {
368: return resolvedPath.toOSString();
369: }
370: return ""; //$NON-NLS-1$
371: }
372:
373: private IPath getResolvedPath(IPath path) {
374: if (path != null) {
375: String varName = path.segment(0);
376: if (varName != null) {
377: IPath varPath = JavaCore.getClasspathVariable(varName);
378: if (varPath != null) {
379: return varPath.append(path.removeFirstSegments(1));
380: }
381: }
382: }
383: return null;
384: }
385:
386: private IStatus updateFileNameStatus() {
387: StatusInfo status = new StatusInfo();
388: fFileVariablePath = null;
389:
390: String fileName = fFileNameField.getText();
391: if (fileName.length() == 0) {
392: // no source attachment
393: return status;
394: } else {
395: if (!Path.EMPTY.isValidPath(fileName)) {
396: status
397: .setError(NewWizardMessages.SourceAttachmentBlock_filename_error_notvalid);
398: return status;
399: }
400: IPath filePath = Path.fromOSString(fileName);
401: IPath resolvedPath;
402: if (isVariableEntry()) {
403: if (filePath.getDevice() != null) {
404: status
405: .setError(NewWizardMessages.SourceAttachmentBlock_filename_error_deviceinpath);
406: return status;
407: }
408: String varName = filePath.segment(0);
409: if (varName == null) {
410: status
411: .setError(NewWizardMessages.SourceAttachmentBlock_filename_error_notvalid);
412: return status;
413: }
414: fFileVariablePath = JavaCore
415: .getClasspathVariable(varName);
416: if (fFileVariablePath == null) {
417: status
418: .setError(NewWizardMessages.SourceAttachmentBlock_filename_error_varnotexists);
419: return status;
420: }
421: resolvedPath = fFileVariablePath.append(filePath
422: .removeFirstSegments(1));
423:
424: if (resolvedPath.isEmpty()) {
425: status
426: .setWarning(NewWizardMessages.SourceAttachmentBlock_filename_warning_varempty);
427: return status;
428: }
429: File file = resolvedPath.toFile();
430: if (!file.exists()) {
431: String message = Messages
432: .format(
433: NewWizardMessages.SourceAttachmentBlock_filename_error_filenotexists,
434: resolvedPath.toOSString());
435: status.setWarning(message);
436: return status;
437: }
438: if (!resolvedPath.isAbsolute()) {
439: String message = Messages
440: .format(
441: NewWizardMessages.SourceAttachmentBlock_filename_error_notabsolute,
442: filePath.toString());
443: status.setError(message);
444: return status;
445: }
446:
447: String deprecationMessage = BuildPathSupport
448: .getDeprecationMessage(varName);
449: if (deprecationMessage != null) {
450: status.setWarning(deprecationMessage);
451: return status;
452: }
453:
454: } else {
455: // JDT/Core only supports source attachments in archives on the
456: // local file system. So using getLocation is save here.
457: File file = filePath.toFile();
458: IResource res = fWorkspaceRoot.findMember(filePath);
459: if (res != null && res.getLocation() != null) {
460: file = res.getLocation().toFile();
461: }
462: if (!file.exists()) {
463: String message = Messages
464: .format(
465: NewWizardMessages.SourceAttachmentBlock_filename_error_filenotexists,
466: filePath.toString());
467: status.setError(message);
468: return status;
469: }
470: if (res == null) {
471: if (!filePath.isAbsolute()) {
472: String message = Messages
473: .format(
474: NewWizardMessages.SourceAttachmentBlock_filename_error_notabsolute,
475: filePath.toString());
476: status.setError(message);
477: return status;
478: }
479: }
480: }
481:
482: }
483: return status;
484: }
485:
486: private IPath getFilePath() {
487: return Path.fromOSString(fFileNameField.getText())
488: .makeAbsolute();
489: }
490:
491: private IPath chooseExtension() {
492: IPath currPath = getFilePath();
493: if (currPath.segmentCount() == 0) {
494: currPath = fEntry.getPath();
495: }
496:
497: IPath resolvedPath = getResolvedPath(currPath);
498: File initialSelection = resolvedPath != null ? resolvedPath
499: .toFile() : null;
500:
501: String currVariable = currPath.segment(0);
502: JARFileSelectionDialog dialog = new JARFileSelectionDialog(
503: getShell(), false, true);
504: dialog
505: .setTitle(NewWizardMessages.SourceAttachmentBlock_extvardialog_title);
506: dialog
507: .setMessage(NewWizardMessages.SourceAttachmentBlock_extvardialog_description);
508: dialog.setInput(fFileVariablePath.toFile());
509: dialog.setInitialSelection(initialSelection);
510: if (dialog.open() == Window.OK) {
511: File result = (File) dialog.getResult()[0];
512: IPath returnPath = Path.fromOSString(result.getPath())
513: .makeAbsolute();
514: return modifyPath(returnPath, currVariable);
515: }
516: return null;
517: }
518:
519: /*
520: * Opens a dialog to choose a jar from the file system.
521: */
522: private IPath chooseExtJarFile() {
523: IPath currPath = getFilePath();
524: if (currPath.segmentCount() == 0) {
525: currPath = fEntry.getPath();
526: }
527:
528: if (ArchiveFileFilter.isArchivePath(currPath)) {
529: currPath = currPath.removeLastSegments(1);
530: }
531:
532: FileDialog dialog = new FileDialog(getShell());
533: dialog
534: .setText(NewWizardMessages.SourceAttachmentBlock_extjardialog_text);
535: dialog.setFilterExtensions(new String[] { "*.jar;*.zip" }); //$NON-NLS-1$
536: dialog.setFilterPath(currPath.toOSString());
537: String res = dialog.open();
538: if (res != null) {
539: return Path.fromOSString(res).makeAbsolute();
540: }
541: return null;
542: }
543:
544: private IPath chooseExtFolder() {
545: IPath currPath = getFilePath();
546: if (currPath.segmentCount() == 0) {
547: currPath = fEntry.getPath();
548: }
549: if (ArchiveFileFilter.isArchivePath(currPath)) {
550: currPath = currPath.removeLastSegments(1);
551: }
552:
553: DirectoryDialog dialog = new DirectoryDialog(getShell());
554: dialog
555: .setMessage(NewWizardMessages.SourceAttachmentBlock_extfolderdialog_message);
556: dialog
557: .setText(NewWizardMessages.SourceAttachmentBlock_extfolderdialog_text);
558: dialog.setFilterPath(currPath.toOSString());
559: String res = dialog.open();
560: if (res != null) {
561: return Path.fromOSString(res).makeAbsolute();
562: }
563: return null;
564: }
565:
566: /*
567: * Opens a dialog to choose an internal jar.
568: */
569: private IPath chooseInternal() {
570: String initSelection = fFileNameField.getText();
571:
572: ViewerFilter filter = new ArchiveFileFilter((List) null, false);
573:
574: ILabelProvider lp = new WorkbenchLabelProvider();
575: ITreeContentProvider cp = new WorkbenchContentProvider();
576:
577: IResource initSel = null;
578: if (initSelection.length() > 0) {
579: initSel = fWorkspaceRoot
580: .findMember(new Path(initSelection));
581: }
582: if (initSel == null) {
583: initSel = fWorkspaceRoot.findMember(fEntry.getPath());
584: }
585:
586: FolderSelectionDialog dialog = new FolderSelectionDialog(
587: getShell(), lp, cp);
588: dialog.setAllowMultiple(false);
589: dialog.addFilter(filter);
590: dialog
591: .setTitle(NewWizardMessages.SourceAttachmentBlock_intjardialog_title);
592: dialog
593: .setMessage(NewWizardMessages.SourceAttachmentBlock_intjardialog_message);
594: dialog.setInput(fWorkspaceRoot);
595: dialog.setInitialSelection(initSel);
596: if (dialog.open() == Window.OK) {
597: IResource res = (IResource) dialog.getFirstResult();
598: return res.getFullPath();
599: }
600: return null;
601: }
602:
603: private Shell getShell() {
604: if (fSWTWidget != null) {
605: return fSWTWidget.getShell();
606: }
607: return JavaPlugin.getActiveWorkbenchShell();
608: }
609:
610: /**
611: * Takes a path and replaces the beginning with a variable name
612: * (if the beginning matches with the variables value)
613: */
614: private IPath modifyPath(IPath path, String varName) {
615: if (varName == null || path == null) {
616: return null;
617: }
618: if (path.isEmpty()) {
619: return new Path(varName);
620: }
621:
622: IPath varPath = JavaCore.getClasspathVariable(varName);
623: if (varPath != null) {
624: if (varPath.isPrefixOf(path)) {
625: path = path.removeFirstSegments(varPath.segmentCount());
626: } else {
627: path = new Path(path.lastSegment());
628: }
629: } else {
630: path = new Path(path.lastSegment());
631: }
632: return new Path(varName).append(path);
633: }
634:
635: /**
636: * Creates a runnable that sets the source attachment by modifying the project's classpath.
637: */
638: public static IRunnableWithProgress getRunnable(final Shell shell,
639: final IClasspathEntry newEntry,
640: final IJavaProject jproject, final IPath containerPath) {
641: return new IRunnableWithProgress() {
642: public void run(IProgressMonitor monitor)
643: throws InvocationTargetException {
644: try {
645: String[] changedAttributes = { CPListElement.SOURCEATTACHMENT };
646: BuildPathSupport.modifyClasspathEntry(shell,
647: newEntry, changedAttributes, jproject,
648: containerPath, monitor);
649: } catch (CoreException e) {
650: throw new InvocationTargetException(e);
651: }
652: }
653: };
654: }
655:
656: /**
657: * @deprecated Use {@link #getRunnable(Shell, IClasspathEntry, IJavaProject, IPath)}
658: */
659: public IRunnableWithProgress getRunnable(final Shell shell) {
660: return getRunnable(shell, getNewEntry(), fProject,
661: fContainerPath);
662: }
663:
664: }
|