com.motorola.studio.android.generateviewbylayout.ui.AbstractLayoutItemsDialog.java Source code

Java tutorial

Introduction

Here is the source code for com.motorola.studio.android.generateviewbylayout.ui.AbstractLayoutItemsDialog.java

Source

/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * 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 com.motorola.studio.android.generateviewbylayout.ui;

import java.util.List;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jface.dialogs.TitleAreaDialog;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowData;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.ui.PlatformUI;

import com.motorola.studio.android.codeutils.i18n.CodeUtilsNLS;
import com.motorola.studio.android.common.IAndroidConstants;
import com.motorola.studio.android.common.exception.AndroidException;
import com.motorola.studio.android.common.log.StudioLogger;
import com.motorola.studio.android.generatecode.JDTUtils;
import com.motorola.studio.android.generateviewbylayout.JavaModifierBasedOnLayout;
import com.motorola.studio.android.generateviewbylayout.model.CodeGeneratorDataBasedOnLayout;
import com.motorola.studio.android.generateviewbylayout.model.JavaLayoutData;
import com.motorola.studio.android.generateviewbylayout.model.LayoutNode;

/**
 * Abstract dialog to deal with common methods for the UI dialog involved into the code generation
 */
public abstract class AbstractLayoutItemsDialog extends TitleAreaDialog {

    private JavaModifierBasedOnLayout modifier;

    private ICompilationUnit javaFile;

    private IProject javaProject;

    private CodeGeneratorDataBasedOnLayout codeGeneratorData;

    private Combo projectNameComboBox;

    private Combo classNameComboBox;

    private Label layoutFileNameLabel;

    private TableViewer viewer;

    private Button unselectAllButton;

    private Button selectAllButton;

    private String layoutFileErrorMessage;

    private String helpID = null;

    protected static final String DEFAULT_LAYOUT_FILE_NAME_LABEL_VALUE = "--"; //$NON-NLS-1$

    private final String defaultMessage;

    private final String title;

    private final String shellTitle;

    private final Image image;

    public AbstractLayoutItemsDialog(Shell parentShell, String description, String title, String shellTitle,
            Image image) {
        super(parentShell);
        this.defaultMessage = description != null ? description : ""; //$NON-NLS-1$
        this.title = title != null ? title : ""; //$NON-NLS-1$
        this.shellTitle = shellTitle != null ? shellTitle : ""; //$NON-NLS-1$
        this.image = image;
    }

    /**
     * Initializes the modifier to enable code generation 
     * @param modifier the responsible to modify code
     * @param javaProject the project of the Android file to modify
     * @param javaFile the Android file to change
     */
    public void init(JavaModifierBasedOnLayout modifier, IProject javaProject, IFile javaFile) {
        setModifier(modifier);
        setJavaProject(javaProject);
        setJavaFile(javaFile);
    }

    @Override
    protected Control createContents(Composite parent) {
        Control c = super.createContents(parent);
        setTitle(title);
        if (image != null) {
            setTitleImage(image);
        }
        validate();
        return c;
    }

