blob: 4da7a6b0a5c41ea330a90e866e690cb614671c7a [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 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:
* Christophe Loetz (Loetz GmbH&Co.KG) - initial implementation
*
*
* This copyright notice shows up in the generated Java code
*
*/
package org.eclipse.osbp.xtext.strategy.jvmmodel
import javax.inject.Inject
import org.eclipse.osbp.ecview.core.common.model.core.YEmbeddable
import org.eclipse.osbp.ecview.core.common.model.core.YFocusable
import org.eclipse.osbp.ecview.core.common.model.core.YLayout
import org.eclipse.osbp.ecview.core.common.services.IWidgetAssocationsService
import org.eclipse.osbp.ecview.^extension.api.IFocusingStrategy
import org.eclipse.osbp.ecview.^extension.api.IFocusingStrategyProvider
import org.eclipse.osbp.ecview.^extension.model.YStrategyLayout
import org.eclipse.osbp.runtime.common.keystroke.KeyStrokeDefinition
import org.eclipse.osbp.utils.annotation.CommonUtils
import org.eclipse.osbp.xtext.strategy.FocusingEnum
import org.eclipse.osbp.xtext.strategy.FocusingStrategy
import org.eclipse.osbp.xtext.strategy.StrategyPackage
import org.eclipse.osbp.xtext.strategy.constants.StrategyConstants
import org.eclipse.xtext.common.types.JvmField
import org.eclipse.xtext.common.types.JvmGenericType
import org.eclipse.xtext.common.types.JvmVisibility
import org.eclipse.xtext.common.types.util.TypeReferences
import org.eclipse.xtext.xbase.jvmmodel.IJvmDeclaredTypeAcceptor
import org.eclipse.xtext.xbase.jvmmodel.JvmAnnotationReferenceBuilder
import org.eclipse.xtext.xbase.jvmmodel.JvmTypeReferenceBuilder
import org.eclipse.xtext.xbase.jvmmodel.JvmTypesBuilder
import org.osgi.service.component.annotations.Component
import org.eclipse.osbp.ecview.core.common.model.core.YElement
class StrategyDSLFocusingStrategyCreator {
@Inject extension JvmTypesBuilder
@Inject extension StrategyConstants
@Inject extension CommonUtils
@Inject
private TypeReferences references;
private JvmAnnotationReferenceBuilder _annotationTypesBuilder;
private JvmTypeReferenceBuilder _typeReferenceBuilder;
def void createFocusingStrategy(StrategyPackage pckg, FocusingStrategy focusingStrategy, IJvmDeclaredTypeAcceptor acceptor, JvmAnnotationReferenceBuilder annotationTypesBuilder, JvmTypeReferenceBuilder typeReferenceBuilder){
_annotationTypesBuilder = annotationTypesBuilder
_typeReferenceBuilder = typeReferenceBuilder
// creation of the IFocusingStrategy implementation
var clsStrategy = focusingStrategy.toClass('''«pckg.name».«focusingStrategy.strategyClassName»''')
clsStrategy.getSuperTypes().add(_typeReferenceBuilder.typeRef(typeof(IFocusingStrategy)))
acceptor.accept(clsStrategy,
[
// it.addTranslatorClassesFields(dialog, null, true)
// it.addTranslatorBindingFields(dialog)
it.toFields(focusingStrategy)
it.toOperations(focusingStrategy)
])
// creation of the IFocusingStrategyProvider implementation
var clsProvider = focusingStrategy.toClass('''«pckg.name».«focusingStrategy.strategyProviderClassName»''')
clsProvider.getSuperTypes().add(_typeReferenceBuilder.typeRef(typeof(IFocusingStrategyProvider)))
acceptor.accept(clsProvider,
[
var annotationRef = _annotationTypesBuilder.annotationRef(typeof(Component))
// create the Boolean type
// val booleanDeclaredType = references.findDeclaredType(typeof(Boolean), focusingStrategy) as JvmDeclaredType
annotationRef.addAnnAttr(focusingStrategy, /*references, booleanDeclaredType, */"immediate", true)
// val classDeclaredType = references.findDeclaredType(typeof(IFocusingStrategyProvider), focusingStrategy) as JvmDeclaredType
annotationRef.addAnnAttr(focusingStrategy, /*references, classDeclaredType, */"service", _typeReferenceBuilder.typeRef(IFocusingStrategyProvider))
var propContent = '''ecview.focusing.id=«focusingStrategy.ecviewFocusingId»'''
annotationRef.addAnnAttr(focusingStrategy, /*references, */"property", propContent)
annotations += annotationRef
// val componentAnnoParams = newArrayList("immediate=true", "service = IFocusingStrategyProvider.class");
// annotations += _annotationTypesBuilder.annotationRef(typeof(Component),componentAnnoParams)
// it.addTranslatorClassesFields(dialog, null, true)
// it.addTranslatorBindingFields(dialog)
it.toProviderFields(focusingStrategy)
it.toProviderOperations(focusingStrategy)
])
}
// Strategy Fields
def void toFields(JvmGenericType type, FocusingStrategy focusingStrategy) {
var JvmField field = null
// create index
field = focusingStrategy.toField('''down''', _typeReferenceBuilder.typeRef(boolean))
field.visibility = JvmVisibility.PRIVATE
field.documentation = '''Now fix, but it has to come from the StrategyDSL'''
field.initializer = ([append('''false''')])
type.members += field
}
// Strategy Methods
def void toOperations(JvmGenericType type, FocusingStrategy focusingStrategy){
// create focus
type.members += focusingStrategy.toMethod("focus", _typeReferenceBuilder.typeRef(Void::TYPE),
[
annotations += _annotationTypesBuilder.annotationRef(typeof(Override))
visibility = JvmVisibility.PUBLIC
parameters += focusingStrategy.toParameter("source", _typeReferenceBuilder.typeRef(Object))
parameters += focusingStrategy.toParameter("target", _typeReferenceBuilder.typeRef(Object))
parameters += focusingStrategy.toParameter("yLayout", _typeReferenceBuilder.typeRef(YStrategyLayout))
body = [append('''
YView yView = yLayout.getView();
IViewContext context = ModelUtil.getViewContext(yView);
IWidgetAssocationsService<Object, ? extends YElement> service = context.getService(IWidgetAssocationsService.ID);
YEmbeddable yCurrentFocus = (YEmbeddable) service.getModelElement(target);
// YEmbeddable yNextFocus = findElementToFocus(yCurrentFocus, yLayout);
YEmbeddable yNextFocus = findElementToFocus(yCurrentFocus, service);
yView.setCurrentFocus((YFocusable) yNextFocus);
''')]
])
// create new findElementToFocus
type.members += focusingStrategy.toMethod("findElementToFocus", _typeReferenceBuilder.typeRef(YEmbeddable),
[
visibility = JvmVisibility.PROTECTED
parameters += focusingStrategy.toParameter("yElement", _typeReferenceBuilder.typeRef(YEmbeddable))
parameters += focusingStrategy.toParameter("service", _typeReferenceBuilder.typeRef(IWidgetAssocationsService,_typeReferenceBuilder.typeRef(Object),_typeReferenceBuilder.wildcardExtends(_typeReferenceBuilder.typeRef(YElement))))
body = [append(focusingStrategy.findElementToFocus)]
])
// create getKeyStrokeDefinition
type.members += focusingStrategy.toMethod("getKeyStrokeDefinition", _typeReferenceBuilder.typeRef(KeyStrokeDefinition),
[
annotations += _annotationTypesBuilder.annotationRef(typeof(Override))
visibility = JvmVisibility.PUBLIC
body = [append(focusingStrategy.keyStrokeDefinitionBody)]
])
// create findNextFocusableColumnIdx
type.members += focusingStrategy.toMethod("findNextFocusableColumnIdx", _typeReferenceBuilder.typeRef(int),
[
visibility = JvmVisibility.PRIVATE
parameters += focusingStrategy.toParameter("focusable", _typeReferenceBuilder.typeRef(YFocusable))
body = [append(focusingStrategy.findColumnIdxFocusable)]
])
// create findNextColumnIdx
type.members += focusingStrategy.toMethod("findNextColumnIdx", _typeReferenceBuilder.typeRef(int),
[
visibility = JvmVisibility.PRIVATE
parameters += focusingStrategy.toParameter("idx", _typeReferenceBuilder.typeRef(int))
parameters += focusingStrategy.toParameter("columns", _typeReferenceBuilder.typeRef(int))
body = [append(focusingStrategy.findColumnIdx)]
])
}
def findColumnIdxFocusable(FocusingStrategy focusingStrategy)'''
return findNextColumnIdx(focusable.getLayoutIdx(), focusable.getLayoutColumns());
'''
def findColumnIdx(FocusingStrategy focusingStrategy)'''
if (idx % columns > columns) {
return findNextColumnIdx(idx % columns, columns);
}
return idx % columns;
'''
def getFindElementToFocus(FocusingStrategy focusingStrategy)'''
if (yElement == null) {
return null;
}
if (yElement instanceof YFocusable) {
YEmbeddable nextFocusElement = null;
int idx = ((YFocusable) yElement).getLayoutIdx();
// desired focus strategy to the next element is 'down'
if (down) {
«IF focusingStrategy.focus.literal.equals(FocusingEnum.FORWARD.literal)»
// next element below on forward focus is adding the number of layout columns to the current index
idx = idx + ((YFocusable) yElement).getLayoutColumns();
nextFocusElement = (YEmbeddable) service.getModelElement(idx);
if (nextFocusElement == null) {
// if no element was found to focus search for elements in the next column
nextFocusElement = (YEmbeddable) service.getModelElement(findNextFocusableColumnIdx(((YFocusable) yElement)) + 1);
}
«ELSEIF focusingStrategy.focus.literal.equals(FocusingEnum.BACKWARD.literal)»
if (idx == 1) {
// the current position is the first focusable element so the next focusable element backwards is
// the last focusable element of the last layout column
// finding the index of the last focusable element
«focusingStrategy.findLastElementToFocus»
// the last position of a focusable element in the last layout column
// subtracting the modulo operation between the last element index and the number of layout columns from the last element index
lastElementIdx = lastElementIdx - (lastElementIdx % ((YFocusable) yElement).getLayoutColumns());
nextFocusElement = (YEmbeddable) service.getModelElement(lastElementIdx);
} else {
// next element above on backward focus is subtracting the number of layout columns to the current index
int prevElementIdx = idx - ((YFocusable) yElement).getLayoutColumns();
nextFocusElement = (YEmbeddable) service.getModelElement(prevElementIdx);
if (nextFocusElement == null) {
// if no element was found to focus the current index is the first element of the current column
// so search for the last element in the previous column
// go to the index of the first element of the previous column
idx = idx - 1;
// find the last focusable element in this column
while ((YEmbeddable) service.getModelElement(idx) != null) {
nextFocusElement = (YEmbeddable) service.getModelElement(idx);
idx = idx + ((YFocusable) yElement).getLayoutColumns();
}
}
}
«ENDIF»
// desired focus strategy to the next element is 'right'
} else {
«IF focusingStrategy.focus.literal.equals(FocusingEnum.FORWARD.literal)»
nextFocusElement = (YEmbeddable) service.getModelElement(++idx);
«ELSEIF focusingStrategy.focus.literal.equals(FocusingEnum.BACKWARD.literal)»
nextFocusElement = (YEmbeddable) service.getModelElement(--idx);
«ENDIF»
if (nextFocusElement == null) {
«IF focusingStrategy.focus.literal.equals(FocusingEnum.FORWARD.literal)»
// if no element was found to focus go back to the first element
nextFocusElement = (YEmbeddable) service.getModelElement(0);
«ELSEIF focusingStrategy.focus.literal.equals(FocusingEnum.BACKWARD.literal)»
// if no element was found to focus go back to the last focusable element
«focusingStrategy.findLastElementToFocus»
nextFocusElement = (YEmbeddable) service.getModelElement(lastElementIdx);
«ENDIF»
}
}
if (nextFocusElement instanceof YField) {
YField field = ((YField) nextFocusElement);
if (!field.isEditable() || !field.isEnabled() || !field.isVisible()) {
nextFocusElement = findElementToFocus(nextFocusElement, service);
}
}
return nextFocusElement;
}
return null;'''
def getFindLastElementToFocus(FocusingStrategy focusingStrategy) '''
// finding the index of the last focusable element
int lastElementIdx = 0;
for (YElement element : service.getModelElements()) {
if (element instanceof YFocusable) {
int layoutIdx = ((YFocusable) element).getLayoutIdx();
lastElementIdx = lastElementIdx < layoutIdx ? layoutIdx : lastElementIdx;
}
}'''
def String findNextElementToFocusInSingularLayout(FocusingStrategy focusingStrategy){
return '''
int idx = getIndexToFocus(yParent, index);
return yParent.getElements().get(idx);'''
}
def String findNextElementToFocusInAComplexLayout(FocusingStrategy focusingStrategy){
return '''
int layoutElementListSize = layout.getElements().size();
// in case of more than one element
if (layoutElementListSize > 0){
for (int i = 0; i < layoutElementListSize; i++) {
YEmbeddable layoutElement = layout.getElement(i);
// in case that the layout elements are again layouts
if (layoutElement instanceof YLayout){
// in case that the layout containing the focus event sending element is found
if (yParent.equals(layoutElement)){
«IF focusingStrategy.focus.literal.equals(FocusingEnum.FORWARD.literal)»
if (i!=layoutElementListSize-1){
i = i+1;
} else {
i = 0;
}
// find next layout
YLayout yParentTemp = (YLayout)layout.getElement(i);
// get the first element of the layout
return yParentTemp.getElement(0);
«ELSEIF focusingStrategy.focus.literal.equals(FocusingEnum.BACKWARD.literal)»
if (i!=0){
i = i-1;
} else {
i = layoutElementListSize - 1;
}
// find next layout
YLayout yParentTemp = (YLayout)layout.getElement(i);
// get the last element of the layout
int idx = yParentTemp.getElements().size() - 1;
return yParentTemp.getElement(idx);
«ENDIF»
} else {
YEmbeddable yEmbeddable = findNextElementToFocusInAComplexLayout(yParent, (YLayout)layoutElement, index);
// without this if statement the for loop will be broken.
if (yEmbeddable!=null){
return yEmbeddable;
}
}
}
}
} else {
YEmbeddable layoutElement = layout.getElement(0);
// in case that the layout containing the focus event sending element is found
if (yParent.equals(layoutElement)){
return findNextElementToFocusInSingularLayout(yParent, index);
} else {
// in case that the layout elements are again layouts
if (layoutElement instanceof YLayout){
return findNextElementToFocusInAComplexLayout(yParent, (YLayout)layoutElement, index);
}
}
}
return null;'''
}
def String getIndexToFocus(FocusingStrategy focusingStrategy){
var body = '''int index = idx;'''
if (focusingStrategy.focus.literal.equals(FocusingEnum.FORWARD.literal)){
body = '''«body»«forwardFocusBodyCode»'''
} else if (focusingStrategy.focus.literal.equals(FocusingEnum.BACKWARD.literal)){
body = '''«body»«backwardFocusBodyCode»'''
}
return '''«body»return index;'''
}
def String getKeyStrokeDefinitionBody(FocusingStrategy focusingStrategy){
var body = ''''''
var modifierKeysLength = 0
if (focusingStrategy.modifierKeys!=null){
modifierKeysLength = focusingStrategy.modifierKeys.length
}
body = '''«body»int[] modifierKeys = new int[«modifierKeysLength»];'''
if (!focusingStrategy.modifierKeys.empty){
var idx = 0
for (modifierKey : focusingStrategy.modifierKeys){
body = '''«body»
modifierKeys[«idx»] = ModifierKey.«modifierKey»;'''
idx++
}
}
if (focusingStrategy.keyCode!=null && !focusingStrategy.keyCode.empty){
body = '''«body»
KeyStrokeDefinition def = new KeyStrokeDefinition("", KeyCode.«focusingStrategy.keyCode», modifierKeys);
return def;'''
}
return body
}
def getForwardFocusBodyCode() '''
if (index == yParent.getElements().size() - 1) {
// element is the last -> Start again
index = 0;
} else {
// use the next element
index = index + 1;
}
'''
def getBackwardFocusBodyCode() '''
if (index == 0) {
// element is the first -> Start again
index = yParent.getElements().size() - 1;
} else {
// use the previous element
index = index - 1;
}
'''
// Provider Methods
/**
* <p>build the class variables.</p>
*
*/
def void toProviderFields(JvmGenericType type, FocusingStrategy focusingStrategy){
var JvmField field = null
// create logger
field = focusingStrategy.toField("ID", _typeReferenceBuilder.typeRef(String))[
setInitializer([append('''"«focusingStrategy.ecviewFocusingId»"''')])]
field.final = true
field.static = true
type.members += field
}
def void toProviderOperations(JvmGenericType type, FocusingStrategy focusingStrategy){
// create focus
type.members += focusingStrategy.toMethod("getStrategy", _typeReferenceBuilder.typeRef(IFocusingStrategy),
[
annotations += _annotationTypesBuilder.annotationRef(typeof(Override))
visibility = JvmVisibility.PUBLIC
body = [append('''return new «focusingStrategy.strategyClassName»();''')]
])
}
// Helper Methods
def getStrategyClassName(FocusingStrategy focusingStrategy)'''«focusingStrategy.name»«focusingStrategy.focus.literal»«FOCUSING_STRATEGY_PREFIX»'''
def getStrategyProviderClassName(FocusingStrategy focusingStrategy)'''«focusingStrategy.name»«focusingStrategy.focus.literal»«FOCUSING_STRATEGY_PROVIDER_PREFIX»'''
}