blob: 42ea6d8a335a8886e448adfc0866db230fdfa32b [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2005, 2019 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.internal.r.debug.ui.preferences;
import java.util.HashMap;
import java.util.Map;
import org.osgi.service.prefs.BackingStoreException;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.jface.layout.PixelConverter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Link;
import org.eclipse.ui.PlatformUI;
import org.eclipse.statet.ecommons.preferences.core.Preference;
import org.eclipse.statet.ecommons.preferences.ui.ConfigurationBlockPreferencePage;
import org.eclipse.statet.ecommons.preferences.ui.ManagedConfigurationBlock;
import org.eclipse.statet.ecommons.templates.TemplateVariableProcessor;
import org.eclipse.statet.ecommons.ui.dialogs.groups.Layouter;
import org.eclipse.statet.ecommons.ui.util.LayoutUtils;
import org.eclipse.statet.ecommons.ui.util.UIAccess;
import org.eclipse.statet.internal.r.debug.ui.launcher.RCodeLaunchRegistry;
import org.eclipse.statet.internal.r.debug.ui.launcher.RCodeLaunchRegistry.ContentHandler.FileCommand;
import org.eclipse.statet.internal.r.ui.RUIPlugin;
import org.eclipse.statet.ltk.ui.sourceediting.SnippetEditor;
import org.eclipse.statet.r.core.RCore;
import org.eclipse.statet.r.launching.RRunDebugPreferenceConstants;
import org.eclipse.statet.r.ui.sourceediting.RSourceViewerConfigurator;
import org.eclipse.statet.r.ui.sourceediting.RTemplateSourceViewerConfigurator;
public class RInteractionPreferencePage extends ConfigurationBlockPreferencePage {
public RInteractionPreferencePage() {
setPreferenceStore(RUIPlugin.getInstance().getPreferenceStore());
setDescription(Messages.RInteraction_description);
}
@Override
protected RInteractionConfigurationBlock createConfigurationBlock() {
return new RInteractionConfigurationBlock();
}
}
class RInteractionConfigurationBlock extends ManagedConfigurationBlock {
private RCodeLaunchRegistry.ConnectorConfig[] connectors;
private Combo connectorsSelector;
private Link connectorsDescription;
private FileCommand[] fileCommands;
private SnippetEditor[] commandEditors;
RInteractionConfigurationBlock () {
super(null);
}
@Override
protected void createBlockArea(final Composite pageComposite) {
this.connectors= RCodeLaunchRegistry.getAvailableConnectors();
final Map<Preference<?>, String> prefs= new HashMap<>();
prefs.put(RRunDebugPreferenceConstants.PREF_R_CONNECTOR, null);
setupPreferenceManager(prefs);
LayoutUtils.addSmallFiller(pageComposite, false);
Composite group= createConnectorComponent(pageComposite);
group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
LayoutUtils.addSmallFiller(pageComposite, false);
group= createHandlerComponent(pageComposite);
group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
updateControls();
}
private Composite createConnectorComponent(final Composite parent) {
final String[] connectorLabels= new String[this.connectors.length];
for (int i= 0; i < this.connectors.length; i++) {
connectorLabels[i]= this.connectors[i].fName;
}
final Group group= new Group(parent, SWT.NONE);
group.setText(Messages.RInteraction_RConnector);
final Layouter layouter= new Layouter(group, 2);
this.connectorsSelector= layouter.addComboControl(connectorLabels, 2);
// Description
layouter.addLabel(Messages.RInteraction_RConnector_Description_label, 0, 1, true);
final ScrolledComposite scrolled= new ScrolledComposite(layouter.composite, SWT.V_SCROLL);
this.connectorsDescription= addLinkControl(scrolled, ""); //$NON-NLS-1$
scrolled.addControlListener(new ControlListener() {
@Override
public void controlMoved(final org.eclipse.swt.events.ControlEvent e) {}
@Override
public void controlResized(final org.eclipse.swt.events.ControlEvent e) {
updateDescriptionSize();
}
});
final GridData gd= new GridData(SWT.FILL, SWT.FILL, true, false);
final PixelConverter pixelConverter= new PixelConverter(this.connectorsDescription);
gd.horizontalSpan= 1;
gd.widthHint= pixelConverter.convertWidthInCharsToPixels(40);
gd.heightHint= pixelConverter.convertHeightInCharsToPixels(5);
scrolled.setLayoutData(gd);
scrolled.setContent(this.connectorsDescription);
this.connectorsSelector.addModifyListener(new ModifyListener() {
@Override
public void modifyText(final ModifyEvent e) {
final int idx= RInteractionConfigurationBlock.this.connectorsSelector.getSelectionIndex();
if (idx >= 0) {
setPrefValue(RRunDebugPreferenceConstants.PREF_R_CONNECTOR, RInteractionConfigurationBlock.this.connectors[idx].fId);
updateDescription(idx);
}
}
});
return group;
}
private void updateDescription(final int idx) {
String description= this.connectors[idx].fDescription;
if (description == null) {
description= ""; //$NON-NLS-1$
}
this.connectorsDescription.setText(description);
updateDescriptionSize();
}
private void updateDescriptionSize() {
final Composite scroller= this.connectorsDescription.getParent();
int widthHint= this.connectorsDescription.getParent().getClientArea().width;
if (!scroller.getVerticalBar().isVisible()) {
widthHint-= scroller.getVerticalBar().getSize().x;
}
this.connectorsDescription.setSize(this.connectorsDescription.computeSize(
widthHint, SWT.DEFAULT));
}
private Composite createHandlerComponent(final Composite parent) {
this.fileCommands= RCodeLaunchRegistry.getAvailableFileCommands();
final Group group= new Group(parent, SWT.NONE);
group.setText(Messages.RInteraction_FileCommands_label);
final GridLayout layout= LayoutUtils.newGroupGrid(2);
layout.verticalSpacing= 3;
group.setLayout(layout);
this.commandEditors= new SnippetEditor[this.fileCommands.length];
final TemplateVariableProcessor templateVariableProcessor= new TemplateVariableProcessor();
// templateVariableProcessor does not work without context type, but prevents NPE etc. by use of RTemplateSourceViewerConfiguration
// templateVariableProcessor.setContextType(contextType);
for (int i= 0; i < this.fileCommands.length; i++) {
final Label label= new Label(group, SWT.NONE);
label.setText(this.fileCommands[i].getLabel() + ":"); //$NON-NLS-1$
label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
final RSourceViewerConfigurator configurator= new RTemplateSourceViewerConfigurator(
RCore.WORKBENCH_ACCESS,
templateVariableProcessor );
this.commandEditors[i]= new SnippetEditor(configurator, this.fileCommands[i].getCurrentCommand(), PlatformUI.getWorkbench());
this.commandEditors[i].create(group, SnippetEditor.DEFAULT_SINGLE_LINE_STYLE);
final GridData gd= new GridData(SWT.FILL, SWT.CENTER, true, false);
gd.widthHint= LayoutUtils.hintWidth(this.commandEditors[i].getTextControl(), null, 25);
this.commandEditors[i].getControl().setLayoutData(gd);
}
return group;
}
@Override
protected void updateControls() {
loadValues();
UIAccess.getDisplay(getShell()).asyncExec(new Runnable() {
@Override
public void run() {
final int idx= RInteractionConfigurationBlock.this.connectorsSelector.getSelectionIndex();
if (idx >= 0) {
updateDescription(idx);
}
}
});
}
private void loadValues() {
final String selectedConnector= getPreferenceValue(
RRunDebugPreferenceConstants.PREF_R_CONNECTOR );
for (int i= 0; i < this.connectors.length; i++) {
if (selectedConnector.equals(this.connectors[i].fId)) {
this.connectorsSelector.select(i);
}
}
}
/* Load/Save of Handlers *****************************************************/
private void saveHandlerConfig(final boolean save) {
final IEclipsePreferences node= InstanceScope.INSTANCE.getNode(
RRunDebugPreferenceConstants.CAT_CODELAUNCH_CONTENTHANDLER_QUALIFIER );
for (int i= 0; i < this.fileCommands.length; i++) {
if (this.commandEditors[i] != null) {
final String key= this.fileCommands[i].getId()+":command"; //$NON-NLS-1$
final String command= this.commandEditors[i].getDocument().get();
if (command == null || command.isEmpty() || command.equals(this.fileCommands[i].getDefaultCommand())) {
node.remove(key);
}
else {
node.put(key, command);
}
}
}
if (save) {
try {
node.flush();
} catch (final BackingStoreException e) {
logSaveError(e);
}
}
}
@Override
public void performDefaults() {
for (int i= 0; i < this.fileCommands.length; i++) {
if (this.commandEditors[i] != null) {
this.commandEditors[i].getDocument().set(this.fileCommands[i].getDefaultCommand());
this.commandEditors[i].reset();
}
}
super.performDefaults();
}
@Override
public boolean performOk(final int flags) {
saveHandlerConfig((flags & SAVE_STORE) != 0);
return super.performOk(flags);
}
}