/******************************************************************************* * Copyright (c) 2017 Rogue Wave Software Inc. and others. * 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 * * Contributors: * Rogue Wave Software Inc. - initial implementation *******************************************************************************/ package org.eclipse.php.internal.ui.handlers; import java.lang.reflect.InvocationTargetException; import java.util.*; import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.resources.IProject; import org.eclipse.dltk.core.*; import org.eclipse.dltk.internal.core.ExternalSourceModule; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.operation.IRunnableContext; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRewriteTarget; import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.window.Window; import org.eclipse.php.core.ast.nodes.Program; import org.eclipse.php.core.compiler.PHPFlags; import org.eclipse.php.internal.ui.PHPUiPlugin; import org.eclipse.php.internal.ui.actions.AddGetterSetterOperation; import org.eclipse.php.internal.ui.actions.CodeGenerationSettings; import org.eclipse.php.internal.ui.actions.WorkbenchRunnableAdapter; import org.eclipse.php.internal.ui.dialogs.GettersSettersDialog; import org.eclipse.php.internal.ui.dialogs.GettersSettersDialog.GetterSetterEntry; import org.eclipse.php.internal.ui.dialogs.GettersSettersDialog.GetterSetterLabelProvider; import org.eclipse.php.internal.ui.dialogs.GettersSettersDialog.GettersSettersContentProvider; import org.eclipse.php.internal.ui.dialogs.GettersSettersDialog.GettersSettersSelectionStatusValidator; import org.eclipse.php.internal.ui.editor.PHPStructuredEditor; import org.eclipse.php.internal.ui.util.BusyIndicatorRunnableContext; import org.eclipse.php.ui.util.CodeGenerationUtils; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.dialogs.ISelectionStatusValidator; import org.eclipse.ui.editors.text.TextEditor; import org.eclipse.ui.handlers.HandlerUtil; /** * This is a handler for GettersSettersAction class. Allows contributing to * extension 'org.eclipse.ui.menus'. * */ public class GettersSettersHandler extends AbstractHandler { private static final String DIALOG_TITLE = Messages.GettersSettersHandler_0; private IWorkbenchWindow fWindow; private boolean fSort; private boolean fGenerateComment; private boolean fFinal; private int fVisibility; private int fNumEntries; @Override public Object execute(ExecutionEvent event) throws ExecutionException { fWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); Object selection = HandlerUtil.getCurrentSelection(event); // The action is run from a view. if (selection instanceof IStructuredSelection) { execute((IStructuredSelection) selection); } // The action is run from a editor. if (selection instanceof ITextSelection) { execute(event, (ITextSelection) selection); } return null; } private void execute(IStructuredSelection selection) throws ExecutionException { Object object = selection.getFirstElement(); if (object instanceof IModelElement) { IModelElement element = (IModelElement) object; if (element.getOpenable() instanceof ExternalSourceModule) { MessageDialog.openError(fWindow.getShell(), Messages.bind(DIALOG_TITLE, new String[] { Messages.GettersSettersHandler_1 }), Messages.GettersSettersHandler_2); return; } try { IEditorPart editor = CodeGenerationUtils.openInEditor(element, true); if (editor instanceof PHPStructuredEditor) { run((ISourceModule) ((PHPStructuredEditor) editor).getModelElement(), element, (PHPStructuredEditor) editor); } } catch (PartInitException e) { MessageDialog.openError(fWindow.getShell(), Messages.bind(DIALOG_TITLE, new String[] { Messages.GettersSettersHandler_1 }), Messages.GettersSettersHandler_2); throw new ExecutionException("Editor open Error", e); //$NON-NLS-1$ } catch (ModelException e) { PHPUiPlugin.log(e); } } } private void execute(ExecutionEvent event, ITextSelection selection) throws ExecutionException { PHPStructuredEditor editor = CodeGenerationUtils.getPHPEditor(event); if (editor == null) { return; } IModelElement source = editor.getModelElement(); if (!(source instanceof ISourceModule) || source instanceof ExternalSourceModule) { MessageDialog.openError(fWindow.getShell(), Messages.bind(DIALOG_TITLE, new String[] { Messages.GettersSettersHandler_1 }), Messages.GettersSettersHandler_2); return; } IModelElement element = CodeGenerationUtils.getCurrentModelElement(source, editor, selection); // This is a bug of HandlerUtils. When open the file first time, the // current selection returns the offset as 0. // try to get the element via the editor. if (element == null) { element = CodeGenerationUtils.getCurrentModelElement(event); } try { run((ISourceModule) source, element, editor); } catch (ModelException e) { PHPUiPlugin.log(e); } } /** * The method opens the input dialog and generates the code. * * @param source * the source module. * @param element * the current selected element. * @param editor * the editor */ private void run(ISourceModule source, IModelElement element, TextEditor editor) throws ModelException { IType type = CodeGenerationUtils.getType(element); // The current selection is not in a class. if (type == null) { MessageDialog.openError(fWindow.getShell(), Messages.bind(DIALOG_TITLE, new String[] { Messages.GettersSettersHandler_1 }), Messages.GettersSettersHandler_2); return; } int flags = type.getFlags(); // The current selection is a interface. if (PHPFlags.isInterface(flags)) { MessageDialog.openInformation(fWindow.getShell(), Messages.bind(DIALOG_TITLE, new String[] { Messages.GettersSettersHandler_1 }), Messages.GettersSettersHandler_4); return; } resetNumEntries(); Map<IField, GetterSetterEntry[]> entries = createGetterSetterMapping(type); // No fields are eligible to generate getter/setter. if (entries.isEmpty()) { MessageDialog.openInformation(fWindow.getShell(), Messages.bind(DIALOG_TITLE, new String[] { Messages.GettersSettersHandler_1 }), Messages.GettersSettersHandler_5); return; } GettersSettersDialog dialog = new GettersSettersDialog(fWindow.getShell(), new GetterSetterLabelProvider(), new GettersSettersContentProvider(entries), type, editor); dialog.setTitle(Messages.bind(DIALOG_TITLE, type.getElementName())); String message = Messages.GettersSettersHandler_9; dialog.setMessage(message); dialog.setValidator(createValidator(fNumEntries)); dialog.setProject(source.getScriptProject().getProject()); dialog.setContainerMode(true); dialog.setSize(60, 18); dialog.setInput(type); if (element instanceof IField) { dialog.setInitialSelections(new Object[] { element }); dialog.setExpandedElements(new Object[] { element }); } final Set<IField> keySet = new LinkedHashSet<>(entries.keySet()); int dialogResult = dialog.open(); if (dialogResult != Window.OK) { return; } Object[] result = dialog.getResult(); if (result == null) { return; } fSort = dialog.getSortOrder(); fFinal = dialog.isFinal(); fVisibility = dialog.getVisibilityModifier(); fGenerateComment = dialog.getGenerateComment(); IField[] getterFields, setterFields, getterSetterFields; if (fSort) { getterFields = getGetterFields(result, keySet); setterFields = getSetterFields(result, keySet); getterSetterFields = new IField[0]; } else { getterFields = getGetterOnlyFields(result, keySet); setterFields = getSetterOnlyFields(result, keySet); getterSetterFields = getGetterSetterFields(result, keySet); } IProject project = source.getScriptProject().getProject(); Program program = null; IDocument document = editor.getDocumentProvider().getDocument(editor.getEditorInput()); program = CodeGenerationUtils.getASTRoot(source, document, project); final IRewriteTarget target = editor.getAdapter(IRewriteTarget.class); if (target != null) { target.setRedraw(false); target.beginCompoundChange(); } try { if (program != null) { generate(type, getterFields, setterFields, getterSetterFields, program, document, dialog.getElementPosition()); } } finally { if (target != null) { target.setRedraw(true); target.endCompoundChange(); } } } private void resetNumEntries() { fNumEntries = 0; } private void incNumEntries() { fNumEntries++; } /** * Generates the code. * * @param type * @param getterFields * @param setterFields * @param getterSetterFields * @param program * @param document * @param elementPosition */ private void generate(IType type, IField[] getterFields, IField[] setterFields, IField[] getterSetterFields, Program program, IDocument document, IMethod elementPosition) { try { CodeGenerationSettings settings = new CodeGenerationSettings(); settings.createComments = fGenerateComment; AddGetterSetterOperation op = new AddGetterSetterOperation(type, getterFields, setterFields, getterSetterFields, program, document, elementPosition, settings, true); setOperationStatusFields(op); IRunnableContext context = PHPUiPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow(); if (context == null) { context = new BusyIndicatorRunnableContext(); } PlatformUI.getWorkbench().getProgressService().runInUI(context, new WorkbenchRunnableAdapter(op, op.getSchedulingRule()), op.getSchedulingRule()); } catch (InvocationTargetException e) { String message = Messages.GettersSettersHandler_6; MessageDialog.openError(fWindow.getShell(), Messages.bind(DIALOG_TITLE, new String[] { Messages.GettersSettersHandler_1 }), message); } catch (InterruptedException e) { // operation canceled } finally { } } private void setOperationStatusFields(AddGetterSetterOperation op) { // Set the status fields corresponding to the visibility and modifiers // set int flags = fVisibility; if (fFinal) { flags |= Flags.AccFinal; } op.setSort(fSort); op.setVisibility(flags); } // returns a list of fields with setter entries checked private static IField[] getSetterFields(Object[] result, Set<IField> set) { List<IField> list = new ArrayList<>(); Object each = null; GetterSetterEntry entry = null; for (int i = 0; i < result.length; i++) { each = result[i]; if (each instanceof GetterSetterEntry) { entry = (GetterSetterEntry) each; if (!entry.isGetter) { list.add(entry.field); } } } list = reorderFields(list, set); return list.toArray(new IField[list.size()]); } // returns a list of fields with getter entries checked private static IField[] getGetterFields(Object[] result, Set<IField> set) { List<IField> list = new ArrayList<>(); Object each = null; GetterSetterEntry entry = null; for (int i = 0; i < result.length; i++) { each = result[i]; if ((each instanceof GetterSetterEntry)) { entry = (GetterSetterEntry) each; if (entry.isGetter) { list.add(entry.field); } } } list = reorderFields(list, set); return list.toArray(new IField[list.size()]); } // returns a list of fields with only getter entries checked private static IField[] getGetterOnlyFields(Object[] result, Set<IField> set) { List<IField> list = new ArrayList<>(0); Object each = null; GetterSetterEntry entry = null; boolean getterSet = false; for (int i = 0; i < result.length; i++) { each = result[i]; if (each instanceof GetterSetterEntry) { entry = (GetterSetterEntry) each; if (entry.isGetter) { list.add(entry.field); getterSet = true; } if (!entry.isGetter && getterSet == true) { list.remove(entry.field); getterSet = false; } } else getterSet = false; } list = reorderFields(list, set); return list.toArray(new IField[list.size()]); } // returns a list of fields with only setter entries checked private static IField[] getSetterOnlyFields(Object[] result, Set<IField> set) { List<IField> list = new ArrayList<>(0); Object each = null; GetterSetterEntry entry = null; boolean getterSet = false; for (int i = 0; i < result.length; i++) { each = result[i]; if (each instanceof GetterSetterEntry) { entry = (GetterSetterEntry) each; if (entry.isGetter) { getterSet = true; } if (!entry.isGetter && getterSet != true) { list.add(entry.field); getterSet = false; } } else getterSet = false; } list = reorderFields(list, set); return list.toArray(new IField[list.size()]); } // returns a list of fields with both entries checked private static IField[] getGetterSetterFields(Object[] result, Set<IField> set) { List<IField> list = new ArrayList<>(); Object each = null; GetterSetterEntry entry = null; boolean getterSet = false; for (int i = 0; i < result.length; i++) { each = result[i]; if (each instanceof GetterSetterEntry) { entry = (GetterSetterEntry) each; if (entry.isGetter) { getterSet = true; } if ((!entry.isGetter) && (getterSet == true)) { list.add(entry.field); getterSet = false; } } else getterSet = false; } list = reorderFields(list, set); return list.toArray(new IField[list.size()]); } private static List<IField> reorderFields(List<IField> collection, Set<IField> set) { final List<IField> list = new ArrayList<>(collection.size()); for (final Iterator<IField> iterator = set.iterator(); iterator.hasNext();) { final IField field = iterator.next(); if (collection.contains(field)) { list.add(field); } } return list; } /** * @param type * the type * @return map IField -> GetterSetterEntry[] * @throws ModelException * if the type does not exist or if an exception occurs while * accessing its corresponding resource */ private Map<IField, GetterSetterEntry[]> createGetterSetterMapping(IType type) throws ModelException { IField[] fields = type.getFields(); Map<IField, GetterSetterEntry[]> result = new LinkedHashMap<>(); for (IField field : fields) { int flags = field.getFlags(); if (PHPFlags.isConstant(flags)) { continue; } List<GetterSetterEntry> l = new ArrayList<>(2); if (CodeGenerationUtils.getGetter(field) == null) { l.add(new GetterSetterEntry(field, true, Flags.isFinal(flags), PHPFlags.isConstant(flags))); incNumEntries(); } if (CodeGenerationUtils.getSetter(field) == null) { l.add(new GetterSetterEntry(field, false, Flags.isFinal(flags), PHPFlags.isConstant(flags))); incNumEntries(); } if (!l.isEmpty()) { result.put(field, l.toArray(new GetterSetterEntry[l.size()])); } } return result; } private static ISelectionStatusValidator createValidator(int entries) { return new GettersSettersSelectionStatusValidator(entries); } }