blob: 5f2159ba3dfaadec0368be34a6868a49561ae4ea [file] [log] [blame]
/*****************************************************************************
* 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();
}
}