blob: 4521018f3f9157c350394e9cd01c133eece01eaf [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2018 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
* Johannes Michler <orgler@gmail.com> - Bug 321568 - [ui] Preference for automatic-update-reminder doesn't work in multilanguage-environments
*******************************************************************************/
package org.eclipse.equinox.internal.p2.ui.sdk.scheduler;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.dialogs.PopupDialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferenceDialog;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.*;
import org.eclipse.ui.dialogs.PreferencesUtil;
import org.eclipse.ui.progress.WorkbenchJob;
/**
* AutomaticUpdatesPopup is an async popup dialog for notifying the user of
* updates.
*
* @since 3.4
*/
public class AutomaticUpdatesPopup extends PopupDialog {
public static final String[] ELAPSED_VALUES = { PreferenceConstants.PREF_REMIND_30Minutes,
PreferenceConstants.PREF_REMIND_60Minutes, PreferenceConstants.PREF_REMIND_240Minutes };
public static final String[] ELAPSED_LOCALIZED_STRINGS = {
AutomaticUpdateMessages.AutomaticUpdateScheduler_30Minutes,
AutomaticUpdateMessages.AutomaticUpdateScheduler_60Minutes,
AutomaticUpdateMessages.AutomaticUpdateScheduler_240Minutes };
private static final long MINUTE = 60 * 1000L;
private static final String PREFS_HREF = "PREFS"; //$NON-NLS-1$
private static final String DIALOG_SETTINGS_SECTION = "AutomaticUpdatesPopup"; //$NON-NLS-1$
private static final int POPUP_OFFSET = 20;
IPreferenceStore prefs;
long remindDelay = -1L;
IPropertyChangeListener prefListener;
WorkbenchJob remindJob;
boolean downloaded;
Composite dialogArea;
Link remindLink;
MouseListener clickListener;
public AutomaticUpdatesPopup(Shell parentShell, boolean alreadyDownloaded, IPreferenceStore prefs) {
super(parentShell, PopupDialog.INFOPOPUPRESIZE_SHELLSTYLE | SWT.MODELESS, false, true, true, false, false,
AutomaticUpdateMessages.AutomaticUpdatesPopup_UpdatesAvailableTitle, null);
downloaded = alreadyDownloaded;
this.prefs = prefs;
remindDelay = computeRemindDelay();
clickListener = MouseListener
.mouseDownAdapter(e -> AutomaticUpdatePlugin.getDefault().getAutomaticUpdater().launchUpdate());
}
@Override
protected Control createDialogArea(Composite parent) {
dialogArea = new Composite(parent, SWT.NONE);
dialogArea.setLayoutData(new GridData(GridData.FILL_BOTH));
GridLayout layout = new GridLayout();
layout.numColumns = 1;
dialogArea.setLayout(layout);
dialogArea.addMouseListener(clickListener);
// The "click to update" label
Label infoLabel = new Label(dialogArea, SWT.NONE);
if (downloaded)
infoLabel.setText(AutomaticUpdateMessages.AutomaticUpdatesPopup_ClickToReviewDownloaded);
else
infoLabel.setText(AutomaticUpdateMessages.AutomaticUpdatesPopup_ClickToReviewNotDownloaded);
infoLabel.setLayoutData(new GridData(GridData.FILL_BOTH));
infoLabel.addMouseListener(clickListener);
createRemindSection(dialogArea);
return dialogArea;
}
private void createRemindSection(Composite parent) {
remindLink = new Link(parent, SWT.MULTI | SWT.WRAP | SWT.RIGHT);
updateRemindText();
remindLink.addSelectionListener(SelectionListener.widgetSelectedAdapter(e -> {
PreferenceDialog dialog = PreferencesUtil.createPreferenceDialogOn(getShell(),
PreferenceConstants.PREF_PAGE_AUTO_UPDATES, null, null);
dialog.open();
}));
remindLink.setLayoutData(new GridData(GridData.FILL_BOTH));
}
private void updateRemindText() {
if (prefs.getBoolean(PreferenceConstants.PREF_REMIND_SCHEDULE))
remindLink.setText(NLS.bind(AutomaticUpdateMessages.AutomaticUpdatesPopup_RemindAndPrefLink, new String[] {
getElapsedTimeString(prefs.getString(PreferenceConstants.PREF_REMIND_ELAPSED)), PREFS_HREF }));
else
remindLink.setText(AutomaticUpdateMessages.AutomaticUpdatesPopup_PrefLinkOnly);
remindLink.getParent().layout(true);
}
protected IDialogSettings getDialogBoundsSettings() {
IDialogSettings settings = AutomaticUpdatePlugin.getDefault().getDialogSettings();
IDialogSettings section = settings.getSection(DIALOG_SETTINGS_SECTION);
if (section == null) {
section = settings.addNewSection(DIALOG_SETTINGS_SECTION);
}
return section;
}
@Override
public int open() {
prefListener = this::handlePreferenceChange;
prefs.addPropertyChangeListener(prefListener);
return super.open();
}
@Override
public boolean close() {
return close(true);
}
public boolean close(boolean remind) {
if (remind && prefs.getBoolean(PreferenceConstants.PREF_REMIND_SCHEDULE))
scheduleRemindJob();
else
cancelRemindJob();
if (prefListener != null) {
prefs.removePropertyChangeListener(prefListener);
prefListener = null;
}
return super.close();
}
void scheduleRemindJob() {
// Cancel any pending remind job if there is one
if (remindJob != null)
remindJob.cancel();
// If no updates have been found, there is nothing to remind
if (remindDelay < 0)
return;
remindJob = new WorkbenchJob(AutomaticUpdateMessages.AutomaticUpdatesPopup_ReminderJobTitle) {
@Override
public IStatus runInUIThread(IProgressMonitor monitor) {
if (monitor.isCanceled())
return Status.CANCEL_STATUS;
open();
return Status.OK_STATUS;
}
};
remindJob.setSystem(true);
remindJob.setPriority(Job.INTERACTIVE);
remindJob.schedule(remindDelay);
}
/*
* Computes the number of milliseconds for the delay in reminding the user of
* updates
*/
long computeRemindDelay() {
if (prefs.getBoolean(PreferenceConstants.PREF_REMIND_SCHEDULE)) {
String elapsed = prefs.getString(PreferenceConstants.PREF_REMIND_ELAPSED);
for (int d = 0; d < ELAPSED_VALUES.length; d++)
if (ELAPSED_VALUES[d].equals(elapsed))
switch (d) {
case 0:
// 30 minutes
return 30 * MINUTE;
case 1:
// 60 minutes
return 60 * MINUTE;
case 2:
// 240 minutes
return 240 * MINUTE;
}
}
return -1L;
}
void cancelRemindJob() {
if (remindJob != null) {
remindJob.cancel();
remindJob = null;
}
}
@Override
protected void configureShell(Shell newShell) {
super.configureShell(newShell);
newShell.setText(AutomaticUpdateMessages.AutomaticUpdatesPopup_UpdatesAvailableTitle);
}
@Override
protected Point getInitialLocation(Point initialSize) {
Shell parent = getParentShell();
Point parentSize, parentLocation;
if (parent != null) {
parentSize = parent.getSize();
parentLocation = parent.getLocation();
} else {
Rectangle bounds = getShell().getDisplay().getBounds();
parentSize = new Point(bounds.width, bounds.height);
parentLocation = new Point(0, 0);
}
// We have to take parent location into account because SWT considers all
// shell locations to be in display coordinates, even if the shell is parented.
return new Point(parentSize.x - initialSize.x + parentLocation.x - POPUP_OFFSET,
parentSize.y - initialSize.y + parentLocation.y - POPUP_OFFSET);
}
void handlePreferenceChange(PropertyChangeEvent event) {
if (PreferenceConstants.PREF_REMIND_SCHEDULE.equals(event.getProperty())) {
// Reminders turned on
if (prefs.getBoolean(PreferenceConstants.PREF_REMIND_SCHEDULE)) {
if (remindLink == null)
createRemindSection(dialogArea);
else {
updateRemindText();
getShell().layout(true, true);
}
computeRemindDelay();
scheduleRemindJob();
} else { // reminders turned off
if (remindLink != null) {
updateRemindText();
getShell().layout(true, true);
}
cancelRemindJob();
}
} else if (PreferenceConstants.PREF_REMIND_ELAPSED.equals(event.getProperty())) {
// Reminding schedule changed
computeRemindDelay();
scheduleRemindJob();
}
}
/*
* Overridden so that clicking in the title menu area closes the dialog. Also
* creates a close box menu in the title area.
*/
@Override
protected Control createTitleMenuArea(Composite parent) {
Composite titleComposite = (Composite) super.createTitleMenuArea(parent);
titleComposite.addMouseListener(clickListener);
ToolBar toolBar = new ToolBar(titleComposite, SWT.FLAT);
ToolItem closeButton = new ToolItem(toolBar, SWT.PUSH, 0);
GridDataFactory.fillDefaults().align(SWT.END, SWT.CENTER).applyTo(toolBar);
closeButton.setImage(
AutomaticUpdatePlugin.getDefault().getImageRegistry().get((AutomaticUpdatePlugin.IMG_TOOL_CLOSE)));
closeButton.setHotImage(
AutomaticUpdatePlugin.getDefault().getImageRegistry().get((AutomaticUpdatePlugin.IMG_TOOL_CLOSE_HOT)));
closeButton.addSelectionListener(SelectionListener.widgetSelectedAdapter(e -> close()));
// See https://bugs.eclipse.org/bugs/show_bug.cgi?id=177183
toolBar.addMouseListener(MouseListener.mouseDownAdapter(e -> close()));
return titleComposite;
}
/*
* Overridden to adjust the span of the title label. Reachy, reachy....
*/
@Override
protected Control createTitleControl(Composite parent) {
Control control = super.createTitleControl(parent);
Object data = control.getLayoutData();
if (data instanceof GridData) {
((GridData) data).horizontalSpan = 1;
}
return control;
}
public static String getElapsedTimeString(String elapsedTimeKey) {
for (int i = 0; i < AutomaticUpdatesPopup.ELAPSED_VALUES.length; i++) {
if (AutomaticUpdatesPopup.ELAPSED_VALUES[i].equals(elapsedTimeKey))
return AutomaticUpdatesPopup.ELAPSED_LOCALIZED_STRINGS[i];
}
return AutomaticUpdatesPopup.ELAPSED_LOCALIZED_STRINGS[0];
}
}