| /* |
| * Copyright (c) 2014-2017 Eike Stepper (Loehne, Germany) and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v2.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v20.html |
| * |
| * Contributors: |
| * Eike Stepper - initial API and implementation |
| */ |
| package org.eclipse.oomph.setup.ui.wizards; |
| |
| import org.eclipse.oomph.base.util.BaseUtil; |
| import org.eclipse.oomph.internal.setup.SetupProperties; |
| import org.eclipse.oomph.internal.ui.AccessUtil; |
| import org.eclipse.oomph.internal.ui.OomphAdapterFactoryContentProvider; |
| import org.eclipse.oomph.setup.Installation; |
| import org.eclipse.oomph.setup.LicenseInfo; |
| import org.eclipse.oomph.setup.PreferenceTask; |
| import org.eclipse.oomph.setup.SetupTask; |
| import org.eclipse.oomph.setup.Trigger; |
| import org.eclipse.oomph.setup.UnsignedPolicy; |
| import org.eclipse.oomph.setup.User; |
| import org.eclipse.oomph.setup.Workspace; |
| import org.eclipse.oomph.setup.impl.DynamicSetupTaskImpl; |
| import org.eclipse.oomph.setup.internal.core.SetupContext; |
| import org.eclipse.oomph.setup.internal.core.SetupTaskPerformer; |
| import org.eclipse.oomph.setup.internal.core.SetupTaskPerformer.ExecutableInfo; |
| import org.eclipse.oomph.setup.internal.core.util.SetupCoreUtil; |
| import org.eclipse.oomph.setup.log.ProgressLog; |
| import org.eclipse.oomph.setup.log.ProgressLog.Severity; |
| import org.eclipse.oomph.setup.log.ProgressLogFilter; |
| import org.eclipse.oomph.setup.log.ProgressLogProvider; |
| import org.eclipse.oomph.setup.log.ProgressLogRunnable; |
| import org.eclipse.oomph.setup.provider.SetupEditPlugin; |
| import org.eclipse.oomph.setup.ui.AbstractConfirmDialog; |
| import org.eclipse.oomph.setup.ui.AbstractDialogConfirmer; |
| import org.eclipse.oomph.setup.ui.LicenseDialog; |
| import org.eclipse.oomph.setup.ui.LicensePrePrompter; |
| import org.eclipse.oomph.setup.ui.SetupPropertyTester; |
| import org.eclipse.oomph.setup.ui.SetupUIPlugin; |
| import org.eclipse.oomph.setup.ui.ToolTipLabelProvider; |
| import org.eclipse.oomph.setup.ui.UnsignedContentDialog; |
| import org.eclipse.oomph.setup.util.FileUtil; |
| import org.eclipse.oomph.ui.BackgroundProgressPart; |
| import org.eclipse.oomph.ui.ButtonBar; |
| import org.eclipse.oomph.ui.ErrorDialog; |
| import org.eclipse.oomph.ui.UIUtil; |
| import org.eclipse.oomph.util.Confirmer; |
| import org.eclipse.oomph.util.IORuntimeException; |
| import org.eclipse.oomph.util.IOUtil; |
| import org.eclipse.oomph.util.OS; |
| import org.eclipse.oomph.util.Pair; |
| import org.eclipse.oomph.util.PropertiesUtil; |
| |
| import org.eclipse.emf.common.ui.viewer.ColumnViewerInformationControlToolTipSupport; |
| import org.eclipse.emf.common.util.BasicEList; |
| import org.eclipse.emf.common.util.EList; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.resource.ResourceSet; |
| import org.eclipse.emf.edit.provider.IItemFontProvider; |
| import org.eclipse.emf.edit.provider.ItemProvider; |
| import org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider; |
| import org.eclipse.emf.edit.ui.provider.ExtendedFontRegistry; |
| |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.OperationCanceledException; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.runtime.jobs.IJobChangeEvent; |
| import org.eclipse.core.runtime.jobs.IJobManager; |
| import org.eclipse.core.runtime.jobs.Job; |
| import org.eclipse.core.runtime.jobs.JobChangeAdapter; |
| import org.eclipse.equinox.p2.metadata.IInstallableUnit; |
| import org.eclipse.equinox.p2.metadata.ILicense; |
| import org.eclipse.jface.dialogs.IDialogConstants; |
| import org.eclipse.jface.dialogs.IMessageProvider; |
| import org.eclipse.jface.resource.JFaceResources; |
| import org.eclipse.jface.text.Document; |
| import org.eclipse.jface.text.TextViewer; |
| import org.eclipse.jface.viewers.ILabelProvider; |
| import org.eclipse.jface.viewers.ISelectionChangedListener; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| import org.eclipse.jface.viewers.SelectionChangedEvent; |
| import org.eclipse.jface.viewers.StructuredSelection; |
| import org.eclipse.jface.viewers.TreeViewer; |
| import org.eclipse.jface.wizard.IWizardContainer; |
| import org.eclipse.jface.wizard.ProgressMonitorPart; |
| import org.eclipse.jface.wizard.WizardDialog; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.browser.LocationEvent; |
| import org.eclipse.swt.browser.LocationListener; |
| import org.eclipse.swt.custom.SashForm; |
| import org.eclipse.swt.custom.StyleRange; |
| import org.eclipse.swt.custom.StyledText; |
| import org.eclipse.swt.events.SelectionAdapter; |
| import org.eclipse.swt.events.SelectionEvent; |
| import org.eclipse.swt.graphics.Color; |
| import org.eclipse.swt.graphics.Font; |
| import org.eclipse.swt.graphics.Point; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.widgets.Button; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Layout; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.swt.widgets.ToolBar; |
| import org.eclipse.swt.widgets.ToolItem; |
| import org.eclipse.swt.widgets.Tree; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.internal.progress.JobInfo; |
| import org.eclipse.ui.internal.progress.ProgressManager; |
| |
| import java.io.File; |
| import java.lang.reflect.Constructor; |
| import java.security.cert.Certificate; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.concurrent.atomic.AtomicBoolean; |
| |
| /** |
| * @author Eike Stepper |
| */ |
| public class ProgressPage extends SetupWizardPage |
| { |
| public static final Object PROGRESS_FAMILY = new Object(); |
| |
| public static final String PROGRESS_STATUS = "org.eclipse.oomph.setup.status"; |
| |
| public static final String PAGE_NAME = "ProgressPage"; |
| |
| private final Map<SetupTask, Point> setupTaskSelections = new HashMap<SetupTask, Point>(); |
| |
| private Constructor<? extends ProgressLog> progressLogWrapper; |
| |
| private TreeViewer treeViewer; |
| |
| private final ISelectionChangedListener treeViewerSelectionChangedListener = new ISelectionChangedListener() |
| { |
| public void selectionChanged(SelectionChangedEvent event) |
| { |
| IStructuredSelection selection = (IStructuredSelection)event.getSelection(); |
| Object element = selection.getFirstElement(); |
| if (element instanceof EObject) |
| { |
| for (EObject eObject = (EObject)element; eObject != null; eObject = eObject.eContainer()) |
| { |
| if (eObject != currentTask && eObject instanceof SetupTask) |
| { |
| Point textSelection = setupTaskSelections.get(eObject); |
| if (textSelection != null) |
| { |
| int start = textSelection.x; |
| // Treat -1 so that at selects to the very end. |
| int end = textSelection.y; |
| if (end == -1) |
| { |
| end = logText.getCharCount(); |
| } |
| |
| String selectedText = logText.getText(start, end); |
| int index = 0; |
| int length = selectedText.length(); |
| |
| // Skip leading line feeds. |
| for (; index < length; ++index) |
| { |
| char c = selectedText.charAt(index); |
| if (c == '\n' || c == '\r') |
| { |
| ++start; |
| } |
| else |
| { |
| break; |
| } |
| } |
| |
| // Force the first line to be scrolled into view |
| logText.setSelection(start, start); |
| |
| // Determine the number of lines of text to be selected |
| int lineFeedCount = 0; |
| int carriageReturnCount = 0; |
| for (; index < length; ++index) |
| { |
| char c = selectedText.charAt(index); |
| if (c == '\n') |
| { |
| ++lineFeedCount; |
| } |
| else if (c == '\r') |
| { |
| ++carriageReturnCount; |
| } |
| } |
| |
| // If the number of visible lines is greater than the number of lines in the selection, invert the |
| // selection range to scroll the top line into view. |
| int visibleLineCount = logText.getClientArea().height / logText.getLineHeight(); |
| if (lineFeedCount > visibleLineCount || carriageReturnCount > visibleLineCount) |
| { |
| logText.setSelection(end, start); |
| } |
| else |
| { |
| logText.setSelection(start, end); |
| } |
| } |
| } |
| } |
| } |
| } |
| }; |
| |
| private StyledText logText; |
| |
| private ProgressMonitorPart progressMonitorPart; |
| |
| private final Document logDocument = new Document(); |
| |
| private final ProgressLogFilter logFilter = new ProgressLogFilter(); |
| |
| private SetupTask currentTask; |
| |
| private ProgressPageLog progressPageLog; |
| |
| private boolean scrollLock; |
| |
| private boolean dismissAutomatically; |
| |
| private boolean launchAutomatically; |
| |
| private Button scrollLockButton; |
| |
| private Button dismissButton; |
| |
| private Button launchButton; |
| |
| private boolean hasLaunched; |
| |
| public static final Confirmer LICENSE_CONFIRMER = new AbstractDialogConfirmer() |
| { |
| @Override |
| protected AbstractConfirmDialog createDialog(boolean defaultConfirmed, Object info) |
| { |
| @SuppressWarnings("unchecked") |
| Map<ILicense, List<IInstallableUnit>> licensesToIUs = (Map<ILicense, List<IInstallableUnit>>)info; |
| return new LicenseDialog(licensesToIUs); |
| } |
| }; |
| |
| public ProgressPage() |
| { |
| super(PAGE_NAME); |
| setTitle("Progress"); |
| setDescription("Wait for the setup to complete, or cancel the progress indicator and press Back to make changes."); |
| } |
| |
| @Override |
| protected Control createUI(final Composite parent) |
| { |
| Composite mainComposite = new Composite(parent, SWT.NONE); |
| mainComposite.setLayout(UIUtil.createGridLayout(1)); |
| |
| SashForm sashForm = new SashForm(mainComposite, SWT.SMOOTH | SWT.VERTICAL); |
| sashForm.setLayoutData(new GridData(GridData.FILL_BOTH)); |
| AccessUtil.setKey(sashForm, "sash"); |
| |
| treeViewer = new TreeViewer(sashForm, SWT.BORDER); |
| Tree tree = treeViewer.getTree(); |
| addHelpCallout(tree, 1); |
| |
| ColumnViewerInformationControlToolTipSupport toolTipSupport = new ColumnViewerInformationControlToolTipSupport(treeViewer, new LocationListener() |
| { |
| public void changing(LocationEvent event) |
| { |
| } |
| |
| public void changed(LocationEvent event) |
| { |
| } |
| }); |
| |
| ILabelProvider labelProvider = createLabelProvider(toolTipSupport); |
| treeViewer.setLabelProvider(labelProvider); |
| |
| final AdapterFactoryContentProvider contentProvider = new OomphAdapterFactoryContentProvider(getAdapterFactory()); |
| treeViewer.setContentProvider(contentProvider); |
| treeViewer.addSelectionChangedListener(treeViewerSelectionChangedListener); |
| |
| tree.setLayoutData(new GridData(GridData.FILL_BOTH)); |
| tree.setBackground(getShell().getDisplay().getSystemColor(SWT.COLOR_WHITE)); |
| |
| TextViewer logTextViewer = new TextViewer(sashForm, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.CANCEL | SWT.MULTI); |
| logTextViewer.setDocument(logDocument); |
| |
| logText = logTextViewer.getTextWidget(); |
| logText.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND)); |
| logText.setFont(JFaceResources.getFont(JFaceResources.TEXT_FONT)); |
| logText.setEditable(false); |
| logText.setLayoutData(new GridData(GridData.FILL_BOTH)); |
| logText.getVerticalBar().addSelectionListener(new SelectionAdapter() |
| { |
| @Override |
| public void widgetSelected(SelectionEvent event) |
| { |
| if (event.detail == SWT.DRAG && !scrollLock) |
| { |
| scrollLockButton.setSelection(true); |
| scrollLock = true; |
| } |
| } |
| }); |
| |
| addHelpCallout(logText, 2); |
| AccessUtil.setKey(logText, "log"); |
| |
| return mainComposite; |
| } |
| |
| @Override |
| protected void createCheckButtons(ButtonBar buttonBar) |
| { |
| scrollLockButton = buttonBar.addCheckButton("Scroll lock", "Keep the log from scrolling to the end when new messages are added", false, null); |
| scrollLock = scrollLockButton.getSelection(); |
| scrollLockButton.addSelectionListener(new SelectionAdapter() |
| { |
| @Override |
| public void widgetSelected(SelectionEvent e) |
| { |
| scrollLock = scrollLockButton.getSelection(); |
| } |
| }); |
| AccessUtil.setKey(scrollLockButton, "lock"); |
| |
| dismissButton = buttonBar.addCheckButton("Dismiss automatically", "Dismiss this wizard when all setup tasks have performed successfully", false, |
| "dismissAutomatically"); |
| dismissAutomatically = dismissButton.getSelection(); |
| dismissButton.addSelectionListener(new SelectionAdapter() |
| { |
| @Override |
| public void widgetSelected(SelectionEvent e) |
| { |
| dismissAutomatically = dismissButton.getSelection(); |
| } |
| }); |
| AccessUtil.setKey(dismissButton, "dismiss"); |
| |
| if (getWizard().getOS().isCurrentOS()) |
| { |
| // If the property is not set, create a check box for controlling launchAutomatically. Otherwise use the property value directly. |
| final Boolean launchAutomaticallyPropertyValue = PropertiesUtil.getBoolean(SetupProperties.PROP_SETUP_LAUNCH_AUTOMATICALLY); |
| if (launchAutomaticallyPropertyValue == null) |
| { |
| if (getTrigger() == Trigger.BOOTSTRAP) |
| { |
| launchButton = buttonBar.addCheckButton("Launch automatically", "Launch the installed product when all setup tasks have performed successfully", true, |
| "launchAutomatically"); |
| } |
| else |
| { |
| launchButton = buttonBar.addCheckButton("Restart automatically if needed", |
| "Restart the current product if the installation has been changed by setup tasks", false, "restartIfNeeded"); |
| } |
| |
| launchAutomatically = launchButton.getSelection(); |
| launchButton.addSelectionListener(new SelectionAdapter() |
| { |
| @Override |
| public void widgetSelected(SelectionEvent e) |
| { |
| launchAutomatically = launchButton.getSelection(); |
| } |
| }); |
| AccessUtil.setKey(launchButton, "launch"); |
| } |
| else |
| { |
| launchAutomatically = launchAutomaticallyPropertyValue; |
| } |
| } |
| } |
| |
| @Override |
| protected void createFooter(Composite parent) |
| { |
| progressMonitorPart = new BackgroundProgressPart(parent, null, true) |
| { |
| @Override |
| protected void initialize(Layout layout, int progressIndicatorHeight) |
| { |
| super.initialize(layout, progressIndicatorHeight); |
| fLabel.dispose(); |
| |
| if (PlatformUI.isWorkbenchRunning()) |
| { |
| for (Control child : getChildren()) |
| { |
| if (child instanceof ToolBar) |
| { |
| ToolBar toolBar = (ToolBar)child; |
| ToolItem minimizeButton = new ToolItem(toolBar, SWT.PUSH); |
| minimizeButton.setImage(SetupUIPlugin.INSTANCE.getSWTImage("hide")); |
| minimizeButton.setToolTipText("Minimize to the status area"); |
| minimizeButton.addSelectionListener(new SelectionAdapter() |
| { |
| @Override |
| public void widgetSelected(SelectionEvent event) |
| { |
| getWizard().getShell().setVisible(false); |
| } |
| }); |
| |
| break; |
| } |
| } |
| } |
| } |
| |
| @Override |
| protected void updateLabel() |
| { |
| } |
| |
| @Override |
| public void done() |
| { |
| UIUtil.syncExec(new Runnable() |
| { |
| public void run() |
| { |
| fProgressIndicator.sendRemainingWork(); |
| fProgressIndicator.done(); |
| removeFromCancelComponent(null); |
| progressMonitorPart.setLayoutData(new GridData(0, 0)); |
| progressMonitorPart.getParent().layout(); |
| } |
| }); |
| } |
| }; |
| |
| progressMonitorPart.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); |
| AccessUtil.setKey(progressMonitorPart, "progress"); |
| } |
| |
| @Override |
| public void enterPage(boolean forward) |
| { |
| if (forward) |
| { |
| setPageComplete(false); |
| setErrorMessage(null); |
| setMessage(null); |
| |
| hasLaunched = false; |
| |
| progressPageLog = new ProgressPageLog(progressMonitorPart); |
| logDocument.set(""); |
| |
| // This is a private hook so we can monitor progress for documentation capture. |
| ProgressLog progressLog = progressPageLog; |
| if (progressLogWrapper != null) |
| { |
| try |
| { |
| progressLog = progressLogWrapper.newInstance(progressLog); |
| } |
| catch (Throwable ex) |
| { |
| // Ignore. |
| } |
| } |
| |
| final SetupTaskPerformer performer = getPerformer(); |
| User performerUser = performer.getUser(); |
| |
| performer.setProgress(progressLog); |
| |
| if (performer.get(ILicense.class) == null) |
| { |
| performer.put(ILicense.class, LICENSE_CONFIRMER); |
| } |
| |
| if (performer.get(Certificate.class) == null) |
| { |
| performer.put(Certificate.class, UnsignedContentDialog.createUnsignedContentConfirmer(performerUser, false)); |
| } |
| |
| File renamed = null; |
| if (getTrigger() == Trigger.BOOTSTRAP) |
| { |
| File configurationLocation = performer.getProductConfigurationLocation(); |
| if (configurationLocation.exists()) |
| { |
| try |
| { |
| // This must happen before the performer opens the logStream for the first logging! |
| renamed = FileUtil.rename(configurationLocation); |
| } |
| catch (RuntimeException ex) |
| { |
| throw ex; |
| } |
| catch (Exception ex) |
| { |
| progressPageLog.log(ex); |
| setErrorMessage("Could not rename '" + configurationLocation + "'. Press Back twice to choose a different installation location."); |
| progressPageLog.done(); |
| |
| throw new IORuntimeException(ex); |
| } |
| } |
| |
| if (UIUtil.isBrowserAvailable()) |
| { |
| EList<LicenseInfo> licenses = LicensePrePrompter.execute(getShell(), performerUser); |
| if (licenses != null) |
| { |
| ResourceSet resourceSet = SetupCoreUtil.createResourceSet(); |
| User user = SetupContext.createUserOnly(resourceSet).getUser(); |
| user.getAcceptedLicenses().addAll(licenses); |
| BaseUtil.saveEObject(user); |
| } |
| } |
| } |
| |
| treeViewer.setInput(new ItemProvider(performer.getNeededTasks())); |
| |
| String jobName = "Executing " + getTriggerName().toLowerCase() + " tasks"; |
| performer.log(jobName, false, Severity.INFO); |
| |
| if (renamed != null) |
| { |
| performer.log("Renamed existing configuration folder to " + renamed); |
| } |
| |
| run(jobName, new ProgressLogRunnable() |
| { |
| public Set<String> run(ProgressLog log) throws Exception |
| { |
| final ProgressManager oldProgressProvider = ProgressManager.getInstance(); |
| ProgressLogProvider newProgressLogProvider = new ProgressLogProvider(progressPageLog, oldProgressProvider); |
| |
| // When the workbench isn't running org.eclipse.ui.internal.progress.new JobChangeAdapter()'s done(IJobChangeEvent) method one cleanup. |
| JobChangeAdapter jobChangeListener = PlatformUI.isWorkbenchRunning() ? null : new JobChangeAdapter() |
| { |
| @Override |
| public void done(IJobChangeEvent event) |
| { |
| Job job = event.getJob(); |
| for (JobInfo jobInfo : oldProgressProvider.getJobInfos(true)) |
| { |
| if (jobInfo.getJob() == job) |
| { |
| oldProgressProvider.removeJobInfo(jobInfo); |
| break; |
| } |
| } |
| } |
| }; |
| |
| IJobManager jobManager = Job.getJobManager(); |
| jobManager.setProgressProvider(newProgressLogProvider); |
| if (jobChangeListener != null) |
| { |
| jobManager.addJobChangeListener(jobChangeListener); |
| } |
| |
| try |
| { |
| performer.perform(progressPageLog); |
| return performer.getRestartReasons(); |
| } |
| finally |
| { |
| jobManager.setProgressProvider(oldProgressProvider); |
| if (jobChangeListener != null) |
| { |
| jobManager.removeJobChangeListener(jobChangeListener); |
| } |
| } |
| } |
| }); |
| } |
| } |
| |
| @Override |
| public void leavePage(boolean forward) |
| { |
| if (forward) |
| { |
| setPageComplete(false); |
| } |
| else |
| { |
| setPageComplete(false); |
| hasLaunched = false; |
| setButtonState(IDialogConstants.CANCEL_ID, true); |
| } |
| } |
| |
| @Override |
| public boolean performCancel() |
| { |
| boolean isPerforming = getWizard().getCurrentPage() instanceof ProgressPage && !progressPageLog.isCanceled() && !progressPageLog.isDone(); |
| if (isPerforming && PlatformUI.isWorkbenchRunning()) |
| { |
| getWizard().getShell().setVisible(false); |
| return false; |
| } |
| |
| return !isPerforming; |
| } |
| |
| @Override |
| protected void setButtonState(int buttonID, boolean enabled) |
| { |
| super.setButtonState(buttonID, enabled); |
| |
| if (buttonID == IDialogConstants.CANCEL_ID && getPerformer().hasSuccessfullyPerformed()) |
| { |
| scrollLockButton.setEnabled(enabled); |
| dismissButton.setEnabled(enabled); |
| |
| if (launchButton != null) |
| { |
| launchButton.setEnabled(!hasLaunched); |
| } |
| } |
| } |
| |
| private ILabelProvider createLabelProvider(ColumnViewerInformationControlToolTipSupport toolTipSupport) |
| { |
| return new ToolTipLabelProvider(getAdapterFactory(), toolTipSupport) |
| { |
| @Override |
| public Font getFont(Object element) |
| { |
| if (element == currentTask) |
| { |
| return ExtendedFontRegistry.INSTANCE.getFont(treeViewer.getControl().getFont(), IItemFontProvider.BOLD_FONT); |
| } |
| |
| return super.getFont(element); |
| } |
| }; |
| } |
| |
| private void run(final String jobName, final ProgressLogRunnable runnable) |
| { |
| try |
| { |
| // Remember and use the progressPageLog that is valid at this point in time. |
| final ProgressPageLog progressLog = progressPageLog; |
| |
| Runnable jobRunnable = new Runnable() |
| { |
| public void run() |
| { |
| final SetupWizard wizard = getWizard(); |
| final Shell shell = wizard.getShell(); |
| |
| setButtonState(IDialogConstants.CANCEL_ID, false); |
| setButtonState(IDialogConstants.BACK_ID, false); |
| |
| final Job job = new Job(jobName) |
| { |
| @Override |
| protected IStatus run(IProgressMonitor monitor) |
| { |
| progressLog.setProgressMonitor(monitor); |
| |
| final Trigger trigger = getTrigger(); |
| long start = System.currentTimeMillis(); |
| boolean success = false; |
| Set<String> restartReasons = null; |
| |
| UIUtil.syncExec(new Runnable() |
| { |
| public void run() |
| { |
| shell.setData(PROGRESS_STATUS, null); |
| if (trigger != Trigger.BOOTSTRAP) |
| { |
| if (trigger == Trigger.STARTUP || !SetupPropertyTester.isShowProgressInWizard()) |
| { |
| shell.setVisible(false); |
| } |
| |
| SetupPropertyTester.setPerformingShell(shell); |
| } |
| } |
| }); |
| |
| try |
| { |
| restartReasons = runnable.run(progressLog); |
| |
| SetupTaskPerformer performer = getPerformer(); |
| saveLocalFiles(performer); |
| |
| if (launchAutomatically && trigger == Trigger.BOOTSTRAP) |
| { |
| progressLog.setTerminating(); |
| hasLaunched = launchProduct(performer); |
| } |
| |
| success = true; |
| } |
| catch (OperationCanceledException ex) |
| { |
| // Do nothing |
| } |
| catch (Throwable ex) |
| { |
| final IStatus status = SetupUIPlugin.INSTANCE.getStatus(ex); |
| SetupUIPlugin.INSTANCE.log(new IStatus() |
| { |
| public IStatus[] getChildren() |
| { |
| return status.getChildren(); |
| } |
| |
| public int getCode() |
| { |
| return status.getCode(); |
| } |
| |
| public Throwable getException() |
| { |
| return status.getException(); |
| } |
| |
| public String getMessage() |
| { |
| return status.getMessage(); |
| } |
| |
| public String getPlugin() |
| { |
| return status.getPlugin(); |
| } |
| |
| public int getSeverity() |
| { |
| return IStatus.WARNING; |
| } |
| |
| public boolean isMultiStatus() |
| { |
| return status.isMultiStatus(); |
| } |
| |
| public boolean isOK() |
| { |
| return false; |
| } |
| |
| public boolean matches(int severityMask) |
| { |
| return (severityMask & IStatus.WARNING) != 0; |
| } |
| |
| @Override |
| public String toString() |
| { |
| StringBuilder result = new StringBuilder(); |
| result.append("Status WARNING"); |
| result.append(": "); |
| result.append(getPlugin()); |
| result.append(" code="); |
| result.append(getCode()); |
| result.append(' '); |
| result.append(getMessage()); |
| result.append(' '); |
| result.append(getException()); |
| result.append(" children=["); |
| result.append(status); |
| result.append("]"); |
| return result.toString(); |
| } |
| }); |
| progressLog.log(ex); |
| } |
| finally |
| { |
| long seconds = (System.currentTimeMillis() - start) / 1000; |
| progressLog.setTerminating(); |
| progressLog.message("Took " + seconds + " seconds."); |
| |
| getWizard().sendStats(success); |
| |
| final AtomicBoolean disableCancelButton = new AtomicBoolean(true); |
| |
| final boolean restart = restartReasons != null && !restartReasons.isEmpty() && trigger != Trigger.BOOTSTRAP; |
| |
| if (trigger == Trigger.STARTUP) |
| { |
| StringBuilder startupLogMessage = new StringBuilder("Setup tasks were performed during startup"); |
| int preferenceTaskCount = 0; |
| if (!restart) |
| { |
| for (SetupTask setupTask : getPerformer().getTriggeredSetupTasks()) |
| { |
| if (setupTask instanceof PreferenceTask) |
| { |
| ++preferenceTaskCount; |
| } |
| } |
| } |
| |
| if (preferenceTaskCount == 1) |
| { |
| startupLogMessage.append(" updating 1 preference"); |
| } |
| else if (preferenceTaskCount > 1) |
| { |
| startupLogMessage.append(" updating ").append(preferenceTaskCount).append(" preferences"); |
| } |
| |
| startupLogMessage.append(". See '").append(SetupContext.SETUP_LOG_URI.toFileString()).append("' for details"); |
| |
| SetupUIPlugin.INSTANCE.log(startupLogMessage.toString(), IStatus.INFO); |
| } |
| |
| if (restart) |
| { |
| progressLog.message("A restart is needed for the following reasons:", false, Severity.INFO); |
| for (String reason : restartReasons) |
| { |
| progressLog.message(" - " + reason); |
| } |
| |
| wizard.setFinishAction(new Runnable() |
| { |
| public void run() |
| { |
| progressLog.done(); |
| |
| UIUtil.asyncExec(new Runnable() |
| { |
| public void run() |
| { |
| // Also include any triggered task whose implementation is currently unavailable. |
| // Such tasks will not be needed by are likely needed after the restart when their implementations have been installed. |
| SetupTaskPerformer performer = getPerformer(); |
| EList<SetupTask> remainingTasks = new BasicEList<SetupTask>(performer.getNeededTasks()); |
| for (SetupTask setupTask : performer.getTriggeredSetupTasks()) |
| { |
| if (setupTask instanceof DynamicSetupTaskImpl) |
| { |
| remainingTasks.add(setupTask); |
| } |
| } |
| |
| SetupUIPlugin.restart(trigger, remainingTasks); |
| } |
| }); |
| } |
| }); |
| |
| if (success && launchAutomatically) |
| { |
| wizard.performFinish(); |
| progressLog.setTerminated(); |
| return Status.OK_STATUS; |
| } |
| |
| progressLog.message("Press Finish to restart now or Cancel to restart later.", Severity.INFO); |
| disableCancelButton.set(false); |
| } |
| else |
| { |
| if (success && dismissAutomatically) |
| { |
| wizard.setFinishAction(new Runnable() |
| { |
| public void run() |
| { |
| IWizardContainer container = getContainer(); |
| if (container instanceof WizardDialog) |
| { |
| WizardDialog dialog = (WizardDialog)container; |
| progressLog.done(); |
| progressLog.setTerminated(); |
| dialog.close(); |
| } |
| } |
| }); |
| |
| wizard.performFinish(); |
| return Status.OK_STATUS; |
| } |
| |
| if (success) |
| { |
| progressLog.message("Press Finish to close the dialog.", Severity.INFO); |
| |
| if (launchButton != null && !hasLaunched && trigger == Trigger.BOOTSTRAP) |
| { |
| wizard.setFinishAction(new Runnable() |
| { |
| public void run() |
| { |
| if (launchAutomatically) |
| { |
| try |
| { |
| hasLaunched = launchProduct(getPerformer()); |
| } |
| catch (Exception ex) |
| { |
| SetupUIPlugin.INSTANCE.log(ex); |
| } |
| } |
| } |
| }); |
| } |
| } |
| else |
| { |
| if (progressLog.isCanceled()) |
| { |
| progressLog.message("Task execution was canceled.", Severity.WARNING); |
| } |
| else |
| { |
| progressLog.message("There are failed tasks.", Severity.ERROR); |
| } |
| |
| progressLog.message("Press Back to choose different settings or Cancel to abort.", Severity.INFO); |
| } |
| } |
| |
| IOUtil.close(getPerformer().getLogStream()); |
| |
| final boolean finalSuccess = success; |
| UIUtil.syncExec(new Runnable() |
| { |
| public void run() |
| { |
| progressLog.done(); |
| setPageComplete(finalSuccess); |
| setButtonState(IDialogConstants.BACK_ID, true); |
| |
| if (finalSuccess) |
| { |
| if (restart) |
| { |
| setMessage("Task execution has successfully completed but requires a restart. Press Finish to restart now or Cancel to restart later.", |
| IMessageProvider.WARNING); |
| setButtonState(IDialogConstants.CANCEL_ID, true); |
| |
| shell.setData(PROGRESS_STATUS, new Status(IStatus.WARNING, SetupEditPlugin.INSTANCE.getSymbolicName(), |
| "Task execution has successfully completed but requires a restart")); |
| } |
| else |
| { |
| setMessage("Task execution has successfully completed. Press Back to choose different settings or Finish to exit."); |
| if (disableCancelButton.get()) |
| { |
| setButtonState(IDialogConstants.CANCEL_ID, false); |
| } |
| |
| shell.setData(PROGRESS_STATUS, |
| new Status(IStatus.OK, SetupEditPlugin.INSTANCE.getSymbolicName(), "Task execution has successfully completed")); |
| } |
| } |
| else |
| { |
| setButtonState(IDialogConstants.CANCEL_ID, true); |
| if (progressLog.isCanceled()) |
| { |
| setErrorMessage("Task execution was canceled. Press Back to choose different settings or Cancel to abort."); |
| |
| shell.setData(PROGRESS_STATUS, new Status(IStatus.CANCEL, SetupEditPlugin.INSTANCE.getSymbolicName(), "Task execution was canceled.")); |
| } |
| else |
| { |
| setErrorMessage("There are failed tasks. Press Back to choose different settings or Cancel to abort."); |
| |
| shell.setData(PROGRESS_STATUS, new Status(IStatus.ERROR, SetupEditPlugin.INSTANCE.getSymbolicName(), "Task execution was failed.")); |
| } |
| } |
| } |
| }); |
| } |
| |
| progressLog.setTerminated(); |
| return Status.OK_STATUS; |
| } |
| |
| @Override |
| public boolean belongsTo(Object family) |
| { |
| return family == PROGRESS_FAMILY; |
| } |
| }; |
| |
| job.schedule(); |
| } |
| }; |
| |
| UIUtil.asyncExec(jobRunnable); |
| } |
| catch (Throwable ex) |
| { |
| SetupUIPlugin.INSTANCE.log(ex); |
| ErrorDialog.open(ex); |
| } |
| |
| } |
| |
| private void saveLocalFiles(SetupTaskPerformer performer) |
| { |
| User performerUser = performer.getUser(); |
| ResourceSet resourceSet = SetupCoreUtil.createResourceSet(); |
| User user = SetupContext.createUserOnly(resourceSet).getUser(); |
| |
| boolean shouldSave = user.getAcceptedLicenses().addAll(performerUser.getAcceptedLicenses()); |
| UnsignedPolicy userUnsignedPolicy = user.getUnsignedPolicy(); |
| UnsignedPolicy performerUserUnsignedPolicy = performerUser.getUnsignedPolicy(); |
| if (userUnsignedPolicy != performerUserUnsignedPolicy) |
| { |
| user.setUnsignedPolicy(performerUserUnsignedPolicy); |
| shouldSave = true; |
| } |
| |
| if (shouldSave) |
| { |
| BaseUtil.saveEObject(user); |
| } |
| |
| SetupContext setupContext = getWizard().getSetupContext(); |
| |
| Installation installation = setupContext.getInstallation(); |
| BaseUtil.saveEObject(installation); |
| |
| Workspace workspace = setupContext.getWorkspace(); |
| if (workspace != null) |
| { |
| BaseUtil.saveEObject(workspace); |
| } |
| |
| SetupContext.associate(installation, workspace); |
| } |
| |
| public static boolean launchProduct(SetupTaskPerformer performer) throws Exception |
| { |
| OS os = performer.getOS(); |
| if (os.isCurrentOS()) |
| { |
| performer.log("Launching the installed product..."); |
| ExecutableInfo info = performer.getExecutableInfo(); |
| |
| List<String> command = new ArrayList<String>(); |
| File executable = info.getExecutable(); |
| command.add(executable.toString()); |
| |
| File ws = performer.getWorkspaceLocation(); |
| if (ws != null) |
| { |
| SetupUIPlugin.initialStart(ws, performer.isOffline(), performer.isMirrors()); |
| |
| command.add("-data"); |
| command.add(ws.toString()); |
| } |
| |
| command.add("-vmargs"); |
| command.add("-Duser.dir=" + info.getEclipseLocation()); |
| |
| try |
| { |
| os.execute(command, info.needsConsole()); |
| } |
| catch (Exception ex) |
| { |
| performer.log("Launching the installed product failed."); |
| performer.log(ex); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| performer.log("Launching the installed product is not possible for cross-platform installs. Skipping."); |
| return false; |
| } |
| |
| /** |
| * @author Eike Stepper |
| */ |
| private class ProgressPageLog implements ProgressLog, IProgressMonitor |
| { |
| /** |
| * A list that contains instances of String and/or Pair<String, ProgressLog.Severity>. |
| */ |
| private List<Object> queue; |
| |
| private final ProgressMonitorPart progressMonitorPart; |
| |
| private IProgressMonitor progressMonitor; |
| |
| private boolean canceled; |
| |
| private boolean terminating; |
| |
| private boolean done; |
| |
| public ProgressPageLog(ProgressMonitorPart progressMonitorPart) |
| { |
| this.progressMonitorPart = progressMonitorPart; |
| progressMonitorPart.attachToCancelComponent(null); |
| progressMonitorPart.setCanceled(false); |
| progressMonitorPart.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); |
| progressMonitorPart.getParent().layout(); |
| } |
| |
| public void setProgressMonitor(IProgressMonitor progressMonitor) |
| { |
| this.progressMonitor = progressMonitor; |
| } |
| |
| public void setTerminating() |
| { |
| terminating = true; |
| } |
| |
| public void setTerminated() |
| { |
| terminating = false; |
| done = true; |
| } |
| |
| public boolean isCanceled() |
| { |
| if (!canceled) |
| { |
| if (progressMonitorPart.isCanceled() || progressMonitor != null && progressMonitor.isCanceled()) |
| { |
| canceled = true; |
| } |
| } |
| |
| return canceled; |
| } |
| |
| public boolean isDone() |
| { |
| return done; |
| } |
| |
| public void done() |
| { |
| done = true; |
| progressMonitorPart.done(); |
| |
| if (progressMonitor != null) |
| { |
| progressMonitor.done(); |
| } |
| } |
| |
| public void beginTask(final String name, final int totalWork) |
| { |
| progressMonitorPart.beginTask(name, totalWork); |
| logTaskName(name); |
| |
| if (progressMonitor != null) |
| { |
| progressMonitor.beginTask(name, totalWork); |
| } |
| } |
| |
| public void internalWorked(final double work) |
| { |
| progressMonitorPart.internalWorked(work); |
| if (progressMonitor != null) |
| { |
| progressMonitor.internalWorked(work); |
| } |
| } |
| |
| public void setCanceled(boolean canceled) |
| { |
| this.canceled = canceled; |
| if (progressMonitor != null) |
| { |
| progressMonitor.setCanceled(canceled); |
| } |
| } |
| |
| public void setTaskName(String name) |
| { |
| logTaskName(name); |
| |
| if (progressMonitor != null) |
| { |
| progressMonitor.setTaskName(name); |
| } |
| } |
| |
| public void subTask(String name) |
| { |
| logTaskName(name); |
| |
| if (progressMonitor != null) |
| { |
| progressMonitor.subTask(name); |
| } |
| } |
| |
| public void worked(final int work) |
| { |
| progressMonitorPart.worked(work); |
| if (progressMonitor != null) |
| { |
| progressMonitor.internalWorked(work); |
| } |
| } |
| |
| public void task(final SetupTask setupTask) |
| { |
| UIUtil.syncExec(new Runnable() |
| { |
| public void run() |
| { |
| SetupTask previousCurrentTask = currentTask; |
| currentTask = setupTask; |
| |
| int offset = 0; |
| if (previousCurrentTask != null) |
| { |
| Point previousTextSelection = setupTaskSelections.get(previousCurrentTask); |
| offset = logText.getCharCount() - 1; |
| int start = previousTextSelection.x; |
| setupTaskSelections.put(previousCurrentTask, new Point(start, offset)); |
| treeViewer.refresh(previousCurrentTask, true); |
| } |
| |
| if (setupTask != null) |
| { |
| setupTaskSelections.put(setupTask, new Point(offset, -1)); |
| treeViewer.refresh(setupTask, true); |
| treeViewer.removeSelectionChangedListener(treeViewerSelectionChangedListener); |
| treeViewer.setSelection(new StructuredSelection(setupTask), true); |
| treeViewer.addSelectionChangedListener(treeViewerSelectionChangedListener); |
| } |
| } |
| }); |
| } |
| |
| public void log(String line) |
| { |
| log(line, true); |
| } |
| |
| public void log(IStatus status) |
| { |
| String string = SetupUIPlugin.toString(status); |
| log(string, false, Severity.fromStatus(status)); |
| } |
| |
| public void log(Throwable t) |
| { |
| String string = SetupUIPlugin.toString(t); |
| log(string, false, Severity.ERROR); |
| } |
| |
| public void log(String line, Severity severity) |
| { |
| log(line, true, severity); |
| } |
| |
| public void log(String line, boolean filter) |
| { |
| log(line, filter, Severity.OK); |
| } |
| |
| public void log(String line, boolean filter, Severity severity) |
| { |
| if (done && !terminating) |
| { |
| return; |
| } |
| |
| message(line, filter, severity); |
| } |
| |
| public void message(String line) |
| { |
| message(line, true, Severity.OK); |
| } |
| |
| public void message(String line, Severity severity) |
| { |
| message(line, true, severity); |
| } |
| |
| private void message(String line, boolean filter, Severity severity) |
| { |
| if (!terminating && isCanceled()) |
| { |
| throw new OperationCanceledException(); |
| } |
| |
| if (filter) |
| { |
| line = logFilter.filter(line); |
| } |
| |
| if (line == null) |
| { |
| return; |
| } |
| |
| boolean wasEmpty = enqueue(line, severity); |
| if (wasEmpty) |
| { |
| UIUtil.asyncExec(new Runnable() |
| { |
| public void run() |
| { |
| List<Object> lines = dequeue(); |
| appendText(lines); |
| } |
| }); |
| } |
| } |
| |
| private synchronized boolean enqueue(String line, Severity severity) |
| { |
| boolean wasEmpty = queue == null; |
| if (wasEmpty) |
| { |
| queue = new ArrayList<Object>(); |
| } |
| |
| if (severity == Severity.OK) |
| { |
| queue.add(line); |
| } |
| else |
| { |
| queue.add(Pair.create(line, severity)); |
| } |
| |
| return wasEmpty; |
| } |
| |
| private synchronized List<Object> dequeue() |
| { |
| List<Object> result = queue; |
| queue = null; |
| return result; |
| } |
| |
| private void appendText(List<Object> lines) |
| { |
| if (logText.isDisposed()) |
| { |
| return; |
| } |
| |
| for (Object value : lines) |
| { |
| String line; |
| Severity severity; |
| if (value instanceof String) |
| { |
| line = (String)value; |
| severity = Severity.OK; |
| } |
| else |
| { |
| @SuppressWarnings("unchecked") |
| Pair<String, Severity> pair = (Pair<String, Severity>)value; |
| |
| line = pair.getElement1(); |
| severity = pair.getElement2(); |
| } |
| |
| line += "\n"; |
| |
| try |
| { |
| int length = logDocument.getLength(); |
| logDocument.replace(length, 0, line); |
| |
| int colorID; |
| switch (severity) |
| { |
| case INFO: |
| colorID = SWT.COLOR_BLUE; |
| break; |
| |
| case WARNING: |
| colorID = SWT.COLOR_DARK_YELLOW; |
| break; |
| |
| case ERROR: |
| colorID = SWT.COLOR_RED; |
| break; |
| |
| default: |
| colorID = SWT.COLOR_BLACK; |
| break; |
| |
| } |
| |
| if (colorID != SWT.COLOR_BLACK) |
| { |
| Color color = logText.getDisplay().getSystemColor(colorID); |
| StyleRange styleRange = new StyleRange(length, line.length(), color, null); |
| if (severity == Severity.INFO) |
| { |
| styleRange.fontStyle = SWT.BOLD; |
| } |
| |
| logText.setStyleRange(styleRange); |
| } |
| |
| if (!scrollLock) |
| { |
| int lineCount = logText.getLineCount(); |
| logText.setTopIndex(lineCount - 1); |
| } |
| } |
| catch (Exception ex) |
| { |
| SetupUIPlugin.INSTANCE.log(ex); |
| } |
| } |
| } |
| |
| private void logTaskName(String name) |
| { |
| SetupTaskPerformer performer = getPerformer(); |
| if (performer != null) |
| { |
| performer.log(name); |
| } |
| } |
| } |
| } |