/* * Copyright (C) 2006-2016 DLR, Germany * * All rights reserved * * http://www.rcenvironment.de/ */ package de.rcenvironment.core.gui.workflow.executor.properties; import org.eclipse.swt.SWT; import org.eclipse.swt.events.KeyAdapter; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; import org.eclipse.ui.forms.widgets.Section; import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage; import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetWidgetFactory; import de.rcenvironment.core.component.executor.SshExecutorConstants; import de.rcenvironment.core.component.workflow.model.api.WorkflowNode; import de.rcenvironment.core.component.workflow.model.api.WorkflowNodeUtil; import de.rcenvironment.core.configuration.PersistentSettingsService; import de.rcenvironment.core.gui.resources.api.FontManager; import de.rcenvironment.core.gui.resources.api.StandardFonts; import de.rcenvironment.core.gui.utils.common.widgets.LineNumberStyledText; import de.rcenvironment.core.gui.workflow.editor.properties.ValidatingWorkflowNodePropertySection; import de.rcenvironment.core.gui.workflow.editor.properties.WorkflowNodeCommand; import de.rcenvironment.core.utils.incubator.ServiceRegistry; /** * Abstract component for the ScriptSection. * * @author Sascha Zur */ public abstract class AbstractScriptSection extends ValidatingWorkflowNodePropertySection { /** Load script from local file system should be supported. */ public static final int LOCAL_FILE = 1; /** Use script from built-in editor should be supported. */ public static final int NEW_SCRIPT_FILE = 4; /** Both supported. */ public static final int ALL = LOCAL_FILE | NEW_SCRIPT_FILE; /** None supported. */ public static final int NO_SCRIPT_FILENAME = 8; /** Check WhiteSpaceCharacter key. */ public static final String CHECKBOX_KEY = "checkShowWhitespace"; private static final String KEY_SCRIPT_WHITESPACE_BOX = "ScriptWhitespaceBox"; private static final int MINIMUM_HEIGHT_OF_JOB_SCRIPTING_TEXT = 200; protected Button openInEditorButton; protected Button checkBoxWhitespace; protected WhitespaceShowListener whitespaceListener; protected Composite newScriptArea; protected EditScriptRunnable esr = null; protected LineNumberStyledText scriptingText; private final String scriptName; private final PersistentSettingsService persistentSettingsService; public AbstractScriptSection(int style, String scriptName) { this.scriptName = scriptName; whitespaceListener = new WhitespaceShowListener(); persistentSettingsService = ServiceRegistry.createAccessFor(this).getService(PersistentSettingsService.class); } /** * Template method to allow subclasses to add content at the very top. */ protected void createCompositeContentAtVeryTop(Composite composite, TabbedPropertySheetWidgetFactory factory) { } @Override protected void createCompositeContent(final Composite parent, final TabbedPropertySheetPage aTabbedPropertySheetPage) { TabbedPropertySheetWidgetFactory factory = aTabbedPropertySheetPage.getWidgetFactory(); Section jobSection = factory.createSection(parent, Section.TITLE_BAR | Section.EXPANDED); jobSection.setText(Messages.configureScript); Composite jobParent = factory.createFlatFormComposite(jobSection); createCompositeContentAtVeryTop(jobParent, factory); GridLayout layout = new GridLayout(); layout.numColumns = 1; jobParent.setLayout(layout); GridData gridData = new GridData(); gridData.grabExcessHorizontalSpace = true; gridData.horizontalAlignment = GridData.FILL; gridData.widthHint = 1; openInEditorButton = factory.createButton(jobParent, Messages.openInEditor, SWT.PUSH); checkBoxWhitespace = factory.createButton(jobParent, Messages.showWhitespace, SWT.CHECK); openInEditorButton.addSelectionListener(new SelectionListener() { @Override public void widgetSelected(SelectionEvent arg0) { esr = new EditScriptRunnable(node); esr.run(); } @Override public void widgetDefaultSelected(SelectionEvent arg0) { widgetSelected(arg0); } }); gridData = new GridData(); gridData.grabExcessHorizontalSpace = true; gridData.horizontalAlignment = GridData.FILL; gridData.widthHint = 1; newScriptArea = factory.createFlatFormComposite(jobParent); newScriptArea.setLayoutData(gridData); layout = new GridLayout(); layout.numColumns = 2; newScriptArea.setLayout(layout); gridData = new GridData(); gridData.horizontalSpan = 2; gridData.grabExcessHorizontalSpace = true; gridData.horizontalAlignment = GridData.FILL; gridData.grabExcessVerticalSpace = true; gridData.verticalAlignment = GridData.FILL; final int aKeyCode = 97; scriptingText = new LineNumberStyledText(newScriptArea, SWT.MULTI | SWT.V_SCROLL | SWT.BORDER | SWT.WRAP); scriptingText.setFont(FontManager.getInstance().getFont(StandardFonts.CONSOLE_TEXT_FONT)); scriptingText.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if (e.stateMask == SWT.CTRL && e.keyCode == aKeyCode) { scriptingText.selectAll(); } updateEditor(node); } }); whitespaceListener.setScriptingText(scriptingText); scriptingText.addPaintListener(whitespaceListener); checkBoxWhitespace.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) { boolean selected = checkBoxWhitespace.getSelection(); if (selected) { whitespaceListener.setOn(true); whitespaceListener.drawStyledText(); updateEditor(node); } else { whitespaceListener.setOn(false); whitespaceListener.redrawAll(); } persistentSettingsService.saveStringValue(KEY_SCRIPT_WHITESPACE_BOX, String.valueOf(checkBoxWhitespace.getSelection())); } }); scriptingText.setLayoutData(gridData); scriptingText.setData(CONTROL_PROPERTY_KEY, SshExecutorConstants.CONFIG_KEY_SCRIPT); ((GridData) newScriptArea.getLayoutData()).heightHint = MINIMUM_HEIGHT_OF_JOB_SCRIPTING_TEXT; addResizingListenerForJobScriptingText(parent.getParent()); jobSection.setClient(jobParent); } private void updateEditor(WorkflowNode node) { if (esr != null && scriptingText != null && esr.getNode().equals(node)) { esr.update(scriptingText.getText()); } } @Override public void aboutToBeShown() { super.aboutToBeShown(); refresh(); String whitespaceBoxSelection = persistentSettingsService.readStringValue(KEY_SCRIPT_WHITESPACE_BOX); if (whitespaceBoxSelection == null || !Boolean.parseBoolean(whitespaceBoxSelection)) { checkBoxWhitespace.setSelection(false); whitespaceListener.setOn(false); whitespaceListener.redrawAll(); } else { checkBoxWhitespace.setSelection(true); whitespaceListener.setOn(true); whitespaceListener.drawStyledText(); updateEditor(node); } } private void addResizingListenerForJobScriptingText(final Composite parent) { parent.addListener(SWT.Resize, new Listener() { @Override public void handleEvent(Event e) { setSizeOfJobScriptingText(parent); } }); } private void setSizeOfJobScriptingText(Composite parent) { final int topMargin = 125; if (parent.getSize().y < MINIMUM_HEIGHT_OF_JOB_SCRIPTING_TEXT) { ((GridData) newScriptArea.getLayoutData()).heightHint = MINIMUM_HEIGHT_OF_JOB_SCRIPTING_TEXT; } else { ((GridData) newScriptArea.getLayoutData()).heightHint = parent.getSize().y - topMargin; newScriptArea.update(); } } /** * Implementation of {@link AbstractEditScriptRunnable}. * * @author Doreen Seider * @author Sascha Zur */ private class EditScriptRunnable extends AbstractEditScriptRunnable { private final WorkflowNode node; EditScriptRunnable(WorkflowNode node) { this.node = node; } public WorkflowNode getNode() { return node; } @Override protected void setScript(String script) { setScriptProperty(node, script); } @Override protected String getScript() { return node.getComponentDescription().getConfigurationDescription() .getConfigurationValue(SshExecutorConstants.CONFIG_KEY_SCRIPT); } @Override protected String getScriptName() { return scriptName; } } /** * If the script is edited in an open editor, the workflow editor must get dirty when the script is saved. To do so, a command must be * executed, but it must contain the correct node. * * @param node to execute the save command to. * @param newValue of the script. * @author Sascha Zur */ private void setScriptProperty(WorkflowNode node, final String newValue) { final String oldValue = WorkflowNodeUtil.getConfigurationValue(node, SshExecutorConstants.CONFIG_KEY_SCRIPT); if ((oldValue != null && !oldValue.equals(newValue)) || (oldValue == null && oldValue != newValue)) { final WorkflowNodeCommand command = new SetConfigurationValueCommand(SshExecutorConstants.CONFIG_KEY_SCRIPT, oldValue, newValue); execute(node, command); } } }