/*
* 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.lang.reflect.InvocationTargetException;
import java.util.Iterator;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.commands.IHandler;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.ui.JavaUI;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.text.TextSelection;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.window.Window;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.handlers.HandlerUtil;
import org.eclipse.ui.texteditor.ITextEditor;
import com.motorola.studio.android.codeutils.CodeUtilsActivator;
import com.motorola.studio.android.codeutils.i18n.CodeUtilsNLS;
import com.motorola.studio.android.common.log.StudioLogger;
import com.motorola.studio.android.common.log.UsageDataConstants;
import com.motorola.studio.android.common.utilities.EclipseUtils;
import com.motorola.studio.android.generatecode.JDTUtils;
import com.motorola.studio.android.generatemenucode.model.codegenerators.JavaModifierBasedOnMenu;
import com.motorola.studio.android.generateviewbylayout.ui.AbstractCodeGeneratorHandler;
/**
* Command handler to start code generation based on menu
*/
public class GenerateMenuCodeHandler extends AbstractHandler implements IHandler
{
private static final String WIZARD_IMAGE_PATH = "icons/wizban/fill_activity_ban.png"; //$NON-NLS-1$
/**
* Open {@link GenerateMenuCodeDialog} and use {@link JavaModifierBasedOnMenu} to insert code into Android source code (Activity/Fragment).
*/
public Object execute(ExecutionEvent event) throws ExecutionException
{
SelectionBean selectionBean = resolveSelection(event);
if (selectionBean.isProject() || selectionBean.isAllowedClassInstance())
{
final IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindow(event);
GenerateMenuCodeDialog menuDialog =
new GenerateMenuCodeDialog(window.getShell(),
CodeUtilsNLS.GenerateMenuCodeDialog_DefaultMessage,
CodeUtilsNLS.GenerateMenuCodeDialog_Title,
CodeUtilsNLS.GenerateMenuCodeDialog_ShellTitle, CodeUtilsActivator
.getImageDescriptor(WIZARD_IMAGE_PATH).createImage());
final JavaModifierBasedOnMenu modifier = new JavaModifierBasedOnMenu();
menuDialog.init(modifier, selectionBean.getJavaProject(), selectionBean.getJavaFile());
int status = menuDialog.open();
if (status == Window.OK)
{
ICompilationUnit compilationUnit = menuDialog.getJavaFile();
IEditorPart editor = null;
try
{
editor = JavaUI.openInEditor(compilationUnit);
}
catch (Exception e)
{
StudioLogger
.warn(GenerateMenuCodeHandler.class,
"Unable to open editor or bring it to front for Java file while trying to generate menu code based on xml file", //$NON-NLS-1$
e);
}
final ProgressMonitorDialog dialog =
new ProgressMonitorDialog(menuDialog.getShell());
final IEditorPart editorPart = editor;
PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable()
{
public void run()
{
try
{
dialog.run(true, false, new IRunnableWithProgress()
{
public void run(IProgressMonitor monitor)
throws InvocationTargetException, InterruptedException
{
try
{
// collect usage data - UDC
StudioLogger.collectUsageData(
UsageDataConstants.WHAT_VIEW_BY_MENU_EXEC,
UsageDataConstants.KIND_VIEW_BY_MENU_EXEC,
"View by menu feature executed.", //$NON-NLS-1$
CodeUtilsActivator.PLUGIN_ID, CodeUtilsActivator
.getDefault().getBundle().getVersion()
.toString());
modifier.insertCode(monitor, editorPart);
}
catch (final JavaModelException e)
{
final MultiStatus errorStatus =
new MultiStatus(
CodeUtilsActivator.PLUGIN_ID,
IStatus.ERROR,
"Error inserting code on activity/fragment based on menu", //$NON-NLS-1$
null);
errorStatus.merge(e.getStatus());
PlatformUI.getWorkbench().getDisplay()
.asyncExec(new Runnable()
{
public void run()
{
IStatus mostSevere =
EclipseUtils
.findMostSevereError(errorStatus);
ErrorDialog
.openError(
PlatformUI.getWorkbench()
.getDisplay()
.getActiveShell(),
"Error inserting code on activity/fragment based on menu", //$NON-NLS-1$
e.getMessage(), mostSevere);
}
});
StudioLogger.error(this.getClass(),
"Error inserting code on activity/fragment based on menu" //$NON-NLS-1$
+ ": " + e.getMessage()); //$NON-NLS-1$
}
}
});
}
catch (Exception e)
{
StudioLogger.error(this.getClass(),
"Error inserting code on activity/fragment based on menu" //$NON-NLS-1$
+ ": " + e.getMessage()); //$NON-NLS-1$
}
}
});
}
}
else
{
EclipseUtils.showErrorDialog(CodeUtilsNLS.GenerateMenuCodeDialog_Title,
CodeUtilsNLS.GenerateMenuCodeHandler_SelectedClassNeitherActivityFragment);//GenerateMenuCodeHandler_SelectedClassNeitherActivityFragment
}
return null;
}
protected static SelectionBean resolveSelection(ExecutionEvent event) throws ExecutionException
{
SelectionBean selectionBean = new SelectionBean();
ITextEditor editor = null;
IFileEditorInput fileEditorInput = null;
ISelection selection = HandlerUtil.getCurrentSelection(event);
// case where the selection comes from the Text Editor
if (selection instanceof TextSelection)
{
editor = (ITextEditor) HandlerUtil.getActiveEditorChecked(event);
if (editor.getEditorInput() instanceof IFileEditorInput)
{
fileEditorInput = (IFileEditorInput) editor.getEditorInput();
selectionBean.setJavaFile(fileEditorInput.getFile());
}
}
else if (selection instanceof IStructuredSelection)
{
Iterator<?> selectionIterator = ((IStructuredSelection) selection).iterator();
Object selectedObject = selectionIterator.next();
// case where the selection comes from the package explorer
if (selectedObject instanceof IFile)
{
selectionBean.setJavaFile((IFile) selectedObject);
}
// again, case where the selection comes from the package explorer
else if (selectedObject instanceof ICompilationUnit)
{
ICompilationUnit compilationUnit = (ICompilationUnit) selectedObject;
selectionBean.setJavaFile((IFile) compilationUnit.getResource());
}
// case where the selection comes from a project
else if (selectedObject instanceof IAdaptable)
{
try
{
IResource resource =
(IResource) ((IAdaptable) selectedObject).getAdapter(IResource.class);
selectionBean.setJavaProject(resource.getProject());
selectionBean.setProject(true);
}
catch (Exception ex)
{
StudioLogger.error(AbstractCodeGeneratorHandler.class,
"Error retrieving class information", ex); //$NON-NLS-1$
throw new RuntimeException(
CodeUtilsNLS.GenerateMenuCodeHandler_Error_CannotRetrieveClassInformation,
ex);
}
}
}
// just check classes in case classes were selected, not project
if (!selectionBean.isProject())
{
try
{
// the selected class must be either an Activity or a Fragment
selectionBean.setAllowedClassInstance(JDTUtils.isSubclass(
selectionBean.getJavaFile(), "android.app.Activity") //$NON-NLS-1$
|| JDTUtils.isFragmentSubclass(selectionBean.getJavaFile())
|| JDTUtils.isCompatibilityFragmentSubclass(selectionBean.getJavaFile()));
}
catch (JavaModelException jme)
{
StudioLogger.error(AbstractCodeGeneratorHandler.class,
"Error retrieving class information", jme); //$NON-NLS-1$
throw new RuntimeException(
CodeUtilsNLS.GenerateMenuCodeHandler_Error_CannotRetrieveClassInformation,
jme);
}
}
return selectionBean;
}
}
class SelectionBean
{
private boolean isProject = false;
private boolean isAllowedClassInstance = false;
private IFile javaFile = null;
private IProject javaProject = null;
public boolean isProject()
{
return isProject;
}
public void setProject(boolean isProject)
{
this.isProject = isProject;
}
/**
* @return true if activity or fragment, false otherwise
*/
public boolean isAllowedClassInstance()
{
return isAllowedClassInstance;
}
public void setAllowedClassInstance(boolean isAllowedClassInstance)
{
this.isAllowedClassInstance = isAllowedClassInstance;
}
/**
* @return selected Android file (Activity or Fragment)
*/
public IFile getJavaFile()
{
return javaFile;
}
/**
* Sets the Android file selected (Activity or Fragment)
* @param javaFile
*/
public void setJavaFile(IFile javaFile)
{
this.javaFile = javaFile;
javaProject = javaFile.getProject();
}
/**
* @return the project where the Android file (Activity or Fragment) is located
*/
public IProject getJavaProject()
{
return javaProject;
}
public void setJavaProject(IProject javaProject)
{
this.javaProject = javaProject;
}
}