blob: e7008beef90980687902211f0cd66d411a14148d [file] [log] [blame]
/**
*
* Copyright (c) 2011, 2016 - Loetz GmbH&Co.KG (69115 Heidelberg, Germany)
*
* 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:
* Christophe Loetz (Loetz GmbH&Co.KG) - initial implementation
*
*
* This copyright notice shows up in the generated Java code
*
*/
package org.eclipse.osbp.xtext.topologydsl.jvmmodel
import com.vaadin.ui.Component
import com.vaadin.ui.VerticalLayout
import java.util.Locale
import javax.annotation.PostConstruct
import javax.annotation.PreDestroy
import javax.inject.Inject
import org.eclipse.e4.core.contexts.IEclipseContext
import org.eclipse.e4.core.services.events.IEventBroker
import org.eclipse.e4.ui.model.application.MApplication
import org.eclipse.osbp.osgi.hybrid.api.AbstractHybridVaaclipseView
import org.eclipse.osbp.ui.api.metadata.IDSLMetadataService
import org.eclipse.osbp.ui.api.user.IUser
import org.eclipse.osbp.utils.constants.GeneratorConstants
import org.eclipse.osbp.utils.theme.EnumCssClass
import org.eclipse.osbp.utils.vaadin.ViewLayoutManager
import org.eclipse.osbp.xtext.topologydsl.Topology
import org.eclipse.osbp.xtext.topologydsl.TopologyPackage
import org.eclipse.xtext.common.types.JvmDeclaredType
import org.eclipse.xtext.common.types.JvmField
import org.eclipse.xtext.common.types.JvmVisibility
import org.eclipse.xtext.naming.IQualifiedNameProvider
import org.eclipse.xtext.xbase.jvmmodel.AbstractModelInferrer
import org.eclipse.xtext.xbase.jvmmodel.IJvmDeclaredTypeAcceptor
import org.eclipse.xtext.xbase.jvmmodel.JvmTypesBuilder
import org.osgi.service.event.EventHandler
import org.slf4j.Logger
/**
* <p>
* This inferrer infers models of extension .topology and generates code to be used by a e4 application as view. Underlying components
* are from the vaadin component repository and especially JavaScript components based on D3.
* </p>
*
* @author Jose Dominguez
*/
/**
* <p>Infers a JVM model from the source model.</p>
*
* <p>The JVM model should contain all elements that would appear in the Java code
* which is generated from the source model. Other models link against the JVM model rather than the source model.</p>
*/
class TopologyDSLJvmModelInferrer extends AbstractModelInferrer {
/**
* convenience API to build and initialize JVM types and their members.
*/
@Inject extension IQualifiedNameProvider
@Inject extension JvmTypesBuilder
@Inject extension TopologyDSLD3JavaComponentsCreator
def dispatch void infer(TopologyPackage pckg, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {
for (Topology topology : pckg.topologies) {
var cls = topology.toClass(pckg.name.concat(".").concat(topology.name).concat("Topology"))
cls.superTypes.add(_typeReferenceBuilder.typeRef(AbstractHybridVaaclipseView))
cls.superTypes.add(_typeReferenceBuilder.typeRef(IUser.UserLocaleListener))
acceptor.accept(cls,
[
documentation = GeneratorConstants.GENERATED_CLASSES_DOCUMENTATION
it.toFields(topology)
it.toConstructor(topology)
it.toOperations(topology)
])
topology.createJsJavaComponent(acceptor)
}
}
/**
* <p>build the constructors to be used by an e4 application.</p>
*
*/
def void toConstructor(JvmDeclaredType type, Topology topology) {
type.members += topology.toConstructor(
[
annotations += _annotationTypesBuilder.annotationRef(Inject)
parameters += topology.toParameter("parent", _typeReferenceBuilder.typeRef(VerticalLayout))
parameters += topology.toParameter("context", _typeReferenceBuilder.typeRef(IEclipseContext))
parameters += topology.toParameter("app", _typeReferenceBuilder.typeRef(MApplication))
body = [append('''super(parent,context,app);''')]
])
}
/**
* <p>build the class variables.</p>
*
*/
def void toFields(JvmDeclaredType type, Topology topology) {
var JvmField field = null
// create logger
field = topology.toField("log", _typeReferenceBuilder.typeRef(Logger))[setInitializer([append('''org.slf4j.LoggerFactory.getLogger("topology")''')])]
field.static = true
field.visibility = JvmVisibility::PRIVATE
type.members += field
field = topology.toField("layoutManager", _typeReferenceBuilder.typeRef(ViewLayoutManager))
type.members += field
field = topology.toField("dataComponent", _typeReferenceBuilder.typeRef(Component))
type.members += field
field = topology.toField("eventBroker", _typeReferenceBuilder.typeRef(IEventBroker))[
annotations += _annotationTypesBuilder.annotationRef(Inject)]
type.members += field
field = topology.toField("refreshView", _typeReferenceBuilder.typeRef(EventHandler))
type.members += field
field = topology.toField("panelWidth", _typeReferenceBuilder.typeRef(int))
type.members += field
field = topology.toField("panelHeight", _typeReferenceBuilder.typeRef(int))
type.members += field
field = topology.toField("dslMetadataService", _typeReferenceBuilder.typeRef(IDSLMetadataService)) [annotations += _annotationTypesBuilder.annotationRef(Inject)]
type.members += field
field = topology.toField("locale", _typeReferenceBuilder.typeRef(Locale))
type.members += field
field = topology.toField("user", _typeReferenceBuilder.typeRef(IUser))[annotations += _annotationTypesBuilder.annotationRef(Inject)]
type.members += field
}
/**
* <p>build the methods.</p>
*
*/
def void toOperations(JvmDeclaredType type, Topology topology) {
// create view
type.members += topology.toMethod("createView", _typeReferenceBuilder.typeRef(Void::TYPE),
[
parameters += topology.toParameter("parent", _typeReferenceBuilder.typeRef(VerticalLayout))
body = [append('''«topology.createView»''')]
])
// create components
type.members += topology.toMethod("createComponents", _typeReferenceBuilder.typeRef(Void::TYPE),
[
body = [append('''«topology.createComponents»''')]
])
// create D3 Topology
type.members += topology.toMethod("createD3Topology", _typeReferenceBuilder.typeRef(Component),
[
body = [append('''«topology.createD3Topology»''')]
])
// subscribe to eventBroker
type.members += topology.toMethod("subscribe", _typeReferenceBuilder.typeRef(Void::TYPE),
[
visibility = JvmVisibility.PROTECTED
annotations += _annotationTypesBuilder.annotationRef(PostConstruct)
body = [append('''«topology.subscribe»''')]
])
// unsubscribe from eventBroker
type.members += topology.toMethod("unsubscribe", _typeReferenceBuilder.typeRef(Void::TYPE),
[
visibility = JvmVisibility.PROTECTED
annotations += _annotationTypesBuilder.annotationRef(PreDestroy)
body = [append('''«topology.unsubscribe»''')]
])
// locale notification
type.members += topology.toMethod("localeChanged", _typeReferenceBuilder.typeRef(Void::TYPE),
[
visibility = JvmVisibility.PUBLIC
annotations += _annotationTypesBuilder.annotationRef(Override)
parameters += topology.toParameter("locale", _typeReferenceBuilder.typeRef(Locale))
body = [append('''«topology.localeChanged»''')]
])
}
// subscribe to view refresh
def subscribe(Topology topology) '''
eventBroker.subscribe(EventBrokerMsg.REFRESH_VIEW+"«topology.name»Topology", refreshView);'''
def unsubscribe(Topology topology) '''
eventBroker.unsubscribe(refreshView);'''
/**
* <p>build the main method to be called from e4.</p>
*
*/
def String createView(Topology topology) {
var body = '''
layoutManager = new ViewLayoutManager();
layoutManager.init(parent);
refreshView = «topology.refreshView»
user.addUserLocaleListener(this);
// to resize the chart according to split positions of partsashcontainer - setContainerData is tracked
((EObject)getPart()).eAdapters().add(new AdapterImpl() {
public void notifyChanged(Notification notification) {
if (notification.getEventType()==Notification.SET &&
notification.getFeatureID(UIElementImpl.class) == UiPackageImpl.UI_ELEMENT__CONTAINER_DATA)
{
log.debug("render due to split position changed");
renderData();
}
}
});
SizeReporter sizeReporter = new SizeReporter(layoutManager.getDataArea());
sizeReporter.addResizeListener(new ComponentResizeListener() {
@Override
public void sizeChanged(ComponentResizeEvent event) {
boolean changed = false;
if (panelWidth != event.getWidth()) {
changed = true;
panelWidth = event.getWidth();
}
if (panelHeight != event.getHeight()) {
changed = true;
panelHeight = event.getHeight();
}
if (changed) {
log.debug("Panel size changed : " + event.getWidth() + " x " + event.getHeight());
renderData();
}
}
});
'''
return body
}
/**
* <p>create a handler for external triggered refresh requests.</p>
*
*/
def String refreshView(Topology topology) {
var body = ""
body = '''
«body»
new EventHandler() {
@Override
public void handleEvent(Event event) {
renderData();
}
};
'''
return body
}
/**
* <p>build the data components.</p>
*
*/
def String createComponents(Topology topology) {
var body = '''
if (panelWidth == 0 && panelHeight == 0) {
return;
}
log.debug("topology creates components");
try {
// remove any previous component
if (dataComponent != null) {
layoutManager.getDataArea().removeComponent(dataComponent);
dataComponent = null;
}
// generate a new result component
dataComponent = createD3Topology();
dataComponent.setSizeFull();
dataComponent.addStyleName("«EnumCssClass.DATA_COMPONENT.styleName»"); // <== is THIS necessary any more???
layoutManager.getDataArea().addComponent(dataComponent);
layoutManager.getDataArea().setExpandRatio(dataComponent, 1);
} catch (Exception e) {
log.error(e.getLocalizedMessage());
}
log.debug("topology creating components finished");
'''
return body
}
def localeChanged(Topology topology)
'''
if(layoutManager != null) {
layoutManager.setLabelValue(dslMetadataService.translate(locale.toLanguageTag(), "«topology.titleValue»"));
}
'''
}