blob: 1f01b21cd0c6976a1a7dbd921d09429bc31662d5 [file] [log] [blame]
/*******************************************************************************
* 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;
}
}
}