blob: 8a38b7d0dd9666d03be26407b18d68f03e2e4317 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.update.internal.ui.forms;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Locale;
import java.util.StringTokenizer;
import java.util.Vector;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.PluginVersionIdentifier;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.custom.BusyIndicator;
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.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.help.WorkbenchHelp;
import org.eclipse.update.configuration.IConfiguredSite;
import org.eclipse.update.configuration.IInstallConfiguration;
import org.eclipse.update.configuration.ILocalSite;
import org.eclipse.update.core.IFeature;
import org.eclipse.update.core.IFeatureReference;
import org.eclipse.update.core.IIncludedFeatureReference;
import org.eclipse.update.core.ISite;
import org.eclipse.update.core.SiteManager;
import org.eclipse.update.core.VersionedIdentifier;
import org.eclipse.update.internal.ui.UpdatePerspective;
import org.eclipse.update.internal.ui.UpdateUI;
import org.eclipse.update.internal.ui.UpdateUIImages;
import org.eclipse.update.internal.ui.model.IConfiguredSiteContext;
import org.eclipse.update.internal.ui.model.IFeatureAdapter;
import org.eclipse.update.internal.ui.model.IUpdateModelChangedListener;
import org.eclipse.update.internal.ui.model.MissingFeature;
import org.eclipse.update.internal.ui.model.PendingChange;
import org.eclipse.update.internal.ui.model.UpdateModel;
import org.eclipse.update.internal.ui.pages.UpdateFormPage;
import org.eclipse.update.internal.ui.parts.SWTUtil;
import org.eclipse.update.internal.ui.preferences.UpdateColors;
import org.eclipse.update.internal.ui.views.DetailsView;
import org.eclipse.update.internal.ui.wizards.InstallWizard;
import org.eclipse.update.internal.ui.wizards.InstallWizardDialog;
import org.eclipse.update.ui.forms.internal.ExpandableGroup;
import org.eclipse.update.ui.forms.internal.FormWidgetFactory;
import org.eclipse.update.ui.forms.internal.HTMLTableLayout;
import org.eclipse.update.ui.forms.internal.HyperlinkAdapter;
import org.eclipse.update.ui.forms.internal.HyperlinkHandler;
import org.eclipse.update.ui.forms.internal.IHyperlinkListener;
import org.eclipse.update.ui.forms.internal.SelectableFormLabel;
import org.eclipse.update.ui.forms.internal.TableData;
public class DetailsForm extends PropertyWebForm {
// NL keys
private static final String KEY_PROVIDER = "FeaturePage.provider"; //$NON-NLS-1$
private static final String KEY_VERSION = "FeaturePage.version"; //$NON-NLS-1$
private static final String KEY_IVERSION = "FeaturePage.installedVersion"; //$NON-NLS-1$
private static final String KEY_PENDING_VERSION =
"FeaturePage.pendingVersion"; //$NON-NLS-1$
private static final String KEY_SIZE = "FeaturePage.size"; //$NON-NLS-1$
private static final String KEY_ESTIMATE = "FeaturePage.estimate"; //$NON-NLS-1$
private static final String KEY_OS = "FeaturePage.os"; //$NON-NLS-1$
private static final String KEY_WS = "FeaturePage.ws"; //$NON-NLS-1$
private static final String KEY_NL = "FeaturePage.nl"; //$NON-NLS-1$
private static final String KEY_ARCH = "FeaturePage.arch"; //$NON-NLS-1$
private static final String KEY_PLATFORMS = "FeaturePage.platforms"; //$NON-NLS-1$
private static final String KEY_DESC = "FeaturePage.description"; //$NON-NLS-1$
private static final String KEY_INFO_LINK = "FeaturePage.infoLink"; //$NON-NLS-1$
private static final String KEY_LICENSE_LINK = "FeaturePage.licenseLink"; //$NON-NLS-1$
private static final String KEY_COPYRIGHT_LINK =
"FeaturePage.copyrightLink"; //$NON-NLS-1$
private static final String KEY_NOT_INSTALLED = "FeaturePage.notInstalled"; //$NON-NLS-1$
private static final String KEY_SIZE_VALUE = "FeaturePage.sizeValue"; //$NON-NLS-1$
private static final String KEY_ESTIMATE_VALUE =
"FeaturePage.estimateValue"; //$NON-NLS-1$
private static final String KEY_MINUTE_ESTIMATE_VALUE =
"FeaturePage.minuteEstimateValue"; //$NON-NLS-1$
private static final String KEY_UNKNOWN_SIZE_VALUE =
"FeaturePage.unknownSizeValue"; //$NON-NLS-1$
private static final String KEY_UNKNOWN_ESTIMATE_VALUE =
"FeaturePage.unknownEstimateValue"; //$NON-NLS-1$
private static final String KEY_DO_UNCONFIGURE =
"FeaturePage.doButton.unconfigure"; //$NON-NLS-1$
private static final String KEY_DO_CONFIGURE =
"FeaturePage.doButton.configure"; //$NON-NLS-1$
private static final String KEY_DO_REPAIR = "FeaturePage.doButton.repair"; //$NON-NLS-1$
private static final String KEY_DO_CHANGE = "FeaturePage.doButton.change"; //$NON-NLS-1$
private static final String KEY_DO_UPDATE = "FeaturePage.doButton.update"; //$NON-NLS-1$
private static final String KEY_DO_INSTALL = "FeaturePage.doButton.install"; //$NON-NLS-1$
private static final String KEY_DO_UNINSTALL =
"FeaturePage.doButton.uninstall"; //$NON-NLS-1$
private static final String KEY_BATCH_UNCONFIGURE =
"FeaturePage.batchButton.unconfigure"; //$NON-NLS-1$
private static final String KEY_BATCH_CONFIGURE =
"FeaturePage.batchButton.configure"; //$NON-NLS-1$
private static final String KEY_BATCH_REPAIR =
"FeaturePage.batchButton.repair"; //$NON-NLS-1$
private static final String KEY_BATCH_CHANGE =
"FeaturePage.batchButton.change"; //$NON-NLS-1$
private static final String KEY_BATCH_UPDATE =
"FeaturePage.batchButton.update"; //$NON-NLS-1$
private static final String KEY_BATCH_INSTALL =
"FeaturePage.batchButton.install"; //$NON-NLS-1$
private static final String KEY_BATCH_UNINSTALL =
"FeaturePage.batchButton.uninstall"; //$NON-NLS-1$
private static final String KEY_BATCH = "FeaturePage.batch"; //$NON-NLS-1$
private static final String KEY_SELECTED_UPDATES =
"FeaturePage.selectedUpdates"; //$NON-NLS-1$
private static final String KEY_DIALOG_UTITLE = "FeaturePage.dialog.utitle"; //$NON-NLS-1$
private static final String KEY_DIALOG_TITLE = "FeaturePage.dialog.title"; //$NON-NLS-1$
private static final String KEY_DIALOG_CTITLE = "FeaturePage.dialog.ctitle"; //$NON-NLS-1$
private static final String KEY_DIALOG_UCTITLE =
"FeaturePage.dialog.uctitle"; //$NON-NLS-1$
private static final String KEY_DIALOG_UMESSAGE =
"FeaturePage.dialog.umessage"; //$NON-NLS-1$
private static final String KEY_DIALOG_MESSAGE =
"FeaturePage.dialog.message"; //$NON-NLS-1$
private static final String KEY_DIALOG_CMESSAGE =
"FeaturePage.dialog.cmessage"; //$NON-NLS-1$
private static final String KEY_DIALOG_UCMESSAGE =
"FeaturePage.dialog.ucmessage"; //$NON-NLS-1$
private static final String KEY_MISSING_TITLE = "FeaturePage.missing.title"; //$NON-NLS-1$
private static final String KEY_MISSING_MESSAGE =
"FeaturePage.missing.message"; //$NON-NLS-1$
private static final String KEY_MISSING_SEARCH =
"FeaturePage.missing.search"; //$NON-NLS-1$
private static final String KEY_MISSING_ABORT = "FeaturePage.missing.abort"; //$NON-NLS-1$
private static final String KEY_SEARCH_OBJECT_NAME =
"FeaturePage.missing.searchObjectName"; //$NON-NLS-1$
private static final String KEY_OPTIONAL_INSTALL_MESSAGE =
"FeaturePage.optionalInstall.message"; //$NON-NLS-1$
private static final String KEY_OPTIONAL_INSTALL_TITLE =
"FeaturePage.optionalInstall.title"; //$NON-NLS-1$
//
private static final int REPAIR = 1;
private static final int CHANGE = 2;
private int reinstallCode = 0;
private Label imageLabel;
private Label providerLabel;
private Label versionLabel;
private Label installedVersionLabel;
private Label sizeLabel;
private Label estimatedTime;
private Label osLabel;
private Label wsLabel;
private Label nlLabel;
private Label archLabel;
private Label descriptionText;
private Label groupUpdatesLabel;
private URL infoLinkURL;
private SelectableFormLabel infoLinkLabel;
private SelectableFormLabel itemsLink;
private InfoLink licenseLink;
private InfoLink copyrightLink;
private ReflowGroup supportedPlatformsGroup;
private Image providerImage;
//private Button uninstallButton;
private Button addButton;
private Button doButton;
private IFeature currentFeature;
private IFeatureAdapter currentAdapter;
private ModelListener modelListener;
private Hashtable imageCache = new Hashtable();
private HyperlinkHandler sectionHandler;
private boolean alreadyInstalled;
private IFeature[] installedFeatures;
private boolean newerVersion;
private boolean addBlock;
private boolean inputBlock;
private static boolean inProgress;
class ModelListener implements IUpdateModelChangedListener {
/**
* @see IUpdateModelChangedListener#objectAdded(Object, Object)
*/
public void objectsAdded(Object parent, Object[] children) {
if (isCurrentFeature(children)) {
SWTUtil.getStandardDisplay().asyncExec(new Runnable() {
public void run() {
refresh();
}
});
}
}
boolean isCurrentFeature(Object[] children) {
for (int i = 0; i < children.length; i++) {
Object obj = children[i];
if (obj instanceof PendingChange) {
PendingChange job = (PendingChange) obj;
if (job.getFeature().equals(currentFeature)) {
return true;
}
}
}
return false;
}
/**
* @see IUpdateModelChangedListener#objectRemoved(Object, Object)
*/
public void objectsRemoved(Object parent, Object[] children) {
if (isCurrentFeature(children)) {
SWTUtil.getStandardDisplay().asyncExec(new Runnable() {
public void run() {
//doButton.setEnabled(true);
refresh();
}
});
}
}
/**
* @see IUpdateModelChangedListener#objectChanged(Object, String)
*/
public void objectChanged(Object object, String property) {
}
}
abstract class LinkListener implements IHyperlinkListener {
public abstract URL getURL();
public void linkActivated(Control linkLabel) {
URL url = getURL();
if (url != null)
openURL(url.toString());
}
public void linkEntered(Control linkLabel) {
URL url = getURL();
if (url != null)
showStatus(url.toString());
}
public void linkExited(Control linkLabel) {
showStatus(null);
}
private void showStatus(String text) {
IViewSite site = getPage().getView().getViewSite();
IStatusLineManager sm = site.getActionBars().getStatusLineManager();
sm.setMessage(text);
}
}
abstract class ReflowGroup extends ExpandableGroup {
public void expanded() {
reflow();
updateSize();
}
public void collapsed() {
reflow();
updateSize();
}
protected SelectableFormLabel createTextLabel(
Composite parent,
FormWidgetFactory factory) {
SelectableFormLabel label = super.createTextLabel(parent, factory);
label.setFont(JFaceResources.getBannerFont());
return label;
}
protected HyperlinkHandler getHyperlinkHandler(FormWidgetFactory factory) {
return sectionHandler;
}
}
public DetailsForm(UpdateFormPage page) {
super(page);
providerImage = UpdateUIImages.DESC_PROVIDER.createImage();
modelListener = new ModelListener();
UpdateModel model = UpdateUI.getDefault().getUpdateModel();
model.addUpdateModelChangedListener(modelListener);
sectionHandler = new HyperlinkHandler();
}
public void dispose() {
UpdateModel model = UpdateUI.getDefault().getUpdateModel();
model.removeUpdateModelChangedListener(modelListener);
providerImage.dispose();
for (Enumeration enum = imageCache.elements();
enum.hasMoreElements();
) {
Image image = (Image) enum.nextElement();
image.dispose();
}
imageCache.clear();
sectionHandler.dispose();
super.dispose();
}
public void initialize(Object modelObject) {
setHeadingText(""); //$NON-NLS-1$
super.initialize(modelObject);
}
private void configureSectionHandler(
FormWidgetFactory factory,
Display display) {
sectionHandler.setHyperlinkUnderlineMode(
HyperlinkHandler.UNDERLINE_NEVER);
sectionHandler.setBackground(factory.getBackgroundColor());
sectionHandler.setForeground(UpdateColors.getTopicColor(display));
}
protected void updateHeadings() {
Control control = getControl();
if (control==null) return;
sectionHandler.setForeground(
UpdateColors.getTopicColor(control.getDisplay()));
super.updateHeadings();
}
public void createContents(Composite container) {
HTMLTableLayout layout = new HTMLTableLayout();
layout.numColumns = 2;
container.setLayout(layout);
//layout.rightMargin = 0;
GridData gd;
configureSectionHandler(factory, container.getDisplay());
GridLayout glayout = new GridLayout();
Composite properties = factory.createComposite(container);
properties.setLayout(glayout);
glayout.marginWidth = glayout.marginHeight = 0;
glayout.verticalSpacing = 0;
providerLabel =
createProperty(properties, UpdateUI.getString(KEY_PROVIDER));
versionLabel =
createProperty(properties, UpdateUI.getString(KEY_VERSION));
installedVersionLabel =
createProperty(properties, UpdateUI.getString(KEY_IVERSION));
sizeLabel = createProperty(properties, UpdateUI.getString(KEY_SIZE));
estimatedTime =
createProperty(properties, UpdateUI.getString(KEY_ESTIMATE));
supportedPlatformsGroup = new ReflowGroup() {
public void fillExpansion(
Composite expansion,
FormWidgetFactory factory) {
GridLayout layout = new GridLayout();
expansion.setLayout(layout);
layout.marginWidth = 0;
osLabel = createProperty(expansion, UpdateUI.getString(KEY_OS));
wsLabel = createProperty(expansion, UpdateUI.getString(KEY_WS));
nlLabel = createProperty(expansion, UpdateUI.getString(KEY_NL));
archLabel =
createProperty(expansion, UpdateUI.getString(KEY_ARCH));
}
};
supportedPlatformsGroup.setText(UpdateUI.getString(KEY_PLATFORMS));
new Label(properties, SWT.NULL);
supportedPlatformsGroup.createControl(properties, factory);
setFocusControl(supportedPlatformsGroup.getControl());
imageLabel = factory.createLabel(container, null);
TableData td = new TableData();
td.align = TableData.CENTER;
//td.valign = TableData.MIDDLE;
imageLabel.setLayoutData(td);
Label label = createHeading(container, UpdateUI.getString(KEY_DESC));
td = new TableData();
td.colspan = 2;
label.setLayoutData(td);
descriptionText = factory.createLabel(container, null, SWT.WRAP);
td = new TableData();
td.colspan = 2;
td.grabHorizontal = true;
descriptionText.setLayoutData(td);
glayout = new GridLayout();
glayout.numColumns = 4;
glayout.horizontalSpacing = 20;
glayout.marginWidth = 10;
addSeparator(container);
Composite footer = factory.createComposite(container);
td = new TableData();
td.colspan = 2;
td.align = TableData.FILL;
footer.setLayoutData(td);
footer.setLayout(glayout);
LinkListener listener = new LinkListener() {
public URL getURL() {
return infoLinkURL;
}
};
infoLinkLabel = new SelectableFormLabel(footer, SWT.NULL);
infoLinkLabel.setText(UpdateUI.getString(KEY_INFO_LINK));
factory.turnIntoHyperlink(infoLinkLabel, listener);
gd = new GridData(GridData.VERTICAL_ALIGN_BEGINNING);
infoLinkLabel.setLayoutData(gd);
licenseLink = new InfoLink((DetailsView) getPage().getView());
licenseLink.setText(UpdateUI.getString(KEY_LICENSE_LINK));
licenseLink.createControl(footer, factory);
gd = new GridData(GridData.VERTICAL_ALIGN_BEGINNING);
licenseLink.getControl().setLayoutData(gd);
copyrightLink = new InfoLink((DetailsView) getPage().getView());
copyrightLink.setText(UpdateUI.getString(KEY_COPYRIGHT_LINK));
copyrightLink.createControl(footer, factory);
gd = new GridData(GridData.VERTICAL_ALIGN_BEGINNING);
copyrightLink.getControl().setLayoutData(gd);
doButton = factory.createButton(footer, "", SWT.PUSH); //$NON-NLS-1$
doButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
doButtonSelected();
}
});
gd =
new GridData(
GridData.HORIZONTAL_ALIGN_CENTER
| GridData.VERTICAL_ALIGN_BEGINNING);
gd.grabExcessHorizontalSpace = true;
doButton.setLayoutData(gd);
Composite batch = factory.createComposite(container);
glayout = new GridLayout();
glayout.numColumns = 2;
glayout.marginWidth = 0;
glayout.marginHeight = 0;
batch.setLayout(glayout);
td = new TableData();
td.colspan = 2;
td.align = TableData.FILL;
//td.grabHorizontal = true;
batch.setLayoutData(td);
groupUpdatesLabel = createHeading(batch, UpdateUI.getString(KEY_BATCH));
gd = new GridData();
gd.horizontalSpan = 2;
groupUpdatesLabel.setLayoutData(gd);
addButton =
factory.createButton(
batch,
UpdateUI.getString(KEY_BATCH_INSTALL),
SWT.CHECK);
addButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
if (!addBlock)
doAdd(addButton.getSelection());
}
});
addButton.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_CENTER));
itemsLink =
factory.createSelectableLabel(
batch,
UpdateUI.getString(KEY_SELECTED_UPDATES));
factory.turnIntoHyperlink(itemsLink, new HyperlinkAdapter() {
public void linkActivated(Control link) {
openUpdateItems();
}
});
itemsLink.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_CENTER));
//SWTUtil.setButtonDimensionHint(doButton);
WorkbenchHelp.setHelp(container, "org.eclipse.update.ui.DetailsForm"); //$NON-NLS-1$
}
private void addSeparator(Composite container) {
Composite l = factory.createCompositeSeparator(container);
l.setBackground(factory.getBorderColor());
TableData td = new TableData();
td.colspan = 2;
td.heightHint = 1;
td.align = TableData.FILL;
l.setLayoutData(td);
}
private void openUpdateItems() {
BusyIndicator.showWhile(SWTUtil.getStandardDisplay(), new Runnable() {
public void run() {
try {
IWorkbenchPage page = UpdateUI.getActivePage();
IViewPart view = page.findView(UpdatePerspective.ID_ITEMS);
if (view != null)
page.bringToTop(view);
else {
inputBlock = true;
page.showView(UpdatePerspective.ID_ITEMS);
inputBlock = false;
}
} catch (PartInitException e) {
UpdateUI.logException(e);
}
}
});
}
public void expandTo(final Object obj) {
if (inputBlock)
return;
BusyIndicator.showWhile(getControl().getDisplay(), new Runnable() {
public void run() {
if (obj instanceof IFeature) {
currentAdapter = null;
currentFeature = (IFeature) obj;
refresh();
} else if (obj instanceof IFeatureAdapter) {
IFeatureAdapter adapter = (IFeatureAdapter) obj;
try {
currentAdapter = adapter;
currentFeature = adapter.getFeature(null);
} catch (CoreException e) {
//UpdateUI.logException(e);
currentFeature =
new MissingFeature(
adapter.getSite(),
adapter.getURL());
} finally {
refresh();
}
} else {
currentFeature = null;
currentAdapter = null;
refresh();
}
}
});
}
private boolean isConfigured(IFeature feature) {
ISite site = feature.getSite();
IConfiguredSite csite = site.getCurrentConfiguredSite();
if (csite == null)
return false;
return csite.isConfigured(feature);
}
private String getInstalledVersionText(IFeature feature) {
alreadyInstalled = false;
VersionedIdentifier vid = feature.getVersionedIdentifier();
PluginVersionIdentifier version = vid.getVersion();
newerVersion = installedFeatures.length > 0;
StringBuffer buf = new StringBuffer();
for (int i = 0; i < installedFeatures.length; i++) {
IFeature installedFeature = installedFeatures[i];
boolean enabled = isConfigured(installedFeature);
VersionedIdentifier ivid =
installedFeature.getVersionedIdentifier();
if (buf.length() > 0)
buf.append(", "); //$NON-NLS-1$
PluginVersionIdentifier iversion = ivid.getVersion();
buf.append(iversion.toString());
if (!enabled) {
buf.append(" "); //$NON-NLS-1$
buf.append(UpdateUI.getString("FeaturePage.disabledVersion")); //$NON-NLS-1$
}
if (ivid.equals(vid)) {
alreadyInstalled = true;
} else {
if (iversion.isGreaterOrEqualTo(version))
newerVersion = false;
}
}
if (buf.length() > 0) {
String versionText = buf.toString();
UpdateModel model = UpdateUI.getDefault().getUpdateModel();
PendingChange change = model.findRelatedPendingChange(feature);
if (change != null) {
return UpdateUI.getFormattedMessage(
KEY_PENDING_VERSION,
versionText);
} else
return versionText;
} else
return null;
}
private void refresh() {
IFeature feature = currentFeature;
if (feature == null)
return;
installedFeatures = UpdateUI.getInstalledFeatures(feature);
if (installedFeatures.length == 0)
installedFeatures = UpdateUI.getInstalledFeatures(feature, false);
setHeadingText(feature.getLabel());
providerLabel.setText(feature.getProvider());
versionLabel.setText(
feature.getVersionedIdentifier().getVersion().toString());
String installedVersion = getInstalledVersionText(feature);
if (installedVersion == null)
installedVersion = UpdateUI.getString(KEY_NOT_INSTALLED);
installedVersionLabel.setText(installedVersion);
long size = feature.getDownloadSize();
String sizeText;
if (size != -1) {
String stext = Long.toString(size);
sizeText = UpdateUI.getFormattedMessage(KEY_SIZE_VALUE, stext);
} else {
sizeText = UpdateUI.getString(KEY_UNKNOWN_SIZE_VALUE);
}
sizeLabel.setText(sizeText);
estimatedTime.setText(getEstimatedTimeText(feature, size));
if (feature.getDescription() != null
&& feature.getDescription().getAnnotation() != null)
descriptionText.setText(feature.getDescription().getAnnotation());
else
descriptionText.setText(""); //$NON-NLS-1$
Image logoImage = loadProviderImage(feature);
if (logoImage == null)
logoImage = providerImage;
imageLabel.setImage(logoImage);
infoLinkURL = null;
if (feature.getDescription() != null)
infoLinkURL = feature.getDescription().getURL();
infoLinkLabel.setVisible(infoLinkURL != null);
setOS(feature.getOS());
setWS(feature.getWS());
setNL(feature.getNL());
setArch(feature.getOSArch());
licenseLink.setInfo(feature.getLicense());
copyrightLink.setInfo(feature.getCopyright());
this.reinstallCode = 0;
UpdateModel model = UpdateUI.getDefault().getUpdateModel();
PendingChange relatedJob =
model.findRelatedPendingChange(currentFeature);
doButton.setVisible(getDoButtonVisibility(false, relatedJob));
addButton.setVisible(getDoButtonVisibility(true, relatedJob));
itemsLink.setVisible(addButton.isVisible());
groupUpdatesLabel.setVisible(addButton.isVisible());
if (addButton.isVisible()) {
if (relatedJob != null) {
IFeature relatedFeature = relatedJob.getFeature();
addButton.setEnabled(
currentFeature.getVersionedIdentifier().equals(
relatedFeature.getVersionedIdentifier()));
} else
addButton.setEnabled(true);
}
addBlock = true;
addButton.setSelection(
relatedJob != null && relatedJob.isProcessed() == false);
addBlock = false;
updateButtonText(newerVersion);
reflow();
updateSize();
((Composite) getControl()).redraw();
}
private String getEstimatedTimeText(IFeature feature, long size) {
long estimate = SiteManager.getEstimatedTransferRate(feature.getURL());
String estimateFormat = null;
if (estimate >= 0 && size != -1) {
long nhours = estimate / 3600000;
long nminutes = estimate % 3600000;
if (nhours == 0 && nminutes == 0) {
estimateFormat = UpdateUI.getString(KEY_MINUTE_ESTIMATE_VALUE);
} else {
String hours = Long.toString(nhours);
String minutes = Long.toString(nminutes);
estimateFormat =
UpdateUI.getFormattedMessage(
KEY_ESTIMATE_VALUE,
new String[] { hours, minutes });
}
} else {
estimateFormat = UpdateUI.getString(KEY_UNKNOWN_ESTIMATE_VALUE);
}
return estimateFormat;
}
private boolean getDoButtonVisibility(
boolean add,
PendingChange relatedJob) {
if (currentFeature instanceof MissingFeature) {
MissingFeature mf = (MissingFeature) currentFeature;
if (mf.isOptional() && mf.getOriginatingSiteURL() != null)
return add ? false : true;
else
return false;
}
if (currentAdapter == null)
return false;
boolean localContext = currentAdapter instanceof IConfiguredSiteContext;
if (currentAdapter.isIncluded()) {
if (!localContext)
return false;
if (!currentAdapter.isOptional())
return false;
}
if (localContext) {
IConfiguredSiteContext context =
(IConfiguredSiteContext) currentAdapter;
if (!context.getInstallConfiguration().isCurrent())
return false;
if (context.getConfiguredSite().isEnabled() == false)
return false;
}
if (relatedJob != null) {
/*if (add)
return false;
*/
if (relatedJob.isProcessed())
return false;
}
if (localContext) {
IConfiguredSiteContext context =
(IConfiguredSiteContext) currentAdapter;
if (!context.getInstallConfiguration().isCurrent())
return false;
else
return true;
} else {
// found on a remote site
// Cannot install feature without a license
/* Commenting - license is now checked in
* ActivityConstraints - bug #33582
if (!UpdateModel.hasLicense(currentFeature))
return false;
*/
}
// Random site feature
if (alreadyInstalled) {
if (isBrokenFeatureUpdate()) {
reinstallCode = REPAIR;
return true;
}
if (isOptionalFeatureInstall()) {
reinstallCode = CHANGE;
return true;
}
return false;
}
// Not installed - check if there are other
// features with this ID that are installed
// and that are newer than this one
if (installedFeatures.length > 0 && !newerVersion)
return false;
return true;
}
private boolean isBrokenFeatureUpdate() {
if (installedFeatures.length != 1)
return false;
IFeature installedFeature = installedFeatures[0];
if (installedFeature
.getVersionedIdentifier()
.equals(currentFeature.getVersionedIdentifier())) {
return isBroken(installedFeature);
}
return false;
}
private boolean isBroken(IFeature feature) {
try {
IStatus status =
SiteManager.getLocalSite().getFeatureStatus(feature);
if (status != null && status.getSeverity() == IStatus.ERROR)
return true;
} catch (CoreException e) {
}
return false;
}
private boolean isOptionalFeatureInstall() {
return hasMissingOptionalFeatures(installedFeatures[0]);
}
private boolean hasMissingOptionalFeatures(IFeature feature) {
try {
IIncludedFeatureReference refs[] =
feature.getIncludedFeatureReferences();
for (int i = 0; i < refs.length; i++) {
IIncludedFeatureReference ref = refs[i];
try {
IFeature child = ref.getFeature(null);
// not missing - try children
if (hasMissingOptionalFeatures(child))
return true;
} catch (CoreException e) {
// missing - if optional, return true
if (ref.isOptional())
return true;
}
}
} catch (CoreException e) {
// problem with the feature itself
}
return false;
}
private boolean getUninstallButtonVisibility() {
/*
* We will not allow uninstalls for now.
if (currentFeature instanceof MissingFeature)
return false;
if (currentAdapter == null || currentAdapter.isIncluded())
return false;
UpdateModel model = UpdateUI.getDefault().getUpdateModel();
if (model.isPending(currentFeature))
return false;
if (currentAdapter instanceof IConfiguredSiteContext) {
boolean configured = isConfigured();
return !configured;
}
*/
return false;
}
private boolean isConfigured() {
if (currentAdapter instanceof IConfiguredSiteContext) {
IConfiguredSiteContext context =
(IConfiguredSiteContext) currentAdapter;
IConfiguredSite csite = context.getConfiguredSite();
IFeatureReference fref =
csite.getSite().getFeatureReference(currentFeature);
IFeatureReference[] cfeatures = csite.getConfiguredFeatures();
for (int i = 0; i < cfeatures.length; i++) {
if (cfeatures[i].equals(fref))
return true;
}
}
return false;
}
private void updateButtonText(boolean update) {
if (reinstallCode == REPAIR) {
doButton.setText(UpdateUI.getString(KEY_DO_REPAIR));
addButton.setText(UpdateUI.getString(KEY_BATCH_REPAIR));
return;
}
if (reinstallCode == CHANGE) {
doButton.setText(UpdateUI.getString(KEY_DO_CHANGE));
addButton.setText(UpdateUI.getString(KEY_BATCH_CHANGE));
return;
}
if (currentFeature instanceof MissingFeature) {
MissingFeature mf = (MissingFeature) currentFeature;
if (mf.isOptional() && mf.getOriginatingSiteURL() != null) {
doButton.setText(UpdateUI.getString(KEY_DO_INSTALL));
return;
}
}
if (currentAdapter instanceof IConfiguredSiteContext) {
boolean configured = isConfigured();
if (configured) {
doButton.setText(UpdateUI.getString(KEY_DO_UNCONFIGURE));
addButton.setText(UpdateUI.getString(KEY_BATCH_UNCONFIGURE));
} else {
doButton.setText(UpdateUI.getString(KEY_DO_CONFIGURE));
addButton.setText(UpdateUI.getString(KEY_BATCH_CONFIGURE));
}
} else if (update && !alreadyInstalled) {
doButton.setText(UpdateUI.getString(KEY_DO_UPDATE));
addButton.setText(UpdateUI.getString(KEY_BATCH_UPDATE));
} else {
doButton.setText(UpdateUI.getString(KEY_DO_INSTALL));
addButton.setText(UpdateUI.getString(KEY_BATCH_INSTALL));
}
}
private Image loadProviderImage(IFeature feature) {
Image image = null;
URL imageURL = feature.getImage();
if (imageURL == null)
return null;
// check table
image = (Image) imageCache.get(imageURL);
if (image == null) {
ImageDescriptor id = ImageDescriptor.createFromURL(imageURL);
try {
image = id.createImage();
} catch (SWTException e) {
image = null;
}
if (image != null)
imageCache.put(imageURL, image);
}
return image;
}
private void reflow() {
versionLabel.getParent().layout(true);
doButton.getParent().layout(true);
imageLabel.getParent().layout(true);
((Composite) getControl()).layout(true);
}
private void setOS(String os) {
if (os == null)
osLabel.setText(UpdateUI.getString("FeaturePage.all")); //$NON-NLS-1$
else {
String[] array = getTokens(os);
StringBuffer buf = new StringBuffer();
for (int i = 0; i < array.length; i++) {
if (i > 0)
buf.append("\n"); //$NON-NLS-1$
buf.append(mapOS(array[i]));
}
osLabel.setText(buf.toString());
}
}
private String mapOS(String key) {
return key;
}
private String mapWS(String key) {
return key;
}
private String mapArch(String key) {
return key;
}
private String mapNL(String nl) {
String language, country;
int loc = nl.indexOf('_');
if (loc != -1) {
language = nl.substring(0, loc);
country = nl.substring(loc + 1);
} else {
language = nl;
country = ""; //$NON-NLS-1$
}
Locale locale = new Locale(language, country);
return locale.getDisplayName();
}
private void setWS(String ws) {
if (ws == null)
wsLabel.setText(UpdateUI.getString("FeaturePage.all")); //$NON-NLS-1$
else {
String[] array = getTokens(ws);
StringBuffer buf = new StringBuffer();
for (int i = 0; i < array.length; i++) {
if (i > 0)
buf.append("\n"); //$NON-NLS-1$
buf.append(mapWS(array[i]));
}
wsLabel.setText(buf.toString());
}
}
private void setArch(String arch) {
if (arch == null)
archLabel.setText(UpdateUI.getString("FeaturePage.all")); //$NON-NLS-1$
else {
String[] array = getTokens(arch);
StringBuffer buf = new StringBuffer();
for (int i = 0; i < array.length; i++) {
if (i > 0)
buf.append("\n"); //$NON-NLS-1$
buf.append(mapArch(array[i]));
}
archLabel.setText(buf.toString());
}
}
private void setNL(String nl) {
if (nl == null)
nlLabel.setText(UpdateUI.getString("FeaturePage.all")); //$NON-NLS-1$
else {
String[] array = getTokens(nl);
StringBuffer buf = new StringBuffer();
for (int i = 0; i < array.length; i++) {
if (i > 0)
buf.append("\n"); //$NON-NLS-1$
buf.append(mapNL(array[i]));
}
nlLabel.setText(buf.toString());
}
}
private String[] getTokens(String source) {
Vector result = new Vector();
StringTokenizer stok = new StringTokenizer(source, ","); //$NON-NLS-1$
while (stok.hasMoreTokens()) {
String tok = stok.nextToken();
result.add(tok);
}
return (String[]) result.toArray(new String[result.size()]);
}
private void openURL(final String url) {
BusyIndicator.showWhile(getControl().getDisplay(), new Runnable() {
public void run() {
DetailsView.showURL(url);
}
});
}
private void doAdd(boolean selection) {
UpdateModel model = UpdateUI.getDefault().getUpdateModel();
if (selection) {
int mode = getCurrentJobType();
PendingChange job = createPendingChange(mode);
if (!checkEnabledDuplicates(job)) {
addButton.setSelection(false);
return;
}
model.addPendingChange(job);
} else {
PendingChange job = model.findRelatedPendingChange(currentFeature);
if (job != null)
model.removePendingChange(job);
}
}
private void doUninstall() {
executeJob(PendingChange.UNINSTALL);
}
private void executeJob(int mode) {
if (currentFeature != null) {
PendingChange job = createPendingChange(mode);
touchChildren(getControl().getShell(), currentFeature);
executeJob(getControl().getShell(), job, true);
}
}
private void executeOptionalInstall(MissingFeature mf) {
VersionedIdentifier vid = mf.getVersionedIdentifier();
URL siteURL = mf.getOriginatingSiteURL();
IConfiguredSite targetSite = null;
if (mf.getParent() != null) {
ISite psite = mf.getParent().getSite();
targetSite = psite.getCurrentConfiguredSite();
}
IFeature feature =
fetchFeatureFromServer(getControl().getShell(), siteURL, vid);
if (feature != null) {
PendingChange job = new PendingChange(feature, targetSite);
executeJob(getControl().getShell(), job, true);
}
}
public static IFeature fetchFeatureFromServer(
Shell shell,
final URL siteURL,
final VersionedIdentifier vid) {
// Locate remote site, find the optional feature
// and install it
final IFeature[] result = new IFeature[1];
final CoreException[] exception = new CoreException[1];
final boolean aborted[] = new boolean[1];
aborted[0] = false;
IRunnableWithProgress op = new IRunnableWithProgress() {
public void run(IProgressMonitor monitor) throws InvocationTargetException {
try {
monitor.beginTask(UpdateUI.getString("DetailsForm.locatingFeature"), 3); //$NON-NLS-1$
ISite site = SiteManager.getSite(siteURL, new SubProgressMonitor(monitor, 1));
if (site==null || monitor.isCanceled()) {
aborted[0] = true;
return;
}
IFeatureReference[] refs = site.getFeatureReferences();
result[0] = findFeature(vid, refs, new SubProgressMonitor(monitor, 1));
if (result[0]!=null) {
monitor.setTaskName(UpdateUI.getString("DetailsForm.downloadingInfo")); //$NON-NLS-1$
touchFeatureChildren(result[0], new SubProgressMonitor(monitor, 1));
}
} catch (CoreException e) {
throw new InvocationTargetException(e);
}
finally {
monitor.done();
}
}
};
ProgressMonitorDialog pmd = new ProgressMonitorDialog(shell);
try {
pmd.run(true, true, op);
}
catch (InterruptedException e) {
return null;
}
catch (InvocationTargetException e) {
UpdateUI.logException(e);
return null;
}
IStatus status = null;
if (result[0] != null) {
return result[0];
} else if (!aborted[0]) {
String message =
UpdateUI.getFormattedMessage(
KEY_OPTIONAL_INSTALL_MESSAGE,
siteURL.toString());
status =
new Status(
IStatus.ERROR,
UpdateUI.PLUGIN_ID,
IStatus.OK,
message,
null);
}
if (status != null) {
// Show error dialog
ErrorDialog.openError(
shell,
UpdateUI.getString(KEY_OPTIONAL_INSTALL_TITLE),
null,
status);
}
return null;
}
private static IFeature findFeature(
VersionedIdentifier vid,
IFeatureReference[] refs,
IProgressMonitor monitor) {
monitor.beginTask("", refs.length*2); //$NON-NLS-1$
for (int i = 0; i < refs.length; i++) {
IFeatureReference ref = refs[i];
try {
VersionedIdentifier refVid = ref.getVersionedIdentifier();
if (refVid.equals(vid)) {
return ref.getFeature(null);
}
monitor.worked(1);
// Try children
IFeature feature = ref.getFeature(null);
IFeatureReference[] irefs =
feature.getIncludedFeatureReferences();
IFeature result = findFeature(vid, irefs, new SubProgressMonitor(monitor, 1));
if (result != null)
return result;
} catch (CoreException e) {
}
}
return null;
}
private void touchChildren(Shell shell, final IFeature feature) {
IRunnableWithProgress op = new IRunnableWithProgress() {
public void run(IProgressMonitor monitor) {
monitor.beginTask(UpdateUI.getString("DetailsForm.downloadingIncluded"), 1); //$NON-NLS-1$
try {
touchFeatureChildren(feature, new SubProgressMonitor(monitor, 1));
}
catch (CoreException e) {
// ignore
}
finally {
monitor.done();
}
}
};
try {
ProgressMonitorDialog pmd = new ProgressMonitorDialog(shell);
pmd.run(true, false, op);
}
catch (InvocationTargetException e) {
}
catch (InterruptedException e) {
}
}
private static void touchFeatureChildren(IFeature feature, IProgressMonitor monitor) throws CoreException {
IFeatureReference[] irefs =
feature.getIncludedFeatureReferences();
if (irefs.length>0) {
monitor.beginTask("", irefs.length*2); //$NON-NLS-1$
for (int i=0; i<irefs.length; i++) {
IFeatureReference iref = irefs[i];
IFeature child = iref.getFeature(null);
monitor.worked(1);
touchFeatureChildren(child, new SubProgressMonitor(monitor, 1));
}
}
else {
monitor.beginTask("", 1); //$NON-NLS-1$
monitor.worked(1);
}
}
public static boolean isInProgress() {
return inProgress;
}
public static boolean executeJob(
Shell shell,
final PendingChange job,
final boolean needLicensePage) {
if (inProgress) {
return true;
}
inProgress = true;
IStatus validationStatus =
ActivityConstraints.validatePendingChange(job);
if (validationStatus != null) {
ErrorDialog.openError(
UpdateUI.getActiveWorkbenchShell(),
null,
null,
validationStatus);
return false;
}
if (!checkEnabledDuplicates(job))
return false;
if (job.getJobType() == PendingChange.UNCONFIGURE
&& job.getFeature().isPatch()) {
unconfigurePatch(shell, job.getFeature());
return false;
}
BusyIndicator.showWhile(shell.getDisplay(), new Runnable() {
public void run() {
InstallWizard wizard = new InstallWizard(job, needLicensePage);
WizardDialog dialog =
new InstallWizardDialog(
UpdateUI.getActiveWorkbenchShell(),
wizard);
dialog.create();
dialog.getShell().setSize(600, 500);
dialog.open();
inProgress = false;
if (wizard.isSuccessfulInstall())
UpdateUI.informRestartNeeded();
}
});
return false;
}
private static void unconfigurePatch(Shell shell, IFeature feature) {
IInstallConfiguration config =
UpdateUI.getBackupConfigurationFor(feature);
if (config == null) {
String message =
UpdateUI.getString("DetailsForm.featureAPatch"); //$NON-NLS-1$
MessageDialog.openError(shell, UpdateUI.getString("DetailsForm.disableFeature.title"), message); //$NON-NLS-1$
return;
}
try {
ILocalSite localSite = SiteManager.getLocalSite();
boolean success = RevertSection.performRevert(config, false, false);
if (success) {
localSite.removeFromPreservedConfigurations(config);
localSite.save();
UpdateUI.informRestartNeeded();
}
} catch (CoreException e) {
UpdateUI.logException(e);
}
}
private void doButtonSelected() {
if (currentFeature != null) {
if (currentFeature instanceof MissingFeature) {
MissingFeature mf = (MissingFeature) currentFeature;
if (mf.isOptional() && mf.getOriginatingSiteURL() != null) {
executeOptionalInstall(mf);
return;
}
}
int mode;
if (currentAdapter instanceof IConfiguredSiteContext) {
boolean configured = isConfigured();
if (configured)
mode = PendingChange.UNCONFIGURE;
else
mode = PendingChange.CONFIGURE;
} else {
mode = PendingChange.INSTALL;
}
executeJob(mode);
}
}
private int getCurrentJobType() {
int mode;
if (currentAdapter instanceof IConfiguredSiteContext) {
boolean configured = isConfigured();
if (configured)
mode = PendingChange.UNCONFIGURE;
else
mode = PendingChange.CONFIGURE;
} else {
mode = PendingChange.INSTALL;
}
return mode;
}
private PendingChange createPendingChange(int type) {
if (type == PendingChange.INSTALL && installedFeatures.length > 0) {
return new PendingChange(
installedFeatures[0],
currentFeature,
alreadyInstalled);
} else {
return new PendingChange(currentFeature, type);
}
}
private static boolean checkEnabledDuplicates(PendingChange job) {
if (job.getJobType() != PendingChange.CONFIGURE)
return true;
IFeature[] installedEnabledFeatures =
UpdateUI.getInstalledFeatures(job.getFeature(), true);
if (installedEnabledFeatures.length == 0)
return true;
String title =
UpdateUI.getString("FeaturePage.duplicatesEnabled.title"); //$NON-NLS-1$
String message =
UpdateUI.getString("FeaturePage.duplicatesEnabled.message"); //$NON-NLS-1$
MessageDialog dialog =
new MessageDialog(
UpdateUI.getActiveWorkbenchShell(),
title,
null,
// accept the default window icon
message,
MessageDialog.WARNING,
new String[] {
IDialogConstants.OK_LABEL,
IDialogConstants.CANCEL_LABEL },
0);
// OK is the default
return dialog.open() == 0;
}
}