| /******************************************************************************* |
| * Copyright (c) 2008, 2020 IBM Corporation 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: |
| * IBM Corporation - initial API and implementation |
| * Sonatype, Inc. - ongoing development |
| * Red Hat,Inc. - filter installed softwares |
| *******************************************************************************/ |
| |
| package org.eclipse.equinox.p2.ui; |
| |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.text.StringMatcher; |
| import org.eclipse.equinox.internal.p2.ui.*; |
| import org.eclipse.equinox.internal.p2.ui.actions.*; |
| import org.eclipse.equinox.internal.p2.ui.dialogs.*; |
| import org.eclipse.equinox.internal.p2.ui.model.InstalledIUElement; |
| import org.eclipse.equinox.internal.p2.ui.viewers.IUColumnConfig; |
| import org.eclipse.equinox.internal.p2.ui.viewers.IUDetailsLabelProvider; |
| import org.eclipse.equinox.p2.metadata.IInstallableUnit; |
| import org.eclipse.jface.action.Action; |
| import org.eclipse.jface.dialogs.IDialogConstants; |
| import org.eclipse.jface.resource.JFaceResources; |
| import org.eclipse.jface.viewers.*; |
| import org.eclipse.jface.window.SameShellProvider; |
| import org.eclipse.jface.window.Window; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.dnd.*; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.layout.GridLayout; |
| import org.eclipse.swt.widgets.*; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.about.InstallationPage; |
| import org.eclipse.ui.menus.AbstractContributionFactory; |
| import org.eclipse.ui.statushandlers.StatusManager; |
| |
| /** |
| * InstalledSoftwarePage displays a profile's IInstallableUnits in |
| * an Installation Page. Clients can use this class as the implementation |
| * class for an installationPages extension. |
| * |
| * @see InstallationPage |
| * |
| * @noextend This class is not intended to be subclassed by clients. |
| * @noinstantiate This class is not intended to be instantiated by clients. |
| * @since 2.0 |
| * |
| */ |
| public class InstalledSoftwarePage extends InstallationPage implements ICopyable { |
| |
| private static final int UPDATE_ID = IDialogConstants.CLIENT_ID; |
| private static final int UNINSTALL_ID = IDialogConstants.CLIENT_ID + 1; |
| private static final int PROPERTIES_ID = IDialogConstants.CLIENT_ID + 2; |
| private static final String BUTTON_ACTION = "org.eclipse.equinox.p2.ui.buttonAction"; //$NON-NLS-1$ |
| |
| AbstractContributionFactory factory; |
| Text detailsArea; |
| InstalledIUGroup installedIUGroup; |
| String profileId; |
| Button updateButton, uninstallButton, propertiesButton; |
| ProvisioningUI ui; |
| |
| @Override |
| public void createControl(Composite parent) { |
| initializeDialogUnits(parent); |
| PlatformUI.getWorkbench().getHelpSystem().setHelp(parent, IProvHelpContextIds.INSTALLED_SOFTWARE); |
| |
| profileId = getProvisioningUI().getProfileId(); |
| if (profileId == null) { |
| IStatus status = getProvisioningUI().getPolicy().getNoProfileChosenStatus(); |
| if (status != null) |
| ProvUI.reportStatus(status, StatusManager.LOG); |
| Text text = new Text(parent, SWT.WRAP | SWT.READ_ONLY); |
| text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); |
| text.setText(ProvUIMessages.InstalledSoftwarePage_NoProfile); |
| setControl(text); |
| return; |
| } |
| |
| Composite composite = new Composite(parent, SWT.NONE); |
| GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true); |
| int width = getDefaultWidth(composite); |
| gd.widthHint = width; |
| composite.setLayoutData(gd); |
| GridLayout layout = new GridLayout(); |
| layout.marginWidth = 0; |
| layout.marginHeight = 0; |
| composite.setLayout(layout); |
| |
| // Table of installed IU's |
| installedIUGroup = new InstalledIUGroup(getProvisioningUI(), composite, JFaceResources.getDialogFont(), profileId, getColumnConfig()); |
| // we hook selection listeners on the viewer in createPageButtons because we |
| // rely on the actions we create there getting selection events before we use |
| // them to update button enablement. |
| |
| CopyUtils.activateCopy(this, installedIUGroup.getStructuredViewer().getControl()); |
| |
| gd = new GridData(SWT.FILL, SWT.FILL, true, false); |
| gd.heightHint = convertHeightInCharsToPixels(ILayoutConstants.DEFAULT_DESCRIPTION_HEIGHT); |
| gd.widthHint = width; |
| |
| detailsArea = new Text(composite, SWT.BORDER | SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL | SWT.READ_ONLY | SWT.WRAP); |
| detailsArea.setBackground(detailsArea.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND)); |
| detailsArea.setLayoutData(gd); |
| |
| setControl(composite); |
| } |
| |
| @Override |
| public void createPageButtons(Composite parent) { |
| if (profileId == null) |
| return; |
| // For the update action, we create a custom selection provider that will interpret no |
| // selection as checking for updates to everything. |
| // We also override the run method to close the containing dialog |
| // if we successfully try to resolve. This is done to ensure that progress |
| // is shown properly. |
| // See https://bugs.eclipse.org/bugs/show_bug.cgi?id=236495 |
| UpdateAction updateAction = new UpdateAction(getProvisioningUI(), new ISelectionProvider() { |
| @Override |
| public void addSelectionChangedListener(ISelectionChangedListener listener) { |
| installedIUGroup.getStructuredViewer().addSelectionChangedListener(listener); |
| } |
| |
| @Override |
| public ISelection getSelection() { |
| StructuredViewer viewer = installedIUGroup.getStructuredViewer(); |
| ISelection selection = viewer.getSelection(); |
| if (selection.isEmpty()) { |
| final Object[] all = ((IStructuredContentProvider) viewer.getContentProvider()).getElements(viewer.getInput()); |
| return new StructuredSelection(all); |
| } |
| return selection; |
| } |
| |
| @Override |
| public void removeSelectionChangedListener(ISelectionChangedListener listener) { |
| installedIUGroup.getStructuredViewer().removeSelectionChangedListener(listener); |
| } |
| |
| @Override |
| public void setSelection(ISelection selection) { |
| installedIUGroup.getStructuredViewer().setSelection(selection); |
| } |
| }, profileId, true) { |
| @Override |
| public void run() { |
| super.run(); |
| if (getReturnCode() == Window.OK) |
| getPageContainer().closeModalContainers(); |
| } |
| }; |
| updateAction.setSkipSelectionPage(true); |
| updateButton = createButton(parent, UPDATE_ID, updateAction.getText()); |
| updateButton.setData(BUTTON_ACTION, updateAction); |
| // Uninstall action |
| Action uninstallAction = new UninstallAction(getProvisioningUI(), installedIUGroup.getStructuredViewer(), profileId) { |
| @Override |
| public void run() { |
| super.run(); |
| if (getReturnCode() == Window.OK) |
| getPageContainer().closeModalContainers(); |
| } |
| }; |
| uninstallButton = createButton(parent, UNINSTALL_ID, uninstallAction.getText()); |
| uninstallButton.setData(BUTTON_ACTION, uninstallAction); |
| |
| // Properties action |
| PropertyDialogAction action = new PropertyDialogAction(new SameShellProvider(getShell()), installedIUGroup.getStructuredViewer()); |
| propertiesButton = createButton(parent, PROPERTIES_ID, action.getText()); |
| propertiesButton.setData(BUTTON_ACTION, action); |
| |
| // We rely on the actions getting selection events before we do, because |
| // we rely on the enablement state of the action. So we don't hook |
| // the selection listener on our table until after actions are created. |
| installedIUGroup.getStructuredViewer().addSelectionChangedListener(event -> { |
| updateDetailsArea(); |
| updateEnablement(); |
| }); |
| |
| final IUPatternFilter searchFilter = new IUPatternFilter(getColumnConfig()); |
| installedIUGroup.getStructuredViewer().addFilter(searchFilter); |
| |
| updateEnablement(); |
| } |
| |
| void updateDetailsArea() { |
| java.util.List<IInstallableUnit> selected = installedIUGroup.getSelectedIUs(); |
| if (selected.size() == 1) { |
| String description = selected.get(0).getProperty(IInstallableUnit.PROP_DESCRIPTION, null); |
| if (description != null) { |
| detailsArea.setText(description); |
| return; |
| } |
| } |
| detailsArea.setText(""); //$NON-NLS-1$ |
| } |
| |
| void updateEnablement() { |
| if (updateButton == null || updateButton.isDisposed()) |
| return; |
| Button[] buttons = {updateButton, uninstallButton, propertiesButton}; |
| for (Button button : buttons) { |
| Action action = (Action) button.getData(BUTTON_ACTION); |
| if (action == null || !action.isEnabled()) |
| button.setEnabled(false); |
| else |
| button.setEnabled(true); |
| } |
| } |
| |
| private IUColumnConfig[] getColumnConfig() { |
| return new IUColumnConfig[] {new IUColumnConfig(ProvUIMessages.ProvUI_NameColumnTitle, IUColumnConfig.COLUMN_NAME, ILayoutConstants.DEFAULT_PRIMARY_COLUMN_WIDTH), new IUColumnConfig(ProvUIMessages.ProvUI_VersionColumnTitle, IUColumnConfig.COLUMN_VERSION, ILayoutConstants.DEFAULT_SMALL_COLUMN_WIDTH), new IUColumnConfig(ProvUIMessages.ProvUI_IdColumnTitle, IUColumnConfig.COLUMN_ID, ILayoutConstants.DEFAULT_COLUMN_WIDTH), new IUColumnConfig(ProvUIMessages.ProvUI_ProviderColumnTitle, IUColumnConfig.COLUMN_PROVIDER, ILayoutConstants.DEFAULT_COLUMN_WIDTH)}; |
| } |
| |
| private int getDefaultWidth(Control control) { |
| IUColumnConfig[] columns = getColumnConfig(); |
| int totalWidth = 0; |
| for (IUColumnConfig column : columns) { |
| totalWidth += column.getWidthInPixels(control); |
| } |
| return totalWidth + 20; // buffer for surrounding composites |
| } |
| |
| @Override |
| public void copyToClipboard(Control activeControl) { |
| Object[] elements = installedIUGroup.getSelectedIUElements(); |
| if (elements.length == 0) |
| return; |
| String text = CopyUtils.getIndentedClipboardText(elements, new IUDetailsLabelProvider(null, getColumnConfig(), null)); |
| Clipboard clipboard = new Clipboard(PlatformUI.getWorkbench().getDisplay()); |
| clipboard.setContents(new Object[] {text}, new Transfer[] {TextTransfer.getInstance()}); |
| clipboard.dispose(); |
| } |
| |
| @Override |
| protected void buttonPressed(int buttonId) { |
| switch (buttonId) { |
| case UPDATE_ID : |
| ((Action) updateButton.getData(BUTTON_ACTION)).run(); |
| break; |
| case UNINSTALL_ID : |
| ((Action) uninstallButton.getData(BUTTON_ACTION)).run(); |
| break; |
| case PROPERTIES_ID : |
| ((Action) propertiesButton.getData(BUTTON_ACTION)).run(); |
| break; |
| default : |
| super.buttonPressed(buttonId); |
| break; |
| } |
| } |
| |
| ProvisioningUI getProvisioningUI() { |
| // if a UI has not been set then assume that the current default UI is the right thing |
| if (ui == null) |
| return ui = ProvisioningUI.getDefaultUI(); |
| return ui; |
| } |
| |
| /** |
| * Set the provisioning UI to use with this page |
| * |
| * @param value the provisioning ui to use |
| * @since 2.1 |
| */ |
| public void setProvisioningUI(ProvisioningUI value) { |
| ui = value; |
| } |
| |
| /** |
| * Filters {@link InstalledIUElement}s from a viewer using a String pattern. |
| * Filtering is dependent on a given array of {@link IUColumnConfig}s : |
| * <ul> |
| * <li>if {@link IUColumnConfig#COLUMN_ID} is present, filters on the Installable Unit's id;</li> |
| * <li>if {@link IUColumnConfig#COLUMN_NAME} is present, filters on the Installable Unit's name;</li> |
| * <li>if {@link IUColumnConfig#COLUMN_PROVIDER} is present, filters on the Installable Unit's provider;</li> |
| * </ul> |
| * |
| * @since 2.3 |
| */ |
| class IUPatternFilter extends ViewerFilter { |
| |
| private StringMatcher matcher; |
| |
| private boolean filterOnId; |
| |
| private boolean filterOnName; |
| |
| private boolean filterOnProvider; |
| |
| public IUPatternFilter() { |
| this(null); |
| } |
| |
| public IUPatternFilter(IUColumnConfig[] columnConfig) { |
| if (columnConfig == null) { |
| columnConfig = ProvUI.getIUColumnConfig(); |
| } |
| for (IUColumnConfig colConfig : columnConfig) { |
| switch (colConfig.getColumnType()) { |
| case IUColumnConfig.COLUMN_ID : |
| filterOnId = true; |
| break; |
| case IUColumnConfig.COLUMN_NAME : |
| filterOnName = true; |
| break; |
| case IUColumnConfig.COLUMN_PROVIDER : |
| filterOnProvider = true; |
| break; |
| default : |
| break; |
| } |
| if (filterOnId && filterOnName && filterOnProvider) { |
| break; |
| } |
| } |
| } |
| |
| public void setPattern(String searchPattern) { |
| if (searchPattern == null || searchPattern.length() == 0) { |
| this.matcher = null; |
| } else { |
| String pattern = "*" + searchPattern + "*"; //$NON-NLS-1$//$NON-NLS-2$ |
| this.matcher = new StringMatcher(pattern, true, false); |
| } |
| } |
| |
| @Override |
| public boolean select(Viewer viewer, Object parentElement, Object element) { |
| if (matcher == null || !(filterOnName || filterOnId || filterOnProvider)) { |
| return true; |
| } |
| |
| if (element instanceof InstalledIUElement) { |
| InstalledIUElement data = (InstalledIUElement) element; |
| IInstallableUnit iu = data.getIU(); |
| boolean match = false; |
| if (iu != null) { |
| if (filterOnName) { |
| String name = iu.getProperty(IInstallableUnit.PROP_NAME, null); |
| match = matcher.match(name); |
| } |
| if (!match && filterOnId) { |
| match = matcher.match(iu.getId()); |
| } |
| if (!match && filterOnProvider) { |
| String provider = iu.getProperty(IInstallableUnit.PROP_PROVIDER, null); |
| match = matcher.match(provider); |
| } |
| } |
| return match; |
| } |
| return true; |
| } |
| } |
| } |