/* * SoapUI, Copyright (C) 2004-2016 SmartBear Software * * Licensed under the EUPL, Version 1.1 or - as soon as they will be approved by the European Commission - subsequent * versions of the EUPL (the "Licence"); * You may not use this work except in compliance with the Licence. * You may obtain a copy of the Licence at: * * http://ec.europa.eu/idabc/eupl * * Unless required by applicable law or agreed to in writing, software distributed under the Licence is * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the Licence for the specific language governing permissions and limitations * under the Licence. */ package com.eviware.soapui.impl.wsdl.panels.teststeps.support; import com.eviware.soapui.impl.wsdl.WsdlProject; import com.eviware.soapui.model.settings.Settings; import com.eviware.soapui.model.settings.SettingsListener; import com.eviware.soapui.model.support.ModelSupport; import com.eviware.soapui.settings.UISettings; import com.eviware.soapui.support.DocumentListenerAdapter; import com.eviware.soapui.support.UISupport; import com.eviware.soapui.support.components.JEditorStatusBar.JEditorStatusBarTarget; import com.eviware.soapui.support.scripting.groovy.GroovyScriptEngineFactory; import com.eviware.soapui.support.scripting.js.JsScriptEngineFactory; import com.eviware.soapui.support.xml.actions.EnableLineNumbersAction; import com.eviware.soapui.support.xml.actions.FormatXmlAction; import com.eviware.soapui.support.xml.actions.GoToLineAction; import com.eviware.soapui.ui.support.FindAndReplaceDialogView; import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; import org.fife.ui.rsyntaxtextarea.SyntaxConstants; import org.fife.ui.rtextarea.RTextScrollPane; import javax.swing.Action; import javax.swing.BorderFactory; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.KeyStroke; import javax.swing.event.CaretListener; import javax.swing.text.Document; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import static com.eviware.soapui.impl.wsdl.teststeps.Script.SCRIPT_PROPERTY; /** * Groovy editor wrapper * * @author ole.matzura */ public class GroovyEditor extends JPanel implements JEditorStatusBarTarget, PropertyChangeListener { private final RSyntaxTextArea editArea; private final GoToLineAction goToLineAction; private final EnableLineNumbersAction enableLineNumbersAction; private FindAndReplaceDialogView findAndReplaceDialog; private FormatXmlAction formatXmlAction; private GroovyEditorModel model; private final InternalSettingsListener settingsListener; private final GroovyDocumentListener groovyDocumentListener; private final RTextScrollPane scrollPane; private boolean updating; public GroovyEditor(GroovyEditorModel model) { super(new BorderLayout()); this.model = model; model.addPropertyChangeListener(this); Settings settings = model.getSettings(); Font editorFont = UISupport.getEditorFont(settings); editArea = new RSyntaxTextArea(); editArea.restoreDefaultSyntaxScheme(); String defaultScriptLanguage = ((WsdlProject) ModelSupport.getModelItemProject(model.getModelItem())) .getDefaultScriptLanguage(); if (defaultScriptLanguage.equals(GroovyScriptEngineFactory.ID)) { editArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_GROOVY); } else if (defaultScriptLanguage.equals(JsScriptEngineFactory.ID)) { editArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_JAVASCRIPT); } editArea.setFont(editorFont); editArea.setBorder(BorderFactory.createMatteBorder(0, 2, 0, 0, Color.WHITE)); editArea.setText(model.getScript()); editArea.setCaretPosition(0); editArea.setHighlightCurrentLine(false); Action runAction = model.getRunAction(); if (runAction != null) { editArea.getInputMap().put(KeyStroke.getKeyStroke("alt ENTER"), "run-action"); editArea.getActionMap().put("run-action", runAction); } groovyDocumentListener = new GroovyDocumentListener(); editArea.getDocument().addDocumentListener(groovyDocumentListener); settingsListener = new InternalSettingsListener(); settings.addSettingsListener(settingsListener); scrollPane = new RTextScrollPane(editArea, true); scrollPane.setPreferredSize(new Dimension(500, 300)); add(scrollPane); UISupport.addPreviewCorner(scrollPane, true); addFocusListener(new FocusAdapter() { public void focusGained(FocusEvent e) { editArea.requestFocusInWindow(); } }); JPopupMenu popup = editArea.getPopupMenu(); findAndReplaceDialog = new FindAndReplaceDialogView(editArea); if (UISupport.isMac()) { editArea.getInputMap().put(KeyStroke.getKeyStroke("meta F"), findAndReplaceDialog); } else { editArea.getInputMap().put(KeyStroke.getKeyStroke("ctrl F"), findAndReplaceDialog); } popup.add(findAndReplaceDialog); popup.addSeparator(); goToLineAction = new GoToLineAction(editArea, "Go To Line"); enableLineNumbersAction = new EnableLineNumbersAction(scrollPane, "Show Line Numbers"); popup.add(goToLineAction); popup.add(enableLineNumbersAction); editArea.getInputMap().put(KeyStroke.getKeyStroke("control G"), goToLineAction); editArea.getInputMap().put(KeyStroke.getKeyStroke("control L"), enableLineNumbersAction); editArea.setComponentPopupMenu(popup); } @Override public void setEnabled(boolean enabled) { super.setEnabled(enabled); editArea.setEnabled(enabled); } public RSyntaxTextArea getEditArea() { return editArea; } public void release() { if (model != null) { model.getSettings().removeSettingsListener(settingsListener); model.removePropertyChangeListener(this); } model = null; editArea.getDocument().removeDocumentListener(groovyDocumentListener); } public void selectError(String message) { int ix = message == null ? -1 : message.indexOf("@ line "); if (ix >= 0) { try { int ix2 = message.indexOf(',', ix); int line = ix2 == -1 ? Integer.parseInt(message.substring(ix + 6).trim()) : Integer.parseInt(message .substring(ix + 6, ix2).trim()); int column = 0; if (ix2 != -1) { ix = message.indexOf("column ", ix2); if (ix >= 0) { ix2 = message.indexOf('.', ix); column = ix2 == -1 ? Integer.parseInt(message.substring(ix + 7).trim()) : Integer .parseInt(message.substring(ix + 7, ix2).trim()); } } editArea.setCaretPosition(editArea.getLineStartOffset(line - 1) + column - 1); } catch (Exception ex) { } editArea.requestFocus(); } } private final class GroovyDocumentListener extends DocumentListenerAdapter { public void update(Document document) { if (!updating) { GroovyEditor.this.model.setScript(editArea.getText()); } } } private final class InternalSettingsListener implements SettingsListener { public void settingChanged(String name, String newValue, String oldValue) { if (name.equals(UISettings.EDITOR_FONT)) { Font newFont = Font.decode(newValue); setEditorFont(newFont); invalidate(); } } @Override public void settingsReloaded() { // TODO Auto-generated method stub } } public void setEditorFont(Font newFont) { editArea.setFont(newFont); } public void addCaretListener(CaretListener listener) { editArea.addCaretListener(listener); } public int getCaretPosition() { return editArea.getCaretPosition(); } public int getLineOfOffset(int offset) throws Exception { return editArea.getLineOfOffset(offset); } public int getLineStartOffset(int line) throws Exception { return editArea.getLineStartOffset(line); } public void removeCaretListener(CaretListener listener) { editArea.removeCaretListener(listener); } public void propertyChange(PropertyChangeEvent evt) { if (evt.getPropertyName().equals(SCRIPT_PROPERTY)) { updating = true; editArea.setText(String.valueOf(evt.getNewValue())); updating = false; } } }