package bndtools.editor.project; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.Collections; import java.util.EnumSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import org.bndtools.core.ui.resource.RequirementLabelProvider; import org.bndtools.utils.dnd.AbstractViewerDropAdapter; import org.bndtools.utils.dnd.SupportedTransfer; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jface.dialogs.ErrorDialog; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.ISelection; 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.window.Window; import org.eclipse.jface.wizard.WizardDialog; import org.eclipse.swt.SWT; import org.eclipse.swt.events.KeyAdapter; import org.eclipse.swt.events.KeyEvent; 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.Composite; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.ToolBar; import org.eclipse.swt.widgets.ToolItem; import org.eclipse.ui.ISharedImages; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.forms.editor.IFormPage; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.Section; import org.osgi.framework.namespace.IdentityNamespace; import org.osgi.resource.Namespace; import org.osgi.resource.Requirement; import aQute.bnd.build.model.clauses.VersionedClause; import aQute.bnd.osgi.resource.CapReqBuilder; import aQute.bnd.osgi.resource.Filters; import aQute.bnd.version.Version; import aQute.libg.filters.AndFilter; import aQute.libg.filters.Filter; import aQute.libg.filters.LiteralFilter; import aQute.libg.filters.Operator; import aQute.libg.filters.SimpleFilter; import bndtools.BndConstants; import bndtools.Plugin; import bndtools.editor.common.BndEditorPart; import bndtools.model.repo.DependencyPhase; import bndtools.model.repo.ProjectBundle; import bndtools.model.repo.RepositoryBundle; import bndtools.model.repo.RepositoryBundleVersion; import bndtools.wizards.repo.RepoBundleSelectionWizard; public class RunBlacklistPart extends BndEditorPart implements PropertyChangeListener { private static final String[] SUBSCRIBE_PROPS = new String[] { BndConstants.RUNBLACKLIST }; private Table table; private TableViewer viewer; private List<Requirement> blacklists; private ToolItem addBundleTool; private ToolItem removeTool; private boolean committing = false; public RunBlacklistPart(Composite parent, FormToolkit toolkit, int style) { super(parent, toolkit, style); createSection(getSection(), toolkit); } @Override protected String[] getProperties() { return SUBSCRIBE_PROPS; } private void createSection(Section section, FormToolkit tk) { section.setText("Run Blacklist"); section.setDescription("The specified requirements will be excluded from the resolution."); // Create toolbar ToolBar toolbar = new ToolBar(section, SWT.FLAT); section.setTextClient(toolbar); fillToolBar(toolbar); // Create main panel Composite composite = tk.createComposite(section); section.setClient(composite); table = tk.createTable(composite, SWT.FULL_SELECTION | SWT.MULTI | SWT.BORDER); viewer = new TableViewer(table); viewer.setContentProvider(ArrayContentProvider.getInstance()); viewer.setLabelProvider(new RequirementLabelProvider()); // Listeners viewer.addSelectionChangedListener(new ISelectionChangedListener() { @Override public void selectionChanged(SelectionChangedEvent event) { removeTool.setEnabled(!viewer.getSelection().isEmpty()); } }); table.addKeyListener(new KeyAdapter() { @Override public void keyReleased(KeyEvent e) { if (e.character == SWT.DEL) { doRemove(); } else if (e.character == '+') { doAddBundle(); } } }); RequirementViewerDropAdapter dropper = new RequirementViewerDropAdapter(); dropper.install(viewer); // Layout GridLayout layout; GridData gd; layout = new GridLayout(2, false); layout.horizontalSpacing = 0; layout.verticalSpacing = 5; layout.marginHeight = 0; layout.marginWidth = 0; composite.setLayout(layout); gd = new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1); gd.widthHint = 50; gd.heightHint = 50; table.setLayoutData(gd); gd = new GridData(SWT.RIGHT, SWT.CENTER, true, false); } private void fillToolBar(ToolBar toolbar) { // Add Bundle addBundleTool = new ToolItem(toolbar, SWT.PUSH); addBundleTool.setImage(PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_ADD)); addBundleTool.setToolTipText("Add Bundle Requirement"); addBundleTool.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { doAddBundle(); } }); // Remove removeTool = new ToolItem(toolbar, SWT.PUSH); removeTool.setImage(PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_TOOL_DELETE)); removeTool.setDisabledImage(PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_TOOL_DELETE_DISABLED)); removeTool.setToolTipText("Remove"); removeTool.setEnabled(false); removeTool.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { doRemove(); } }); } private static Requirement createRequirement(Object elem) { String bsn = null; Version version = null; if (elem instanceof RepositoryBundle) { bsn = ((RepositoryBundle) elem).getBsn(); } else if (elem instanceof RepositoryBundleVersion) { RepositoryBundleVersion rbv = (RepositoryBundleVersion) elem; bsn = rbv.getBsn(); version = rbv.getVersion(); } else if (elem instanceof ProjectBundle) { bsn = ((ProjectBundle) elem).getBsn(); } if (bsn != null) { Filter filter = new SimpleFilter(IdentityNamespace.IDENTITY_NAMESPACE, bsn); if (version != null) { filter = new AndFilter().addChild(filter).addChild(new SimpleFilter("version", Operator.GreaterThanOrEqual, version.toString())); } Requirement req = new CapReqBuilder(IdentityNamespace.IDENTITY_NAMESPACE).addDirective(Namespace.REQUIREMENT_FILTER_DIRECTIVE, filter.toString()).buildSyntheticRequirement(); return req; } return null; } private void doAddBundle() { try { RepoBundleSelectionWizard wizard = new RepoBundleSelectionWizard(new ArrayList<VersionedClause>(), DependencyPhase.Run); wizard.setSelectionPageTitle("Add Bundle Blacklist"); WizardDialog dialog = new WizardDialog(getSection().getShell(), wizard); if (Window.OK == dialog.open()) { List<VersionedClause> result = wizard.getSelectedBundles(); Set<Requirement> adding = new LinkedHashSet<Requirement>(result.size()); for (VersionedClause bundle : result) { Filter filter = new SimpleFilter(IdentityNamespace.IDENTITY_NAMESPACE, bundle.getName()); String versionRange = bundle.getVersionRange(); if (versionRange != null && !"latest".equals(versionRange)) { filter = new AndFilter().addChild(filter).addChild(new LiteralFilter(Filters.fromVersionRange(versionRange))); } Requirement req = new CapReqBuilder(IdentityNamespace.IDENTITY_NAMESPACE).addDirective(Namespace.REQUIREMENT_FILTER_DIRECTIVE, filter.toString()).buildSyntheticRequirement(); adding.add(req); } updateViewerWithNewBlacklist(adding); } } catch (Exception e) { ErrorDialog.openError(getSection().getShell(), "Error", null, new Status(IStatus.ERROR, Plugin.PLUGIN_ID, 0, "Error selecting bundles for blacklist.", e)); } } private void doRemove() { IStructuredSelection selection = (IStructuredSelection) viewer.getSelection(); if (!selection.isEmpty()) { Iterator< ? > elements = selection.iterator(); List<Object> removed = new LinkedList<Object>(); while (elements.hasNext()) { Object element = elements.next(); if (blacklists.remove(element)) removed.add(element); } if (!removed.isEmpty()) { viewer.remove(removed.toArray()); markDirty(); } } } @Override public void commitToModel(boolean onSave) { try { committing = true; model.setRunBlacklist(blacklists); } finally { committing = false; } } @Override public void refreshFromModel() { List<Requirement> blacklistEntries = model.getRunBlacklist(); blacklists = new ArrayList<Requirement>(blacklistEntries != null ? blacklistEntries : Collections.<Requirement> emptyList()); viewer.setInput(blacklists); } @Override public void propertyChange(PropertyChangeEvent evt) { if (!committing) { IFormPage page = (IFormPage) getManagedForm().getContainer(); if (page.isActive()) { refresh(); } else { markStale(); } } } /** * Update the blacklists already available with new ones. Already existing blacklists will be removed from the given * set. * * @param adding * Set with {@link Requirement}s to add * @return true if blacklists were added. */ private boolean updateViewerWithNewBlacklist(Set<Requirement> adding) { // remove duplicates adding.removeAll(blacklists); if (adding.isEmpty()) { return false; } blacklists.addAll(adding); viewer.add(adding.toArray()); markDirty(); return true; } private class RequirementViewerDropAdapter extends AbstractViewerDropAdapter { public RequirementViewerDropAdapter() { super(viewer, EnumSet.of(SupportedTransfer.LocalSelection)); } @Override protected boolean performSelectionDrop(ISelection data, Object target, int location) { Set<Requirement> adding = new LinkedHashSet<Requirement>(); if (data instanceof IStructuredSelection) { IStructuredSelection structSel = (IStructuredSelection) data; for (Object elem : structSel.toList()) { Requirement requirement = createRequirement(elem); if (requirement != null) adding.add(requirement); } } return updateViewerWithNewBlacklist(adding); } } }