/******************************************************************************* * Copyright (c) 2010 Neil Bartlett. * 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: * Neil Bartlett - initial API and implementation *******************************************************************************/ package bndtools.wizards.bndfile; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.jar.Manifest; import org.bndtools.api.ILogger; import org.bndtools.api.Logger; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; 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.jface.dialogs.IMessageProvider; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.ViewerDropAdapter; import org.eclipse.jface.window.Window; import org.eclipse.jface.wizard.WizardPage; import org.eclipse.swt.SWT; import org.eclipse.swt.dnd.DND; import org.eclipse.swt.dnd.DropTargetEvent; import org.eclipse.swt.dnd.FileTransfer; import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.dnd.TransferData; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.FileDialog; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Table; import org.eclipse.ui.dialogs.ElementTreeSelectionDialog; import org.eclipse.ui.dialogs.ISelectionStatusValidator; import org.eclipse.ui.model.WorkbenchContentProvider; import org.eclipse.ui.model.WorkbenchLabelProvider; import aQute.bnd.osgi.Constants; import aQute.bnd.osgi.Jar; import bndtools.Plugin; import bndtools.utils.ClassPathLabelProvider; import bndtools.utils.FileExtensionFilter; public class JarListWizardPage extends WizardPage { private static final ILogger logger = Logger.getLogger(JarListWizardPage.class); public static final String PROP_PATHS = "paths"; private final PropertyChangeSupport propertySupport = new PropertyChangeSupport(this); private final Collection<IPath> paths = new LinkedList<IPath>(); private TableViewer viewer; private Button btnAdd; private Button btnAddExternal; private Button btnRemove; public JarListWizardPage(final String pageName) { super(pageName); } @Override public void createControl(final Composite parent) { setTitle("Select JARs"); final Composite composite = new Composite(parent, SWT.NONE); Label lblHint = new Label(composite, SWT.WRAP); lblHint.setText("Selected files (hint: drag files from an external application into this list):"); final Table table = new Table(composite, SWT.FULL_SELECTION | SWT.MULTI | SWT.BORDER); viewer = new TableViewer(table); viewer.setContentProvider(new ArrayContentProvider()); viewer.setLabelProvider(new ClassPathLabelProvider()); btnAdd = new Button(composite, SWT.PUSH); btnAdd.setText("Add"); btnAddExternal = new Button(composite, SWT.PUSH); btnAddExternal.setText("Add External"); btnRemove = new Button(composite, SWT.PUSH); btnRemove.setText("Remove"); viewer.setInput(paths); update(); // Listeners ViewerDropAdapter dropAdapter = new ViewerDropAdapter(viewer) { @Override public void dragEnter(DropTargetEvent event) { super.dragEnter(event); event.detail = DND.DROP_COPY; } @Override public boolean validateDrop(Object target, int operation, TransferData transferType) { return true; } @Override public boolean performDrop(Object data) { if (data instanceof String[]) { String[] newPaths = (String[]) data; List<IPath> added = new ArrayList<IPath>(newPaths.length); for (String path : newPaths) { added.add(new Path(path)); } if (!added.isEmpty()) { addToPaths(added); viewer.add(added.toArray()); update(); } } return true; } }; dropAdapter.setFeedbackEnabled(false); dropAdapter.setSelectionFeedbackEnabled(false); viewer.addDropSupport(DND.DROP_COPY | DND.DROP_MOVE, new Transfer[] { FileTransfer.getInstance() }, dropAdapter); viewer.addSelectionChangedListener(new ISelectionChangedListener() { @Override public void selectionChanged(final SelectionChangedEvent event) { update(); } }); btnAdd.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { // IResource newFile = ResourcesPlugin.getWorkspace().getRoot(); // if(newFile != null) { ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog(getShell(), new WorkbenchLabelProvider(), new WorkbenchContentProvider()); dialog.setValidator(new ISelectionStatusValidator() { @Override public IStatus validate(Object[] selection) { if (selection.length > 0 && selection[0] instanceof IFile) { return new Status(IStatus.OK, Plugin.PLUGIN_ID, IStatus.OK, "", null); //$NON-NLS-1$ } return new Status(IStatus.ERROR, Plugin.PLUGIN_ID, IStatus.ERROR, "", null); //$NON-NLS-1$ } }); dialog.setAllowMultiple(true); dialog.setTitle("JAR File Selection"); dialog.setMessage("Select one or more JAR files."); dialog.addFilter(new FileExtensionFilter("jar")); //$NON-NLS-1$ dialog.setInput(ResourcesPlugin.getWorkspace()); if (dialog.open() == Window.OK) { Object[] files = dialog.getResult(); List<IPath> added = new ArrayList<IPath>(files.length); for (Object file : files) { added.add(((IResource) file).getFullPath().makeRelative()); } if (!added.isEmpty()) { addToPaths(added); viewer.add(added.toArray()); } } // } update(); } }); btnAddExternal.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { FileDialog dialog = new FileDialog(getShell(), SWT.OPEN | SWT.MULTI); dialog.setFilterExtensions(new String[] { "*.jar" //$NON-NLS-1$ }); String res = dialog.open(); if (res != null) { IPath filterPath = new Path(dialog.getFilterPath()); String[] fileNames = dialog.getFileNames(); List<IPath> added = new ArrayList<IPath>(fileNames.length); for (String fileName : fileNames) { added.add(filterPath.append(fileName)); } if (!added.isEmpty()) { addToPaths(added); viewer.add(added.toArray()); } } update(); } }); btnRemove.addSelectionListener(new SelectionAdapter() { @SuppressWarnings("unchecked") @Override public void widgetSelected(SelectionEvent e) { removeFromPaths(((IStructuredSelection) viewer.getSelection()).toList()); viewer.remove(((IStructuredSelection) viewer.getSelection()).toArray()); update(); } }); // Layout composite.setLayout(new GridLayout(2, false)); table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 3)); btnAdd.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false)); btnAddExternal.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false)); btnRemove.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false)); lblHint.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false, 2, 1)); setControl(composite); } private void addToPaths(List<IPath> added) { List<IPath> oldPaths = new ArrayList<IPath>(paths.size()); oldPaths.addAll(paths); paths.addAll(added); propertySupport.firePropertyChange(PROP_PATHS, oldPaths, paths); checkExistingBundles(); } private void removeFromPaths(List<IPath> removed) { List<IPath> oldPaths = new ArrayList<IPath>(paths.size()); oldPaths.addAll(paths); paths.removeAll(removed); propertySupport.firePropertyChange(PROP_PATHS, oldPaths, paths); checkExistingBundles(); } @Override public boolean isPageComplete() { return !paths.isEmpty(); } private void update() { btnRemove.setEnabled(!viewer.getSelection().isEmpty()); if (isCurrentPage()) { getContainer().updateButtons(); getContainer().updateMessage(); } } private void checkExistingBundles() { List<IPath> alreadyBundles = new LinkedList<IPath>(); for (IPath path : paths) { Jar jar = null; try { if (path.isAbsolute()) { jar = new Jar(path.toFile()); } else { path = ResourcesPlugin.getWorkspace().getRoot().getLocation().append(path); jar = new Jar(path.toFile()); } Manifest manifest = jar.getManifest(); if (manifest != null) { String bsn = manifest.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME); if (bsn != null) { alreadyBundles.add(path); } } } catch (Exception e) { logger.logError("Error inspecting JAR file: " + path.toString(), e); } finally { if (jar != null) jar.close(); } } String warning = null; if (!alreadyBundles.isEmpty()) { StringBuilder builder = new StringBuilder(); builder.append("The following JAR files are already bundles: "); for (Iterator<IPath> iterator = alreadyBundles.iterator(); iterator.hasNext();) { IPath path = iterator.next(); builder.append(path.toString()); if (iterator.hasNext()) builder.append("; "); } warning = builder.toString(); } setMessage(warning, IMessageProvider.WARNING); } public Collection<IPath> getPaths() { return paths; } public void addPropertyChangeListener(PropertyChangeListener listener) { propertySupport.addPropertyChangeListener(listener); } public void removePropertyChangeListener(PropertyChangeListener listener) { propertySupport.removePropertyChangeListener(listener); } public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { propertySupport.addPropertyChangeListener(propertyName, listener); } public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { propertySupport.removePropertyChangeListener(propertyName, listener); } }