| /** |
| * |
| * 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»''' |
| } |