/*=============================================================================#
# Copyright (c) 2005-2016 Stephan Wahlbrink (WalWare.de) and others.
# All rights reserved. This program and the accompanying materials
# are 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:
# Stephan Wahlbrink - initial API and implementation
#=============================================================================*/
package de.walware.statet.r.internal.debug.ui.preferences;
import java.util.HashMap;
import java.util.Map;
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.osgi.service.prefs.BackingStoreException;
import de.walware.ecommons.ltk.ui.sourceediting.SnippetEditor;
import de.walware.ecommons.preferences.core.Preference;
import de.walware.ecommons.preferences.ui.ConfigurationBlockPreferencePage;
import de.walware.ecommons.preferences.ui.ManagedConfigurationBlock;
import de.walware.ecommons.templates.TemplateVariableProcessor;
import de.walware.ecommons.ui.dialogs.groups.Layouter;
import de.walware.ecommons.ui.util.LayoutUtil;
import de.walware.ecommons.ui.util.UIAccess;
import de.walware.statet.r.core.RCore;
import de.walware.statet.r.internal.debug.ui.launcher.RCodeLaunchRegistry;
import de.walware.statet.r.internal.debug.ui.launcher.RCodeLaunchRegistry.ContentHandler.FileCommand;
import de.walware.statet.r.internal.ui.RUIPlugin;
import de.walware.statet.r.launching.RRunDebugPreferenceConstants;
import de.walware.statet.r.ui.sourceediting.RSourceViewerConfigurator;
import de.walware.statet.r.ui.sourceediting.RTemplateSourceViewerConfigurator;
public class RInteractionPreferencePage extends ConfigurationBlockPreferencePage {
public RInteractionPreferencePage() {
setPreferenceStore(RUIPlugin.getDefault().getPreferenceStore());
setDescription(Messages.RInteraction_description);
}
@Override
protected RInteractionConfigurationBlock createConfigurationBlock() {
return new RInteractionConfigurationBlock();
}
}
class RInteractionConfigurationBlock extends ManagedConfigurationBlock {
private RCodeLaunchRegistry.ConnectorConfig[] fConnectors;
private Combo fConnectorsSelector;
private Link fConnectorsDescription;
private FileCommand[] fFileCommands;
private SnippetEditor[] fCommandEditors;
RInteractionConfigurationBlock () {
super(null);
}
@Override
protected void createBlockArea(final Composite pageComposite) {
fConnectors = RCodeLaunchRegistry.getAvailableConnectors();
final Map<Preference<?>, String> prefs= new HashMap<>();
prefs.put(RRunDebugPreferenceConstants.PREF_R_CONNECTOR, null);
setupPreferenceManager(prefs);
LayoutUtil.addSmallFiller(pageComposite, false);
Composite group = createConnectorComponent(pageComposite);
group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
LayoutUtil.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[fConnectors.length];
for (int i = 0; i < fConnectors.length; i++) {
connectorLabels[i] = fConnectors[i].fName;
}
final Group group = new Group(parent, SWT.NONE);
group.setText(Messages.RInteraction_RConnector);
final Layouter layouter = new Layouter(group, 2);
fConnectorsSelector = 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);
fConnectorsDescription = 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(fConnectorsDescription);
gd.horizontalSpan = 1;
gd.widthHint = pixelConverter.convertWidthInCharsToPixels(40);
gd.heightHint = pixelConverter.convertHeightInCharsToPixels(5);
scrolled.setLayoutData(gd);
scrolled.setContent(fConnectorsDescription);
fConnectorsSelector.addModifyListener(new ModifyListener() {
@Override
public void modifyText(final ModifyEvent e) {
final int idx = fConnectorsSelector.getSelectionIndex();
if (idx >= 0) {
setPrefValue(RRunDebugPreferenceConstants.PREF_R_CONNECTOR, fConnectors[idx].fId);
updateDescription(idx);
}
};
});
return group;
}
private void updateDescription(final int idx) {
String description = fConnectors[idx].fDescription;
if (description == null) {
description = ""; //$NON-NLS-1$
}
fConnectorsDescription.setText(description);
updateDescriptionSize();
}
private void updateDescriptionSize() {
final Composite scroller = fConnectorsDescription.getParent();
int widthHint = fConnectorsDescription.getParent().getClientArea().width;
if (!scroller.getVerticalBar().isVisible()) {
widthHint -= scroller.getVerticalBar().getSize().x;
}
fConnectorsDescription.setSize(fConnectorsDescription.computeSize(
widthHint, SWT.DEFAULT));
}
private Composite createHandlerComponent(final Composite parent) {
fFileCommands = RCodeLaunchRegistry.getAvailableFileCommands();
final Group group = new Group(parent, SWT.NONE);
group.setText(Messages.RInteraction_FileCommands_label);
final GridLayout layout = LayoutUtil.applyGroupDefaults(new GridLayout(), 2);
layout.verticalSpacing = 3;
group.setLayout(layout);
fCommandEditors = new SnippetEditor[fFileCommands.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 < fFileCommands.length; i++) {
final Label label = new Label(group, SWT.NONE);
label.setText(fFileCommands[i].getLabel() + ":"); //$NON-NLS-1$
label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
final RSourceViewerConfigurator configurator = new RTemplateSourceViewerConfigurator(
RCore.WORKBENCH_ACCESS,
templateVariableProcessor );
fCommandEditors[i] = new SnippetEditor(configurator, fFileCommands[i].getCurrentCommand(), PlatformUI.getWorkbench());
fCommandEditors[i].create(group, SnippetEditor.DEFAULT_SINGLE_LINE_STYLE);
final GridData gd = new GridData(SWT.FILL, SWT.CENTER, true, false);
gd.widthHint = LayoutUtil.hintWidth(fCommandEditors[i].getTextControl(), null, 25);
fCommandEditors[i].getControl().setLayoutData(gd);
}
return group;
}
@Override
protected void updateControls() {
loadValues();
UIAccess.getDisplay(getShell()).asyncExec(new Runnable() {
@Override
public void run() {
final int idx = fConnectorsSelector.getSelectionIndex();
if (idx >= 0) {
updateDescription(idx);
}
}
});
}
private void loadValues() {
final String selectedConnector = getPreferenceValue(
RRunDebugPreferenceConstants.PREF_R_CONNECTOR );
for (int i = 0; i < fConnectors.length; i++) {
if (selectedConnector.equals(fConnectors[i].fId)) {
fConnectorsSelector.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 < fFileCommands.length; i++) {
if (fCommandEditors[i] != null) {
final String key = fFileCommands[i].getId()+":command"; //$NON-NLS-1$
final String command = fCommandEditors[i].getDocument().get();
if (command == null || command.isEmpty() || command.equals(fFileCommands[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 < fFileCommands.length; i++) {
if (fCommandEditors[i] != null) {
fCommandEditors[i].getDocument().set(fFileCommands[i].getDefaultCommand());
fCommandEditors[i].reset();
}
}
super.performDefaults();
}
@Override
public void performApply() {
saveHandlerConfig(true);
super.performApply();
}
@Override
public boolean performOk() {
saveHandlerConfig(false);
return super.performOk();
}
}