Package com.google.gdt.eclipse.designer.uibinder.editor

Source Code of com.google.gdt.eclipse.designer.uibinder.editor.ExposePropertySupport$ExposePropertyAction$ExposeDialog

/*******************************************************************************
* Copyright 2011 Google Inc. All Rights Reserved.
*
* 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
*
* 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 com.google.gdt.eclipse.designer.uibinder.editor;

import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.gdt.eclipse.designer.uibinder.model.util.NameSupport;
import com.google.gdt.eclipse.designer.uibinder.model.widgets.UIObjectInfo;
import com.google.gdt.eclipse.designer.uibinder.parser.UiBinderContext;

import org.eclipse.wb.core.model.AbstractComponentInfo;
import org.eclipse.wb.internal.core.DesignerPlugin;
import org.eclipse.wb.internal.core.editor.structure.property.IPropertiesMenuContributor;
import org.eclipse.wb.internal.core.model.ModelMessages;
import org.eclipse.wb.internal.core.model.property.Property;
import org.eclipse.wb.internal.core.utils.ast.AstEditor;
import org.eclipse.wb.internal.core.utils.ast.AstNodeUtils;
import org.eclipse.wb.internal.core.utils.ast.BodyDeclarationTarget;
import org.eclipse.wb.internal.core.utils.ast.DomGenerics;
import org.eclipse.wb.internal.core.utils.dialogfields.AbstractValidationTitleAreaDialog;
import org.eclipse.wb.internal.core.utils.dialogfields.DialogField;
import org.eclipse.wb.internal.core.utils.dialogfields.DialogFieldUtils;
import org.eclipse.wb.internal.core.utils.dialogfields.SelectionButtonDialogFieldGroup;
import org.eclipse.wb.internal.core.utils.dialogfields.StringDialogField;
import org.eclipse.wb.internal.core.utils.execution.ExecutionUtils;
import org.eclipse.wb.internal.core.utils.execution.RunnableEx;
import org.eclipse.wb.internal.core.utils.execution.RunnableObjectEx;
import org.eclipse.wb.internal.core.utils.jdt.core.CodeUtils;
import org.eclipse.wb.internal.core.utils.jdt.ui.JdtUiUtils;
import org.eclipse.wb.internal.core.utils.reflect.ReflectionUtils;
import org.eclipse.wb.internal.core.utils.ui.GridDataFactory;
import org.eclipse.wb.internal.core.utils.ui.GridLayoutFactory;
import org.eclipse.wb.internal.core.xml.model.property.GenericPropertyImpl;
import org.eclipse.wb.internal.core.xml.model.property.accessor.ExpressionAccessor;
import org.eclipse.wb.internal.core.xml.model.property.accessor.MethodExpressionAccessor;

import org.eclipse.core.runtime.IStatus;
import org.eclipse.jdt.core.JavaConventions;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.VariableDeclaration;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.text.source.SourceViewer;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;

import org.apache.commons.lang.StringUtils;

import java.text.MessageFormat;
import java.util.List;

/**
* Contributes "Expose property..." action for UiBinder properties.
*
* @author scheglov_ke
* @coverage GWT.UiBinder.editor
*/
public final class ExposePropertySupport implements IPropertiesMenuContributor {
  ////////////////////////////////////////////////////////////////////////////
  //
  // Instance
  //
  ////////////////////////////////////////////////////////////////////////////
  public static final IPropertiesMenuContributor INSTANCE = new ExposePropertySupport();

  private ExposePropertySupport() {
  }

  ////////////////////////////////////////////////////////////////////////////
  //
  // IPropertiesMenuContributor
  //
  ////////////////////////////////////////////////////////////////////////////
  public void contributeMenu(IMenuManager manager, Property property) throws Exception {
    if (property instanceof GenericPropertyImpl) {
      GenericPropertyImpl genericProperty = (GenericPropertyImpl) property;
      if (genericProperty.getObject() instanceof UIObjectInfo) {
        UIObjectInfo object = (UIObjectInfo) genericProperty.getObject();
        MethodExpressionAccessor accessor = getMethodAccessor(genericProperty);
        if (accessor != null) {
          manager.insertAfter(GROUP_EDIT, new ExposePropertyAction(genericProperty,
              object,
              accessor));
        }
      }
    }
  }

