package bndtools.wizards.repo; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.bndtools.api.ILogger; import org.bndtools.api.Logger; import org.eclipse.jface.viewers.IOpenListener; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.OpenEvent; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.jface.wizard.WizardPage; import org.eclipse.swt.SWT; import org.eclipse.swt.events.KeyAdapter; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; 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.Control; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.Text; import org.eclipse.swt.widgets.Tree; import aQute.bnd.build.Workspace; import aQute.bnd.build.model.clauses.VersionedClause; import aQute.bnd.header.Attrs; import aQute.bnd.osgi.Constants; import bndtools.central.Central; import bndtools.central.RepositoryUtils; import bndtools.model.clauses.VersionedClauseLabelProvider; import bndtools.model.repo.DependencyPhase; import bndtools.model.repo.ProjectBundle; import bndtools.model.repo.RepositoryBundle; import bndtools.model.repo.RepositoryBundleUtils; import bndtools.model.repo.RepositoryBundleVersion; import bndtools.model.repo.RepositoryTreeContentProvider; import bndtools.model.repo.RepositoryTreeLabelProvider; public class RepoBundleSelectionWizardPage extends WizardPage { private static final ILogger logger = Logger.getLogger(RepoBundleSelectionWizardPage.class); public static final String PROP_SELECTION = "selection"; private final PropertyChangeSupport propSupport = new PropertyChangeSupport(this); private final Map<String,VersionedClause> selectedBundles = new LinkedHashMap<String,VersionedClause>(); private final DependencyPhase phase; TreeViewer availableViewer; Text selectionSearchTxt; TableViewer selectedViewer; Button addButton; Button removeButton; ViewerFilter alreadySelectedFilter = new ViewerFilter() { @Override public boolean select(Viewer viewer, Object parentElement, Object element) { String search = selectionSearchTxt.getText().toLowerCase(); String bsn = null; if (element instanceof RepositoryBundle) { bsn = ((RepositoryBundle) element).getBsn(); } else if (element instanceof ProjectBundle) { bsn = ((ProjectBundle) element).getBsn(); } if (bsn != null) { if (search.length() > 0 && bsn.toLowerCase().indexOf(search) == -1) { return false; } return !selectedBundles.containsKey(bsn); } return true; } }; protected RepoBundleSelectionWizardPage(DependencyPhase phase) { super("bundleSelectionPage"); this.phase = phase; } public void setSelectedBundles(Collection<VersionedClause> selectedBundles) { for (VersionedClause clause : selectedBundles) { this.selectedBundles.put(clause.getName(), clause); } } public List<VersionedClause> getSelectedBundles() { return new ArrayList<VersionedClause>(selectedBundles.values()); } Control createAvailableBundlesPanel(Composite parent) { Composite panel = new Composite(parent, SWT.NONE); new Label(panel, SWT.NONE).setText("Available Bundles:"); selectionSearchTxt = new Text(panel, SWT.BORDER | SWT.SEARCH | SWT.ICON_SEARCH | SWT.ICON_CANCEL); selectionSearchTxt.setMessage("filter bundle name"); final Tree availableTree = new Tree(panel, SWT.FULL_SELECTION | SWT.MULTI | SWT.BORDER); availableViewer = new TreeViewer(availableTree); availableViewer.setLabelProvider(new RepositoryTreeLabelProvider(false)); availableViewer.setContentProvider(new RepositoryTreeContentProvider()); availableViewer.setAutoExpandLevel(2); availableViewer.setFilters(new ViewerFilter[] { alreadySelectedFilter }); // Load data try { refreshBundleList(); } catch (Exception e) { setErrorMessage("Error querying repositories: " + e.getMessage()); logger.logError("Error querying repository configuration.", e); } // Listeners selectionSearchTxt.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if (e.keyCode == SWT.ARROW_DOWN) availableTree.setFocus(); } }); selectionSearchTxt.addModifyListener(new ModifyListener() { @Override public void modifyText(ModifyEvent e) { availableViewer.setFilters(new ViewerFilter[] { alreadySelectedFilter }); } }); availableViewer.addSelectionChangedListener(new ISelectionChangedListener() { // Enable add button when a bundle or bundle version is selected on // the left @Override public void selectionChanged(SelectionChangedEvent event) { IStructuredSelection sel = (IStructuredSelection) availableViewer.getSelection(); for (Iterator< ? > iter = sel.iterator(); iter.hasNext();) { Object element = iter.next(); if (element instanceof RepositoryBundle || element instanceof RepositoryBundleVersion || element instanceof ProjectBundle) { addButton.setEnabled(true); return; } } addButton.setEnabled(false); } }); availableViewer.addOpenListener(new IOpenListener() { @Override public void open(OpenEvent event) { doAdd(); } }); GridLayout layout; GridData gd; layout = new GridLayout(1, false); panel.setLayout(layout); gd = new GridData(SWT.FILL, SWT.CENTER, true, false); selectionSearchTxt.setLayoutData(gd); gd = new GridData(SWT.FILL, SWT.FILL, true, true); gd.heightHint = 300; gd.widthHint = 250; availableTree.setLayoutData(gd); return panel; } Control createSelectedBundlesPanel(Composite parent) { Composite panel = new Composite(parent, SWT.NONE); new Label(panel, SWT.NONE).setText("Selected Bundles:"); Table selectedTable = new Table(panel, SWT.FULL_SELECTION | SWT.MULTI | SWT.BORDER); selectedViewer = new TableViewer(selectedTable); selectedViewer.setContentProvider(new MapValuesContentProvider()); selectedViewer.setLabelProvider(new VersionedClauseLabelProvider()); selectedViewer.setInput(selectedBundles); selectedViewer.addSelectionChangedListener(new ISelectionChangedListener() { // Enable the remove button when a bundle is selected on the right @Override public void selectionChanged(SelectionChangedEvent event) { ISelection sel = selectedViewer.getSelection(); removeButton.setEnabled(!sel.isEmpty()); } }); selectedViewer.addOpenListener(new IOpenListener() { @Override public void open(OpenEvent event) { doRemove(); } }); GridLayout layout; GridData gd; layout = new GridLayout(1, false); panel.setLayout(layout); gd = new GridData(SWT.FILL, SWT.FILL, true, true); gd.heightHint = 300; gd.widthHint = 250; selectedTable.setLayoutData(gd); return panel; } @Override public void createControl(Composite parent) { // Create controls Composite composite = new Composite(parent, SWT.NONE); Control leftPanel = createAvailableBundlesPanel(composite); Composite middlePanel = new Composite(composite, SWT.NONE); Control rightPanel = createSelectedBundlesPanel(composite); addButton = new Button(middlePanel, SWT.PUSH); addButton.setText("Add -->"); addButton.setEnabled(false); removeButton = new Button(middlePanel, SWT.PUSH); removeButton.setText("<-- Remove"); removeButton.setEnabled(false); addButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { doAdd(); } }); removeButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { doRemove(); } }); // LAYOUT GridLayout layout; layout = new GridLayout(3, false); layout.horizontalSpacing = 0; layout.marginWidth = 0; layout.marginHeight = 0; composite.setLayout(layout); leftPanel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); middlePanel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, true)); rightPanel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); layout = new GridLayout(1, false); layout.horizontalSpacing = 0; layout.marginWidth = 0; middlePanel.setLayout(layout); addButton.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, false, true)); removeButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, true)); setControl(composite); } protected void refreshBundleList() throws Exception { Workspace workspace = Central.getWorkspace(); workspace.refresh(); availableViewer.setInput(RepositoryUtils.listRepositories(workspace, true)); } void doAdd() { IStructuredSelection selection = (IStructuredSelection) availableViewer.getSelection(); List<VersionedClause> adding = new ArrayList<VersionedClause>(selection.size()); for (Iterator< ? > iter = selection.iterator(); iter.hasNext();) { Object item = iter.next(); if (item instanceof RepositoryBundle) { adding.add(RepositoryBundleUtils.convertRepoBundle((RepositoryBundle) item)); } else if (item instanceof RepositoryBundleVersion) { adding.add(RepositoryBundleUtils.convertRepoBundleVersion((RepositoryBundleVersion) item, phase)); } else if (item instanceof ProjectBundle) { String bsn = ((ProjectBundle) item).getBsn(); Attrs attribs = new Attrs(); attribs.put(Constants.VERSION_ATTRIBUTE, "latest"); adding.add(new VersionedClause(bsn, attribs)); } } if (!adding.isEmpty()) { for (VersionedClause clause : adding) { selectedBundles.put(clause.getName(), clause); } selectedViewer.add(adding.toArray()); availableViewer.refresh(); propSupport.firePropertyChange(PROP_SELECTION, null, selectedBundles); } } void doRemove() { IStructuredSelection selection = (IStructuredSelection) selectedViewer.getSelection(); for (Object clause : selection.toList()) { selectedBundles.remove(((VersionedClause) clause).getName()); } selectedViewer.remove(selection.toArray()); availableViewer.refresh(); propSupport.firePropertyChange(PROP_SELECTION, null, selectedBundles); } public void addPropertyChangeListener(PropertyChangeListener listener) { propSupport.addPropertyChangeListener(listener); } public void removePropertyChangeListener(PropertyChangeListener listener) { propSupport.removePropertyChangeListener(listener); } public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { propSupport.addPropertyChangeListener(propertyName, listener); } public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { propSupport.removePropertyChangeListener(propertyName, listener); } } class MapValuesContentProvider implements IStructuredContentProvider { @Override public Object[] getElements(Object inputElement) { Map< ? , ? > map = (Map< ? , ? >) inputElement; Collection< ? > values = map.values(); return values.toArray(); } @Override public void dispose() {} @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {} }