| /***************************************************************************** |
| * Copyright (c) 2019 CEA LIST. |
| * |
| * |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Xavier Le Pallec (for CEA LIST) xlepallec@lilo.org - Bug 558456 |
| * |
| *****************************************************************************/ |
| |
| package org.eclipse.papyrus.uml.diagram.clazz.lf.classtextualedition.swt; |
| |
| import org.eclipse.draw2d.geometry.Rectangle; |
| import org.eclipse.gef.EditPart; |
| import org.eclipse.gmf.runtime.diagram.ui.editparts.CompartmentEditPart; |
| import org.eclipse.papyrus.uml.diagram.clazz.lf.classtextualedition.Activator; |
| import org.eclipse.papyrus.uml.diagram.clazz.lf.classtextualedition.javascript.functions.FunctionsFactory; |
| import org.eclipse.papyrus.uml.diagram.clazz.lf.classtextualedition.webpages.HtmlPage; |
| import org.eclipse.papyrus.uml.diagram.clazz.lf.classtextualedition.webpages.ResourceAccessUtils; |
| import org.eclipse.papyrus.uml.diagram.common.editparts.ClassEditPart; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.graphics.Point; |
| import org.eclipse.swt.layout.FillLayout; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.ui.PlatformUI; |
| |
| import com.sun.javafx.webkit.WebConsoleListener; |
| |
| import javafx.embed.swt.FXCanvas; |
| import javafx.scene.Scene; |
| import javafx.scene.input.KeyCode; |
| import javafx.scene.input.KeyEvent; |
| import javafx.scene.web.WebEngine; |
| import javafx.scene.web.WebView; |
| import netscape.javascript.JSObject; |
| |
| /** |
| * This class aims at constructing the window that displays the editor. This |
| * class uses a browser widget that allows to load web pages: the editor is made |
| * with web technologies (html, css, javascript). |
| * |
| */ |
| public class UmlClassHTMLEditionDialog { |
| |
| static final String PREFIX = "/html/umlclasseditor/"; //$NON-NLS-1$ |
| static final String PREFIX_LIB = PREFIX + "lib/"; //$NON-NLS-1$ |
| static final String PREFIX_LIB_SCRIPTS = PREFIX_LIB + "scripts/"; //$NON-NLS-1$ |
| static final String PREFIX_LIB_STYLES = PREFIX_LIB + "styles/"; //$NON-NLS-1$ |
| static final String PREFIX_SCRIPTS = PREFIX + "scripts/"; //$NON-NLS-1$ |
| static final String PREFIX_STYLES = PREFIX + "styles/"; //$NON-NLS-1$ |
| |
| static final int EDITOR_WIDTH = 300; |
| static final int EDITOR_HEIGHT = 200; |
| static final int SPACE_BETWEEN_CLASS_AND_EDITOR = 5; |
| private ClassEditPart editPart; |
| private Shell shell; |
| static final String[] cssFiles = { PREFIX_LIB_STYLES + "docs.css", PREFIX_LIB_STYLES + "codemirror.css", //$NON-NLS-1$ //$NON-NLS-2$ |
| PREFIX_LIB_STYLES + "show-hint.css", PREFIX_STYLES + "uml.css" }; //$NON-NLS-1$ //$NON-NLS-2$ |
| static final String[] scripts = { PREFIX_LIB_SCRIPTS + "codemirror.js", PREFIX_LIB_SCRIPTS + "show-hint.js", //$NON-NLS-1$ //$NON-NLS-2$ |
| PREFIX_SCRIPTS + "utils.js", PREFIX_SCRIPTS + "logFunction.js", PREFIX_SCRIPTS + "javaProxy.js", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| PREFIX_SCRIPTS + "readingTokens.js", PREFIX_SCRIPTS + "statesTypesAndLabels.js", //$NON-NLS-1$ //$NON-NLS-2$ |
| PREFIX_SCRIPTS + "autoComplete.js", PREFIX_SCRIPTS + "errorManagment.js", //$NON-NLS-1$ //$NON-NLS-2$ |
| PREFIX_SCRIPTS + "editorStateMachine.js", PREFIX_SCRIPTS + "propertyManagment.js" }; //$NON-NLS-1$ //$NON-NLS-2$ |
| |
| private static final Activator LOGGER = Activator.getDefault(); |
| |
| private WebView browser; |
| private WebEngine engine; |
| private FXCanvas fxCanvas; |
| |
| /** |
| * The constructor takes a class (edit part) on which the editor will be based. |
| * The constructor also launches the initialization of the component (and so the |
| * whole display). |
| * |
| * @param editPart |
| * the class (edit part) |
| */ |
| UmlClassHTMLEditionDialog(ClassEditPart editPart) { |
| this.editPart = editPart; |
| init(); |
| } |
| |
| /** |
| * The initialization of the component (and so the whole display): it constructs |
| * the dialog box, load the whole web page and show the dialog box. |
| */ |
| private void init() { |
| |
| constructDialog(); |
| constructBrowserInDialog(); |
| showDialog(); |
| fxCanvas.setFocus(); |
| browser.requestFocus(); |
| |
| } |
| |
| /** |
| * Display the dialog box and makes the focus on it. |
| */ |
| private void showDialog() { |
| shell.open(); |
| shell.forceFocus(); |
| } |
| |
| /** |
| * Constructs the browser component, load the html page, all the Java-Javascript |
| * functions and the key listener (ESC to escape without validate). |
| */ |
| private void constructBrowserInDialog() { |
| fxCanvas = new FXCanvas(shell, SWT.NONE); |
| shell.setLayout(new FillLayout()); |
| browser = new WebView(); |
| engine = browser.getEngine(); |
| engine.setJavaScriptEnabled(true); |
| Scene scene = new Scene(browser); |
| fxCanvas.setScene(scene); |
| |
| redirectConsoleLog(); |
| |
| initJSObjectProxy(); |
| |
| loadHtmlPage(); |
| |
| addKeyListenerForBrowser(); |
| |
| } |
| |
| protected void initJSObjectProxy() { |
| JSObject window = (JSObject) engine.executeScript("window"); //$NON-NLS-1$ |
| window.setMember("javaTextualEditor", FunctionsFactory.getInstance().createObjectWithFunctions(this, editPart)); //$NON-NLS-1$ |
| } |
| |
| protected void redirectConsoleLog() { |
| WebConsoleListener.setDefaultListener((webView, message, lineNumber, sourceId) -> { |
| LOGGER.logInfo(message + "[at " + lineNumber + "]"); //$NON-NLS-1$ //$NON-NLS-2$ |
| }); |
| } |
| |
| /** |
| * Loads the html page: load all the css, javascripts and html pages that |
| * compose the editor. For this, it uses functions from |
| * {@link org.eclipse.papyrus.uml.diagram.clazz.lf.classtextualedition.webpages.HtmlPage}. |
| */ |
| private void loadHtmlPage() { |
| |
| ResourceAccessUtils.getInstance().getContentOfFileLocatedInTheJar(PREFIX + "body.html"); //$NON-NLS-1$ |
| engine.loadContent(HtmlPage.getInstance().createHtmlContentFromHeadScriptBody(PREFIX + "head.html", cssFiles, scripts, //$NON-NLS-1$ |
| PREFIX + "body.html")); //$NON-NLS-1$ |
| } |
| |
| /** |
| * Adds the ESC pressed listener. |
| */ |
| private void addKeyListenerForBrowser() { |
| browser.setOnKeyPressed((KeyEvent event) -> { |
| if (event.getCode() == KeyCode.ESCAPE) { |
| close(); |
| } |
| }); |
| } |
| |
| /** |
| * Constructs the dialog box (and set corresponding bounds |
| */ |
| private void constructDialog() { |
| Rectangle epBound = editPart.getFigure().getBounds().getCopy(); |
| editPart.getFigure().translateToAbsolute(epBound); |
| |
| Point absoluteLocationOfUmlClass = editPart.getViewer().getControl().toDisplay(epBound.getTopRight().x, epBound.getTopRight().y); |
| shell = new Shell(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), SWT.APPLICATION_MODAL); |
| shell.setLayout(new FillLayout()); |
| shell.setBounds(absoluteLocationOfUmlClass.x + SPACE_BETWEEN_CLASS_AND_EDITOR, |
| absoluteLocationOfUmlClass.y, EDITOR_WIDTH, EDITOR_HEIGHT); |
| |
| } |
| |
| protected Rectangle getEditPartBounds() { |
| Rectangle bounds = editPart.getFigure().getBounds().getCopy(); |
| |
| // computer translation according to possible containers |
| |
| EditPart parent = editPart.getParent(); |
| while (parent != null) { |
| if (parent instanceof CompartmentEditPart) { |
| CompartmentEditPart compartment = CompartmentEditPart.class.cast(parent); |
| Rectangle compartmentBounds = compartment.getFigure().getBounds(); |
| bounds.x += compartmentBounds.x; |
| bounds.y += compartmentBounds.y; |
| } |
| parent = parent.getParent(); |
| } |
| |
| return bounds; |
| } |
| |
| /** |
| * This method is called by the javascript function closeAndPerform (just to |
| * close the dialog box). |
| */ |
| public void closeAndPerform() { |
| close(); |
| } |
| |
| /** |
| * Closes the dialog box |
| */ |
| protected void close() { |
| shell.dispose(); |
| } |
| |
| } |