/* * Copyright 2014 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.drools.workbench.screens.guided.dtree.client.widget.popups; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.TreeMap; import com.google.gwt.core.client.GWT; import com.google.gwt.event.dom.client.ChangeEvent; import com.google.gwt.event.dom.client.ChangeHandler; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.logical.shared.ValueChangeEvent; import com.google.gwt.event.logical.shared.ValueChangeHandler; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.uibinder.client.UiHandler; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; import org.drools.workbench.models.guided.dtree.shared.model.nodes.ActionFieldValue; import org.drools.workbench.models.guided.dtree.shared.model.nodes.ActionUpdateNode; import org.drools.workbench.models.guided.dtree.shared.model.nodes.BoundNode; import org.drools.workbench.models.guided.dtree.shared.model.nodes.Node; import org.drools.workbench.models.guided.dtree.shared.model.nodes.TypeNode; import org.drools.workbench.models.guided.dtree.shared.model.nodes.impl.ActionFieldValueImpl; import org.drools.workbench.models.guided.dtree.shared.model.nodes.impl.ActionUpdateNodeImpl; import org.drools.workbench.screens.guided.dtree.client.resources.i18n.GuidedDecisionTreeConstants; import org.drools.workbench.screens.guided.dtree.client.widget.utils.ValueUtilities; import org.gwtbootstrap3.client.ui.Button; import org.gwtbootstrap3.client.ui.CheckBox; import org.gwtbootstrap3.client.ui.Container; import org.gwtbootstrap3.client.ui.FormGroup; import org.gwtbootstrap3.client.ui.ListBox; import org.kie.workbench.common.widgets.client.datamodel.AsyncPackageDataModelOracle; import org.uberfire.ext.widgets.common.client.common.popups.BaseModal; import org.uberfire.ext.widgets.common.client.common.popups.footers.ModalFooterOKCancelButtons; import org.uberfire.mvp.ParameterizedCommand; public class EditActionUpdatePopup extends BaseModal { interface EditActionUpdateBinder extends UiBinder<Widget, EditActionUpdatePopup> { } private static EditActionUpdateBinder uiBinder = GWT.create( EditActionUpdateBinder.class ); private final ActionUpdateNode node; private final ActionUpdateNode clone; private final Command callback; private final AsyncPackageDataModelOracle oracle; private final ParameterizedCommand<ActionFieldValue> onDeleteCallback = new ParameterizedCommand<ActionFieldValue>() { @Override public void execute( final ActionFieldValue afv ) { if ( clone.getFieldValues() == null ) { return; } final int index = clone.getFieldValues().indexOf( afv ); clone.getFieldValues().remove( index ); containerFieldValues.remove( index ); } }; private final Command okCommand = new Command() { @Override public void execute() { onOKButtonClick(); } }; private final Command cancelCommand = new Command() { @Override public void execute() { hide(); } }; private final ModalFooterOKCancelButtons footer = new ModalFooterOKCancelButtons( okCommand, cancelCommand ); @UiField FormGroup bindingGroup; @UiField ListBox bindingListBox; @UiField CheckBox modifyCheckBox; @UiField Container containerFieldValues; @UiField Button addFieldValueButton; /** * Edit the given ActionModifyNode. A clone is taken whilst editing is in progress to preserve the state * of the original node should editing be cancelled by the User. * @param node The node to edit * @param callback Callback to execute when the User commits changes */ public EditActionUpdatePopup( final ActionUpdateNode node, final AsyncPackageDataModelOracle oracle, final Command callback ) { setTitle( GuidedDecisionTreeConstants.INSTANCE.popupTitleEditActionUpdate() ); setWidth( "700px" ); setBody( uiBinder.createAndBindUi( this ) ); add( footer ); this.node = node; this.clone = cloneNode( node ); this.oracle = oracle; this.callback = callback; initialiseModify(); initialiseBoundTypes(); initialiseFieldValues(); } //Clone node whilst editing to preserve original node should User cancel the edit private ActionUpdateNode cloneNode( final ActionUpdateNode node ) { final ActionUpdateNode clone = new ActionUpdateNodeImpl( node.getBoundNode() ); clone.getFieldValues().addAll( clone( node.getFieldValues() ) ); clone.setParent( node.getParent() ); clone.setModify( node.isModify() ); return clone; } private List<ActionFieldValue> clone( final List<ActionFieldValue> afvs ) { final List<ActionFieldValue> clone = new ArrayList<ActionFieldValue>(); for ( ActionFieldValue afv : afvs ) { clone.add( clone( afv ) ); } return clone; } private ActionFieldValue clone( final ActionFieldValue afv ) { final ActionFieldValue clone = new ActionFieldValueImpl( afv.getFieldName(), ValueUtilities.clone( afv.getValue() ) ); return clone; } private void initialiseModify() { modifyCheckBox.addValueChangeHandler( new ValueChangeHandler<Boolean>() { @Override public void onValueChange( final ValueChangeEvent<Boolean> event ) { clone.setModify( event.getValue() ); } } ); this.modifyCheckBox.setValue( clone.isModify() ); } private void initialiseBoundTypes() { //Extract all bindings available on the path to the root final Map<String, TypeNode> bindings = new TreeMap<String, TypeNode>(); Node parent = clone.getParent(); while ( parent != null ) { if ( parent instanceof TypeNode ) { final TypeNode tn = (TypeNode) parent; if ( tn.isBound() ) { bindings.put( tn.getBinding(), tn ); } } parent = parent.getParent(); } bindingListBox.setEnabled( !bindings.isEmpty() ); if ( bindings.isEmpty() ) { bindingListBox.addItem( GuidedDecisionTreeConstants.INSTANCE.noBindings() ); return; } //Add them to the ListBox int selectedIndex = 0; final BoundNode boundNode = clone.getBoundNode(); for ( String binding : bindings.keySet() ) { bindingListBox.addItem( binding ); if ( boundNode != null ) { if ( binding.equals( boundNode.getBinding() ) ) { selectedIndex = bindingListBox.getItemCount() - 1; } } } //Attach event handler before we set the selected index in case we're selecting the first item bindingListBox.addChangeHandler( new ChangeHandler() { @Override public void onChange( final ChangeEvent event ) { final String binding = bindingListBox.getItemText( bindingListBox.getSelectedIndex() ); clone.setBoundNode( bindings.get( binding ) ); clone.getFieldValues().clear(); initialiseFieldValues(); } } ); bindingListBox.setSelectedIndex( selectedIndex ); } private void initialiseFieldValues() { containerFieldValues.clear(); addFieldValueButton.setEnabled( true ); for ( ActionFieldValue afv : clone.getFieldValues() ) { final ActionFieldValueEditor afvEditor = new ActionFieldValueEditor( clone.getBoundNode().getClassName(), afv, clone.getFieldValues(), oracle, onDeleteCallback ); containerFieldValues.add( afvEditor ); } } @UiHandler("addFieldValueButton") void onAddFieldValueButtonClick( final ClickEvent event ) { final ActionFieldValue afv = new ActionFieldValueImpl(); final ActionFieldValueEditor afvEditor = new ActionFieldValueEditor( clone.getBoundNode().getClassName(), afv, clone.getFieldValues(), oracle, onDeleteCallback ); containerFieldValues.add( afvEditor ); clone.getFieldValues().add( afv ); } private void onOKButtonClick() { node.setBoundNode( clone.getBoundNode() ); node.setModify( clone.isModify() ); node.getFieldValues().clear(); node.getFieldValues().addAll( clone.getFieldValues() ); if ( callback != null ) { callback.execute(); } hide(); } }