/* * Copyright 2015 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.kie.workbench.common.screens.datamodeller.client.widgets.advanceddomain.annotationlisteditor; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.annotation.PreDestroy; import javax.enterprise.context.Dependent; import javax.enterprise.inject.Instance; import javax.inject.Inject; import com.google.gwt.user.client.ui.IsWidget; import com.google.gwt.user.client.ui.Widget; import org.jboss.errai.common.client.api.Caller; import org.jboss.errai.common.client.api.RemoteCallback; import org.kie.workbench.common.screens.datamodeller.client.resources.i18n.Constants; import org.kie.workbench.common.screens.datamodeller.client.widgets.advanceddomain.annotationlisteditor.item.AnnotationListItem; import org.kie.workbench.common.screens.datamodeller.client.widgets.advanceddomain.valuepaireditor.ValuePairEditorPopup; import org.kie.workbench.common.screens.datamodeller.client.widgets.advanceddomain.valuepaireditor.ValuePairEditorPopupView; import org.kie.workbench.common.screens.datamodeller.service.DataModelerService; import org.kie.workbench.common.services.datamodeller.core.Annotation; import org.kie.workbench.common.services.datamodeller.core.AnnotationDefinition; import org.kie.workbench.common.services.datamodeller.core.AnnotationValuePairDefinition; import org.kie.workbench.common.services.datamodeller.core.ElementType; import org.kie.workbench.common.services.datamodeller.driver.model.AnnotationParseRequest; import org.kie.workbench.common.services.datamodeller.driver.model.AnnotationParseResponse; import org.kie.workbench.common.services.datamodeller.driver.model.AnnotationSource; import org.kie.workbench.common.services.datamodeller.driver.model.AnnotationSourceRequest; import org.kie.workbench.common.services.datamodeller.driver.model.AnnotationSourceResponse; import org.kie.workbench.common.services.datamodeller.driver.model.DriverError; import org.kie.workbench.common.services.shared.project.KieProject; import org.uberfire.client.callbacks.Callback; import org.uberfire.mvp.Command; @Dependent public class AdvancedAnnotationListEditor implements IsWidget, AdvancedAnnotationListEditorView.Presenter { private AdvancedAnnotationListEditorView view; private AdvancedAnnotationListEditorView.DeleteAnnotationHandler deleteAnnotationHandler; private AdvancedAnnotationListEditorView.ClearValuePairHandler clearValuePairHandler; private AdvancedAnnotationListEditorView.ValuePairChangeHandler valuePairChangeHandler; private AdvancedAnnotationListEditorView.AddAnnotationHandler addAnnotationHandler; private Caller<DataModelerService> modelerService; private Instance<ValuePairEditorPopup> valuePairEditorInstance; private Instance<AnnotationListItem> itemInstance; private Map<String, AnnotationSource> annotationSources; private List<Annotation> annotations; private Map< Annotation, AnnotationListItem > annotationItems = new HashMap< Annotation, AnnotationListItem >( ); private Map< String, Boolean > annotationStatus = new HashMap< String, Boolean >( ); private KieProject project; private ElementType elementType; private boolean readonly = false; private Command deleteAnnotationCommand; private Command noActionCommand; private Callback<Annotation> addAnnotationCallback; @Inject public AdvancedAnnotationListEditor( AdvancedAnnotationListEditorView view, Caller<DataModelerService> modelerService, Instance<ValuePairEditorPopup> valuePairEditorInstance, Instance<AnnotationListItem> itemInstance ) { this.view = view; view.init( this ); this.modelerService = modelerService; this.valuePairEditorInstance = valuePairEditorInstance; this.itemInstance = itemInstance; } @Override public Widget asWidget() { return view.asWidget(); } public void init( final KieProject project, final ElementType elementType ) { this.project = project; this.elementType = elementType; } public void loadAnnotations( List<Annotation> annotations ) { this.annotations = annotations; if ( annotations != null && annotations.size() > 0 ) { AnnotationSourceRequest sourceRequest = new AnnotationSourceRequest(); sourceRequest.withAnnotations( annotations ); modelerService.call( getLoadAnnotationSourcesSuccessCallback() ) .resolveSourceRequest( sourceRequest ); } } public void loadAnnotations( List< Annotation > annotations, Map< String, AnnotationSource > annotationSources ) { view.clear( ); clearListItems(); this.annotationSources = annotationSources; if ( annotations != null ) { for ( Annotation annotation : annotations ) { final Annotation currentAnnotation = annotation; final AnnotationListItem annotationListItem = createListItem(); annotationListItem.loadAnnotation( annotation, annotationSources != null ? annotationSources.get( annotation.getClassName( ) ) : null ); annotationListItem.setCollapsed( !isExpanded( annotation.getClassName( ) ) ); annotationListItem.setDeleteAnnotationHandler( new AdvancedAnnotationListEditorView.DeleteAnnotationHandler( ) { @Override public void onDeleteAnnotation( Annotation annotation ) { AdvancedAnnotationListEditor.this.onDeleteAnnotation( annotation ); } } ); annotationListItem.setClearValuePairHandler( new AdvancedAnnotationListEditorView.ClearValuePairHandler( ) { @Override public void onClearValuePair( Annotation annotation, String valuePair ) { AdvancedAnnotationListEditor.this.onClearValuePair( annotation, valuePair ); } } ); annotationListItem.setEditValuePairHandler( new AdvancedAnnotationListEditorView.EditValuePairHandler( ) { @Override public void onEditValuePair( Annotation annotation, String valuePair ) { AdvancedAnnotationListEditor.this.onEditValuePair( annotation, valuePair ); } } ); annotationListItem.setCollapseChangeHandler( new AdvancedAnnotationListEditorView.CollapseChangeHandler( ) { @Override public void onCollapseChange( ) { AdvancedAnnotationListEditor.this.onCollapseChange( currentAnnotation, annotationListItem.isCollapsed() ); } } ); annotationListItem.setReadonly( readonly ); annotationItems.put( annotation, annotationListItem ); view.addItem( annotationListItem ); } } } public boolean isReadonly() { return readonly; } public void setReadonly( boolean readonly ) { this.readonly = readonly; view.setReadonly( readonly ); for ( AnnotationListItem annotationListItem : annotationItems.values() ) { annotationListItem.setReadonly( readonly ); } } @Override public void onAddAnnotation() { view.invokeCreateAnnotationWizard( getAddAnnotationCallback(), project, elementType ); } protected Callback<Annotation> getAddAnnotationCallback() { if ( addAnnotationCallback == null ) { addAnnotationCallback = new Callback< Annotation >( ) { @Override public void callback( Annotation annotation ) { if ( annotation != null && addAnnotationHandler != null ) { addAnnotationHandler.onAddAnnotation( annotation ); } } }; } return addAnnotationCallback; } protected void onDeleteAnnotation( final Annotation annotation ) { String message = Constants.INSTANCE.advanced_domain_annotation_list_editor_message_confirm_annotation_deletion( annotation.getClassName(), ( elementType != null ? elementType.name() : " object/field" ) ); view.showYesNoDialog( message, getDeleteAnnotationCommand( annotation ), getNoActionCommand(), getNoActionCommand() ); } protected Command getDeleteAnnotationCommand( final Annotation annotation ) { if ( deleteAnnotationCommand == null ) { deleteAnnotationCommand = new Command( ) { @Override public void execute( ) { if ( deleteAnnotationHandler != null ) { deleteAnnotationHandler.onDeleteAnnotation( annotation ); } } }; } return deleteAnnotationCommand; } protected Command getNoActionCommand() { if ( noActionCommand == null ) { noActionCommand = new Command() { @Override public void execute() { //do nothing } }; } return noActionCommand; } protected void onEditValuePair( Annotation annotation, String valuePair ) { ValuePairEditorPopup valuePairEditor = createValuePairEditor( annotation, valuePair ); if ( valuePairEditor.isGenericEditor() ) { AnnotationSource annotationSource = annotationSources.get( annotation.getClassName() ); String valuePairSource = annotationSource != null ? annotationSource.getValuePairSource( valuePair ) : null; valuePairEditor.setValue( valuePairSource ); } else { valuePairEditor.setValue( annotation.getValue( valuePair ) ); } valuePairEditor.show(); } protected void onClearValuePair( Annotation annotation, String valuePair ) { AnnotationDefinition annotationDefinition = annotation.getAnnotationDefinition(); AnnotationValuePairDefinition valuePairDefinition = annotationDefinition.getValuePair( valuePair ); if ( valuePairDefinition.getDefaultValue() == null ) { //if the value pair has no default value, it should be applied wherever the annotation is applied, if not //the resulting code won't compile. String message = Constants.INSTANCE.advanced_domain_annotation_list_editor_message_value_pair_has_no_default_value( valuePair, annotation.getClassName() ); view.showYesNoDialog( message, getNoActionCommand() ); } else if ( clearValuePairHandler != null ) { clearValuePairHandler.onClearValuePair( annotation, valuePair ); } } protected void onCollapseChange( Annotation currentAnnotation, boolean collapsed ) { setExpanded( currentAnnotation.getClassName( ), !collapsed ); } public void addDeleteAnnotationHandler( AdvancedAnnotationListEditorView.DeleteAnnotationHandler deleteAnnotationHandler ) { this.deleteAnnotationHandler = deleteAnnotationHandler; } public void addClearValuePairHandler( AdvancedAnnotationListEditorView.ClearValuePairHandler clearValuePairHandler ) { this.clearValuePairHandler = clearValuePairHandler; } public void addValuePairChangeHandler( AdvancedAnnotationListEditorView.ValuePairChangeHandler valuePairChangeHandler ) { this.valuePairChangeHandler = valuePairChangeHandler; } public void addAddAnnotationHandler( AdvancedAnnotationListEditorView.AddAnnotationHandler addAnnotationHandler ) { this.addAnnotationHandler = addAnnotationHandler; } public void clear() { view.clear(); clearListItems(); } public void removeAnnotation( Annotation annotation ) { AnnotationListItem listItem = annotationItems.get( annotation ); if ( listItem != null ) { view.removeItem( listItem ); annotationItems.remove( annotation ); dispose( listItem ); } } private RemoteCallback<AnnotationSourceResponse> getLoadAnnotationSourcesSuccessCallback() { return new RemoteCallback<AnnotationSourceResponse>() { @Override public void callback( AnnotationSourceResponse annotationSourceResponse ) { loadAnnotations( annotations, annotationSourceResponse.getAnnotationSources() ); } }; } protected void doValuePairChange( final ValuePairEditorPopup valuePairEditor, final Object value ) { if ( valuePairEditor.isGenericEditor() ) { String strValue = value != null ? value.toString() : null; modelerService.call( getValuePairChangeSuccessCallback( valuePairEditor ) ) .resolveParseRequest( new AnnotationParseRequest( valuePairEditor.getAnnotationClassName(), elementType, valuePairEditor.getValuePairDefinition().getName(), strValue ), project ); } else { applyValuePairChange( valuePairEditor, value ); } } protected void doValuePairNoAction( final ValuePairEditorPopup valuePairEditor ) { valuePairEditor.hide(); dispose( valuePairEditor ); } private RemoteCallback<AnnotationParseResponse> getValuePairChangeSuccessCallback( final ValuePairEditorPopup valuePairEditor ) { return new RemoteCallback<AnnotationParseResponse>() { @Override public void callback( AnnotationParseResponse annotationParseResponse ) { if ( !annotationParseResponse.hasErrors() && annotationParseResponse.getAnnotation() != null ) { Object newValue = annotationParseResponse.getAnnotation().getValue( valuePairEditor.getValuePairDefinition().getName() ); applyValuePairChange( valuePairEditor, newValue ); } else { //TODO improve this error handling String errorMessage = ""; for ( DriverError error : annotationParseResponse.getErrors() ) { errorMessage = errorMessage + "\n" + error.getMessage(); } valuePairEditor.setErrorMessage( errorMessage ); } } }; } private void applyValuePairChange( ValuePairEditorPopup valuePairEditor, Object newValue ) { if ( !valuePairEditor.isValid() ) { valuePairEditor.setErrorMessage( Constants.INSTANCE.advanced_domain_annotation_list_editor_message_invalid_value_for_value_pair( valuePairEditor.getValuePairDefinition().getName() ) ); } else { if ( !valuePairEditor.getValuePairDefinition().hasDefaultValue() && newValue == null ) { valuePairEditor.setErrorMessage( Constants.INSTANCE.advanced_domain_annotation_list_editor_message_value_pair_cant_be_null( valuePairEditor.getValuePairDefinition().getName() ) ); } else { valuePairChangeHandler.onValuePairChange( valuePairEditor.getAnnotationClassName(), valuePairEditor.getValuePairDefinition().getName(), newValue ); valuePairEditor.hide(); dispose( valuePairEditor ); } } } private ValuePairEditorPopup createValuePairEditor( Annotation annotation, String valuePair ) { final ValuePairEditorPopup valuePairEditor = createValuePairEditor(); valuePairEditor.init( annotation.getClassName(), annotation.getAnnotationDefinition().getValuePair( valuePair ) ); valuePairEditor.addPopupHandler( new ValuePairEditorPopupView.ValuePairEditorPopupHandler() { @Override public void onOk() { doValuePairChange( valuePairEditor, valuePairEditor.getValue() ); } @Override public void onCancel() { doValuePairNoAction( valuePairEditor ); } @Override public void onClose() { doValuePairNoAction( valuePairEditor ); } } ); return valuePairEditor; } @PreDestroy protected void destroy() { clearListItems(); } protected AnnotationListItem createListItem() { return itemInstance.get(); } private void clearListItems() { for ( AnnotationListItem item : annotationItems.values() ) { dispose( item ); } annotationItems.clear(); } private void dispose( AnnotationListItem listItem ) { itemInstance.destroy( listItem ); } protected ValuePairEditorPopup createValuePairEditor() { return valuePairEditorInstance.get(); } private void dispose( ValuePairEditorPopup valuePairEditor ) { valuePairEditorInstance.destroy( valuePairEditor ); } private boolean isExpanded( String annotation ) { return annotationStatus.get( annotation ) != null ? annotationStatus.get( annotation ) : false; } private void setExpanded( String annotation, boolean expanded ) { annotationStatus.put( annotation, expanded ); } }