/*******************************************************************************
* Copyright (c) 2015 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is 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:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.openshift.internal.ui.preferences;
import static org.jboss.tools.openshift.core.preferences.IOpenShiftCoreConstants.DOWNLOAD_INSTRUCTIONS_URL;
import java.io.File;
import java.util.Objects;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.SystemUtils;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.preference.FieldEditorPreferencePage;
import org.eclipse.jface.preference.FileFieldEditor;
import org.eclipse.jface.preference.StringFieldEditor;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Link;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPreferencePage;
import org.jboss.tools.foundation.ui.util.BrowserUtility;
import org.jboss.tools.openshift.core.preferences.IOpenShiftCoreConstants;
import org.jboss.tools.openshift.internal.common.ui.job.UIUpdatingJob;
import org.jboss.tools.openshift.internal.core.preferences.OCBinary;
import org.jboss.tools.openshift.internal.core.preferences.OCBinaryVersionValidator;
import org.jboss.tools.openshift.internal.ui.OpenShiftUIActivator;
import org.osgi.framework.Version;
/**
* @author jeff.cantrill
* @author Andre Dietisheim
*/
public class OpenShiftPreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage {
private CliFileEditor cliLocationEditor;
private OCBinary ocBinary;
private Label ocVersionLabel;
private Composite ocMessageComposite;
private Label ocMessageLabel;
private UIUpdatingJob versionVerificationJob;
public OpenShiftPreferencePage() {
super(GRID);
this.ocBinary = OCBinary.getInstance();
}
@Override
public void createFieldEditors() {
Link link = new Link(getFieldEditorParent(), SWT.WRAP);
link.setText("The OpenShift client binary (oc) is required for features such as Port Forwarding or Log Streaming. "
+ "You can find more information about how to install it from <a>here</a>.");
GridDataFactory.fillDefaults().span(3, 1).hint(1,60).grab(true, false).applyTo(link);
link.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
new BrowserUtility().checkedCreateExternalBrowser(DOWNLOAD_INSTRUCTIONS_URL,
OpenShiftUIActivator.PLUGIN_ID,
OpenShiftUIActivator.getDefault().getLog());
}
});
this.cliLocationEditor = new CliFileEditor();
cliLocationEditor.setFilterPath(SystemUtils.getUserHome());
String[] suffixes = ocBinary.getExtensions();
String[] filters = new String[suffixes.length];
for( int i = 0; i < filters.length; i++ ) {
filters[i] = "*" + suffixes[i];
}
cliLocationEditor.setFileExtensions(filters);
cliLocationEditor.setValidateStrategy(FileFieldEditor.VALIDATE_ON_KEY_STROKE);
addField(cliLocationEditor);
ocVersionLabel = new Label(getFieldEditorParent(), SWT.WRAP);
ocVersionLabel.setFont(JFaceResources.getFontRegistry().getItalic(JFaceResources.DEFAULT_FONT));
GridDataFactory.fillDefaults().span(3, 1).applyTo(ocVersionLabel);
ocMessageComposite = new Composite(getFieldEditorParent(), SWT.NONE);
GridDataFactory.fillDefaults().span(3, 1).applyTo(ocMessageComposite);
GridLayoutFactory.fillDefaults().numColumns(2).applyTo(ocMessageComposite);
Label label = new Label(ocMessageComposite, SWT.NONE);
label.setImage(JFaceResources.getImage(Dialog.DLG_IMG_MESSAGE_WARNING));
GridDataFactory.fillDefaults().align(SWT.BEGINNING, SWT.TOP).applyTo(label);
ocMessageLabel = new Label(ocMessageComposite, SWT.NONE);
GridDataFactory.fillDefaults().grab(true, false).applyTo(ocMessageLabel);
ocMessageComposite.setVisible(false);
}
@Override
public void init(IWorkbench workbench) {
setPreferenceStore(OpenShiftUIActivator.getDefault().getCorePreferenceStore());
}
@Override
protected void performDefaults() {
String location = ocBinary.getSystemPathLocation();
if (location == null) {
//We have to update default value in preferences even if it is empty.
location = "";
}
getPreferenceStore().setDefault(IOpenShiftCoreConstants.OPENSHIFT_CLI_LOC, location);
if (StringUtils.isBlank(location)) {
String message = NLS.bind("Could not find the OpenShift client executable \"{0}\" on your path.", ocBinary.getName());
OpenShiftUIActivator.getDefault().getLogger().logWarning(message);
MessageDialog.openWarning(getShell(), "No OpenShift client executable", message);
return;
}
super.performDefaults();
//Super implementation changes instance value, we need it clean.
getPreferenceStore().setToDefault(IOpenShiftCoreConstants.OPENSHIFT_CLI_LOC);
}
@Override
public boolean performOk() {
boolean valid = true;
if (cliLocationEditor.getStringValue()
.equals(getPreferenceStore().getDefaultString(IOpenShiftCoreConstants.OPENSHIFT_CLI_LOC))) {
//Super implementation changes instance value, we need it clean.
getPreferenceStore().setToDefault(IOpenShiftCoreConstants.OPENSHIFT_CLI_LOC);
} else {
valid = super.performOk();
}
valid = validateLocation(cliLocationEditor.getStringValue()) && valid;
setValid(valid);
return valid;
}
private boolean validateLocation(String location) {
if (StringUtils.isBlank(location)) {
return true;
}
File file = new File(location);
// Error messages have to be set to field editor, not directly to the
// page.
if (!file.exists()) {
cliLocationEditor.setErrorMessage(NLS.bind("{0} was not found.", file));
return false;
}
if (!file.canExecute()) {
cliLocationEditor.setErrorMessage(NLS.bind("{0} does not have execute permissions.", file));
return false;
}
setValid(false);
ocVersionLabel.setText("Checking OpenShift client version...");
this.versionVerificationJob = new UIUpdatingJob("Checking oc binary...") {
private Version version;
@Override
protected IStatus run(IProgressMonitor monitor) {
version = new OCBinaryVersionValidator(location).getVersion(monitor);
if (monitor.isCanceled()) {
return Status.CANCEL_STATUS;
}
return Status.OK_STATUS;
}
@Override
protected IStatus updateUI(IProgressMonitor monitor) {
if (!getResult().isOK()) {
return getResult();
}
if (!ocMessageComposite.isDisposed() && !monitor.isCanceled()) {
setValid(true);
if (Version.emptyVersion.equals(version)) {
ocVersionLabel.setText("Could not determine your OpenShift client version");
} else {
ocVersionLabel.setText(NLS.bind("Your OpenShift client version is {0}.{1}.{2}",
new Object[] { version.getMajor(), version.getMinor(), version.getMicro() }));
}
ocMessageLabel.setText(NLS.bind(
"OpenShift client version 1.1.1 or higher is required to avoid rsync issues.", version));
ocMessageComposite.setVisible(!OCBinaryVersionValidator.isCompatibleForPublishing(version));
}
return super.updateUI(monitor);
}
};
versionVerificationJob.schedule();
return true;
}
class CliFileEditor extends FileFieldEditor {
private String lastCheckedValue = null;
public CliFileEditor() {
//Validation strategy should be set in constructor, later setting it has no effect.
super(IOpenShiftCoreConstants.OPENSHIFT_CLI_LOC,
NLS.bind("''{0}'' executable location", ocBinary.getName()),
false, StringFieldEditor.VALIDATE_ON_KEY_STROKE, getFieldEditorParent());
}
@Override
protected boolean checkState() {
//We have to return the default error message that is used
//by super implementation if file does not exist.
String newCheckedValue = getStringValue();
if (!Objects.equals(newCheckedValue, lastCheckedValue)) {
setErrorMessage(JFaceResources.getString("FileFieldEditor.errorMessage"));
ocVersionLabel.setText("");
ocMessageComposite.setVisible(false);
if (versionVerificationJob != null){
versionVerificationJob.cancel();
}
}
boolean state = super.checkState();
if (!state) {
lastCheckedValue = newCheckedValue;
}
return state;
}
@Override
public boolean doCheckState() {
String newCheckedValue = getStringValue();
boolean state = true;
if (!Objects.equals(newCheckedValue, lastCheckedValue)) {
state = validateLocation(newCheckedValue);
}
lastCheckedValue = getStringValue();
return state;
}
}
}