| /******************************************************************************* |
| * Copyright (c) 2014, 2020 TwelveTone LLC and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Steven Spungin <steven@spungin.tv> - initial API and implementation, Bug 424730, Bug 435625, Bug 436281 |
| * Andrej ten Brummelhuis <andrejbrummelhuis@gmail.com> - Bug 395283 |
| * Marco Descher <marco@descher.at> - Bug 442647 |
| *******************************************************************************/ |
| |
| package org.eclipse.e4.tools.emf.ui.internal.common.component.dialogs; |
| |
| import java.io.BufferedReader; |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.InputStreamReader; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.EnumSet; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Scanner; |
| |
| import org.eclipse.core.databinding.observable.list.IObservableList; |
| import org.eclipse.core.databinding.observable.list.WritableList; |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.runtime.jobs.Job; |
| import org.eclipse.e4.core.contexts.IEclipseContext; |
| import org.eclipse.e4.tools.emf.ui.common.IClassContributionProvider.ContributionData; |
| import org.eclipse.e4.tools.emf.ui.common.IClassContributionProvider.ContributionResultHandler; |
| import org.eclipse.e4.tools.emf.ui.common.IClassContributionProvider.Filter; |
| import org.eclipse.e4.tools.emf.ui.common.ProviderStatus; |
| import org.eclipse.e4.tools.emf.ui.common.ResourceSearchScope; |
| import org.eclipse.e4.tools.emf.ui.internal.Messages; |
| import org.eclipse.e4.tools.emf.ui.internal.common.ClassContributionCollector; |
| import org.eclipse.e4.tools.emf.ui.internal.common.component.dialogs.AbstractIconDialogWithScopeAndFilter.Entry; |
| import org.eclipse.e4.tools.emf.ui.internal.common.component.tabs.empty.E; |
| import org.eclipse.e4.tools.emf.ui.internal.common.component.tabs.empty.TitleAreaFilterDialog; |
| import org.eclipse.e4.tools.emf.ui.internal.common.resourcelocator.TargetPlatformClassContributionCollector; |
| import org.eclipse.e4.tools.emf.ui.internal.common.resourcelocator.TargetPlatformContributionCollector; |
| import org.eclipse.e4.tools.emf.ui.internal.common.resourcelocator.TargetPlatformIconContributionCollector; |
| import org.eclipse.e4.tools.emf.ui.internal.common.resourcelocator.dialogs.NonReferencedResourceDialog; |
| import org.eclipse.e4.tools.emf.ui.internal.common.resourcelocator.dialogs.NonReferencedResourceWizard; |
| import org.eclipse.jface.databinding.viewers.ObservableListContentProvider; |
| import org.eclipse.jface.dialogs.IDialogConstants; |
| import org.eclipse.jface.text.Document; |
| import org.eclipse.jface.viewers.ColumnLabelProvider; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| import org.eclipse.jface.viewers.StyledCellLabelProvider; |
| import org.eclipse.jface.viewers.StyledString; |
| import org.eclipse.jface.viewers.TableViewer; |
| import org.eclipse.jface.viewers.ViewerCell; |
| import org.eclipse.jface.window.Window; |
| import org.eclipse.jface.wizard.WizardDialog; |
| import org.eclipse.pde.internal.core.project.PDEProject; |
| import org.eclipse.pde.internal.core.text.bundle.BundleModel; |
| import org.eclipse.pde.internal.core.text.bundle.ImportPackageHeader; |
| import org.eclipse.pde.internal.core.text.bundle.ImportPackageObject; |
| import org.eclipse.pde.internal.core.text.bundle.RequireBundleHeader; |
| import org.eclipse.pde.internal.core.text.bundle.RequireBundleObject; |
| 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.graphics.Image; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.layout.GridLayout; |
| import org.eclipse.swt.layout.RowLayout; |
| import org.eclipse.swt.widgets.Button; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Event; |
| import org.eclipse.swt.widgets.Label; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.swt.widgets.Text; |
| |
| /** |
| * Abstract base class for a find contribution dialog.<br /> |
| * Includes a filter text box, scope options, and filter options. |
| * |
| * @author Steven Spungin |
| * |
| */ |
| public abstract class FilteredContributionDialog extends SaveDialogBoundsSettingsDialog { |
| |
| private static final int MAX_RESULTS = 500; |
| private static final int DIALOG_MINIMUM_WIDTH = 600; |
| private static final int DIALOG_MINIMUM_HEIGHT = 350; |
| |
| private Image contributionTypeImage; |
| private TableViewer viewer; |
| private static final String PREF_SEARCHSCOPE = "searchScope"; //$NON-NLS-1$ |
| private ResourceSearchScope searchScope = ResourceSearchScope.PROJECT; |
| private static final String PREF_SEARCHSCOPES = "searchScopes"; //$NON-NLS-1$ |
| private EnumSet<ResourceSearchScope> searchScopes = EnumSet.of(ResourceSearchScope.PROJECT); |
| // private EnumSet<SearchScope> searchScopes = |
| // EnumSet.of(SearchScope.PROJECT, SearchScope.REFERENCES); |
| protected ClassContributionCollector collector; |
| private Text textBox; |
| private Button btnFilterNone; |
| private Button btnFilterBundle; |
| private Button btnFilterPackage; |
| private List<String> filterBundles; |
| private List<String> filterPackages; |
| private Button btnFilterLocation; |
| private List<String> filterLocations; |
| private Button btnClearCache; |
| private final IEclipseContext context; |
| private Composite compOptions; |
| protected boolean includeNonBundles; |
| private Label lblStatus; |
| private Button btnIncludeNoneBundle; |
| private WritableList<ContributionData> viewerList; |
| protected BundleImageCache imageCache; |
| protected Job currentSearchThread; |
| private ContributionResultHandlerImpl currentResultHandler; |
| protected ProviderStatus providerStatus; |
| protected int hint; |
| protected int maxResults; |
| protected boolean searching; |
| |
| abstract protected ClassContributionCollector getCollector(); |
| |
| abstract protected String getFilterTextMessage(); |
| |
| abstract protected String getResourceNameText(); |
| |
| abstract protected String getDialogMessage(); |
| |
| abstract protected String getDialogTitle(); |
| |
| abstract protected String getShellTitle(); |
| |
| private void updateStatusMessage() { |
| String message = ""; //$NON-NLS-1$ |
| if (searching) { |
| message += Messages.FilteredContributionDialog_Searching; |
| } |
| // dlg.setStatus("More than " + filter.maxResults + |
| // " items were found and have not been displayed"); |
| if (hint != 0) { |
| if (hint == ContributionResultHandler.MORE_CANCELED) { |
| message += Messages.FilteredContributionDialog_SearchWasCancelled; |
| } else { |
| message += Messages.FilteredContributionDialog_MoreThan + maxResults |
| + Messages.FilteredContributionDialog_itemsWereFound; |
| } |
| } |
| |
| if (getCollector() instanceof TargetPlatformContributionCollector) { |
| if (providerStatus != null) { |
| switch (providerStatus) { |
| case READY: |
| break; |
| case INITIALIZING: |
| message += Messages.FilteredContributionDialog_ProviderInitializing; |
| break; |
| case CANCELLED: |
| message += Messages.FilteredContributionDialog_ProviderWasCancelled; |
| break; |
| } |
| } |
| } |
| setMessage(message); |
| } |
| |
| private class ContributionResultHandlerImpl implements ContributionResultHandler { |
| private boolean cancled = false; |
| private final IObservableList<ContributionData> list; |
| |
| public ContributionResultHandlerImpl(IObservableList<ContributionData> list) { |
| this.list = list; |
| } |
| |
| @Override |
| public void result(final ContributionData data) { |
| if (!cancled) { |
| getShell().getDisplay().syncExec(() -> list.add(data)); |
| } |
| } |
| |
| @Override |
| public void moreResults(final int hint, final Filter filter) { |
| if (!cancled) { |
| getShell().getDisplay().syncExec(() -> { |
| final FilteredContributionDialog dlg = (FilteredContributionDialog) filter.userData; |
| dlg.hint = hint; |
| dlg.maxResults = filter.maxResults; |
| dlg.updateStatusMessage(); |
| }); |
| } |
| } |
| } |
| |
| @Override |
| public boolean close() { |
| stopSearchThread(true); |
| getPreferences().put(PREF_SEARCHSCOPE, searchScope.toString()); |
| getPreferences().put(PREF_SEARCHSCOPES, searchScopes.toString()); |
| return super.close(); |
| } |
| |
| @Override |
| protected Control createContents(Composite parent) { |
| final Control ret = super.createContents(parent); |
| textBox.notifyListeners(SWT.Modify, new Event()); |
| textBox.setFocus(); |
| return ret; |
| } |
| |
| public FilteredContributionDialog(Shell parentShell, IEclipseContext context) { |
| super(parentShell); |
| this.context = context; |
| imageCache = new BundleImageCache(context.get(Display.class), getClass().getClassLoader()); |
| |
| final String searchScopeString = getPreferences().get(PREF_SEARCHSCOPE, ResourceSearchScope.PROJECT.toString()); |
| searchScope = ResourceSearchScope.valueOf(searchScopeString); |
| |
| final String searchScopesString = getPreferences().get(PREF_SEARCHSCOPES, |
| EnumSet.of(ResourceSearchScope.PROJECT).toString()); |
| searchScopes = valueOf(ResourceSearchScope.class, searchScopesString); |
| } |
| |
| public static <TheType extends Enum<TheType>> EnumSet<TheType> valueOf(Class<TheType> eClass, String str) { |
| final String[] arr = str.substring(1, str.length() - 1).split(","); //$NON-NLS-1$ |
| final EnumSet<TheType> set = EnumSet.noneOf(eClass); |
| for (final String e : arr) { |
| set.add(Enum.valueOf(eClass, e.trim())); |
| } |
| return set; |
| } |
| |
| public void setStatus(final String message) { |
| getShell().getDisplay().asyncExec(() -> lblStatus.setText(message)); |
| } |
| |
| @Override |
| protected void configureShell(Shell newShell) { |
| super.configureShell(newShell); |
| newShell.setMinimumSize(DIALOG_MINIMUM_WIDTH, DIALOG_MINIMUM_HEIGHT); |
| } |
| |
| @Override |
| protected void createButtonsForButtonBar(Composite parent) { |
| |
| // Rename the default OK text for the button |
| createButton(parent, IDialogConstants.OK_ID, Messages.FilteredContributionDialog_Select, true); |
| createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false); |
| ((GridLayout) parent.getLayout()).numColumns = 4; |
| |
| btnClearCache = new Button(parent, SWT.PUSH); |
| btnClearCache.setText(Messages.FilteredContributionDialog_ClearCache); |
| btnClearCache.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| getCollector().clearModelCache(); |
| } |
| }); |
| |
| btnClearCache.moveAbove(getButton(0)); |
| |
| lblStatus = new Label(parent, SWT.NONE); |
| lblStatus.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); |
| lblStatus.setText(""); //$NON-NLS-1$ |
| lblStatus.moveAbove(btnClearCache); |
| |
| // This is called here instead of create contents because btnClearCache |
| // is referenced in updateUiState. |
| updateUiState(); |
| } |
| |
| // TODO add results found (and/or more indicator) |
| @Override |
| protected Control createDialogArea(Composite parent) { |
| final Composite comp = (Composite) super.createDialogArea(parent); |
| getShell().addDisposeListener(e -> { |
| imageCache.dispose(); |
| |
| if (contributionTypeImage.isDisposed() == false) { |
| contributionTypeImage.dispose(); |
| } |
| if (getTitleImageLabel().getImage() != null && getTitleImage().isDisposed() == false) { |
| getTitleImageLabel().getImage().dispose(); |
| } |
| }); |
| |
| getShell().setText(getShellTitle()); |
| setTitle(getDialogTitle()); |
| setMessage(getDialogMessage()); |
| |
| final Image titleImage = getTitleImage(); |
| setTitleImage(titleImage); |
| |
| // TODO param or context |
| contributionTypeImage = imageCache.create("/icons/full/obj16/class_obj.png"); //$NON-NLS-1$ |
| |
| compOptions = new Composite(comp, SWT.NONE); |
| compOptions.setLayoutData(new GridData(GridData.FILL_BOTH)); |
| compOptions.setLayout(new GridLayout(2, false)); |
| |
| createOptions(compOptions); |
| |
| final Label l = new Label(compOptions, SWT.NONE); |
| l.setText(getResourceNameText()); |
| |
| textBox = new Text(compOptions, SWT.BORDER | SWT.SEARCH | SWT.ICON_SEARCH); |
| textBox.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); |
| textBox.setMessage(getFilterTextMessage()); |
| |
| new Label(compOptions, SWT.NONE); |
| |
| rebuildViewer(); |
| |
| collector = getCollector(); |
| |
| textBox.addKeyListener(new KeyAdapter() { |
| @Override |
| public void keyPressed(KeyEvent e) { |
| if (e.keyCode == SWT.ARROW_DOWN) { |
| if (viewer.getTable().getItemCount() > 0) { |
| viewer.getTable().setFocus(); |
| viewer.getTable().select(0); |
| } |
| } |
| } |
| }); |
| |
| viewer.getTable().addKeyListener(new KeyAdapter() { |
| @Override |
| public void keyPressed(KeyEvent e) { |
| super.keyPressed(e); |
| if (e.keyCode == SWT.ARROW_UP && viewer.getTable().getSelectionIndex() == 0) { |
| textBox.setFocus(); |
| } |
| } |
| }); |
| |
| textBox.addModifyListener(e -> { |
| stopSearchThread(true); |
| setMessage(""); //$NON-NLS-1$ |
| |
| viewerList.clear(); |
| if (doSearch() == true) { |
| return; |
| } |
| searching = true; |
| updateStatusMessage(); |
| |
| currentSearchThread = new Job(Messages.FilteredContributionDialog_ContributionSearch) { |
| |
| Filter filter; |
| |
| @Override |
| protected IStatus run(IProgressMonitor monitor) { |
| monitor.beginTask(Messages.FilteredContributionDialog_ContributionSearch, IProgressMonitor.UNKNOWN); |
| currentResultHandler = new ContributionResultHandlerImpl(viewerList); |
| getShell().getDisplay().syncExec(() -> { |
| if (searchScopes.contains(ResourceSearchScope.PROJECT)) { |
| filter = new Filter(context.get(IProject.class), textBox.getText()); |
| } else { |
| // filter = new Filter(null, |
| // textBox.getText()); |
| filter = new Filter(context.get(IProject.class), textBox.getText()); |
| } |
| }); |
| filter.maxResults = MAX_RESULTS; |
| filter.userData = FilteredContributionDialog.this; |
| filter.setBundles(filterBundles); |
| filter.setPackages(filterPackages); |
| filter.setLocations(filterLocations); |
| filter.setSearchScope(searchScopes); |
| filter.setIncludeNonBundles(includeNonBundles); |
| filter.setProgressMonitor(monitor); |
| filter.setProviderStatusCallback(status -> { |
| providerStatus = status; |
| try { |
| getShell().getDisplay().syncExec(() -> { |
| updateStatusMessage(); |
| switch (status) { |
| case READY: |
| // This will deadlock if |
| // currentSearchThread is not |
| // null |
| currentSearchThread = null; |
| if (currentResultHandler != null) { |
| currentResultHandler.cancled = true; |
| } |
| refreshSearch(); |
| break; |
| case CANCELLED: |
| case INITIALIZING: |
| break; |
| } |
| }); |
| } catch (final Exception e2) { |
| // Dialog may have been closed while |
| // provider was still indexing |
| } |
| }); |
| collector.findContributions(filter, currentResultHandler); |
| |
| monitor.done(); |
| searching = false; |
| currentSearchThread = null; |
| getShell().getDisplay().syncExec(() -> updateStatusMessage()); |
| return Status.OK_STATUS; |
| } |
| |
| }; |
| currentSearchThread.schedule(); |
| |
| }); |
| |
| return comp; |
| } |
| |
| protected Image getTitleImage() { |
| return imageCache.create("/icons/full/wizban/newsearch_wiz.png"); //$NON-NLS-1$ |
| } |
| |
| protected void createOptions(Composite compOptions) { |
| { |
| final Label lblScope = new Label(compOptions, SWT.NONE); |
| lblScope.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false)); |
| lblScope.setText(Messages.FilteredContributionDialog_Scope); |
| |
| final Composite compScope = new Composite(compOptions, SWT.NONE); |
| compScope.setLayoutData(new GridData(SWT.BEGINNING, SWT.TOP, false, false)); |
| compScope.setLayout(new RowLayout()); |
| |
| final Button btnScopeProject = new Button(compScope, SWT.RADIO); |
| btnScopeProject.setText(Messages.FilteredContributionDialog_ProjectOnly); |
| btnScopeProject.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| if (btnScopeProject.getSelection()) { |
| searchScope = ResourceSearchScope.PROJECT; |
| searchScopes = EnumSet.of(ResourceSearchScope.PROJECT); |
| updateUiState(); |
| getCollector(); |
| refreshSearch(); |
| } |
| } |
| }); |
| btnScopeProject.setSelection(searchScopes.contains(ResourceSearchScope.PROJECT) |
| && !searchScopes.contains(ResourceSearchScope.REFERENCES)); |
| |
| final Button btnProjectAndReferences = new Button(compScope, SWT.RADIO); |
| btnProjectAndReferences.setText(Messages.FilteredContributionDialog_ProjectAndReferences); |
| btnProjectAndReferences.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| if (btnProjectAndReferences.getSelection()) { |
| searchScope = ResourceSearchScope.PROJECT; |
| searchScopes = EnumSet.of(ResourceSearchScope.PROJECT, ResourceSearchScope.REFERENCES); |
| updateUiState(); |
| getCollector(); |
| refreshSearch(); |
| } |
| } |
| }); |
| btnProjectAndReferences.setSelection(searchScopes.contains(ResourceSearchScope.PROJECT) |
| && searchScopes.contains(ResourceSearchScope.REFERENCES)); |
| |
| final Button btnScopeWorkspace = new Button(compScope, SWT.RADIO); |
| btnScopeWorkspace.setText(Messages.FilteredContributionDialog_Workspace); |
| btnScopeWorkspace.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| if (btnScopeWorkspace.getSelection()) { |
| searchScope = ResourceSearchScope.WORKSPACE; |
| searchScopes = EnumSet.of(ResourceSearchScope.WORKSPACE); |
| updateUiState(); |
| getCollector(); |
| refreshSearch(); |
| } |
| } |
| }); |
| btnScopeWorkspace.setSelection(searchScopes.contains(ResourceSearchScope.WORKSPACE)); |
| |
| final Button btnScopeTargetPlatform = new Button(compScope, SWT.RADIO); |
| btnScopeTargetPlatform.setText(Messages.FilteredContributionDialog_TargetPlatform); |
| btnScopeTargetPlatform.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| if (btnScopeTargetPlatform.getSelection()) { |
| searchScope = ResourceSearchScope.TARGET_PLATFORM; |
| searchScopes = EnumSet.of(ResourceSearchScope.TARGET_PLATFORM); |
| updateUiState(); |
| getCollector(); |
| refreshSearch(); |
| } |
| } |
| }); |
| btnScopeTargetPlatform.setSelection(searchScopes.contains(ResourceSearchScope.TARGET_PLATFORM)); |
| } |
| |
| { |
| final Label lblFilter = new Label(compOptions, SWT.NONE); |
| lblFilter.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false)); |
| lblFilter.setText(Messages.FilteredContributionDialog_ScopeFilter); |
| |
| final Composite compFilter = new Composite(compOptions, SWT.NONE); |
| compFilter.setLayoutData(new GridData(SWT.BEGINNING, SWT.TOP, false, false)); |
| compFilter.setLayout(new RowLayout()); |
| |
| btnFilterNone = new Button(compFilter, SWT.CHECK); |
| btnFilterNone.setText(Messages.FilteredContributionDialog_None); |
| btnFilterNone.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| if (btnFilterNone.getSelection()) { |
| removeFilters(); |
| } |
| } |
| }); |
| |
| btnFilterBundle = new Button(compFilter, SWT.CHECK); |
| btnFilterBundle.setText(Messages.FilteredContributionDialog_Bundle); |
| btnFilterBundle.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| if (btnFilterBundle.getSelection()) { |
| showBundleFilter(); |
| } else { |
| filterBundles = null; |
| refreshSearch(); |
| updateUiState(); |
| } |
| } |
| }); |
| |
| btnFilterPackage = new Button(compFilter, SWT.CHECK); |
| btnFilterPackage.setText(Messages.FilteredContributionDialog_Package); |
| btnFilterPackage.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| if (btnFilterPackage.getSelection()) { |
| showPackageFilter(); |
| } else { |
| filterPackages = null; |
| refreshSearch(); |
| updateUiState(); |
| } |
| } |
| }); |
| |
| btnFilterLocation = new Button(compFilter, SWT.CHECK); |
| btnFilterLocation.setText(Messages.FilteredContributionDialog_Location); |
| btnFilterLocation.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| if (btnFilterLocation.getSelection()) { |
| showLocationFilter(); |
| } else { |
| filterLocations = null; |
| refreshSearch(); |
| updateUiState(); |
| } |
| } |
| }); |
| |
| } |
| { |
| final Label lblIncludeNoneBundle = new Label(compOptions, SWT.NONE); |
| lblIncludeNoneBundle.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false)); |
| lblIncludeNoneBundle.setText(Messages.FilteredContributionDialog_NonBundles); |
| |
| btnIncludeNoneBundle = new Button(compOptions, SWT.CHECK); |
| btnIncludeNoneBundle.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false)); |
| btnIncludeNoneBundle.setText(""); //$NON-NLS-1$ |
| btnIncludeNoneBundle.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| includeNonBundles = btnIncludeNoneBundle.getSelection(); |
| refreshSearch(); |
| } |
| }); |
| } |
| } |
| |
| /** |
| * |
| * @return false if default search should be performed, or true if virtual |
| * function will handle |
| */ |
| protected boolean doSearch() { |
| return false; |
| } |
| |
| protected void updateUiState() { |
| btnFilterNone.setSelection(E.isEmpty(filterBundles) && E.isEmpty(filterPackages) && E.isEmpty(filterLocations)); |
| btnFilterBundle.setSelection(E.notEmpty(filterBundles)); |
| btnFilterPackage.setSelection(E.notEmpty(filterPackages)); |
| btnFilterLocation.setSelection(E.notEmpty(filterLocations)); |
| |
| // original (default) contribution filter does not support this |
| // filtering API |
| final boolean enabled = !searchScopes.contains(ResourceSearchScope.PROJECT); |
| btnFilterNone.setEnabled(enabled); |
| btnFilterBundle.setEnabled(enabled); |
| btnFilterLocation.setEnabled(enabled); |
| btnFilterPackage.setEnabled(enabled); |
| btnClearCache.setEnabled(enabled); |
| btnIncludeNoneBundle.setEnabled(enabled); |
| } |
| |
| protected void removeFilters() { |
| filterBundles = null; |
| setFilterPackages(null); |
| filterLocations = null; |
| refreshSearch(); |
| updateUiState(); |
| } |
| |
| public List<String> getFilterPackages() { |
| return filterPackages; |
| } |
| |
| public void setFilterPackages(List<String> filterPackages) { |
| this.filterPackages = filterPackages; |
| } |
| |
| public List<String> getFilterLocations() { |
| return filterLocations; |
| } |
| |
| public void setFilterLocations(List<String> filterLocations) { |
| this.filterLocations = filterLocations; |
| } |
| |
| public List<String> getFilterBundles() { |
| return filterBundles; |
| } |
| |
| public void setFilterBundles(List<String> filterBundles) { |
| this.filterBundles = filterBundles; |
| } |
| |
| protected void refreshSearch() { |
| textBox.notifyListeners(SWT.Modify, new Event()); |
| } |
| |
| protected void showBundleFilter() { |
| final Collection<String> bundleIds; |
| // TODO make HasBundles an interface so we are not tied to |
| // implementation |
| if (getCollector() instanceof TargetPlatformClassContributionCollector) { |
| bundleIds = TargetPlatformClassContributionCollector.getInstance().getBundleIds(); |
| } else if (getCollector() instanceof TargetPlatformIconContributionCollector) { |
| bundleIds = TargetPlatformIconContributionCollector.getInstance().getBundleIds(); |
| } else { |
| return; |
| } |
| |
| final ArrayList<String> sorted = new ArrayList<>(bundleIds); |
| sorted.sort(null); |
| |
| final TitleAreaFilterDialog dlg = new TitleAreaFilterDialog(getShell(), new ColumnLabelProvider()) { |
| @Override |
| protected Control createContents(Composite parent) { |
| final Control ret = super.createContents(parent); |
| getViewer().setInput(sorted); |
| setMessage(Messages.FilteredContributionDialog_SelectTheBundle); |
| setTitle(Messages.FilteredContributionDialog_BundleFilter); |
| getShell().setText(Messages.FilteredContributionDialog_BundleFilter); |
| try { |
| setTitleImage(imageCache.create("/icons/full/wizban/plugin_wiz.gif")); //$NON-NLS-1$ |
| } catch (final Exception e) { |
| e.printStackTrace(); |
| } |
| return ret; |
| } |
| }; |
| if (dlg.open() == Window.OK) { |
| final ArrayList<String> result = new ArrayList<>(); |
| result.add(dlg.getFirstSelection()); |
| setFilterBundles(result); |
| refreshSearch(); |
| } |
| updateUiState(); |
| } |
| |
| protected void showPackageFilter() { |
| final Collection<String> packages; |
| // TODO make HasPackages an interface so we are not tied to |
| // implementation |
| if (getCollector() instanceof TargetPlatformClassContributionCollector) { |
| packages = TargetPlatformClassContributionCollector.getInstance().getPackages(); |
| } else if (getCollector() instanceof TargetPlatformIconContributionCollector) { |
| packages = TargetPlatformIconContributionCollector.getInstance().getPackages(); |
| } else { |
| return; |
| } |
| |
| final ArrayList<String> sorted = new ArrayList<>(packages); |
| sorted.sort(null); |
| |
| final TitleAreaFilterDialog dlg = new TitleAreaFilterDialog(getShell(), new ColumnLabelProvider()) { |
| @Override |
| protected Control createContents(Composite parent) { |
| final Control ret = super.createContents(parent); |
| getViewer().setInput(sorted); |
| setMessage(Messages.FilteredContributionDialog_SelectThePackage); |
| setTitle(Messages.FilteredContributionDialog_PackageFilter); |
| getShell().setText(Messages.FilteredContributionDialog_PackageFilter); |
| setTitleImage(imageCache.create("/icons/full/wizban/package_wiz.png")); //$NON-NLS-1$ |
| return ret; |
| } |
| }; |
| if (dlg.open() == Window.OK) { |
| final ArrayList<String> result = new ArrayList<>(); |
| result.add(dlg.getFirstSelection()); |
| setFilterBundles(result); |
| refreshSearch(); |
| } |
| updateUiState(); |
| } |
| |
| public ResourceSearchScope getScope() { |
| return searchScope; |
| } |
| |
| public void setScope(ResourceSearchScope scope) { |
| searchScope = scope; |
| } |
| |
| public void setCollector(ClassContributionCollector collector) { |
| this.collector = collector; |
| } |
| |
| protected void showLocationFilter() { |
| final Collection<String> locations; |
| // TODO make HasLocations an interface so we are not tied to |
| // implementation |
| if (getCollector() instanceof TargetPlatformClassContributionCollector) { |
| locations = TargetPlatformClassContributionCollector.getInstance().getLocations(); |
| } else if (getCollector() instanceof TargetPlatformIconContributionCollector) { |
| locations = TargetPlatformIconContributionCollector.getInstance().getLocations(); |
| } else { |
| return; |
| } |
| |
| // add all parent paths |
| final HashSet<String> parentLocations = new HashSet<>(); |
| for (String location : locations) { |
| if (location.endsWith(".jar")) { //$NON-NLS-1$ |
| final int index = location.lastIndexOf(File.separator); |
| if (index >= 0) { |
| location = location.substring(0, index); |
| parentLocations.add(location); |
| } |
| } else { |
| parentLocations.add(location); |
| } |
| } |
| |
| final ArrayList<String> sorted = new ArrayList<>(parentLocations); |
| sorted.sort(null); |
| |
| final TitleAreaFilterDialog dlg = new TitleAreaFilterDialog(getShell(), new ColumnLabelProvider()) { |
| @Override |
| protected Control createContents(Composite parent) { |
| final Control ret = super.createContents(parent); |
| getViewer().setInput(sorted); |
| setMessage(Messages.FilteredContributionDialog_SelectTheLocation); |
| setTitle(Messages.FilteredContributionDialog_LocationFilter); |
| getShell().setText(Messages.FilteredContributionDialog_LocationFilter); |
| setTitleImage(imageCache.create("/icons/full/wizban/location_wiz.png")); //$NON-NLS-1$ |
| return ret; |
| } |
| }; |
| if (dlg.open() == Window.OK) { |
| final ArrayList<String> result = new ArrayList<>(); |
| result.add(dlg.getFirstSelection()); |
| setFilterBundles(result); |
| refreshSearch(); |
| } |
| updateUiState(); |
| } |
| |
| protected void rebuildViewer() { |
| |
| viewerList = new WritableList<>(); |
| |
| final TableViewer oldViewer = viewer; |
| viewer = new TableViewer(compOptions, SWT.FULL_SELECTION | SWT.BORDER); |
| if (oldViewer != null) { |
| viewer.getTable().moveAbove(oldViewer.getTable()); |
| oldViewer.getTable().dispose(); |
| } |
| final GridData gd = new GridData(GridData.FILL_BOTH); |
| viewer.getControl().setLayoutData(gd); |
| viewer.setContentProvider(new ObservableListContentProvider<>()); |
| viewer.setLabelProvider(new StyledCellLabelProvider() { |
| @Override |
| public void update(ViewerCell cell) { |
| ContributionData data; |
| if (cell.getElement() instanceof ContributionData) { |
| data = (ContributionData) cell.getElement(); |
| } else if (cell.getElement() instanceof ContributionDataFile) { |
| data = ((ContributionDataFile) cell.getElement()).getContributionData(); |
| } else { |
| return; |
| } |
| |
| final StyledString styledString = new StyledString(); |
| if (data.className != null) { |
| styledString.append(data.className, null); |
| } |
| |
| if (data.bundleName != null) { |
| styledString.append(" - " + data.bundleName, StyledString.DECORATIONS_STYLER); //$NON-NLS-1$ |
| } else if (data.installLocation != null) { |
| styledString.append(" - " + data.installLocation, StyledString.DECORATIONS_STYLER); //$NON-NLS-1$ |
| } |
| |
| if (data.sourceType != null) { |
| styledString.append(" - ", StyledString.DECORATIONS_STYLER); //$NON-NLS-1$ |
| styledString.append(data.sourceType + "", StyledString.COUNTER_STYLER); //$NON-NLS-1$ |
| } |
| |
| if (data.iconPath == null) { |
| cell.setImage(contributionTypeImage); |
| } |
| |
| cell.setText(styledString.getString()); |
| cell.setStyleRanges(styledString.getStyleRanges()); |
| } |
| }); |
| viewer.addDoubleClickListener(event -> okPressed()); |
| |
| viewer.setInput(viewerList); |
| |
| if (oldViewer != null) { |
| getViewer().getTable().getParent().layout(true, true); |
| getViewer().getTable().getParent().redraw(); |
| } |
| } |
| |
| public TableViewer getViewer() { |
| return viewer; |
| } |
| |
| public void setViewer(TableViewer viewer) { |
| this.viewer = viewer; |
| } |
| |
| protected Text getFilterTextBox() { |
| return textBox; |
| } |
| |
| public ResourceSearchScope getSearchScope() { |
| return searchScope; |
| } |
| |
| protected IFile getSelectedIfile() { |
| final IStructuredSelection s = (IStructuredSelection) getViewer().getSelection(); |
| if (!s.isEmpty()) { |
| final Object selected = s.getFirstElement(); |
| if (selected instanceof ContributionData) { |
| final ContributionData contributionData = (ContributionData) selected; |
| return new ContributionDataFile(contributionData); |
| } else if (selected instanceof IFile) { |
| return (IFile) selected; |
| } else if (selected instanceof Entry) { |
| final Entry entry = (Entry) selected; |
| final ContributionData cd = new ContributionData(null, null, Messages.FilteredContributionDialog_Java, |
| entry.file.getFullPath().toOSString()); |
| cd.installLocation = entry.installLocation; |
| cd.resourceRelativePath = entry.file.getProjectRelativePath().toOSString(); |
| return new ContributionDataFile(cd); |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Returns non null if the selected resource is accessible from the current |
| * project<br /> |
| * Restrictions may include non-existent file, non exported class, or the |
| * resource is in a location that is not a bundle.<br /> |
| * The function, through user intervention, may find a way to resolve the |
| * file and return a resolution. |
| * |
| * @param file |
| * @param installLocation |
| * @return The original file, a fixed-up (copied or referred) file, or null. |
| */ |
| protected IFile checkResourceAccessible(final IFile file, String installLocation) { |
| |
| // Obviously null is not accessible |
| if (file == null) { |
| return null; |
| } |
| |
| // Not a bundle |
| final String bundle = getBundle(file); |
| if (bundle == null) { |
| final String message = Messages.FilteredContributionDialog_ResourceIsNotContainedInABundle; |
| final NonReferencedResourceWizard wizard = new NonReferencedResourceWizard(getShell(), |
| context.get(IProject.class), bundle, file, installLocation, context); |
| wizard.setMessage(message); |
| final WizardDialog wizDlg = new WizardDialog(getShell(), wizard); |
| wizDlg.setBlockOnOpen(true); |
| if (wizDlg.open() == IDialogConstants.OK_ID) { |
| return wizard.getResult(); |
| } |
| return null; |
| } |
| |
| // Reference by current project |
| final IProject currentProject = context.get(IProject.class); |
| if (currentProject != null && !getBundle(currentProject).equals(bundle)) { |
| boolean found = false; |
| // search the current project's manifest for require-bundle |
| try { |
| final BundleModel model = loadBundleModel(currentProject); |
| |
| final RequireBundleHeader rbh = (RequireBundleHeader) model.getBundle().getManifestHeader( |
| "Require-Bundle"); //$NON-NLS-1$ |
| if (rbh != null) { |
| for (final RequireBundleObject item : rbh.getRequiredBundles()) { |
| if (item.getValue().equals(bundle)) { |
| found = true; |
| break; |
| } |
| } |
| } |
| // search the current project's manifest for import-package |
| if (!found) { |
| if (file instanceof ContributionDataFile) { |
| final ContributionDataFile cdFile = (ContributionDataFile) file; |
| final String className = cdFile.getContributionData().className; |
| if (className != null) { |
| final String pakage = NonReferencedResourceDialog.getPackageFromClassName(className); |
| final ImportPackageHeader iph = (ImportPackageHeader) model.getBundle().getManifestHeader( |
| "Import-Package"); //$NON-NLS-1$ |
| if (iph != null) { |
| for (final ImportPackageObject item : iph.getPackages()) { |
| if (item.getValue().equals(pakage)) { |
| found = true; |
| break; |
| } |
| } |
| } |
| } |
| } |
| } |
| } catch (final Exception e) { |
| } |
| |
| if (!found) { |
| final String message = Messages.FilteredContributionDialog_ResourceIsNotReferencedByThisBundle; |
| final NonReferencedResourceWizard wizard = new NonReferencedResourceWizard(getShell(), |
| context.get(IProject.class), bundle, file, installLocation, context); |
| wizard.setMessage(message); |
| final WizardDialog wiz = new WizardDialog(getShell(), wizard); |
| wiz.setBlockOnOpen(true); |
| if (wiz.open() == IDialogConstants.OK_ID) { |
| return wizard.getResult(); |
| } |
| return null; |
| } |
| } |
| return file; |
| } |
| |
| public BundleModel loadBundleModel(IProject currentProject) throws CoreException { |
| final Document document = new Document(); |
| try (final Scanner scanner = new Scanner(PDEProject.getManifest(currentProject).getContents())) { |
| final String content = scanner.useDelimiter("\\Z").next(); //$NON-NLS-1$ |
| document.set(content); |
| final BundleModel model = new BundleModel(document, false); |
| model.load(); |
| return model; |
| } |
| } |
| |
| protected EnumSet<ResourceSearchScope> getSearchScopes() { |
| return searchScopes; |
| } |
| |
| public void stopSearchThread(boolean bJoin) { |
| if (currentSearchThread != null) { |
| currentResultHandler.cancled = true; |
| currentSearchThread.cancel(); |
| if (bJoin) { |
| try { |
| if (currentSearchThread != null) { |
| currentSearchThread.join(); |
| } |
| } catch (final InterruptedException e) { |
| } finally { |
| currentSearchThread = null; |
| } |
| } else { |
| currentSearchThread = null; |
| } |
| } |
| } |
| |
| static public String getBundle(IFile file) { |
| |
| if (file instanceof ContributionDataFile) { |
| final ContributionDataFile cdFile = (ContributionDataFile) file; |
| final String ret = cdFile.getBundle(); |
| if (ret != null) { |
| return ret; |
| } else if (cdFile.getContributionData().installLocation != null) { |
| return getBundle(cdFile.getContributionData().installLocation); |
| } else { |
| return null; |
| } |
| } |
| |
| final IProject project = file.getProject(); |
| return getBundle(project); |
| } |
| |
| static String getBundle(IProject project) { |
| final IFile f = project.getFile("/META-INF/MANIFEST.MF"); //$NON-NLS-1$ |
| |
| if (f != null && f.exists()) { |
| try (final InputStream s = f.getContents(); |
| BufferedReader r = new BufferedReader(new InputStreamReader(s));) { |
| String line; |
| while ((line = r.readLine()) != null) { |
| if (line.startsWith("Bundle-SymbolicName:")) { //$NON-NLS-1$ |
| final int start = line.indexOf(':'); |
| int end = line.indexOf(';'); |
| if (end == -1) { |
| end = line.length(); |
| } |
| return line.substring(start + 1, end).trim(); |
| } |
| } |
| } catch (final CoreException e) { |
| e.printStackTrace(); |
| } catch (final IOException e) { |
| e.printStackTrace(); |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Searches the directory for a manifest and parses the symbolic name. |
| * |
| * @param rootDirectory |
| * @return the id of the bundle if existing |
| */ |
| public static String getBundle(String rootDirectory) { |
| final File f = new File(new File(rootDirectory), "/META-INF/MANIFEST.MF"); //$NON-NLS-1$ |
| |
| if (f.exists()) { |
| try (final InputStream s = new FileInputStream(f); |
| BufferedReader r = new BufferedReader(new InputStreamReader(s))) { |
| |
| String line; |
| while ((line = r.readLine()) != null) { |
| if (line.startsWith("Bundle-SymbolicName:")) { //$NON-NLS-1$ |
| final int start = line.indexOf(':'); |
| int end = line.indexOf(';'); |
| if (end == -1) { |
| end = line.length(); |
| } |
| return line.substring(start + 1, end).trim(); |
| } |
| } |
| } catch (final IOException e) { |
| e.printStackTrace(); |
| } |
| } |
| return null; |
| } |
| } |