/******************************************************************************* * 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.dialogs; import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.dltk.core.Flags; import org.eclipse.dltk.core.IType; import org.eclipse.dltk.core.ModelException; import org.eclipse.dltk.ti.types.IEvaluatedType; import org.eclipse.jface.dialogs.IDialogSettings; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.viewers.CheckboxTreeViewer; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerComparator; import org.eclipse.php.core.ast.nodes.*; import org.eclipse.php.internal.core.typeinference.PHPClassType; import org.eclipse.php.internal.ui.PHPUiPlugin; import org.eclipse.php.internal.ui.viewsupport.BindingLabelProvider; import org.eclipse.php.ui.util.CodeGenerationUtils; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.ViewForm; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Link; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.dialogs.ISelectionStatusValidator; import org.eclipse.ui.editors.text.TextEditor; public class OverrideMethodDialog extends PHPSourceActionDialog { private static class OverrideMethodContentProvider implements ITreeContentProvider { private final Object[] fEmpty = new Object[0]; private IMethodBinding[] fMethods; private IDialogSettings fSettings; private boolean fShowTypes; private Object[] fTypes; private static final String SETTINGS_SECTION = "OverrideMethodDialog"; //$NON-NLS-1$ private static final String SETTINGS_SHOWTYPES = "showtypes"; //$NON-NLS-1$ /** * Constructor for OverrideMethodContentProvider. */ public OverrideMethodContentProvider() { IDialogSettings dialogSettings = PHPUiPlugin.getDefault().getDialogSettings(); fSettings = dialogSettings.getSection(SETTINGS_SECTION); if (fSettings == null) { fSettings = dialogSettings.addNewSection(SETTINGS_SECTION); fSettings.put(SETTINGS_SHOWTYPES, true); } fShowTypes = fSettings.getBoolean(SETTINGS_SHOWTYPES); } @Override public void dispose() { } @Override public Object[] getChildren(Object parentElement) { if (parentElement instanceof ITypeBinding) { ArrayList<IMethodBinding> result = new ArrayList<>(fMethods.length); for (IMethodBinding method : fMethods) { if (method.getDeclaringClass().equals((IBinding) parentElement)) { result.add(method); } } return result.toArray(); } return fEmpty; } @Override public Object[] getElements(Object inputElement) { return fShowTypes ? fTypes : fMethods; } @Override public Object getParent(Object element) { if (element instanceof IMethodBinding) { return ((IMethodBinding) element).getDeclaringClass(); } return null; } @Override public boolean hasChildren(Object element) { return getChildren(element).length > 0; } public void init(IMethodBinding[] methods, ITypeBinding[] types) { fMethods = methods; fTypes = types; } @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { } } private static class OverrideMethodComparator extends ViewerComparator { private ITypeBinding[] fAllTypes = new ITypeBinding[0]; public OverrideMethodComparator(ITypeBinding curr) { if (curr != null) { ITypeBinding[] superTypes = Bindings.getAllSuperTypes(curr); fAllTypes = new ITypeBinding[superTypes.length + 1]; fAllTypes[0] = curr; System.arraycopy(superTypes, 0, fAllTypes, 1, superTypes.length); } } @Override public int compare(Viewer viewer, Object first, Object second) { if (first instanceof ITypeBinding && second instanceof ITypeBinding) { final ITypeBinding left = (ITypeBinding) first; final ITypeBinding right = (ITypeBinding) second; if (right.isSubTypeCompatible(left)) { return +1; } else if (left.isSubTypeCompatible(right)) { return -1; } return 0; } else { return super.compare(viewer, first, second); } } } private static class OverrideMethodValidator implements ISelectionStatusValidator { private static int fNumMethods; public OverrideMethodValidator(int entries) { fNumMethods = entries; } @Override public IStatus validate(Object[] selection) { int count = 0; for (Object element : selection) { if (element instanceof IMethodBinding) { count++; } } if (count == 0) { return new Status(IStatus.ERROR, PHPUiPlugin.ID, ""); //$NON-NLS-1$ } return new Status(IStatus.INFO, PHPUiPlugin.ID, MessageFormat.format(Messages.OverrideMethodDialog_7, count, fNumMethods)); } } private Program fUnit = null; public OverrideMethodDialog(Shell shell, TextEditor editor, IType type, boolean isSubType) throws ModelException { super(shell, new BindingLabelProvider(), new OverrideMethodContentProvider(), type, editor); IDocument document = editor.getDocumentProvider().getDocument(editor.getEditorInput()); fUnit = CodeGenerationUtils.getASTRoot(type.getSourceModule(), document, type.getScriptProject().getProject()); ITypeBinding binding = getTypeBinding(fUnit, type); List<IMethodBinding> toImplement = new ArrayList<>(); List<IMethodBinding> overridable = new ArrayList<>(); if (binding != null) { final IMethodBinding[] methods = CodeGenerationUtils.getOverridableMethods(fUnit.getAST(), binding, false); for (final IMethodBinding cur : methods) { if (Bindings.isVisibleInHierarchy(cur)) { overridable.add(cur); } } } for (IMethodBinding element : overridable) { if (Flags.isAbstract(element.getModifiers())) { toImplement.add(element); } } IMethodBinding[] toImplementArray = toImplement.toArray(new IMethodBinding[toImplement.size()]); setInitialSelections(toImplementArray); ArrayList<ITypeBinding> expanded = new ArrayList<>(toImplementArray.length); for (int i = 0; i < toImplementArray.length; i++) { if (!expanded.contains(toImplementArray[i].getDeclaringClass())) { expanded.add(toImplementArray[i].getDeclaringClass()); } } ArrayList<ITypeBinding> types = new ArrayList<>(overridable.size()); for (IMethodBinding o : overridable) { if (!types.contains(o.getDeclaringClass())) { types.add(o.getDeclaringClass()); } } ITypeBinding[] typesArrays = types.toArray(new ITypeBinding[types.size()]); OverrideMethodComparator comparator = new OverrideMethodComparator(binding); if (expanded.isEmpty() && typesArrays.length > 0) { comparator.sort(null, typesArrays); expanded.add(typesArrays[0]); } setExpandedElements(expanded.toArray()); ((OverrideMethodContentProvider) getContentProvider()).init(overridable.toArray(new IMethodBinding[0]), typesArrays); setTitle(Messages.OverrideMethodDialog_8); setMessage(null); setValidator(new OverrideMethodValidator(overridable.size())); setComparator(comparator); setContainerMode(true); setSize(60, 18); setInput(new Object()); } private ITypeBinding getTypeBinding(Program fUnit, IType type) throws ModelException { IEvaluatedType evaluatedType = PHPClassType.fromIType(type); return new TypeBinding(fUnit.getAST().getBindingResolver(), evaluatedType, type); } @Override protected Control createLinkControl(Composite composite) { Link link = new Link(composite, SWT.WRAP); link.setText(Messages.OverrideMethodDialog_9); link.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { openCodeTempatePage("org.eclipse.php.ui.editor.templates.php.codetemplates.overridecomment"); //$NON-NLS-1$ } }); link.setToolTipText(Messages.OverrideMethodDialog_11); GridData gridData = new GridData(SWT.FILL, SWT.BEGINNING, true, false); gridData.widthHint = convertWidthInCharsToPixels(40); // only expand link.setLayoutData(gridData); return link; } @Override protected CheckboxTreeViewer createTreeViewer(Composite composite) { initializeDialogUnits(composite); ViewForm pane = new ViewForm(composite, SWT.BORDER | SWT.FLAT); CheckboxTreeViewer treeViewer = super.createTreeViewer(pane); pane.setContent(treeViewer.getControl()); GridLayout paneLayout = new GridLayout(); paneLayout.marginHeight = 0; paneLayout.marginWidth = 0; paneLayout.numColumns = 1; pane.setLayout(paneLayout); GridData gd = new GridData(GridData.FILL_BOTH); gd.widthHint = convertWidthInCharsToPixels(55); gd.heightHint = convertHeightInCharsToPixels(15); pane.setLayoutData(gd); treeViewer.getTree().setFocus(); return treeViewer; } public boolean hasMethodsToOverride() { return getContentProvider().getElements(null).length > 0; } public Program getCompilationUnit() { return fUnit; } }