/*
* Copyright 2015 Nokia Solutions and Networks
* Licensed under the Apache License, Version 2.0,
* see license.txt file for details.
*/
package org.robotframework.ide.eclipse.main.plugin.project.editor.general;
import java.awt.Desktop;
import java.io.File;
import java.io.IOException;
import java.util.List;
import javax.inject.Inject;
import org.eclipse.e4.core.di.annotations.Optional;
import org.eclipse.e4.tools.services.IDirtyProviderService;
import org.eclipse.e4.ui.di.UIEventTopic;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTableViewer;
import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.ViewerColumnsFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.ui.dialogs.PreferencesUtil;
import org.eclipse.ui.forms.events.HyperlinkAdapter;
import org.eclipse.ui.forms.events.HyperlinkEvent;
import org.eclipse.ui.forms.events.IHyperlinkListener;
import org.eclipse.ui.forms.widgets.ExpandableComposite;
import org.eclipse.ui.forms.widgets.FormText;
import org.eclipse.ui.forms.widgets.Section;
import org.rf.ide.core.executor.RobotRuntimeEnvironment;
import org.rf.ide.core.executor.RobotRuntimeEnvironment.PythonInstallationDirectory;
import org.rf.ide.core.executor.SuiteExecutor;
import org.rf.ide.core.project.RobotProjectConfig;
import org.robotframework.ide.eclipse.main.plugin.RedImages;
import org.robotframework.ide.eclipse.main.plugin.preferences.InstalledRobotsEnvironmentsLabelProvider.InstalledRobotsNamesLabelProvider;
import org.robotframework.ide.eclipse.main.plugin.preferences.InstalledRobotsEnvironmentsLabelProvider.InstalledRobotsPathsLabelProvider;
import org.robotframework.ide.eclipse.main.plugin.preferences.InstalledRobotsPreferencesPage;
import org.robotframework.ide.eclipse.main.plugin.project.RobotProjectConfigEvents;
import org.robotframework.ide.eclipse.main.plugin.project.editor.Environments;
import org.robotframework.ide.eclipse.main.plugin.project.editor.RedProjectEditorInput;
import org.robotframework.ide.eclipse.main.plugin.tableeditor.HeaderFilterMatchesCollection;
import org.robotframework.ide.eclipse.main.plugin.tableeditor.ISectionFormFragment;
import org.robotframework.red.forms.RedFormToolkit;
import org.robotframework.red.graphics.ImagesManager;
import org.robotframework.red.viewers.ListInputStructuredContentProvider;
class FrameworksSectionFormFragment implements ISectionFormFragment {
private static final String IMAGE_FOR_LINK = "image";
private static final String PATH_LINK = "systemPath";
private static final String PREFERENCES_LINK = "preferences";
@Inject
private RedFormToolkit toolkit;
@Inject
private IDirtyProviderService dirtyProviderService;
@Inject
private RedProjectEditorInput editorInput;
private CheckboxTableViewer viewer;
private FormText currentFramework;
private Button sourceButton;
TableViewer getViewer() {
return viewer;
}
@Override
public void initialize(final Composite parent) {
final Section section = toolkit.createSection(parent,
ExpandableComposite.EXPANDED | ExpandableComposite.TITLE_BAR
| Section.DESCRIPTION);
section.setText("Robot framework");
section.setDescription(
"Specify which Robot Framework should be used by this project. Currently following framework is in use:");
GridDataFactory.fillDefaults().grab(true, true).applyTo(section);
final Composite sectionInternal = toolkit.createComposite(section);
GridDataFactory.fillDefaults().grab(true, true).applyTo(sectionInternal);
GridLayoutFactory.fillDefaults().extendedMargins(0, 0, 0, 10).applyTo(sectionInternal);
section.setClient(sectionInternal);
createCurrentFrameworkInfo(sectionInternal);
createSeparator(sectionInternal);
createSourceButton(sectionInternal);
createViewer(sectionInternal);
}
private void createCurrentFrameworkInfo(final Composite parent) {
currentFramework = toolkit.createFormText(parent, true);
currentFramework.setImage(IMAGE_FOR_LINK, ImagesManager.getImage(RedImages.getRobotImage()));
GridDataFactory.fillDefaults().grab(true, false).indent(15, 5).applyTo(currentFramework);
final IHyperlinkListener hyperlinkListener = createHyperlinkListener();
currentFramework.addHyperlinkListener(hyperlinkListener);
currentFramework.addDisposeListener(new DisposeListener() {
@Override
public void widgetDisposed(final DisposeEvent e) {
currentFramework.removeHyperlinkListener(hyperlinkListener);
}
});
}
private IHyperlinkListener createHyperlinkListener() {
return new HyperlinkAdapter() {
@Override
public void linkActivated(final HyperlinkEvent event) {
final Shell shell = viewer.getTable().getShell();
if (PATH_LINK.equals(event.getHref())) {
if (Desktop.isDesktopSupported()) {
final File file = new File(event.getLabel());
try {
Desktop.getDesktop().open(file);
} catch (final IOException e) {
ErrorDialog.openError(shell, "Unable to open location",
"Unable to open location: " + file.getAbsolutePath(), null);
}
}
} else if (PREFERENCES_LINK.equals(event.getHref())) {
PreferencesUtil.createPreferenceDialogOn(shell, InstalledRobotsPreferencesPage.ID,
new String[] { InstalledRobotsPreferencesPage.ID }, null).open();
}
}
};
}
private void createSeparator(final Composite parent) {
final Label separator = toolkit.createSeparator(parent, SWT.HORIZONTAL);
GridDataFactory.fillDefaults().indent(0, 10).applyTo(separator);
}
private void createSourceButton(final Composite parent) {
sourceButton = toolkit.createButton(parent, "Use local settings for this project", SWT.CHECK);
sourceButton.setEnabled(false);
sourceButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(final SelectionEvent event) {
viewer.getTable().setEnabled(sourceButton.getSelection());
final Object[] elements = viewer.getCheckedElements();
File file;
SuiteExecutor executor;
if (elements.length == 1 && sourceButton.getSelection()) {
final RobotRuntimeEnvironment env = (RobotRuntimeEnvironment) elements[0];
file = env.getFile();
executor = file instanceof PythonInstallationDirectory
? ((PythonInstallationDirectory) file).getInterpreter() : null;
} else {
file = null;
executor = null;
}
editorInput.getProjectConfiguration().assignPythonLocation(file, executor);
setDirty(true);
}
});
}
private void createViewer(final Composite tableParent) {
final Table table = new Table(tableParent, SWT.CHECK | SWT.BORDER | SWT.FULL_SELECTION | SWT.H_SCROLL
| SWT.V_SCROLL);
viewer = new CheckboxTableViewer(table);
GridDataFactory.fillDefaults().grab(true, true).applyTo(viewer.getTable());
viewer.getTable().setLinesVisible(true);
viewer.getTable().setHeaderVisible(true);
viewer.getTable().setEnabled(false);
final ICheckStateListener checkListener = createCheckListener();
viewer.addCheckStateListener(checkListener);
viewer.getTable().addDisposeListener(new DisposeListener() {
@Override
public void widgetDisposed(final DisposeEvent e) {
viewer.removeCheckStateListener(checkListener);
}
});
ColumnViewerToolTipSupport.enableFor(viewer);
viewer.setContentProvider(new ListInputStructuredContentProvider());
ViewerColumnsFactory.newColumn("Name").withWidth(200)
.labelsProvidedBy(new InstalledRobotsNamesLabelProvider(viewer)).createFor(viewer);
ViewerColumnsFactory.newColumn("Path").withWidth(200)
.shouldGrabAllTheSpaceLeft(true).withMinWidth(30)
.labelsProvidedBy(new InstalledRobotsPathsLabelProvider(viewer)).createFor(viewer);
}
private ICheckStateListener createCheckListener() {
return new ICheckStateListener() {
@Override
public void checkStateChanged(final CheckStateChangedEvent event) {
final RobotProjectConfig configuration = editorInput.getProjectConfiguration();
File file;
SuiteExecutor executor;
if (event.getChecked()) {
final RobotRuntimeEnvironment env = (RobotRuntimeEnvironment) event.getElement();
viewer.setCheckedElements(new Object[] { env });
file = env.getFile();
executor = file instanceof PythonInstallationDirectory
? ((PythonInstallationDirectory) file).getInterpreter() : null;
} else {
sourceButton.setSelection(false);
viewer.getTable().setEnabled(false);
file = null;
executor = null;
}
configuration.assignPythonLocation(file, executor);
setDirty(true);
viewer.refresh();
}
};
}
@Override
public void setFocus() {
viewer.getTable().getParent().setFocus();
}
private void setDirty(final boolean isDirty) {
dirtyProviderService.setDirtyState(isDirty);
}
@Override
public HeaderFilterMatchesCollection collectMatches(final String filter) {
return null;
}
@Inject
@Optional
private void whenEnvironmentLoadingStarted(
@UIEventTopic(RobotProjectConfigEvents.ROBOT_CONFIG_ENV_LOADING_STARTED) final RobotProjectConfig config) {
currentFramework.setText("", false, false);
sourceButton.setEnabled(false);
viewer.getTable().setEnabled(false);
sourceButton.setSelection(!editorInput.getProjectConfiguration().usesPreferences());
}
@Inject
@Optional
private void whenEnvironmentsWereLoaded(
@UIEventTopic(RobotProjectConfigEvents.ROBOT_CONFIG_ENV_LOADED) final Environments envs) {
final List<RobotRuntimeEnvironment> allEnvironments = envs.getAllEnvironments();
final RobotRuntimeEnvironment env = envs.getActiveEnvironment();
final RobotProjectConfig configuration = editorInput.getProjectConfiguration();
final boolean isEditable = editorInput.isEditable();
if (viewer.getTable() == null || viewer.getTable().isDisposed()) {
return;
}
final boolean isUsingPrefs = configuration.usesPreferences();
sourceButton.setEnabled(isEditable);
viewer.setInput(allEnvironments);
if (env != null) {
viewer.setCheckedElements(new Object[] { env });
}
viewer.getTable().setEnabled(isEditable && !isUsingPrefs);
viewer.refresh();
if (env == null) {
currentFramework.setText(createCurrentFrameworkText("unknown"), true, true);
} else {
final String activeText = createActiveFrameworkText(env, isUsingPrefs);
currentFramework.setText(createCurrentFrameworkText(activeText), true, true);
}
currentFramework.getParent().layout();
}
private String createCurrentFrameworkText(final String path) {
final StringBuilder builder = new StringBuilder();
builder.append("<form>");
builder.append("<p><img href=\"" + IMAGE_FOR_LINK + "\"/> " + path + "</p>");
builder.append("</form>");
return builder.toString();
}
private String createActiveFrameworkText(final RobotRuntimeEnvironment env, final boolean isUsingPrefs) {
final StringBuilder activeText = new StringBuilder();
activeText.append("<a href=\"" + PATH_LINK + "\">");
activeText.append(env.getFile().getAbsolutePath());
activeText.append("</a>");
activeText.append(" " + env.getVersion());
if (isUsingPrefs) {
activeText.append(" (<a href=\"" + PREFERENCES_LINK + "\">from Preferences</a>)");
}
return activeText.toString();
}
}