    @Override
    protected final Control createDialogArea(Composite parent) {
        if (helpID != null) {
            PlatformUI.getWorkbench().getHelpSystem().setHelp(parent, helpID);
        }
        Composite parentComposite = (Composite) super.createDialogArea(parent);
        Composite mainComposite = new Composite(parentComposite, SWT.NONE);
        mainComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
        mainComposite.setLayout(new GridLayout(2, false));
        createProjectNameArea(mainComposite);
        createClassNameArea(mainComposite);
        createLayoutFileNameArea(mainComposite);

        Label separator = new Label(mainComposite, SWT.SEPARATOR | SWT.HORIZONTAL);
        separator.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 2, 1));

        createTableArea(mainComposite);
        createCustomContentArea(mainComposite);

        separator = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL);
        separator.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, true, false, 2, 1));

        return parentComposite;

    }

    /**
     * Create a custom area in the end of the dialog
     * The parent composite has a grid layout with two columns
     * @param mainComposite
     */
    protected abstract void createCustomContentArea(Composite mainComposite);

    /**
     * Create GUI items for project name selection.
     * @param optionsComposite
     */
    private void createProjectNameArea(Composite parent) {
        Label projectLabel = new Label(parent, SWT.NONE);
        projectLabel.setText(CodeUtilsNLS.ChooseLayoutItemsDialog_Project);
        projectLabel.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false, 1, 1));

        projectNameComboBox = new Combo(parent, SWT.READ_ONLY | SWT.DROP_DOWN);
        projectNameComboBox.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 1, 1));
        projectNameComboBox.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                setJavaProject((IProject) projectNameComboBox.getData(projectNameComboBox.getText()));
                setErrorMessage(null);
                javaFile = null;
                layoutFileErrorMessage = null;
                codeGeneratorData = null;
                populateClasses();
                populateLayouts();
            }
        });
        populateProjects();
    }

    /**
     * Create GUI items for class name selection.
     * @param parent
     */
    private void createClassNameArea(Composite parent) {
        Label classLabel = new Label(parent, SWT.NONE);
        classLabel.setText(CodeUtilsNLS.ChooseLayoutItemsDialog_TargetClass);
        classLabel.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false, 1, 1));

        classNameComboBox = new Combo(parent, SWT.READ_ONLY | SWT.DROP_DOWN);
        classNameComboBox.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 1, 1));
        classNameComboBox.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                setJavaFile(((IType) classNameComboBox.getData(classNameComboBox.getText())).getCompilationUnit());
                codeGeneratorData = null;
                populateLayouts();
            }
        });
        populateClasses();
    }

    /**
     * Create GUI items for layout file name selection.
     * @param parent
     */
    private void createLayoutFileNameArea(Composite parent) {
        Label layoutFileLabel = new Label(parent, SWT.NONE);
        layoutFileLabel.setText(CodeUtilsNLS.ChooseLayoutItemsDialog_SourceLayoutFile);
        layoutFileLabel.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false, 1, 1));

        layoutFileNameLabel = new Label(parent, SWT.NONE);
        layoutFileNameLabel.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 1, 1));
        layoutFileNameLabel.setText(DEFAULT_LAYOUT_FILE_NAME_LABEL_VALUE);
        populateLayouts();

    }

    /**
     * Create GUI items for GUI Items selection.
     * @param parent
     */
    private void createTableArea(Composite parent) {
        Composite tableArea = new Composite(parent, SWT.NONE);
        tableArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
        tableArea.setLayout(new GridLayout(2, false));

        Label tableLabel = new Label(tableArea, SWT.NONE);
        tableLabel.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false, 2, 1));
        tableLabel.setText(CodeUtilsNLS.ChooseLayoutItemsDialog_GUIItems);

        viewer = new TableViewer(tableArea,
                SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.BORDER | SWT.CHECK);
        viewer.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));

        Composite buttonsComposite = new Composite(tableArea, SWT.NONE);
        buttonsComposite.setLayoutData(new GridData(SWT.RIGHT, SWT.TOP, false, true, 1, 1));
        RowLayout buttonsLayout = new RowLayout(SWT.VERTICAL);
        buttonsLayout.pack = false;
        buttonsComposite.setLayout(buttonsLayout);

        selectAllButton = new Button(buttonsComposite, SWT.PUSH);
        selectAllButton.setText(CodeUtilsNLS.UI_SelectAll);
        selectAllButton.setLayoutData(new RowData());
        selectAllButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                checkAllItems(true);
                validate();
            }

        });

        unselectAllButton = new Button(buttonsComposite, SWT.PUSH);
        unselectAllButton.setText(CodeUtilsNLS.UI_UnselectAll);
        unselectAllButton.setLayoutData(new RowData());
        unselectAllButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                checkAllItems(false);
                validate();
            }
        });

        createColumns(viewer);

        final Table table = viewer.getTable();
        table.setHeaderVisible(true);
        table.setLinesVisible(true);

        ArrayContentProvider provider = new ArrayContentProvider();
        viewer.setContentProvider(provider);

        viewer.addDoubleClickListener(new IDoubleClickListener() {

            @Override
            public void doubleClick(DoubleClickEvent event) {
                if (event.getSource() instanceof TableViewer) {
                    Table tb = ((TableViewer) event.getSource()).getTable();
                    TableItem[] items = tb.getSelection();
                    items[0].setChecked(!items[0].getChecked());
                    itemCheckStateChanged(items[0]);
                    validate();
                }
            }
        });

        viewer.addSelectionChangedListener(new ISelectionChangedListener() {

            @Override
            public void selectionChanged(SelectionChangedEvent event) {
                validate();
            }
        });

        populateViewer();

    }

    /**
     * Notify when the check state changed. This is a workaround for SWT not notifying when we change widget state programatically
     * 
     * @param item
     */
    protected void itemCheckStateChanged(TableItem item) {
        //default implementation does nothing
    };

    private void checkAllItems(boolean checked) {
        for (TableItem item : viewer.getTable().getItems()) {
            item.setChecked(checked);
            itemCheckStateChanged(item);
        }

    }

    /**
     * Creates the columns for the GUI Items table.
     * @param viewer the TableViewer whose columns will be created.
     */
    protected void createColumns(final TableViewer viewer) {
        String[] titles = { CodeUtilsNLS.ChooseLayoutItemsDialog_Id, CodeUtilsNLS.ChooseLayoutItemsDialog_Type,
                CodeUtilsNLS.ChooseLayoutItemsDialog_VariableName, };
        int[] bounds = { 150, 100, 170 };

        TableViewerColumn col = createTableViewerColumn(viewer, titles[0], bounds[0], 0);
        col.setLabelProvider(new ColumnLabelProvider() {
            @Override
            public String getText(Object element) {
                LayoutNode node = (LayoutNode) element;
                return node.getNodeId();
            }
        });

        col = createTableViewerColumn(viewer, titles[1], bounds[1], 1);
        col.setLabelProvider(new ColumnLabelProvider() {
            @Override
            public String getText(Object element) {
                LayoutNode node = (LayoutNode) element;
                return node.getNodeType();
            }
        });

        col = createTableViewerColumn(viewer, titles[2], bounds[2], 2);
        col.setLabelProvider(new ColumnLabelProvider() {
            @Override
            public String getText(Object element) {
                LayoutNode node = (LayoutNode) element;
                return node.getNodeId();
            }
        });

    }

    /**
     * Creates a column for the GUI Items table.
     * @param parent
     */
    protected final TableViewerColumn createTableViewerColumn(TableViewer viewer, String title, int bound,
            final int colNumber) {
        final TableViewerColumn viewerColumn = new TableViewerColumn(viewer, SWT.NONE);
        final TableColumn column = viewerColumn.getColumn();
        column.setText(title);
        column.setWidth(bound);
        column.setResizable(true);
        column.setMoveable(true);
        return viewerColumn;

    }

    /**
     * Populate the combobox that holds projects, with information gathered from the ResourcesPlugin.
     * also selects the project set in the init method
     */
    private void populateProjects() {
        if (projectNameComboBox != null) {
            IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
            int i = 0, selectedProjectIndex = -1;

            for (IProject prj : projects) {
                try {
                    if (prj.hasNature(IAndroidConstants.ANDROID_NATURE)) {
                        projectNameComboBox.add(prj.getName());
                        projectNameComboBox.setData(prj.getName(), prj);
                        if ((javaProject != null) && prj.equals(javaProject)) {
                            selectedProjectIndex = i;
                        }
                        i++;
                    }
                } catch (CoreException e) {
                    StudioLogger.info(CodeUtilsNLS.Info_ChooseLayoutItemsDialog_Project_Nature);
                }
            }

            if (projectNameComboBox.getItemCount() > 0) {
                if (selectedProjectIndex == -1) {
                    projectNameComboBox.select(0);
                    setJavaProject((IProject) projectNameComboBox.getData(projectNameComboBox.getText()));
                } else {
                    projectNameComboBox.select(selectedProjectIndex);
                }
            }

            validate();

        }
    }

    /**
     * Populate the combobox that holds class names. 
     */
    private void populateClasses() {
        if (classNameComboBox != null) {
            classNameComboBox.removeAll();

            if (javaProject != null) {
                int i = 0, selectedTypeIndex = -1;
                try {
                    List<IType> availableClasses = JDTUtils.getAvailableActivities(javaProject,
                            new NullProgressMonitor());

                    availableClasses.addAll(JDTUtils.getAvailableFragmentsSubclasses(
                            (IProject) projectNameComboBox.getData(projectNameComboBox.getText()),
                            new NullProgressMonitor()));

                    //add the fragments JDTUtils.getAvailableFragments to activityClasses

                    for (IType availableClass : availableClasses) {
                        classNameComboBox.add(availableClass.getFullyQualifiedName());
                        classNameComboBox.setData(availableClass.getFullyQualifiedName(), availableClass);
                        if ((javaFile != null) && availableClass.getCompilationUnit().equals(javaFile)) {
                            selectedTypeIndex = i;
                        }
                        i++;
                    }
                    if (classNameComboBox.getItemCount() > 0) {
                        if (selectedTypeIndex == -1) {
                            classNameComboBox.select(0);
                            setJavaFile(((IType) classNameComboBox.getData(classNameComboBox.getText()))
                                    .getCompilationUnit());
                        } else {
                            classNameComboBox.select(selectedTypeIndex);
                        }
                    }
                } catch (JavaModelException e) {
                    StudioLogger.info(CodeUtilsNLS.Info_ChooseLayoutItemsDialog_Available_Classes);
                }

                classNameComboBox.setEnabled(classNameComboBox.getItemCount() > 0);
            }
        }
        validate();
    }

    /**
     * Populate the combobox that holds layout file names. 
     */
    private void populateLayouts() {
        if (layoutFileNameLabel != null) {
            layoutFileNameLabel.setText(DEFAULT_LAYOUT_FILE_NAME_LABEL_VALUE);
            layoutFileErrorMessage = null;
            IType activity = (IType) classNameComboBox.getData(classNameComboBox.getText());
            if (activity != null) {
                try {
                    codeGeneratorData = JDTUtils.createLayoutFile(getJavaProject(), getJavaFile());
                    JavaLayoutData viewLayoutData = getCodeGeneratorData().getJavaLayoutData();
                    if ((viewLayoutData == null) || (viewLayoutData.hasErrorInCompilationUnitAst())) {
                        //there are errors in the compilation unit
                        layoutFileErrorMessage = CodeUtilsNLS.ChooseLayoutItemsDialog_TryToGenerateCodeWhenThereIsAnError;
                        codeGeneratorData = null;
                    } else {
                        if (getCodeGeneratorData().getLayoutFile().getName() != null) {
                            layoutFileNameLabel.setText(getCodeGeneratorData().getLayoutFile().getName());
                        } else {
                            layoutFileErrorMessage = CodeUtilsNLS.UI_ChooseLayoutItemsDialog_Error_onCreate_Not_Declared;
                        }
                    }
                } catch (AndroidException e) {
                    //if layout xml is malformed indicate it on screen                
                    layoutFileErrorMessage = e.getMessage();
                    StudioLogger.error(this.getClass(), "Error parsing layout: " + e.getMessage()); //$NON-NLS-1$
                }

                populateViewer();
            }
            validate();
        }
    }

    protected void populateViewer() {
        if (viewer != null) {
            viewer.getTable().removeAll();

            // Get the content for the viewer, setInput will call getElements in the
            // contentProvider
            if (getCodeGeneratorData() != null) {
                viewer.setInput(getGuiItemsList());
                viewer.refresh();
            }

            if (viewer.getTable().getItemCount() == 0) {
                viewer.getTable().setEnabled(false);
                selectAllButton.setEnabled(false);
                unselectAllButton.setEnabled(false);
            } else {
                selectAllButton.setEnabled(true);
                unselectAllButton.setEnabled(true);
                viewer.getTable().setEnabled(true);
            }
            validate();
        }
    }

    /**
     * Get the list of items to be displayed
     * @return
     */
    protected List<LayoutNode> getGuiItemsList() {
        return getCodeGeneratorData().getGUIItems(false);
    }

    @Override
    protected void configureShell(Shell newShell) {
        super.configureShell(newShell);
        newShell.setText(shellTitle);
    }

    /**
     * Validate the UI
     * @return
     */
    protected void validate() {
        String errorMessage = null;

        if ((projectNameComboBox != null) && (projectNameComboBox.getItemCount() == 0)) {
            errorMessage = CodeUtilsNLS.AbstractLayoutItemsDialog_Error_No_Projects_Found;
        }
        if ((errorMessage == null) && (classNameComboBox != null) && (classNameComboBox.getItemCount() == 0)) {
            errorMessage = CodeUtilsNLS.AbstractLayoutItemsDialog_Error_No_Class_Found;
        }
        if ((errorMessage == null) && (layoutFileNameLabel != null)) {
            if (layoutFileErrorMessage != null) {
                errorMessage = layoutFileErrorMessage;
            } else if (getJavaFile() == null) {
                errorMessage = CodeUtilsNLS.AbstractLayoutItemsDialog_Error_No_Layout_Found;
            }
        }

        setErrorMessage(errorMessage);

        if (errorMessage == null) {
            setMessage(defaultMessage);
        }

        if (getButton(OK) != null) {
            getButton(OK).setEnabled((getErrorMessage() == null) && hasAtLeastOneItemChecked());
        }
    }

    private boolean hasAtLeastOneItemChecked() {
        boolean hasItemsChecked = false;

        TableItem[] items = viewer.getTable().getItems();
        int i = 0;
        while (!hasItemsChecked && (i < items.length)) {
            if (items[i++].getChecked()) {
                hasItemsChecked = true;
            }
        }

        return hasItemsChecked;
    }

    /**
     * @return {@link ICompilationUnit} selected Android file to generate the code
     */
    public ICompilationUnit getJavaFile() {
        return javaFile;
    }

    /**
     * @return {@link IProject} of the selected Android file
     */
    public IProject getJavaProject() {
        return javaProject;
    }

    /**
     * @return {@link JavaModifierBasedOnLayout} responsible to change the source code of Android file
     */
    public JavaModifierBasedOnLayout getModifier() {
        return modifier;
    }

    private void setModifier(JavaModifierBasedOnLayout modifier) {
        this.modifier = modifier;
    }

    private void setJavaFile(IFile javaFile) {
        if (javaFile != null) {
            setJavaFile(JavaCore.createCompilationUnitFrom(javaFile));
        }
    }

    private void setJavaFile(ICompilationUnit javaFile) {
        this.javaFile = javaFile;
        setJavaProject(javaFile.getJavaProject().getProject());
    }

    private void setJavaProject(IProject javaProject) {
        this.javaProject = javaProject;
    }

    /**
     * @return object representing the input data (from layout XML) to use as basis during code generation  
     */
    public CodeGeneratorDataBasedOnLayout getCodeGeneratorData() {
        return codeGeneratorData;
    }

    public void setHelpID(String helpID) {
        this.helpID = helpID;
    }

    /**
     * @return table to select the Android GUI items to generate code for 
     */
    public TableViewer getViewer() {
        return viewer;
    }

}