/* * 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.generatemenucode.ui; import java.util.List; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; 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.jdt.core.dom.CompilationUnit; import org.eclipse.jface.dialogs.IMessageProvider; import org.eclipse.jface.dialogs.TitleAreaDialog; 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.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.ui.PlatformUI; import com.motorola.studio.android.codeutils.CodeUtilsActivator; 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.generatemenucode.model.codegenerators.CodeGeneratorDataBasedOnMenu; import com.motorola.studio.android.generatemenucode.model.codegenerators.JavaModifierBasedOnMenu; /** * Dialog to generate code to deal with Android menus base on a selected menu.xml file */ public class GenerateMenuCodeDialog extends TitleAreaDialog { private ICompilationUnit javaFile; private IProject javaProject = null; private JavaModifierBasedOnMenu modifier; private Combo projectNameComboBox; private Combo classNameComboBox; private Combo menuFileNameComboBox; private String menuFileErrorMessage; private final String helpID = CodeUtilsActivator.PLUGIN_ID + ".generate-code-from-context-menu-dialog"; //$NON-NLS-1$ private Image image = null; private List<IType> availableFragmentClasses = null; private final String defaultMessage; private final String title; private final String shellTitle; /** * Default constructor for the dialog * @param parentShell shell to open the dialog * @param description text to show dialog * @param title text * @param shellTitle window text * @param image icon to show in the dialog */ public GenerateMenuCodeDialog(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; } /** * Set the initial values for project name and class name, if there is some selected. * Also, set the modifier that will be used to generate code - the dialog set its codeGeneratorData * according to the selected menu. * @param modifier modifier that will have its codeGeneratorData set * @param javaProject the project that will be selected when the dialog appears * @param javaFile the class that will be selected when the dialog appears * */ public void init(JavaModifierBasedOnMenu modifier, IProject javaProject, IFile javaFile) { setJavaModifier(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.NULL); mainComposite.setLayoutData(new GridData(GridData.FILL_BOTH)); mainComposite.setLayout(new GridLayout(2, false)); createProjectNameArea(mainComposite); createClassNameArea(mainComposite); createMenuFileNameArea(mainComposite); Label separator = new Label(mainComposite, SWT.SEPARATOR | SWT.HORIZONTAL); separator.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 2, 1)); return parentComposite; } /** * Create GUI items for project name selection. * @param optionsComposite */ private void createProjectNameArea(Composite parent) { Label projectLabel = new Label(parent, SWT.NONE); projectLabel.setText(CodeUtilsNLS.GenerateMenuCodeDialog_ProjectLabel); 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())); populateClasses(); populateMenuFileNames(); } }); 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.GenerateMenuCodeDialog_TargetClassLabel); 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()); populateMenuFileNames(); } }); populateClasses(); } /** * Create GUI items for layout file name selection. * @param parent */ private void createMenuFileNameArea(Composite parent) { Label menuFileLabel = new Label(parent, SWT.NONE); menuFileLabel.setText(CodeUtilsNLS.GenerateMenuCodeDialog_MenuFileLabel); menuFileLabel.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false, 1, 1)); menuFileNameComboBox = new Combo(parent, SWT.READ_ONLY | SWT.DROP_DOWN); menuFileNameComboBox.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 1, 1)); menuFileNameComboBox.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { validateMenuFileNames(menuFileNameComboBox.getText()); } }); populateMenuFileNames(); } /** * 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("Project nature could not be checked."); //$NON-NLS-1$ } } 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()); //Fragment classes can have menu too, so add all fragment classes to menu combo box if (availableFragmentClasses != null) { availableFragmentClasses.clear(); } availableFragmentClasses = JDTUtils.getAvailableFragmentsSubclasses((IProject) projectNameComboBox .getData(projectNameComboBox.getText()), new NullProgressMonitor()); availableClasses.addAll(availableFragmentClasses); for (IType availableClass : availableClasses) { classNameComboBox.add(availableClass.getFullyQualifiedName()); classNameComboBox.setData(availableClass.getFullyQualifiedName(), availableClass); if ((getJavaFile() != null) && availableClass.getCompilationUnit().equals(getJavaFile())) { 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("Could not get available classes for the selected project"); //$NON-NLS-1$ } classNameComboBox.setEnabled(classNameComboBox.getItemCount() > 0); } } validate(); } /** * Validate the selected menu file of the combobox that holds menu file names. */ protected void validateMenuFileNames(String menuFileName) { menuFileErrorMessage = null; if ((menuFileNameComboBox != null) && (menuFileNameComboBox.getData(menuFileName) instanceof String)) { // If the data type is a String, it represents an error message. menuFileErrorMessage = (String) menuFileNameComboBox.getData(menuFileName); } validate(); } /** * Populate the combobox that holds menu file names. */ private void populateMenuFileNames() { if ((menuFileNameComboBox != null) && (getJavaFile() != null)) { menuFileNameComboBox.removeAll(); menuFileErrorMessage = null; CompilationUnit cpAstNode = JDTUtils.parse(getJavaFile()); if (!JDTUtils.hasErrorInCompilationUnitAstUtils(cpAstNode)) { IProject prj = (IProject) this.projectNameComboBox.getData(this.projectNameComboBox .getText()); IFolder menuFolder = prj.getFolder(IAndroidConstants.FD_RESOURCES).getFolder( IAndroidConstants.FD_MENU); String inflatedMenu = JDTUtils.getInflatedMenuFileName(getJavaProject(), getJavaFile()); if ((inflatedMenu != null) && (inflatedMenu.length() > 0)) { //the activity/fragment already inflates a menu //select this menu on the combo box try { inflatedMenu = inflatedMenu + '.' + IAndroidConstants.MENU_FILE_EXTENSION; menuFileNameComboBox.add(inflatedMenu); CodeGeneratorDataBasedOnMenu codeGeneratorData; codeGeneratorData = JDTUtils.createMenuFile(getJavaProject(), getJavaFile(), inflatedMenu, getTypeAssociatedToJavaFile()); menuFileNameComboBox.setData(inflatedMenu, codeGeneratorData); menuFileNameComboBox.select(0); setMessage(CodeUtilsNLS.GenerateMenuCodeDialog_InflatedMessage, IMessageProvider.NONE); } catch (AndroidException e) { menuFileErrorMessage = e.getMessage(); menuFileNameComboBox.setData(inflatedMenu, menuFileErrorMessage); } //Disable the menu combo box so the user cannot change the menu file menuFileNameComboBox.select(0); menuFileNameComboBox.setEnabled(false); } else { //there is no inflated menu setMessage(defaultMessage, IMessageProvider.NONE); //iterate over all files inside res/menu try { for (IResource menuFile : menuFolder.members()) { //only consider xml files if ((menuFile.getType() == IResource.FILE) && menuFile.getFileExtension().equals( IAndroidConstants.MENU_FILE_EXTENSION)) { menuFileNameComboBox.add(menuFile.getName()); try { CodeGeneratorDataBasedOnMenu codeGeneratorData = JDTUtils.createMenuFile(getJavaProject(), getJavaFile(), menuFile.getName(), getTypeAssociatedToJavaFile()); menuFileNameComboBox.setData(menuFile.getName(), codeGeneratorData); } catch (AndroidException e) { // The malformed xml files menuFileErrorMessage = e.getMessage(); menuFileNameComboBox.setData(menuFile.getName(), menuFileErrorMessage); } } } } catch (CoreException e) { menuFileErrorMessage = CodeUtilsNLS.GenerateMenuCodeDialog_Error_MenuFolderDoesNotExist; } menuFileNameComboBox.select(0); //if the combo box is empty, the selection is ignored menuFileNameComboBox.setEnabled(menuFileNameComboBox.getItemCount() > 0); } } else { menuFileErrorMessage = CodeUtilsNLS.GenerateMenuCodeDialog_Class_Error; this.javaFile = null; menuFileNameComboBox.setEnabled(false); } } else { menuFileNameComboBox.setEnabled(false); } validate(); } /** * Retrieve the type ACTIVITY/FRAGMENT from the android class * @return */ private CodeGeneratorDataBasedOnMenu.TYPE getTypeAssociatedToJavaFile() { CodeGeneratorDataBasedOnMenu.TYPE type = CodeGeneratorDataBasedOnMenu.TYPE.ACTIVITY; for (IType availableClass : availableFragmentClasses) { if (availableClass.getCompilationUnit().equals(getJavaFile())) { type = CodeGeneratorDataBasedOnMenu.TYPE.FRAGMENT; break; } } return type; } @Override protected void configureShell(Shell newShell) { newShell.setSize(640, 280); newShell.setText(shellTitle); super.configureShell(newShell); } /** * Validate the UI * @return */ protected void validate() { String errorMessage = null; if ((projectNameComboBox != null) && (projectNameComboBox.getItemCount() == 0)) { errorMessage = CodeUtilsNLS.GenerateMenuCodeDialog_NoSuitableProjects; } if ((errorMessage == null) && (classNameComboBox != null) && (classNameComboBox.getItemCount() == 0)) { errorMessage = CodeUtilsNLS.GenerateMenuCodeDialog_NoSuitableClasses; } if ((errorMessage == null) && (menuFileNameComboBox != null)) { if ((menuFileErrorMessage != null) && (menuFileNameComboBox.getSelectionIndex() >= 0) && (menuFileNameComboBox.getData(menuFileNameComboBox .getItem(menuFileNameComboBox.getSelectionIndex())) instanceof String)) { errorMessage = (String) menuFileNameComboBox.getData(menuFileNameComboBox .getItem(menuFileNameComboBox.getSelectionIndex())); } else { if ((menuFileNameComboBox.getItemCount() == 0) && (getJavaFile() != null)) { errorMessage = CodeUtilsNLS.GenerateMenuCodeDialog_NoSuitableMenus; } else if (getJavaFile() == null) { errorMessage = menuFileErrorMessage; } } } this.setMessage(errorMessage, IMessageProvider.ERROR); if (errorMessage == null) { if ((this.getMessage() == null) || (this.getMessage().length() == 0)) { this.setMessage(defaultMessage, IMessageProvider.NONE); } } if (getButton(OK) != null) { getButton(OK) .setEnabled( (getErrorMessage() == null) || ((getErrorMessage() != null) && (getErrorMessage().trim() .isEmpty()))); } } private void setJavaFile(IFile javaFile) { if (javaFile != null) { setJavaFile(JavaCore.createCompilationUnitFrom(javaFile)); } } private void setJavaFile(ICompilationUnit javaFile) { this.javaFile = javaFile; setJavaProject(javaFile.getJavaProject().getProject()); } /** * @return Compilation unit for the selected file (activity or fragment) */ public ICompilationUnit getJavaFile() { return this.javaFile; } private void setJavaProject(IProject javaProject) { this.javaProject = javaProject; } private IProject getJavaProject() { return this.javaProject; } /** * Returns CodeGeneratorDataBasedOnMenu according to the selected menu file, or null if no menu is selected. * */ private CodeGeneratorDataBasedOnMenu getCodeGeneratorData() { CodeGeneratorDataBasedOnMenu result = null; if (menuFileNameComboBox.getSelectionIndex() >= 0) { result = (CodeGeneratorDataBasedOnMenu) this.menuFileNameComboBox .getData(menuFileNameComboBox.getText()); } return result; } /** * @return the modifier responsible to modify the source code */ public JavaModifierBasedOnMenu getJavaModifier() { return modifier; } /** * @param modifier the modifier to set */ public void setJavaModifier(JavaModifierBasedOnMenu modifier) { this.modifier = modifier; } @Override protected void okPressed() { modifier.setCodeGeneratorData(getCodeGeneratorData()); super.okPressed(); } /** * Sets the focus of the content area of the dialog */ public void setFocus() { this.getContents().setFocus(); } @Override protected boolean isResizable() { return true; } }