blob: 4c9b8670fb2107945614e5129a9fd37801655911 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2018 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
* Frits Jalvingh - Contribution for Bug 459831 - [launching] Support attaching
* external annotations to a JRE container
*******************************************************************************/
package org.eclipse.jdt.internal.debug.ui.jres;
import java.io.File;
import java.net.URL;
import java.util.Iterator;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.internal.ui.SWTFactory;
import org.eclipse.jdt.core.IClasspathAttribute;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.debug.ui.IJavaDebugUIConstants;
import org.eclipse.jdt.debug.ui.launchConfigurations.AbstractVMInstallPage;
import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin;
import org.eclipse.jdt.internal.debug.ui.jres.LibraryContentProvider.SubElement;
import org.eclipse.jdt.internal.launching.EEVMInstall;
import org.eclipse.jdt.internal.launching.EEVMType;
import org.eclipse.jdt.launching.IRuntimeClasspathEntry;
import org.eclipse.jdt.launching.IVMInstall;
import org.eclipse.jdt.launching.JavaRuntime;
import org.eclipse.jdt.launching.LibraryLocation;
import org.eclipse.jdt.launching.VMStandin;
import org.eclipse.jdt.launching.environments.ExecutionEnvironmentDescription;
import org.eclipse.jdt.ui.wizards.BuildPathDialogAccess;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.FileDialog;
/**
* Control used to edit the libraries associated with a VM install
*/
public class VMLibraryBlock extends AbstractVMInstallPage implements SelectionListener, ISelectionChangedListener {
/**
* Attribute name for the last path used to open a file/directory chooser
* dialog.
*/
protected static final String LAST_PATH_SETTING = "LAST_PATH_SETTING"; //$NON-NLS-1$
/**
* the prefix for dialog setting pertaining to this block
*/
protected static final String DIALOG_SETTINGS_PREFIX = "VMLibraryBlock"; //$NON-NLS-1$
protected boolean fInCallback = false;
protected VMStandin fVmInstall;
//widgets
protected LibraryContentProvider fLibraryContentProvider;
protected TreeViewer fLibraryViewer;
private Button fUpButton;
private Button fDownButton;
private Button fRemoveButton;
private Button fAddButton;
private Button fJavadocButton;
private Button fSourceButton;
protected Button fDefaultButton;
private IStatus[] fLibStatus;
private Button fAnnotationsButton;
/**
* Constructs a new wizard page with the given name.
*
* @param pageName page name
*/
VMLibraryBlock() {
super(JREMessages.VMLibraryBlock_2);
fLibStatus = new IStatus[]{Status.OK_STATUS};
}
/* (non-Javadoc)
* @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite)
*/
@Override
public void createControl(Composite parent) {
Font font = parent.getFont();
Composite comp = SWTFactory.createComposite(parent, font, 2, 1, GridData.FILL_BOTH, 0, 0);
fLibraryViewer= new TreeViewer(comp);
GridData gd = new GridData(GridData.FILL_BOTH);
gd.heightHint = 6;
fLibraryViewer.getControl().setLayoutData(gd);
fLibraryContentProvider= new LibraryContentProvider();
fLibraryViewer.setContentProvider(fLibraryContentProvider);
fLibraryViewer.setLabelProvider(new LibraryLabelProvider());
fLibraryViewer.setInput(this);
fLibraryViewer.addSelectionChangedListener(this);
Composite pathButtonComp = SWTFactory.createComposite(comp, font, 1, 1, GridData.VERTICAL_ALIGN_BEGINNING | GridData.HORIZONTAL_ALIGN_FILL, 0, 0);
fAddButton = SWTFactory.createPushButton(pathButtonComp, JREMessages.VMLibraryBlock_7, JREMessages.VMLibraryBlock_16, null);
fAddButton.addSelectionListener(this);
fJavadocButton = SWTFactory.createPushButton(pathButtonComp, JREMessages.VMLibraryBlock_3, JREMessages.VMLibraryBlock_17, null);
fJavadocButton.setEnabled(false);
fJavadocButton.addSelectionListener(this);
fSourceButton = SWTFactory.createPushButton(pathButtonComp, JREMessages.VMLibraryBlock_11, JREMessages.VMLibraryBlock_18, null);
fSourceButton.setEnabled(false);
fSourceButton.addSelectionListener(this);
fAnnotationsButton = SWTFactory.createPushButton(pathButtonComp, JREMessages.VMExternalAnnsBlock_3, JREMessages.VMExternalAnnsBlock_4, null);
fAnnotationsButton.setEnabled(false);
fAnnotationsButton.addSelectionListener(this);
fLibraryViewer.addDoubleClickListener(new IDoubleClickListener() {
@Override
public void doubleClick(DoubleClickEvent event) {
IStructuredSelection sel = (IStructuredSelection)event.getViewer().getSelection();
Object obj = sel.getFirstElement();
if(obj instanceof SubElement) {
edit(sel, ((SubElement)obj).getType());
}
}
});
fRemoveButton = SWTFactory.createPushButton(pathButtonComp, JREMessages.VMLibraryBlock_6, JREMessages.VMLibraryBlock_12, null);
fRemoveButton.setEnabled(false);
fRemoveButton.addSelectionListener(this);
fUpButton = SWTFactory.createPushButton(pathButtonComp, JREMessages.VMLibraryBlock_4, JREMessages.VMLibraryBlock_13, null);
fUpButton.setEnabled(false);
fUpButton.addSelectionListener(this);
fDownButton = SWTFactory.createPushButton(pathButtonComp, JREMessages.VMLibraryBlock_5, JREMessages.VMLibraryBlock_14, null);
fDownButton.setEnabled(false);
fDownButton.addSelectionListener(this);
fDefaultButton = SWTFactory.createPushButton(pathButtonComp, JREMessages.VMLibraryBlock_9, JREMessages.VMLibraryBlock_15, null);
fDefaultButton.addSelectionListener(this);
setControl(comp);
}
/**
* The "default" button has been toggled
*/
private void restoreDefaultLibraries() {
LibraryLocation[] libs = null;
File installLocation = null;
if (fVmInstall != null) {
if (EEVMType.ID_EE_VM_TYPE.equals(fVmInstall.getVMInstallType().getId())) {
File definitionFile = null;
String path = fVmInstall.getAttribute(EEVMInstall.ATTR_DEFINITION_FILE);
if (path != null) {
definitionFile = new File(path);
}
if (definitionFile != null) {
try {
ExecutionEnvironmentDescription desc = new ExecutionEnvironmentDescription(definitionFile);
libs = desc.getLibraryLocations();
} catch (CoreException e) {
libs = new LibraryLocation[0];
}
} else {
libs = new LibraryLocation[0];
}
} else {
installLocation = fVmInstall.getInstallLocation();
if (installLocation == null) {
libs = new LibraryLocation[0];
} else {
libs = fVmInstall.getVMInstallType().getDefaultLibraryLocations(installLocation);
}
}
}
fLibraryContentProvider.setLibraries(libs);
update();
}
/**
* Updates buttons and status based on current libraries
*/
private void update() {
updateButtons();
IStatus status = Status.OK_STATUS;
if (fLibraryContentProvider.getLibraries().length == 0) {
status = new Status(IStatus.ERROR, JDIDebugUIPlugin.getUniqueIdentifier(), IJavaDebugUIConstants.INTERNAL_ERROR, JREMessages.VMLibraryBlock_19, null);
}
LibraryStandin[] standins = fLibraryContentProvider.getStandins();
for (int i = 0; i < standins.length; i++) {
IStatus st = standins[i].validate();
if (!st.isOK()) {
status = st;
break;
}
}
fLibStatus[0] = status;
if (status.isOK()) {
setErrorMessage(null);
setPageComplete(true);
} else {
setErrorMessage(status.getMessage());
setPageComplete(false);
}
// must force since this page is a 'sub-page' and may not be considered the current page
if (getContainer().getCurrentPage() != this) {
getContainer().updateMessage();
getContainer().updateButtons();
}
}
/**
* Determines if the current libraries displayed to the user are the default location
* for the given vm working copy.
* @param vm the virtual machine to check for the default location
* @return true if the current set of locations are the defaults, false otherwise
*/
protected boolean isDefaultLocations(IVMInstall vm) {
LibraryLocation[] libraryLocations = fLibraryContentProvider.getLibraries();
if (vm == null || libraryLocations == null) {
return true;
}
File installLocation = vm.getInstallLocation();
if (installLocation != null) {
LibraryLocation[] def = vm.getVMInstallType().getDefaultLibraryLocations(installLocation);
if (def.length == libraryLocations.length) {
for (int i = 0; i < def.length; i++) {
if (!def[i].equals(libraryLocations[i])) {
return false;
}
}
return true;
}
}
return false;
}
/* (non-Javadoc)
* @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent)
*/
@Override
public void widgetSelected(SelectionEvent e) {
boolean completed = true;
Object source= e.getSource();
if (source == fUpButton) {
fLibraryContentProvider.up((IStructuredSelection) fLibraryViewer.getSelection());
} else if (source == fDownButton) {
fLibraryContentProvider.down((IStructuredSelection) fLibraryViewer.getSelection());
} else if (source == fRemoveButton) {
fLibraryContentProvider.remove((IStructuredSelection) fLibraryViewer.getSelection());
} else if (source == fAddButton) {
completed = add((IStructuredSelection) fLibraryViewer.getSelection());
}
else if(source == fJavadocButton) {
edit((IStructuredSelection) fLibraryViewer.getSelection(), SubElement.JAVADOC_URL);
}
else if(source == fSourceButton) {
edit((IStructuredSelection) fLibraryViewer.getSelection(), SubElement.SOURCE_PATH);
}
else if (source == fAnnotationsButton) {
edit((IStructuredSelection) fLibraryViewer.getSelection(), SubElement.EXTERNAL_ANNOTATIONS_PATH);
}
else if (source == fDefaultButton) {
restoreDefaultLibraries();
}
if (completed) {
update();
}
}
/* (non-Javadoc)
* @see org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent)
*/
@Override
public void widgetDefaultSelected(SelectionEvent e) {}
/**
* Adds external libraries to the JRE. Returns <code>true</code> if successful and
* <code>false</code> if canceled.
*/
private boolean add(IStructuredSelection selection) {
IDialogSettings dialogSettings= JDIDebugUIPlugin.getDefault().getDialogSettings();
String lastUsedPath= dialogSettings.get(LAST_PATH_SETTING);
if (lastUsedPath == null) {
lastUsedPath= ""; //$NON-NLS-1$
}
FileDialog dialog = new FileDialog(fLibraryViewer.getControl().getShell(), SWT.MULTI | SWT.SHEET);
dialog.setText(JREMessages.VMLibraryBlock_10);
dialog.setFilterExtensions(new String[] {"*.jar;*.zip","*.*"}); //$NON-NLS-1$ //$NON-NLS-2$
dialog.setFilterPath(lastUsedPath);
String res= dialog.open();
if (res == null) {
return false;
}
String[] fileNames= dialog.getFileNames();
int nChosen= fileNames.length;
IPath filterPath= new Path(dialog.getFilterPath());
LibraryLocation[] libs= new LibraryLocation[nChosen];
for (int i= 0; i < nChosen; i++) {
libs[i]= new LibraryLocation(filterPath.append(fileNames[i]).makeAbsolute(), Path.EMPTY, Path.EMPTY);
}
dialogSettings.put(LAST_PATH_SETTING, filterPath.toOSString());
fLibraryContentProvider.add(libs, selection);
return true;
}
/**
* Open the javadoc location dialog or the source location dialog, and set the result
* to the selected libraries.
*/
private void edit(IStructuredSelection selection, int type) {
Object obj = selection.getFirstElement();
LibraryStandin standin = null;
if(obj instanceof LibraryStandin) {
standin = (LibraryStandin) obj;
}
else if(obj instanceof SubElement){
SubElement sub = (SubElement)obj;
standin = sub.getParent();
}
if(standin != null) {
LibraryLocation library = standin.toLibraryLocation();
if (type == SubElement.JAVADOC_URL) {
URL[] urls = BuildPathDialogAccess.configureJavadocLocation(fLibraryViewer.getControl().getShell(), library.getSystemLibraryPath().toOSString(), library.getJavadocLocation());
if (urls != null) {
fLibraryContentProvider.setJavadoc(urls[0], selection);
}
}
else if(type == SubElement.SOURCE_PATH){
IRuntimeClasspathEntry entry = JavaRuntime.newArchiveRuntimeClasspathEntry(library.getSystemLibraryPath());
entry.setSourceAttachmentPath(library.getSystemLibrarySourcePath());
entry.setSourceAttachmentRootPath(library.getPackageRootPath());
IClasspathEntry classpathEntry = BuildPathDialogAccess.configureSourceAttachment(fLibraryViewer.getControl().getShell(), entry.getClasspathEntry());
if (classpathEntry != null) {
fLibraryContentProvider.setSourcePath(classpathEntry.getSourceAttachmentPath(), classpathEntry.getSourceAttachmentRootPath(), selection);
}
}
else if(type == SubElement.EXTERNAL_ANNOTATIONS_PATH) {
IRuntimeClasspathEntry entry = JavaRuntime.newArchiveRuntimeClasspathEntry(library.getSystemLibraryPath());
entry.setExternalAnnotationsPath(library.getExternalAnnotationsPath());
IClasspathAttribute[] extraAttributes = entry.getClasspathEntry().getExtraAttributes();
String annotationPathString = findClasspathAttribute(extraAttributes, IClasspathAttribute.EXTERNAL_ANNOTATION_PATH);
IPath annotationPath = null == annotationPathString ? null : new Path(annotationPathString);
IPath newPath = BuildPathDialogAccess.configureExternalAnnotationsAttachment(fLibraryViewer.getControl().getShell(), annotationPath);
if (null == newPath) {
return;
}
fLibraryContentProvider.setAnnotationsPath(newPath.segmentCount() == 0 ? null : newPath, selection);
}
}
}
private static String findClasspathAttribute(IClasspathAttribute[] attributes, String name) {
for(int i = attributes.length; --i >= 0;) {
if(name.equals(attributes[i].getName())) {
return attributes[i].getValue();
}
}
return null;
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent)
*/
@Override
public void selectionChanged(SelectionChangedEvent event) {
updateButtons();
}
/**
* Refresh the enable/disable state for the buttons.
*/
private void updateButtons() {
IStructuredSelection selection = (IStructuredSelection) fLibraryViewer.getSelection();
fRemoveButton.setEnabled(!selection.isEmpty());
boolean enableUp = true,
enableDown = true,
allSource = true,
allJavadoc = true,
allAnnotations = true,
allRoots = true;
Object[] libraries = fLibraryContentProvider.getElements(null);
if (selection.isEmpty() || libraries.length == 0) {
enableUp = false;
enableDown = false;
} else {
Object first = libraries[0];
Object last = libraries[libraries.length - 1];
for (Iterator<?> iter= selection.iterator(); iter.hasNext();) {
Object element= iter.next();
Object lib;
if (element instanceof SubElement) {
allRoots = false;
SubElement subElement= (SubElement)element;
lib = (subElement).getParent().toLibraryLocation();
switch (subElement.getType()) {
case SubElement.JAVADOC_URL:
allSource = false;
allAnnotations = false;
break;
case SubElement.SOURCE_PATH:
allAnnotations = false;
allJavadoc = false;
break;
case SubElement.EXTERNAL_ANNOTATIONS_PATH:
allJavadoc = false;
allSource = false;
break;
}
} else {
lib = element;
allSource = false;
allJavadoc = false;
allAnnotations = false;
}
if (lib == first) {
enableUp = false;
}
if (lib == last) {
enableDown = false;
}
}
}
fUpButton.setEnabled(enableUp);
fDownButton.setEnabled(enableDown);
fJavadocButton.setEnabled(!selection.isEmpty() && (allJavadoc || allRoots));
fSourceButton.setEnabled(!selection.isEmpty() && (allSource || allRoots));
fAnnotationsButton.setEnabled(!selection.isEmpty() && (allAnnotations || allRoots));
}
/* (non-Javadoc)
* @see org.eclipse.jdt.debug.ui.launchConfigurations.AbstractVMInstallPage#finish()
*/
@Override
public boolean finish() {
if (fVmInstall != null) {
if (isDefaultLocations(fVmInstall)) {
fVmInstall.setLibraryLocations(null);
} else {
LibraryLocation[] libs = fLibraryContentProvider.getLibraries();
fVmInstall.setLibraryLocations(libs);
}
}
return true;
}
/* (non-Javadoc)
* @see org.eclipse.jdt.debug.ui.launchConfigurations.AbstractVMInstallPage#getSelection()
*/
@Override
public VMStandin getSelection() {
return fVmInstall;
}
/* (non-Javadoc)
* @see org.eclipse.jdt.debug.ui.launchConfigurations.AbstractVMInstallPage#setSelection(org.eclipse.jdt.launching.VMStandin)
*/
@Override
public void setSelection(VMStandin vm) {
super.setSelection(vm);
LibraryLocation[] libraryLocations = null;
if (vm == null) {
libraryLocations = new LibraryLocation[0];
} else {
libraryLocations = JavaRuntime.getLibraryLocations(vm);
}
fVmInstall = vm;
fLibraryContentProvider.setLibraries(libraryLocations);
}
/* (non-Javadoc)
* @see org.eclipse.jdt.debug.ui.launchConfigurations.AbstractVMInstallPage#getVMStatus()
*/
@Override
protected IStatus[] getVMStatus() {
return fLibStatus;
}
}