blob: 89b0968fea3548934a0da179febda61614333c82 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2008 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Sebastian Davids <sdavids@gmx.de> - Fix for bug 19346 - Dialog
* font should be activated and used by other components.
*******************************************************************************/
package org.eclipse.ui.internal.dialogs;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.swt.SWT;
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.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.Shell;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.jface.dialogs.DialogTray;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.internal.ConfigureColumnsDialog;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.IBaseLabelProvider;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.LabelProviderChangedEvent;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
import org.eclipse.ui.internal.WorkbenchImages;
import org.eclipse.ui.internal.WorkbenchMessages;
import org.eclipse.ui.internal.WorkbenchPlugin;
import org.eclipse.ui.internal.about.AboutBundleData;
import org.eclipse.ui.internal.misc.StatusUtil;
import org.eclipse.ui.internal.util.BundleUtility;
import org.eclipse.ui.progress.UIJob;
import org.eclipse.ui.statushandlers.StatusManager;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.Bundle;
/**
* Displays information about the product plugins.
*
* PRIVATE
* this class is internal to the ide
*/
public class AboutPluginsDialog extends ProductInfoDialog {
public class BundleTableLabelProvider extends LabelProvider implements ITableLabelProvider {
/**
* Scheduling rule for resolve jobs.
*/
private ISchedulingRule resolveRule = new ISchedulingRule() {
public boolean contains(ISchedulingRule rule) {
return rule == this;
}
public boolean isConflicting(ISchedulingRule rule) {
return rule == this;
}};
private Job sortingJob= new UIJob(getShell().getDisplay(), AboutPluginsDialog.class.getName()) {
{
setRule(resolveRule);
setSystem(true);
setPriority(Job.DECORATE);
}
/* (non-Javadoc)
* @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor)
*/
public IStatus runInUIThread(IProgressMonitor monitor) {
fireLabelProviderChanged(new LabelProviderChangedEvent(
BundleTableLabelProvider.this));
return Status.OK_STATUS;
}
};
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object, int)
*/
public Image getColumnImage(Object element, int columnIndex) {
if (columnIndex == 0) {
if (element instanceof AboutBundleData) {
final AboutBundleData data = (AboutBundleData) element;
if (data.isSignedDetermined()) {
return WorkbenchImages
.getImage(data.isSigned() ? IWorkbenchGraphicConstants.IMG_OBJ_SIGNED_YES
: IWorkbenchGraphicConstants.IMG_OBJ_SIGNED_NO);
}
Job resolveJob = new Job(data.getId()){
protected IStatus run(IProgressMonitor monitor) {
data.isSigned();
Shell dialogShell = getShell();
if (dialogShell == null || dialogShell.isDisposed())
return Status.OK_STATUS;
dialogShell.getDisplay().asyncExec(new Runnable() {
public void run() {
fireLabelProviderChanged(new LabelProviderChangedEvent(
BundleTableLabelProvider.this, data));
}
});
sortingJob.schedule();
return Status.OK_STATUS;
}
};
resolveJob.setRule(resolveRule);
resolveJob.setSystem(true);
resolveJob.schedule();
return WorkbenchImages
.getImage(IWorkbenchGraphicConstants.IMG_OBJ_SIGNED_UNKNOWN);
}
}
return null;
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object, int)
*/
public String getColumnText(Object element, int columnIndex) {
if (element instanceof AboutBundleData) {
AboutBundleData data = (AboutBundleData) element;
switch (columnIndex) {
case 1:
return data.getProviderName();
case 2:
return data.getName();
case 3:
return data.getVersion();
case 4:
return data.getId();
}
}
return ""; //$NON-NLS-1$
}
}
/**
* Table height in dialog units (value 200).
*/
private static final int TABLE_HEIGHT = 200;
private static final IPath baseNLPath = new Path("$nl$"); //$NON-NLS-1$
private static final String PLUGININFO = "about.html"; //$NON-NLS-1$
private final static int MORE_ID = IDialogConstants.CLIENT_ID + 1;
private final static int SIGNING_ID = MORE_ID + 1;
private final static int COLUMNS_ID = MORE_ID + 2;
private static final int PLUGIN_NAME_COLUMN_INDEX = 2;
private TableViewer vendorInfo;
private Button moreInfo, signingInfo;
private String title;
private String message;
private String helpContextId;
private String columnTitles[] = {
WorkbenchMessages.AboutPluginsDialog_signed,
WorkbenchMessages.AboutPluginsDialog_provider,
WorkbenchMessages.AboutPluginsDialog_pluginName,
WorkbenchMessages.AboutPluginsDialog_version,
WorkbenchMessages.AboutPluginsDialog_pluginId,
};
private String productName;
private AboutBundleData[] bundleInfos;
/**
* Constructor for AboutPluginsDialog.
*
* @param parentShell the parent shell
* @param productName the product name
*/
public AboutPluginsDialog(Shell parentShell, String productName) {
this(parentShell, productName, WorkbenchPlugin.getDefault()
.getBundles(), null, null, IWorkbenchHelpContextIds.ABOUT_PLUGINS_DIALOG);
WorkbenchPlugin.class.getSigners();
}
/**
* Constructor for AboutPluginsDialog.
*
* @param parentShell
* the parent shell
* @param productName
* must not be null
* @param bundles
* must not be null
* @param title
* the title
* @param message
* the message
* @param helpContextId
* the help context id
*/
public AboutPluginsDialog(Shell parentShell, String productName,
Bundle[] bundles, String title, String message, String helpContextId) {
super(parentShell);
this.title = title;
this.message = message;
this.helpContextId = helpContextId;
this.productName = productName;
// create a data object for each bundle, remove duplicates, and include only resolved bundles (bug 65548)
Map map = new HashMap();
for (int i = 0; i < bundles.length; ++i) {
AboutBundleData data = new AboutBundleData(bundles[i]);
if (BundleUtility.isReady(data.getState()) && !map.containsKey(data.getVersionedId())) {
map.put(data.getVersionedId(), data);
}
}
bundleInfos = (AboutBundleData[]) map.values().toArray(
new AboutBundleData[0]);
}
/*
* (non-Javadoc) Method declared on Dialog.
*/
protected void buttonPressed(int buttonId) {
switch (buttonId) {
case MORE_ID:
handleMoreInfoPressed();
break;
case SIGNING_ID:
handleSigningInfoPressed();
break;
case COLUMNS_ID:
handleColumnsPressed();
break;
default:
super.buttonPressed(buttonId);
break;
}
}
/**
*
*/
private void handleColumnsPressed() {
ConfigureColumnsDialog d = new ConfigureColumnsDialog(this, vendorInfo.getTable());
d.open();
}
/**
*/
private void handleSigningInfoPressed() {
DialogTray existingTray = getTray();
if (existingTray instanceof BundleSigningTray) {
// hide
getButton(SIGNING_ID).setText(WorkbenchMessages.AboutPluginsDialog_signingInfo_show);
closeTray();
}
else {
//show
getButton(SIGNING_ID).setText(WorkbenchMessages.AboutPluginsDialog_signingInfo_hide);
if (existingTray != null)
closeTray();
AboutBundleData bundleInfo = (AboutBundleData) ((IStructuredSelection) vendorInfo
.getSelection()).getFirstElement();
BundleSigningTray tray = new BundleSigningTray(this);
tray.setData(bundleInfo);
openTray(tray);
}
}
/*
* (non-Javadoc) Method declared on Window.
*/
protected void configureShell(Shell newShell) {
super.configureShell(newShell);
//signImage = new Image( this.getParentShell().getDisplay(), AboutPluginsDialog.class.getResourceAsStream("Signed.gif")); //$NON-NLS-1$
if (title == null && productName != null) {
title = NLS.bind(WorkbenchMessages.AboutPluginsDialog_shellTitle, productName);
}
if (title != null) {
newShell.setText(title);
}
PlatformUI.getWorkbench().getHelpSystem().setHelp(newShell,
helpContextId);
}
/**
* Add buttons to the dialog's button bar.
*
* Subclasses should override.
*
* @param parent
* the button bar composite
*/
protected void createButtonsForButtonBar(Composite parent) {
parent.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
moreInfo = createButton(parent, MORE_ID, WorkbenchMessages.AboutPluginsDialog_moreInfo, false);
moreInfo.setEnabled(false);
signingInfo = createButton(parent, SIGNING_ID, WorkbenchMessages.AboutPluginsDialog_signingInfo_show, false);
signingInfo.setEnabled(false);
createButton(parent, COLUMNS_ID, WorkbenchMessages.AboutPluginsDialog_columns, false);
Label l = new Label(parent, SWT.NONE);
l.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
GridLayout layout = (GridLayout) parent.getLayout();
layout.numColumns++;
layout.makeColumnsEqualWidth = false;
createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL,
true);
}
/**
* Create the contents of the dialog (above the button bar).
*
* Subclasses should overide.
*
* @param parent
* the parent composite to contain the dialog area
* @return the dialog area control
*/
protected Control createDialogArea(Composite parent) {
Composite outer = (Composite) super.createDialogArea(parent);
if (message != null) {
Label label = new Label(outer, SWT.NONE);
label.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
label.setFont(parent.getFont());
label.setText(message);
}
createTable(outer);
return outer;
}
/**
* Create the table part of the dialog.
*
* @param parent
* the parent composite to contain the dialog area
*/
protected void createTable(Composite parent) {
vendorInfo = new TableViewer(parent, SWT.H_SCROLL | SWT.V_SCROLL | SWT.SINGLE
| SWT.FULL_SELECTION | SWT.BORDER);
vendorInfo.setUseHashlookup(true);
vendorInfo.getTable().setHeaderVisible(true);
vendorInfo.getTable().setLinesVisible(true);
vendorInfo.getTable().setFont(parent.getFont());
vendorInfo.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
// enable if there is an item selected and that
// item has additional info
IStructuredSelection selection = (IStructuredSelection) event.getSelection();
if (selection.getFirstElement() instanceof AboutBundleData) {
AboutBundleData selected = (AboutBundleData) selection.getFirstElement();
moreInfo.setEnabled(selectionHasInfo(selected));
signingInfo.setEnabled(true);
if (getTray() instanceof BundleSigningTray) {
((BundleSigningTray)getTray()).setData(selected);
}
}
else {
moreInfo.setEnabled(false);
signingInfo.setEnabled(false);
}
}});
final TableComparator comparator = new TableComparator();
vendorInfo.setComparator(comparator);
int[] columnWidths = {
convertHorizontalDLUsToPixels(30), //signature
convertHorizontalDLUsToPixels(120),
convertHorizontalDLUsToPixels(120),
convertHorizontalDLUsToPixels(70),
convertHorizontalDLUsToPixels(130),
};
// create table headers
for (int i = 0; i < columnTitles.length; i++) {
TableColumn column = new TableColumn(vendorInfo.getTable(), SWT.NULL);
if (i == PLUGIN_NAME_COLUMN_INDEX) { // prime initial sorting
updateTableSorting(i);
}
column.setWidth(columnWidths[i]);
column.setText(columnTitles[i]);
final int columnIndex = i;
column.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
updateTableSorting(columnIndex);
}
});
}
vendorInfo.setContentProvider(new ArrayContentProvider());
vendorInfo.setLabelProvider(new BundleTableLabelProvider());
GridData gridData = new GridData(GridData.FILL, GridData.FILL, true,
true);
gridData.heightHint = convertVerticalDLUsToPixels(TABLE_HEIGHT);
vendorInfo.getTable().setLayoutData(gridData);
vendorInfo.setInput(bundleInfos);
}
/**
* Update the sort information on both the comparator and the table.
*
* @param columnIndex
* the index to sort by
* @since 3.4
*/
private void updateTableSorting(final int columnIndex) {
TableComparator comparator = (TableComparator) vendorInfo
.getComparator();
// toggle direction if it's the same column
if (columnIndex == comparator.getSortColumn()) {
comparator.setAscending(!comparator.isAscending());
}
comparator.setSortColumn(columnIndex);
vendorInfo.getTable().setSortColumn(
vendorInfo.getTable().getColumn(columnIndex));
vendorInfo.getTable().setSortDirection(
comparator.isAscending() ? SWT.UP : SWT.DOWN);
vendorInfo.refresh(false);
}
/**
* Check if the currently selected plugin has additional information to
* show.
* @param bundleInfo
*
* @return true if the selected plugin has additional info available to
* display
*/
private boolean selectionHasInfo(AboutBundleData bundleInfo) {
URL infoURL = getMoreInfoURL(bundleInfo, false);
// only report ini problems if the -debug command line argument is used
if (infoURL == null && WorkbenchPlugin.DEBUG) {
WorkbenchPlugin.log("Problem reading plugin info for: " //$NON-NLS-1$
+ bundleInfo.getName());
}
return infoURL != null;
}
/**
* The More Info button was pressed. Open a browser showing the license information
* for the selected bundle or an error dialog if the browser cannot be opened.
*/
protected void handleMoreInfoPressed() {
if (vendorInfo == null) {
return;
}
if (vendorInfo.getSelection().isEmpty())
return;
AboutBundleData bundleInfo = (AboutBundleData) ((IStructuredSelection) vendorInfo
.getSelection()).getFirstElement();
if (!openBrowser(getMoreInfoURL(bundleInfo, true))) {
String message = NLS.bind(
WorkbenchMessages.AboutPluginsDialog_unableToOpenFile,
PLUGININFO, bundleInfo.getId());
StatusUtil.handleStatus(
WorkbenchMessages.AboutPluginsDialog_errorTitle
+ ": " + message, StatusManager.SHOW, getShell()); //$NON-NLS-1$
}
}
/**
* Return an url to the plugin's about.html file (what is shown when "More info" is
* pressed) or null if no such file exists. The method does nl lookup to allow for
* i18n.
*
* @param bundleInfo the bundle info
* @param makeLocal whether to make the about content local
* @return the url or <code>null</code>
*/
private URL getMoreInfoURL(AboutBundleData bundleInfo, boolean makeLocal) {
Bundle bundle = Platform.getBundle(bundleInfo.getId());
if (bundle == null) {
return null;
}
URL aboutUrl = Platform.find(bundle, baseNLPath.append(PLUGININFO), null);
if (!makeLocal) {
return aboutUrl;
}
if (aboutUrl != null) {
try {
URL result = Platform.asLocalURL(aboutUrl);
try {
// Make local all content in the "about" directory.
// This is needed to handle jar'ed plug-ins.
// See Bug 88240 [About] About dialog needs to extract subdirs.
URL about = new URL(aboutUrl, "about_files"); //$NON-NLS-1$
if (about != null) {
Platform.asLocalURL(about);
}
} catch (IOException e) {
// skip the about dir if its not found or there are other problems.
}
return result;
} catch(IOException e) {
// do nothing
}
}
return null;
}
}
class TableComparator extends ViewerComparator {
private int sortColumn = 0;
private boolean ascending = true;
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ViewerComparator#compare(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object)
*/
public int compare(Viewer viewer, Object e1, Object e2) {
if (sortColumn == 0 && e1 instanceof AboutBundleData && e2 instanceof AboutBundleData) {
AboutBundleData d1= (AboutBundleData) e1;
AboutBundleData d2= (AboutBundleData) e2;
int diff= getSignedSortValue(d1) - getSignedSortValue(d2);
return ascending ? diff : -diff;
}
if (viewer instanceof TableViewer) {
TableViewer tableViewer = (TableViewer) viewer;
IBaseLabelProvider baseLabel = tableViewer.getLabelProvider();
if (baseLabel instanceof ITableLabelProvider) {
ITableLabelProvider tableProvider = (ITableLabelProvider) baseLabel;
String e1p = tableProvider.getColumnText(e1, sortColumn);
String e2p = tableProvider.getColumnText(e2, sortColumn);
int result = getComparator().compare(e1p, e2p);
return ascending ? result : (-1) * result;
}
}
return super.compare(viewer, e1, e2);
}
/**
* @param data
* @return a sort value depending on the signed state
*/
private int getSignedSortValue(AboutBundleData data) {
if (! data.isSignedDetermined()) {
return 0;
} else if (data.isSigned()) {
return 1;
} else {
return -1;
}
}
/**
* @return Returns the sortColumn.
*/
public int getSortColumn() {
return sortColumn;
}
/**
* @param sortColumn The sortColumn to set.
*/
public void setSortColumn(int sortColumn) {
this.sortColumn = sortColumn;
}
/**
* @return Returns the ascending.
*/
public boolean isAscending() {
return ascending;
}
/**
* @param ascending The ascending to set.
*/
public void setAscending(boolean ascending) {
this.ascending = ascending;
}
}