blob: 141be74a8e7adbf2710656053aaa408a50f97328 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2001, 2004 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
/*
* $RCSfile: BeaninfoPathsBlock.java,v $
* $Revision: 1.8 $ $Date: 2005/04/06 22:24:40 $
*/
package org.eclipse.jem.internal.beaninfo.ui;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.*;
import java.util.List;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
import org.eclipse.jdt.core.*;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.JavaPluginImages;
import org.eclipse.jdt.internal.ui.dialogs.StatusInfo;
import org.eclipse.jdt.internal.ui.viewsupport.ImageDisposer;
import org.eclipse.jdt.internal.ui.wizards.IStatusChangeListener;
import org.eclipse.jdt.internal.ui.wizards.dialogfields.*;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.*;
import org.eclipse.jem.internal.beaninfo.adapters.BeaninfoNature;
import org.eclipse.jem.internal.beaninfo.core.*;
import org.eclipse.jem.internal.ui.core.JEMUIPlugin;
public class BeaninfoPathsBlock {
private IWorkspaceRoot fWorkspaceRoot;
private CheckedListDialogField fSearchOrder;
// Search path list. filtered for each tab page to appropriate entries
private SelectionButtonDialogField fEnableBeaninfoDialogField;
// Checkbox to add/remove beaninfo nature entirely.
private StatusInfo fSearchStatus;
private IJavaProject fCurrJProject;
private IStatusChangeListener fContext;
private PackagesWorkbookPage fPackagesPage;
private BeaninfosWorkbookPage fBeaninfosPage;
private BuildSearchBasePage fCurrPage;
private SearchPathListLabelProvider labelProvider;
public BeaninfoPathsBlock(IWorkspaceRoot root, IStatusChangeListener context) {
fWorkspaceRoot = root;
fContext = context;
fCurrPage = null;
BuildPathAdapter adapter = new BuildPathAdapter();
String[] buttonLabels = new String[] {
/* 0 */
BeanInfoUIMessages.getString(BeanInfoUIMessages.BPB_SEARCHPATH_UP),
/* 1 */
BeanInfoUIMessages.getString(BeanInfoUIMessages.BPB_SEARCHPATH_DOWN),
/* 2 */ null,
/* 3 */ BeanInfoUIMessages.getString("BeanInfoPathsBlock.ExportAll") , //$NON-NLS-1$
/* 4 */ BeanInfoUIMessages.getString("BeanInfoPathsBlock.UnexportAll") //$NON-NLS-1$
};
labelProvider = new SearchPathListLabelProvider(); // We keep around to update with latest project.
fSearchOrder = new CheckedListDialogField(null, buttonLabels, labelProvider);
fSearchOrder.setDialogFieldListener(adapter);
fSearchOrder.setLabelText(
BeanInfoUIMessages.getString(BeanInfoUIMessages.BPB_SEARCHPATH_LABEL));
fSearchOrder.setUpButtonIndex(0);
fSearchOrder.setDownButtonIndex(1);
fSearchOrder.setCheckAllButtonIndex(3);
fSearchOrder.setUncheckAllButtonIndex(4);
fEnableBeaninfoDialogField = new SelectionButtonDialogField(SWT.CHECK);
fEnableBeaninfoDialogField.setLabelText(
BeanInfoUIMessages.getString(BeanInfoUIMessages.BPB_ENABLEBEANINFO));
fSearchStatus = new StatusInfo();
fCurrJProject = null;
}
public CheckedListDialogField getSearchOrder() {
return fSearchOrder;
}
/*
* searchOrder dialog must never have all of elements set
* directly. Must come through here first so that we can
* make sure updates occur in correct sequence, else
* we will wind up with entries being marked as unexported
* when they really are exported.
*/
public void setSearchOrderElements(List newElements) {
ArrayList exportedEntries = new ArrayList(newElements.size());
for (Iterator iter = newElements.iterator(); iter.hasNext();) {
BPListElement element = (BPListElement) iter.next();
if (element.isExported())
exportedEntries.add(element);
}
inUpdate = true; // So that on first set we don't waste time updating the list and reseting all of our entries.
fSearchOrder.setElements(newElements);
inUpdate = false;
fSearchOrder.setCheckedElements(exportedEntries);
}
// -------- UI creation ---------
public Control createControl(Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
layout.marginWidth = 0;
layout.numColumns = 1;
composite.setLayout(layout);
TabFolder folder = new TabFolder(composite, SWT.NONE);
folder.setLayoutData(new GridData(GridData.FILL_BOTH));
folder.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
tabChanged(e.item);
}
});
ImageRegistry imageRegistry = JavaPlugin.getDefault().getImageRegistry();
TabItem item;
ArrayList interestedDialogFields = new ArrayList(3);
fPackagesPage = new PackagesWorkbookPage(fWorkspaceRoot, this, interestedDialogFields);
item = new TabItem(folder, SWT.NONE);
item.setText(BeanInfoUIMessages.getString("BeanInfoPathsBlock.Page.Tab.Packages")); //$NON-NLS-1$
item.setImage(imageRegistry.get(JavaPluginImages.IMG_OBJS_PACKAGE));
item.setData(fPackagesPage);
item.setControl(fPackagesPage.getControl(folder));
// a non shared image
Image fBeanImage = null;
URL imageURL = Platform.find(JEMUIPlugin.getPlugin().getBundle(), new Path("icons/javabean.gif")); //$NON-NLS-1$
if (imageURL != null)
fBeanImage = ImageDescriptor.createFromURL(imageURL).createImage();
else
fBeanImage = ImageDescriptor.getMissingImageDescriptor().createImage();
composite.addDisposeListener(new ImageDisposer(fBeanImage));
fBeaninfosPage= new BeaninfosWorkbookPage(fWorkspaceRoot, this, interestedDialogFields);
item= new TabItem(folder, SWT.NONE);
item.setText(BeanInfoUIMessages.getString("BeanInfoPathsBlock.Page.Tab.Classes")); //$NON-NLS-1$
item.setImage(fBeanImage);
item.setData(fBeaninfosPage);
item.setControl(fBeaninfosPage.getControl(folder));
// a non shared image
Image cpoImage = JavaPluginImages.DESC_TOOL_CLASSPATH_ORDER.createImage();
composite.addDisposeListener(new ImageDisposer(cpoImage));
SearchpathOrderingWorkbookPage ordpage = new SearchpathOrderingWorkbookPage(fSearchOrder, interestedDialogFields);
item = new TabItem(folder, SWT.NONE);
item.setText(BeanInfoUIMessages.getString(BeanInfoUIMessages.BPB_SEARCHPATH_TAB_ORDER));
item.setImage(cpoImage);
item.setData(ordpage);
item.setControl(ordpage.getControl(folder));
if (fCurrJProject != null) {
fPackagesPage.init(fCurrJProject);
fBeaninfosPage.init(fCurrJProject);
}
fEnableBeaninfoDialogField.doFillIntoGrid(composite, 1);
fEnableBeaninfoDialogField.attachDialogFields((DialogField[]) interestedDialogFields.toArray(new DialogField[interestedDialogFields.size()]));
folder.setSelection(2);
fCurrPage = ordpage;
fSearchOrder.selectFirstElement();
// WorkbenchHelp.setHelp(composite, new Object[] { IJavaHelpContextIds.BUILD_PATH_BLOCK });
return composite;
}
/**
* Initializes the classpath for the given project. Multiple calls to init are allowed,
* but all existing settings will be cleared and replace by the given or default paths.
* @param project The java project to configure.
*/
public void init(IJavaProject jproject) {
fCurrJProject = jproject;
labelProvider.setJavaProject(jproject);
try {
// If we have a config file, we will assume we have a nature. It will add it automatically
// when we ask for the information. Even if we didn't have the nature, as soon as someone
// asks for it, we would create it anyhow, and it would use the existing config file.
// If we don't have a config file, we could have the nature, so we will check for that too.
boolean haveConfigFile = jproject.getProject().getFile(BeaninfoNature.P_BEANINFO_SEARCH_PATH).exists();
boolean haveNature = fCurrJProject.getProject().hasNature(BeaninfoNature.NATURE_ID);
fEnableBeaninfoDialogField.setSelection(haveConfigFile || haveNature);
if (haveNature || haveConfigFile) {
BeaninfosDoc doc = BeaninfoNature.getRuntime(fCurrJProject.getProject()).getSearchPath();
IClasspathEntry[] raw = fCurrJProject.getRawClasspath();
List newSearchpath = new ArrayList();
if (doc != null) {
IBeaninfosDocEntry[] sp = doc.getSearchpath();
for (int i = 0; i < sp.length; i++) {
IBeaninfosDocEntry curr = sp[i];
boolean isMissing = false;
BPListElement elem = null;
if (curr instanceof BeaninfoEntry) {
BeaninfoEntry be = (BeaninfoEntry) curr;
// get the resource, this tells if the beaninfos exist or not.
Object[] paths = be.getClasspath(fCurrJProject);
if (paths != null && paths.length > 0) {
for (int j = 0; !isMissing && j < paths.length; j++) {
Object path = paths[i];
if (path instanceof IProject)
isMissing = !((IProject) path).exists();
else if (path instanceof String) {
File f = new File((String) path);
isMissing = !f.exists();
} else if (path instanceof IPath) {
isMissing = true; // Plugins are invalid in BeaninfoConfig. They only apply within contributions.
} else
isMissing = true; // Invalid, so isMissing.
}
} else
isMissing = true;
elem = new BPBeaninfoListElement(be, getInitialSearchpaths(be), isMissing);
} else {
// Searchpath entry, see if we can find the raw classpath entry that it is for.
boolean isExported = false;
boolean isPackageMissing = true;
isMissing = true; // Initially missing until we find it.
SearchpathEntry ce = (SearchpathEntry) curr;
int kind = ce.getKind();
IPath path = ce.getPath();
for (int j = 0; j < raw.length; j++) {
if (raw[j].getEntryKind() == kind && raw[j].getPath().equals(path)) {
isMissing = false;
isExported = raw[j].isExported() || raw[j].getEntryKind() == IClasspathEntry.CPE_SOURCE;
String packageName = ce.getPackage();
if (packageName != null) {
IPackageFragmentRoot[] roots = fCurrJProject.findPackageFragmentRoots(raw[j]);
for (int k = 0; k < roots.length; k++) {
IPackageFragmentRoot iroot = roots[k];
if (iroot.getPackageFragment(packageName).exists()) {
isPackageMissing = false;
break;
}
}
} else
isPackageMissing = false;
break;
}
}
elem = new BPSearchListElement(ce, isMissing, isPackageMissing, isExported);
}
newSearchpath.add(elem);
}
}
// inits the dialog field
setSearchOrderElements(newSearchpath);
if (fPackagesPage != null) {
fPackagesPage.init(fCurrJProject);
fBeaninfosPage.init(fCurrJProject);
}
} else {
// No nature, disable,
fEnableBeaninfoDialogField.setSelection(false);
}
} catch (JavaModelException e) {
fEnableBeaninfoDialogField.setSelection(false);
} catch (CoreException e) {
fEnableBeaninfoDialogField.setSelection(false);
}
// listenForClasspathChange();
doStatusLineUpdate();
}
/*
* Create the Searchpath elements for a BeaninfoElement.
* Return null if not to update.
*/
private BPSearchListElement[] getInitialSearchpaths(BeaninfoEntry infoEntry) {
// We can only verify the existence of packages within beaninfos that are
// located within a project on the desktop. Otherwise we can't find out what
// packages are in them.
IPackageFragmentRoot[] roots = null;
if (infoEntry.getKind() != BeaninfoEntry.BIE_PLUGIN) {
IClasspathEntry resolved = JavaCore.getResolvedClasspathEntry(infoEntry.getClasspathEntry());
IResource res = fWorkspaceRoot.findMember(resolved.getPath());
if (res != null && res.exists()) {
if (res instanceof IProject) {
// It is a project itself.
IJavaProject jp = (IJavaProject) JavaCore.create(res);
try {
if (jp != null)
roots = jp.getPackageFragmentRoots(); // All of the roots in the project are applicable.
} catch (JavaModelException e) {
}
} else {
// It is within another project
IProject containingProject = res.getProject();
IJavaProject jp = JavaCore.create(containingProject);
if (jp != null) {
// The roots if this is in the classpath of this project
try {
IPackageFragmentRoot root = jp.findPackageFragmentRoot(resolved.getPath());
if (root != null)
roots = new IPackageFragmentRoot[] { root };
} catch (JavaModelException e) {
}
}
}
}
}
SearchpathEntry[] entries = infoEntry.getSearchPaths();
BPSearchListElement[] packageElements = new BPSearchListElement[entries.length];
for (int i = 0;
i < entries.length;
i++) { // Searchpath entry, see if we can find the raw classpath entry that it is for.
boolean isPackageMissing = roots != null;
// If roots is null, then the package isn't missing because we can't test for it.
SearchpathEntry ce = entries[i];
if (roots != null) {
String packageName = ce.getPackage();
for (int k = 0; k < roots.length; k++) {
IPackageFragmentRoot iroot = roots[k];
if (iroot.getPackageFragment(packageName).exists()) {
isPackageMissing = false;
break;
}
}
}
packageElements[i] = new BPSearchListElement(ce, false, isPackageMissing, false);
}
return packageElements;
}
// -------- public api --------
/**
* Returns the Java project. Can return <code>null<code> if the page has not
* been initialized.
*/
public IJavaProject getJavaProject() {
return fCurrJProject;
}
private class BuildPathAdapter implements IDialogFieldListener {
// ---------- IDialogFieldListener --------
public void dialogFieldChanged(DialogField field) {
buildPathDialogFieldChanged(field);
}
}
private void buildPathDialogFieldChanged(DialogField field) {
if (field == fSearchOrder) {
updateSearchPathStatus();
}
doStatusLineUpdate();
}
// -------- verification -------------------------------
private void doStatusLineUpdate() {
fContext.statusChanged(fSearchStatus);
}
private boolean inUpdate;
// Flag to indicate we are in updateSearchPathStatus and to not do it again. This can
// happen due to using setCheckedElements instead of setCheckedWithoutUpdate.
/**
* Validates the search path.
*/
private void updateSearchPathStatus() {
if (inUpdate)
return;
try {
inUpdate = true;
fSearchStatus.setOK();
List elements = fSearchOrder.getElements();
boolean entryMissing = false;
// Because of bug in setcheckedWithoutUpdate, which sets to true no matter what the state is, we need
// to accumulate the checked elements and re-set them again after this so that they will be correct.
ArrayList exported = new ArrayList();
for (Iterator entries = elements.iterator(); entries.hasNext();) {
BPListElement currElement = (BPListElement) entries.next();
boolean isChecked = fSearchOrder.isChecked(currElement);
if (currElement.canExportBeChanged()) {
if (isChecked)
exported.add(currElement);
currElement.setExported(isChecked);
} else {
// fSearchOrder.setCheckedWithoutUpdate(currElement, currElement.isExported());
if (currElement.isExported())
exported.add(currElement);
}
entryMissing = entryMissing || currElement.isMissing();
}
// Now reset the checked states, due to bug
fSearchOrder.setCheckedElements(exported);
if (entryMissing) {
fSearchStatus.setWarning(
BeanInfoUIMessages.getString(BeanInfoUIMessages.BPB_SEARCHPATH_MISSING));
}
} finally {
inUpdate = false;
}
}
// -------- creation -------------------------------
/**
* Creates a runnable that sets the configured build paths.
*/
public IRunnableWithProgress getRunnable() {
final boolean wantNature = fEnableBeaninfoDialogField.isSelected();
final List searchPathEntries = wantNature ? fSearchOrder.getElements() : null;
return new IRunnableWithProgress() {
public void run(IProgressMonitor monitor) throws InvocationTargetException {
if (monitor == null) {
monitor = new NullProgressMonitor();
}
monitor.beginTask(
BeanInfoUIMessages.getString(BeanInfoUIMessages.BPB_SEARCHPATH_OPDESC),
10);
try {
setBeaninfoSearchpath(wantNature, searchPathEntries, monitor);
} catch (CoreException e) {
throw new InvocationTargetException(e);
} finally {
monitor.done();
}
}
};
}
private void setBeaninfoSearchpath(
boolean wantNature,
List searchPathEntries,
IProgressMonitor monitor)
throws CoreException {
if (wantNature) {
// create beaninfo nature
if (!fCurrJProject.getProject().hasNature(BeaninfoNature.NATURE_ID)) {
addNatureIDToProject(fCurrJProject.getProject(), BeaninfoNature.NATURE_ID, monitor);
}
BeaninfoNature nature = BeaninfoNature.getRuntime(fCurrJProject.getProject());
// Now build/set the search path.
if (searchPathEntries.size() > 0) {
IBeaninfosDocEntry[] sparray = new IBeaninfosDocEntry[searchPathEntries.size()];
Iterator itr = searchPathEntries.iterator();
int i = 0;
while (itr.hasNext()) {
BPListElement elem = (BPListElement) itr.next();
sparray[i++] = elem.getEntry();
}
nature.setSearchPath(new BeaninfosDoc(sparray), monitor);
} else
nature.setSearchPath(null, monitor);
} else {
// Remove the nature, no longer wanted.
removeNatureIDFromProject(fCurrJProject.getProject(), BeaninfoNature.NATURE_ID, monitor);
}
}
/**
* Adds a nature to a project
*/
private void addNatureIDToProject(IProject proj, String natureId, IProgressMonitor monitor)
throws CoreException {
IProjectDescription description = proj.getDescription();
String[] prevNatures = description.getNatureIds();
String[] newNatures = new String[prevNatures.length + 1];
System.arraycopy(prevNatures, 0, newNatures, 0, prevNatures.length);
newNatures[prevNatures.length] = natureId;
description.setNatureIds(newNatures);
proj.setDescription(description, monitor);
}
private void removeNatureIDFromProject(IProject proj, String natureId, IProgressMonitor monitor)
throws CoreException {
IProjectDescription description = proj.getDescription();
String[] prevNatures = description.getNatureIds();
int indx = -1;
for (int i = 0; i < prevNatures.length; i++) {
if (prevNatures[i].equals(natureId)) {
indx = i;
break;
}
}
if (indx == -1)
return;
String[] newNatures = new String[prevNatures.length - 1];
if (newNatures.length != 0) {
System.arraycopy(prevNatures, 0, newNatures, 0, indx);
if (indx < newNatures.length)
System.arraycopy(prevNatures, indx + 1, newNatures, indx, newNatures.length - indx);
}
description.setNatureIds(newNatures);
proj.setDescription(description, monitor);
}
// -------- tab switching ----------
private void tabChanged(Widget widget) {
if (widget instanceof TabItem) {
BuildSearchBasePage newPage = (BuildSearchBasePage) ((TabItem) widget).getData();
if (fCurrPage != null) {
List selection = fCurrPage.getSelection();
if (!selection.isEmpty()) {
newPage.setSelection(selection);
}
}
fCurrPage = newPage;
}
}
}