blob: bbe66c70610296d91d6c794bd2512fb8fccc6075 [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2009 Red Hat
* 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:
* Rob Stryker - initial implementation and ongoing maintenance
******************************************************************************/
package org.eclipse.jst.common.ui.internal.assembly.wizard;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.viewers.BaseLabelProvider;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableLayout;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.window.Window;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.jst.common.internal.modulecore.util.ArchiveManifest;
import org.eclipse.jst.common.internal.modulecore.util.JavaModuleComponentUtility;
import org.eclipse.jst.common.internal.modulecore.util.ManifestUtilities;
import org.eclipse.jst.common.internal.modulecore.util.UpdateManifestDataModelProperties;
import org.eclipse.jst.common.internal.modulecore.util.UpdateManifestDataModelProvider;
import org.eclipse.jst.common.ui.internal.IJstCommonUIContextIds;
import org.eclipse.jst.common.ui.internal.Messages;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.ui.PlatformUI;
import org.eclipse.wst.common.componentcore.ComponentCore;
import org.eclipse.wst.common.componentcore.internal.resources.AbstractResourceListVirtualComponent;
import org.eclipse.wst.common.componentcore.resources.IVirtualComponent;
import org.eclipse.wst.common.componentcore.resources.IVirtualFile;
import org.eclipse.wst.common.componentcore.resources.IVirtualFolder;
import org.eclipse.wst.common.componentcore.resources.IVirtualReference;
import org.eclipse.wst.common.componentcore.ui.ModuleCoreUIPlugin;
import org.eclipse.wst.common.componentcore.ui.internal.propertypage.DependencyPageExtensionManager;
import org.eclipse.wst.common.componentcore.ui.internal.propertypage.IVirtualComponentLabelProvider;
import org.eclipse.wst.common.componentcore.ui.propertypage.IModuleDependenciesControl;
import org.eclipse.wst.common.componentcore.ui.propertypage.ModuleAssemblyRootPage;
import org.eclipse.wst.common.frameworks.datamodel.DataModelFactory;
import org.eclipse.wst.common.frameworks.datamodel.IDataModel;
public class ManifestModuleDependencyControl implements
IModuleDependenciesControl {
protected IProject project;
protected IVirtualComponent rootComponent;
protected IProject parentProject;
protected ModuleAssemblyRootPage propPage;
protected Button addButton, removeButton, moveUpButton, moveDownButton;
protected Combo parentSelection;
protected TableViewer manifestEntryViewer;
private ArrayList<IVirtualReference> list = new ArrayList<IVirtualReference>();
private String previousManifest = null;
public ManifestModuleDependencyControl(final IProject project,
final ModuleAssemblyRootPage page) {
this.project = project;
this.propPage = page;
rootComponent = ComponentCore.createComponent(project);
}
/*
* Convenience method to quickly create form datas,
* referencing either pixel counts (via autoboxing) or controls.
* If the object is null, no attachment will be created for that side
*/
public static FormData createFormData(Object top, int topDif, Object bottom, int bottomDif,
Object left, int leftDif, Object right, int rightDif) {
FormData fd = new FormData();
if( top instanceof Control ) fd.top = new FormAttachment((Control)top, topDif);
else if( top != null ) fd.top = new FormAttachment(((Integer)top).intValue(), topDif);
if( bottom instanceof Control ) fd.bottom = new FormAttachment((Control)bottom, bottomDif);
else if( bottom != null ) fd.bottom = new FormAttachment(((Integer)bottom).intValue(), bottomDif);
if( left instanceof Control ) fd.left = new FormAttachment((Control)left, leftDif);
else if( left != null ) fd.left = new FormAttachment(((Integer)left).intValue(), leftDif);
if( right instanceof Control ) fd.right = new FormAttachment((Control)right, rightDif);
else if( right != null ) fd.right = new FormAttachment(((Integer)right).intValue(), rightDif);
return fd;
}
public Composite createContents(Composite parent) {
Composite root = new Composite(parent, SWT.NONE);
PlatformUI.getWorkbench().getHelpSystem().setHelp(root, IJstCommonUIContextIds.DEPLOYMENT_ASSEMBLY_PREFERENCE_PAGE_MANIFEST_ENTRIES_TAB);
root.setLayout(new FormLayout());
Label l = new Label(root, SWT.NONE);
l.setText(Messages.ParentProjects);
l.setLayoutData(createFormData(0,10,null,0, 0, 5, null,0));
parentSelection = new Combo(root, SWT.READ_ONLY);
parentSelection.setLayoutData(createFormData(0,5,null,0,l,5,100,-5));
parentSelection.setItems(getPossibleParentProjects());
parentSelection.addModifyListener(new ModifyListener(){
public void modifyText(ModifyEvent e) {
refreshViewerFromNewParentProject();
}
});
Label tableLabel = new Label(root, SWT.NONE);
tableLabel.setText(Messages.ManifestEntries);
tableLabel.setLayoutData(createFormData(parentSelection,5,null,0, 0, 5, null,0));
manifestEntryViewer = createManifestReferenceTableViewer(root, SWT.SINGLE);
Composite buttonColumn = new Composite(root, SWT.NONE);
buttonColumn.setLayout(new FormLayout());
buttonColumn.setLayoutData(createFormData(tableLabel,5,null,0,null,0, 100,-5));
addButton = new Button(buttonColumn, SWT.PUSH);
removeButton = new Button(buttonColumn, SWT.PUSH);
moveUpButton = new Button(buttonColumn, SWT.PUSH);
moveDownButton = new Button(buttonColumn, SWT.PUSH);
addButton.setText(Messages.Add);
removeButton.setText(Messages.Remove);
moveUpButton.setText(Messages.MoveUp);
moveDownButton.setText(Messages.MoveDown);
IFile manifest = getManifestIFile(rootComponent);
if(manifest == null) {
addButton.setEnabled(false);
} else {
addButton.setEnabled(true);
previousManifest = manifest.getFullPath().toOSString();
}
removeButton.setEnabled(false);
moveUpButton.setEnabled(false);
moveDownButton.setEnabled(false);
addButton.setLayoutData(createFormData(null,0,null,0,manifestEntryViewer.getTable(),5,100,0));
removeButton.setLayoutData(createFormData(addButton,5,null,0,manifestEntryViewer.getTable(),5,100,0));
moveUpButton.setLayoutData(createFormData(removeButton,5,null,0,manifestEntryViewer.getTable(),5,100,0));
moveDownButton.setLayoutData(createFormData(moveUpButton,5,null,0,manifestEntryViewer.getTable(),5,100,0));
addButton.addSelectionListener(new SelectionListener() {
public void widgetSelected(SelectionEvent e) {
addPressed();
}
public void widgetDefaultSelected(SelectionEvent e) {
}
});
removeButton.addSelectionListener(new SelectionListener() {
public void widgetSelected(SelectionEvent e) {
removePressed();
}
public void widgetDefaultSelected(SelectionEvent e) {
}
});
moveUpButton.addSelectionListener(new SelectionListener() {
public void widgetSelected(SelectionEvent e) {
moveUp();
}
public void widgetDefaultSelected(SelectionEvent e) {
}
});
moveDownButton.addSelectionListener(new SelectionListener() {
public void widgetSelected(SelectionEvent e) {
moveDown();
}
public void widgetDefaultSelected(SelectionEvent e) {
}
});
manifestEntryViewer.getTable().setLayoutData(createFormData(
tableLabel, 5, 100, -5, 0, 5, buttonColumn, 0));
manifestEntryViewer.setLabelProvider(new ManifestLabelProvider());
manifestEntryViewer.setContentProvider(new ManifestContentProvider());
manifestEntryViewer.setInput(ResourcesPlugin.getWorkspace());
parentSelection.select(0);
manifestEntryViewer.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
viewerSelectionChanged();
}
});
return root;
}
protected void viewerSelectionChanged() {
updateButtons();
}
protected void updateButtons() {
if(!addButton.isEnabled()) {
removeButton.setEnabled(false);
moveUpButton.setEnabled(false);
moveDownButton.setEnabled(false);
} else {
int index = manifestEntryViewer.getTable().getSelectionIndex();
int size = manifestEntryViewer.getTable().getItems().length;
removeButton.setEnabled(index != -1);
moveUpButton.setEnabled(index != -1 && index != 0);
moveDownButton.setEnabled(index != size-1);
}
}
protected void moveUp() {
int index = manifestEntryViewer.getTable().getSelectionIndex();
IVirtualReference ref = list.remove(index);
list.add(index-1,ref);
refreshViewer();
updateButtons();
}
protected void moveDown() {
int index = manifestEntryViewer.getTable().getSelectionIndex();
IVirtualReference ref = list.remove(index);
list.add(index+1,ref);
refreshViewer();
updateButtons();
}
protected void addPressed() {
AddManifestEntryTaskWizard wizard = new AddManifestEntryTaskWizard();
wizard.getTaskModel().putObject(AddManifestEntryTaskWizard.CHILD_PROJECT, project);
wizard.getTaskModel().putObject(AddManifestEntryTaskWizard.PARENT_PROJECT, parentProject);
wizard.getTaskModel().putObject(AddManifestEntryTaskWizard.CURRENT_REFERENCES, list.toArray(new IVirtualReference[list.size()]));
WizardDialog wd = new WizardDialog(addButton.getShell(), wizard);
if( wd.open() != Window.CANCEL) {
IVirtualReference[] ret = (IVirtualReference[])wizard.getTaskModel().getObject(AddManifestEntryTaskWizard.RETURNED_REFERENCES);
if (ret != null)
list.addAll(Arrays.asList(ret));
refreshViewer();
updateButtons();
}
}
protected void removePressed() {
IStructuredSelection sel = (IStructuredSelection)manifestEntryViewer.getSelection();
Iterator i = sel.iterator();
while(i.hasNext()) {
list.remove(i.next());
}
refreshViewer();
updateButtons();
}
public static class ManifestLabelProvider extends BaseLabelProvider implements ITableLabelProvider {
private IVirtualComponentLabelProvider[] delegates;
protected void getDelegates() {
if( delegates == null )
delegates = DependencyPageExtensionManager.loadDelegates();
}
public Image getColumnImage(Object element, int columnIndex) {
getDelegates();
if( columnIndex == 1 ) {
if( element instanceof IVirtualReference ) {
for( int i = 0; i < delegates.length; i++ )
if( delegates[i].canHandle(((IVirtualReference)element).getReferencedComponent()))
return delegates[i].getSourceImage(((IVirtualReference)element).getReferencedComponent());
}
}
return ModuleCoreUIPlugin.getInstance().getImage("jar_obj");
}
public String getColumnText(Object element, int columnIndex) {
if( element instanceof IVirtualReference ) {
IVirtualReference ref = (IVirtualReference)element;
if( columnIndex == 0 && ref.getArchiveName() != null)
return ref.getRuntimePath().append(ref.getArchiveName()).toString();
if( columnIndex == 1 )
return handleSourceText(ref.getReferencedComponent());
}
return null;
}
private String handleSourceText(IVirtualComponent component) {
getDelegates();
for( int i = 0; i < delegates.length; i++ )
if( delegates[i].canHandle(component))
return delegates[i].getSourceText(component);
// default impl
if( component.isBinary() ) {
IPath p = (IPath)component.getAdapter(IPath.class);
return p == null ? null : p.toString();
}
return component.getProject().getName();
}
}
private class ManifestContentProvider implements IStructuredContentProvider {
public void dispose() {
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
public Object[] getElements(Object inputElement) {
return refsForCurrentProject == null ? new Object[]{} : refsForCurrentProject;
}
}
public static TableViewer createManifestReferenceTableViewer(Composite parent, int style) {
int flags = SWT.BORDER | style;
Table table = new Table(parent, flags);
TableViewer viewer = new TableViewer(table);
// set up table layout
TableLayout tableLayout = new org.eclipse.jface.viewers.TableLayout();
tableLayout.addColumnData(new ColumnWeightData(200, true));
tableLayout.addColumnData(new ColumnWeightData(200, true));
table.setLayout(tableLayout);
table.setHeaderVisible(true);
table.setLinesVisible(true);
// table columns
TableColumn fileNameColumn = new TableColumn(table, SWT.NONE, 0);
fileNameColumn.setText(Messages.ManifestEntryColumn);
fileNameColumn.setResizable(true);
TableColumn projectColumn = new TableColumn(table, SWT.NONE, 1);
projectColumn.setText(Messages.ManifestEntrySourceColumn);
projectColumn.setResizable(true);
tableLayout.layout(table, true);
return viewer;
}
private IVirtualReference[] refsForCurrentProject;
protected void refreshViewerFromNewParentProject() {
String parentString = parentSelection.getText();
refsForCurrentProject = new IVirtualReference[]{};
if( parentString != null && !"".equals(parentString)) { //$NON-NLS-1$
parentProject = ResourcesPlugin.getWorkspace().getRoot().getProject(parentString);
IVirtualReference[] current = JavaModuleComponentUtility.findCurrentManifestEntries(parentProject, project);
refsForCurrentProject = sortRefsForCurrentProject(addMissingDummyEntries(current));
for( int i = 0; i < refsForCurrentProject.length; i++ ) {
list.add(refsForCurrentProject[i]);
}
}
manifestEntryViewer.refresh();
}
private IVirtualReference[] sortRefsForCurrentProject(IVirtualReference[] currentRefs) {
IFile manifestFile = getManifestIFile(rootComponent);
if (manifestFile == null)
return currentRefs;
HashMap<String, IVirtualReference> unsortedRefMap = new HashMap<String, IVirtualReference>();
for (int i = 0; i < currentRefs.length; i++) {
IVirtualReference ref = currentRefs[i];
String entryName = ref.getRuntimePath().append(ref.getArchiveName()).toString();
unsortedRefMap.put(entryName, ref);
}
List<IVirtualReference> sortedRefs = new ArrayList<IVirtualReference>();
ArchiveManifest manifest = ManifestUtilities.getManifest(manifestFile);
String[] entries = manifest.getClassPathTokenized();
for (int i = 0; i < entries.length; i++) {
IVirtualReference ref = unsortedRefMap.get(entries[i]);
if (ref != null) {
sortedRefs.add(ref);
}
}
return sortedRefs.toArray(new IVirtualReference[sortedRefs.size()]);
}
protected void refreshViewer() {
refsForCurrentProject = list.toArray(new IVirtualReference[list.size()]);
manifestEntryViewer.refresh();
}
protected IVirtualReference[] addMissingDummyEntries(IVirtualReference[] current) {
IFile manifestFile = getManifestIFile(rootComponent);
if( manifestFile != null ) {
ArrayList<IVirtualReference> refs = new ArrayList<IVirtualReference>();
refs.addAll(Arrays.asList(current));
ArchiveManifest manifest = ManifestUtilities.getManifest(manifestFile);
String[] entries = manifest.getClassPathTokenized();
String[] unusedEntries = findUnusedEntries(current, entries);
for( int i = 0; i < unusedEntries.length; i++ ) {
refs.add(createDummyReference(unusedEntries[i]));
}
return refs.toArray(new IVirtualReference[refs.size()]);
}
return current;
}
public static class DummyVirtualComponent extends AbstractResourceListVirtualComponent {
private static final String DUMMY_FIRST_SEGMENT = "dummyVirtualComponent"; //$NON-NLS-1$
public DummyVirtualComponent(IProject p, IVirtualComponent referencingComponent) {
super(p, referencingComponent);
}
protected String getFirstIdSegment() {
return DUMMY_FIRST_SEGMENT;
}
protected IContainer[] getUnderlyingContainers() {
return new IContainer[]{};
}
protected IResource[] getLooseResources() {
return new IResource[]{};
}
}
private IVirtualReference createDummyReference(String path) {
return createDummyReference(path, parentProject, ComponentCore.createComponent(parentProject));
}
public static IVirtualReference createDummyReference(String path, IProject project, IVirtualComponent rootComponent) {
IVirtualComponent comp = new DummyVirtualComponent(project, rootComponent);
IVirtualReference ref = ComponentCore.createReference(rootComponent, comp);
IPath path2 = new Path(path);
IPath runtimePath = path2.segmentCount() > 1 ? path2.removeLastSegments(1) : new Path("/"); //$NON-NLS-1$
runtimePath = runtimePath.makeRelative();
ref.setRuntimePath(runtimePath);
ref.setArchiveName(path2.lastSegment());
return ref;
}
private String[] findUnusedEntries(IVirtualReference[] current, String[] entries) {
ArrayList<String> list = new ArrayList<String>();
list.addAll(Arrays.asList(entries));
for( int i = 0; i < current.length; i++ ) {
String currentEntry = current[i].getRuntimePath().append(current[i].getArchiveName()).toString();
list.remove(currentEntry);
}
return list.toArray(new String[list.size()]);
}
/**
* Clients who find this unacceptable should override
* @param root
* @return
*/
public IFile getManifestIFile(IVirtualComponent root) {
IVirtualFolder rootFolder = root.getRootFolder();
IVirtualFile vf = rootFolder.getFile(new Path("META-INF/MANIFEST.MF"));
if( vf.exists() )
return vf.getUnderlyingFile();
return null;
}
protected String[] getPossibleParentProjects() {
IProject[] projects = JavaModuleComponentUtility.findParentProjects(project);
String[] strings = new String[projects.length];
for( int i = 0; i < projects.length; i++ ) {
strings[i] = projects[i].getName();
}
return strings;
}
public boolean performOk() {
if(addButton != null && addButton.isEnabled()) {
IDataModel updateManifestDataModel = DataModelFactory.createDataModel(new UpdateManifestDataModelProvider());
updateManifestDataModel.setProperty(UpdateManifestDataModelProperties.PROJECT_NAME, project.getName());
updateManifestDataModel.setBooleanProperty(UpdateManifestDataModelProperties.MERGE, false);
updateManifestDataModel.setProperty(UpdateManifestDataModelProperties.MANIFEST_FILE, getManifestIFile(rootComponent));
ArrayList<String> asStrings = new ArrayList<String>();
Iterator<IVirtualReference> i = list.iterator();
IVirtualReference tmp;
while(i.hasNext()) {
tmp = i.next();
asStrings.add(tmp.getRuntimePath().append(tmp.getArchiveName()).toString());
}
updateManifestDataModel.setProperty(UpdateManifestDataModelProperties.JAR_LIST, asStrings);
try {
updateManifestDataModel.getDefaultOperation().execute(new NullProgressMonitor(), null );
} catch (ExecutionException e) {
// TODO log J2EEUIPlugin.logError(e);
}
}
return true;
}
public void performDefaults() {
list.clear();
refreshViewerFromNewParentProject();
}
public boolean performCancel() {
return false;
}
public void setVisible(boolean visible) {
}
public void dispose() {
}
public void performApply() {
IFile manifest = getManifestIFile(rootComponent);
if(manifest == null) {
previousManifest = null;
addButton.setEnabled(false);
performDefaults();
} else {
if(previousManifest == null) {
performDefaults();
} else {
String currentManifest = manifest.getFullPath().toOSString();
if(!previousManifest.equals(currentManifest)) {
performDefaults();
}
}
previousManifest = manifest.getFullPath().toOSString();
addButton.setEnabled(true);
}
updateButtons();
performOk();
}
}