  ////////////////////////////////////////////////////////////////////////////
  //
  // Utils
  //
  ////////////////////////////////////////////////////////////////////////////
  /**
   * @return the {@link MethodExpressionAccessor}, may be <code>null</code>.
   */
  private static MethodExpressionAccessor getMethodAccessor(GenericPropertyImpl genericProperty) {
    List<ExpressionAccessor> accessors = genericProperty.getAccessors();
    for (ExpressionAccessor accessor : accessors) {
      if (accessor instanceof MethodExpressionAccessor) {
        return (MethodExpressionAccessor) accessor;
      }
    }
    return null;
  }

  ////////////////////////////////////////////////////////////////////////////
  //
  // Action
  //
  ////////////////////////////////////////////////////////////////////////////
  private static class ExposePropertyAction extends Action {
    private final GenericPropertyImpl m_property;
    private final UIObjectInfo m_object;
    private final UiBinderContext m_context;
    private final MethodExpressionAccessor m_accessor;
    private final String m_propertyTypeName;

    ////////////////////////////////////////////////////////////////////////////
    //
    // Constructor
    //
    ////////////////////////////////////////////////////////////////////////////
    public ExposePropertyAction(GenericPropertyImpl property,
        UIObjectInfo object,
        MethodExpressionAccessor accessor) {
      setImageDescriptor(DesignerPlugin.getImageDescriptor("actions/expose/exposeProperty.png"));
      setText(ModelMessages.ExposePropertyAction_text);
      setToolTipText(ModelMessages.ExposePropertyAction_tooltip);
      // model
      m_property = property;
      m_object = object;
      m_context = object.getContext();
      m_accessor = accessor;
      m_propertyTypeName =
          ReflectionUtils.getFullyQualifiedName(m_accessor.getGetter().getReturnType(), false);
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Run
    //
    ////////////////////////////////////////////////////////////////////////////
    @Override
    public void run() {
      final ExposeDialog dialog = new ExposeDialog();
      if (dialog.open() == Window.OK) {
        ExecutionUtils.run(m_object, new RunnableEx() {
          public void run() throws Exception {
            expose(dialog.isPublic());
          }
        });
      }
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Implementation
    //
    ////////////////////////////////////////////////////////////////////////////
    private String m_exposedName;
    private String m_exposedGetter;
    private String m_exposedSetter;
    private String m_exposedSetterParameter;

    /**
     * @return the {@link AstEditor} for Java source.
     */
    private AstEditor getFormEditor() throws Exception {
      return m_context.getFormEditor();
    }

    /**
     * @return the Java form top level {@link TypeDeclaration}.
     */
    private TypeDeclaration getFormTypeDeclaration() throws Exception {
      CompilationUnit compilationUnit = getFormEditor().getAstUnit();
      return DomGenerics.types(compilationUnit).get(0);
    }

    /**
     * Sets the currently entered by user name of exposed property.<br>
     * This automatically updates all values that depend on it, and used in both
     * {@link ExposeDialog} and this action.
     */
    private void setExposedName(String exposedName) throws Exception {
      m_exposedName = exposedName;
      m_exposedGetter = "get" + StringUtils.capitalize(m_exposedName);
      m_exposedSetter = "set" + StringUtils.capitalize(m_exposedName);
      {
        CompilationUnit astUnit = getFormEditor().getAstUnit();
        final List<VariableDeclaration> variables =
            AstNodeUtils.getVariableDeclarationsAll(astUnit);
        m_exposedSetterParameter =
            CodeUtils.generateUniqueName(m_property.getTitle(), new Predicate<String>() {
              public boolean apply(String name) {
                for (VariableDeclaration variable : variables) {
                  if (variable.getName().getIdentifier().equals(name)) {
                    return false;
                  }
                }
                return true;
              }
            });
      }
    }

    /**
     * Validates the currently entered by user name of exposed property.
     *
     * @return the error message, or <code>null</code> if given name is valid.
     */
    private String validate(final String exposedName) {
      return ExecutionUtils.runObject(new RunnableObjectEx<String>() {
        public String runObject() throws Exception {
          return validateEx(exposedName);
        }
      }, "<Exception, see log>");
    }

    /**
     * Implementation of {@link #validate(String)}.
     */
    @SuppressWarnings("deprecation")
    private String validateEx(final String exposedName) throws Exception {
      setExposedName(exposedName);
      // check for valid identifier
      {
        IStatus status = JavaConventions.validateIdentifier(m_exposedName);
        if (status.getSeverity() == IStatus.ERROR) {
          return status.getMessage();
        }
      }
      // prepare TypeDeclaration
      TypeDeclaration typeDeclaration = getFormTypeDeclaration();
      // check for existing getter
      {
        String signature = m_exposedGetter + "()";
        if (AstNodeUtils.getMethodBySignature(typeDeclaration, signature) != null) {
          return MessageFormat.format(
              ModelMessages.ExposePropertyAction_validateMethodAlreadyExists,
              signature);
        }
      }
      // check for existing setter
      {
        String signature = m_exposedSetter + "(" + m_propertyTypeName + ")";
        if (AstNodeUtils.getMethodBySignature(typeDeclaration, signature) != null) {
          return MessageFormat.format(
              ModelMessages.ExposePropertyAction_validateMethodAlreadyExists,
              signature);
        }
      }
      // OK
      return null;
    }

    /**
     * Prepares source for preview.
     *
     * @param isPublic
     *          is <code>true</code> if <code>public</code> modifier should be used and
     *          <code>false</code> for <code>protected</code> modifier.
     */
    private String getPreviewSource(boolean isPublic) throws Exception {
      String modifierSource = isPublic ? "public" : "protected";
      String propertyTypeName = CodeUtils.getShortClass(m_propertyTypeName);
      String accessExpression = "widget.";
      // prepare source
      String source = "";
      {
        source += "...\n";
        // getter
        if (m_accessor.getGetter() != null) {
          source +=
              MessageFormat.format(
                  "\t{0} {1} {2}() '{'\n",
                  modifierSource,
                  propertyTypeName,
                  m_exposedGetter);
          source +=
              MessageFormat.format(
                  "\t\treturn {0}{1}();\n",
                  accessExpression,
                  m_accessor.getGetter().getName());
          source += "\t}\n";
        }
        // setter
        {
          source +=
              MessageFormat.format(
                  "\t{0} void {1}({2} {3}) '{'\n",
                  modifierSource,
                  m_exposedSetter,
                  propertyTypeName,
                  m_exposedSetterParameter);
          source +=
              MessageFormat.format(
                  "\t\t{0}{1}({2});\n",
                  accessExpression,
                  m_accessor.getSetter().getName(),
                  m_exposedSetterParameter);
          source += "\t}\n";
        }
        // end
        source += "...\n";
      }
      // final result
      return source;
    }

    /**
     * Generates getter/setter for exposing property.
     */
    private void expose(boolean isPublic) throws Exception {
      AstEditor editor = getFormEditor();
      TypeDeclaration typeDeclaration = getFormTypeDeclaration();
      //
      BodyDeclarationTarget methodTarget = new BodyDeclarationTarget(typeDeclaration, false);
      String modifierSource = isPublic ? "public" : "protected";
      String name = NameSupport.ensureName(m_object);
      // getter
      {
        String header = modifierSource + " " + m_propertyTypeName + " " + m_exposedGetter + "()";
        String body =
            MessageFormat.format("return {0}.{1}();", name, m_accessor.getGetter().getName());
        editor.addMethodDeclaration(header, ImmutableList.of(body), methodTarget);
      }
      // setter
      {
        String header =
            MessageFormat.format(
                "{0} void {1}({2} {3})",
                modifierSource,
                m_exposedSetter,
                m_propertyTypeName,
                m_exposedSetterParameter);
        String body =
            MessageFormat.format(
                "{0}.{1}({2});",
                name,
                m_accessor.getSetter().getName(),
                m_exposedSetterParameter);
        editor.addMethodDeclaration(header, ImmutableList.of(body), methodTarget);
      }
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Expose dialog
    //
    ////////////////////////////////////////////////////////////////////////////
    /**
     * Dialog for requesting parameters for exposing {@link AbstractComponentInfo}.
     */
    private class ExposeDialog extends AbstractValidationTitleAreaDialog {
      ////////////////////////////////////////////////////////////////////////////
      //
      // Constructor
      //
      ////////////////////////////////////////////////////////////////////////////
      public ExposeDialog() {
        super(DesignerPlugin.getShell(),
            DesignerPlugin.getDefault(),
            ModelMessages.ExposePropertyAction_dialogShellTitle,
            ModelMessages.ExposePropertyAction_dialogTitle,
            DesignerPlugin.getImage("actions/expose/expose_banner.gif"),
            ModelMessages.ExposePropertyAction_dialogMessage);
        setShellStyle(SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL);
      }

      ////////////////////////////////////////////////////////////////////////////
      //
      // GUI
      //
      ////////////////////////////////////////////////////////////////////////////
      private StringDialogField m_nameField;
      private SelectionButtonDialogFieldGroup m_modifierField;
      private SourceViewer m_previewViewer;

      @Override
      protected void createControls(Composite container) {
        m_fieldsContainer = container;
        GridLayoutFactory.create(container).columns(2);
        // name
        {
          m_nameField = new StringDialogField();
          doCreateField(m_nameField, ModelMessages.ExposePropertyAction_dialogPropertyLabel);
          // initial name
          {
            Class<?> componentClass = m_object.getDescription().getComponentClass();
            String shortClassName = CodeUtils.getShortClass(componentClass.getName());
            String exposedName =
                StringUtils.uncapitalize(shortClassName)
                    + StringUtils.capitalize(m_property.getTitle());
            m_nameField.setText(exposedName);
          }
        }
        // modifier
        {
          m_modifierField =
              new SelectionButtonDialogFieldGroup(SWT.RADIO,
                  new String[]{"&public", "pro&tected"},
                  1,
                  SWT.SHADOW_ETCHED_IN);
          doCreateField(m_modifierField, ModelMessages.ExposePropertyAction_dialogModifier);
        }
        // preview
        {
          new Label(container, SWT.NONE).setText(ModelMessages.ExposePropertyAction_dialogPreview);
          m_previewViewer = JdtUiUtils.createJavaSourceViewer(container, SWT.BORDER | SWT.V_SCROLL);
          GridDataFactory.create(m_previewViewer.getControl()).spanH(2).hintVC(9).grab().fill();
        }
      }

      ////////////////////////////////////////////////////////////////////////////
      //
      // Validation
      //
      ////////////////////////////////////////////////////////////////////////////
      @Override
      protected String validate() throws Exception {
        // validate
        {
          String message = ExposePropertyAction.this.validate(m_nameField.getText());
          if (message != null) {
            JdtUiUtils.setJavaSourceForViewer(
                m_previewViewer,
                ModelMessages.ExposePropertyAction_dialogNoPreview);
            return message;
          }
        }
        // update preview
        {
          boolean isPublic = isPublic();
          JdtUiUtils.setJavaSourceForViewer(m_previewViewer, getPreviewSource(isPublic));
        }
        // OK
        return null;
      }

      ////////////////////////////////////////////////////////////////////////////
      //
      // Access
      //
      ////////////////////////////////////////////////////////////////////////////
      public boolean isPublic() {
        return m_modifierField.getSelection()[0] == 0;
      }

      ////////////////////////////////////////////////////////////////////////////
      //
      // Utils
      //
      ////////////////////////////////////////////////////////////////////////////
      private Composite m_fieldsContainer;

      /**
       * Configures given {@link DialogField} for specific of this dialog.
       */
      protected final void doCreateField(DialogField dialogField, String labelText) {
        dialogField.setLabelText(labelText);
        dialogField.setDialogFieldListener(m_validateListener);
        DialogFieldUtils.fillControls(m_fieldsContainer, dialogField, 2, 40);
      }
    }
  }
}
TOP

Related Classes of com.google.gdt.eclipse.designer.uibinder.editor.ExposePropertySupport$ExposePropertyAction$ExposeDialog

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.