/******************************************************************************* * 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.Arrays; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.dltk.core.IField; import org.eclipse.dltk.core.IMember; import org.eclipse.dltk.core.IType; import org.eclipse.dltk.core.ModelException; import org.eclipse.dltk.ui.ModelElementLabelProvider; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.viewers.*; import org.eclipse.php.core.compiler.PHPFlags; import org.eclipse.php.internal.ui.PHPUiPlugin; import org.eclipse.php.internal.ui.util.PHPPluginImages; import org.eclipse.php.ui.util.CodeGenerationUtils; 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.*; import org.eclipse.ui.dialogs.ISelectionStatusValidator; import org.eclipse.ui.editors.text.TextEditor; public class GettersSettersDialog extends PHPSourceActionDialog { private static final int SELECT_GETTERS_ID = IDialogConstants.CLIENT_ID + 1; private static final int SELECT_SETTERS_ID = IDialogConstants.CLIENT_ID + 2; private SettersForFinalFieldsFilter fSettersForFinalFieldsFilter; private ConstantFieldsFilter fConstantFieldFilter; private boolean fSortOrder = true; public GettersSettersDialog(Shell parent, ILabelProvider labelProvider, GettersSettersContentProvider contentProvider, IType textSelection, TextEditor editor) { super(parent, labelProvider, contentProvider, textSelection, editor); fSettersForFinalFieldsFilter = new SettersForFinalFieldsFilter(contentProvider); fConstantFieldFilter = new ConstantFieldsFilter(); } @Override protected CheckboxTreeViewer createTreeViewer(Composite parent) { CheckboxTreeViewer treeViewer = super.createTreeViewer(parent); treeViewer.addFilter(fSettersForFinalFieldsFilter); treeViewer.addFilter(fConstantFieldFilter); return treeViewer; } private Composite addSortOrder(Composite composite) { Label label = new Label(composite, SWT.NONE); label.setText(Messages.GettersSettersAction_56); GridData gd = new GridData(GridData.FILL_BOTH); label.setLayoutData(gd); final Combo combo = new Combo(composite, SWT.READ_ONLY); combo.setItems(new String[] { Messages.GettersSettersAction_57, Messages.GettersSettersAction_58 }); final int methodIndex = 1; // Hard-coded. Change this if the // list gets more complicated. // http://bugs.eclipse.org/bugs/show_bug.cgi?id=38400 int sort = getSortOrder() ? 1 : 0; combo.setText(combo.getItem(sort)); gd = new GridData(GridData.FILL_BOTH); combo.setLayoutData(gd); combo.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { setSortOrder(combo.getSelectionIndex() == methodIndex); } }); return composite; } @Override protected Composite createSelectionButtons(Composite composite) { Composite buttonComposite = super.createSelectionButtons(composite); GridLayout layout = new GridLayout(); buttonComposite.setLayout(layout); createButton(buttonComposite, SELECT_GETTERS_ID, Messages.GettersSettersAction_0, false); createButton(buttonComposite, SELECT_SETTERS_ID, Messages.GettersSettersAction_38, false); layout.marginHeight = 0; layout.marginWidth = 0; layout.numColumns = 1; return buttonComposite; } @Override protected void buttonPressed(int buttonId) { super.buttonPressed(buttonId); switch (buttonId) { case SELECT_GETTERS_ID: { getTreeViewer().setCheckedElements(getGetterSetterElements(true)); updateOKStatus(); break; } case SELECT_SETTERS_ID: { getTreeViewer().setCheckedElements(getGetterSetterElements(false)); updateOKStatus(); break; } } } /* * @see * org.eclipse.jdt.internal.ui.dialogs.SourceActionDialog#createLinkControl * (org.eclipse.swt.widgets.Composite) */ @Override protected Control createLinkControl(Composite composite) { Link link = new Link(composite, SWT.WRAP); link.setText(Messages.GettersSettersDialog_0); link.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { openCodeTempatePage("org.eclipse.php.ui.editor.templates.php.codetemplates.gettercomment"); //$NON-NLS-1$ } }); link.setToolTipText(""); //$NON-NLS-1$ GridData gridData = new GridData(SWT.FILL, SWT.BEGINNING, true, false); gridData.widthHint = convertWidthInCharsToPixels(40); // only expand link.setLayoutData(gridData); return link; } @Override protected Composite createInsertPositionCombo(Composite composite) { Composite entryComposite = super.createInsertPositionCombo(composite); addSortOrder(entryComposite); addVisibilityAndModifiersChoices(entryComposite); return entryComposite; } private Object[] getGetterSetterElements(boolean isGetter) { Object[] allFields = fContentProvider.getElements(null); Set<GetterSetterEntry> result = new HashSet<>(); for (Object object : allFields) { IField field = (IField) object; GetterSetterEntry[] entries = getEntries(field); for (GetterSetterEntry entry : entries) { if (entry.isGetter == isGetter) { result.add(entry); } } } return result.toArray(); } private GetterSetterEntry[] getEntries(IField field) { List<Object> result = Arrays.asList(fContentProvider.getChildren(field)); return result.toArray(new GetterSetterEntry[result.size()]); } public boolean getSortOrder() { return fSortOrder; } public void setSortOrder(boolean sort) { if (fSortOrder != sort) { fSortOrder = sort; if (getTreeViewer() != null) { getTreeViewer().refresh(); } } } private static class SettersForFinalFieldsFilter extends ViewerFilter { private final GettersSettersContentProvider fContentProvider; public SettersForFinalFieldsFilter(GettersSettersContentProvider contentProvider) { fContentProvider = contentProvider; } @Override public boolean select(Viewer viewer, Object parentElement, Object element) { if (element instanceof GetterSetterEntry) { GetterSetterEntry getterSetterEntry = (GetterSetterEntry) element; return getterSetterEntry.isGetter || !getterSetterEntry.isFinal; } else if (element instanceof IField) { Object[] children = fContentProvider.getChildren(element); for (Object element2 : children) { GetterSetterEntry curr = (GetterSetterEntry) element2; if (curr.isGetter || !curr.isFinal) { return true; } } return false; } return true; } } private static class ConstantFieldsFilter extends ViewerFilter { @Override public boolean select(Viewer viewer, Object parentElement, Object element) { if (element instanceof GetterSetterEntry) { GetterSetterEntry getterSetterEntry = (GetterSetterEntry) element; return !getterSetterEntry.isConstant; } else if (element instanceof IField) { IField field = (IField) element; try { int flags = field.getFlags(); if (!PHPFlags.isConstant(flags)) { return true; } } catch (ModelException e) { PHPUiPlugin.log(e); } } return false; } } public static class GettersSettersContentProvider implements ITreeContentProvider { private static final Object[] EMPTY = new Object[0]; private Viewer fViewer; private Map<IField, GetterSetterEntry[]> fGetterSetterEntries; public GettersSettersContentProvider(Map<IField, GetterSetterEntry[]> entries) { fGetterSetterEntries = entries; } @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { fViewer = viewer; } public Viewer getViewer() { return fViewer; } @Override public Object[] getChildren(Object parentElement) { if (parentElement instanceof IField) { IField parentField = (IField) parentElement; int flags; try { flags = parentField.getFlags(); if (!PHPFlags.isConstant(flags)) { return fGetterSetterEntries.get(parentElement); } } catch (ModelException e) { PHPUiPlugin.log(e); } } return EMPTY; } @Override public Object getParent(Object element) { if (element instanceof IMember) { return ((IMember) element).getDeclaringType(); } if (element instanceof GetterSetterEntry) { return ((GetterSetterEntry) element).field; } return null; } @Override public boolean hasChildren(Object element) { return getChildren(element).length > 0; } @Override public Object[] getElements(Object inputElement) { return fGetterSetterEntries.keySet().toArray(); } @Override public void dispose() { } } public static class GetterSetterLabelProvider extends ModelElementLabelProvider { @Override public String getText(Object element) { if (element instanceof GetterSetterEntry) { GetterSetterEntry entry = (GetterSetterEntry) element; try { if (entry.isGetter) { return CodeGenerationUtils.getGetterName(entry.field) + "()"; //$NON-NLS-1$ } else { return CodeGenerationUtils.getSetterName(entry.field) + '(' + entry.field.getElementName() + ')'; } } catch (ModelException e) { PHPUiPlugin.log(e); return ""; //$NON-NLS-1$ } } return super.getText(element); } @Override public Image getImage(Object element) { if (element instanceof GetterSetterEntry) { return PHPPluginImages.get(PHPPluginImages.IMG_FIELD_PUBLIC); } return super.getImage(element); } } public static class GettersSettersSelectionStatusValidator implements ISelectionStatusValidator { private static int fEntries; public GettersSettersSelectionStatusValidator(int entries) { fEntries = entries; } @Override public IStatus validate(Object[] selection) { if (selection == null || selection.length == 0) { return new Status(IStatus.ERROR, PHPUiPlugin.ID, ""); //$NON-NLS-1$ } Set<String> map = new HashSet<>(selection.length); int count = 0; for (Object element : selection) { try { if (element instanceof GetterSetterEntry) { IField getsetField = ((GetterSetterEntry) element).field; if (((GetterSetterEntry) element).isGetter) { if (!map.add(CodeGenerationUtils.getGetterName(getsetField))) { return new Status(IStatus.WARNING, PHPUiPlugin.ID, Messages.GettersSettersDialog_3); } } else { String key = createSignatureKey(CodeGenerationUtils.getSetterName(getsetField), getsetField); if (!map.add(key)) { return new Status(IStatus.WARNING, PHPUiPlugin.ID, Messages.GettersSettersDialog_3); } } count++; } } catch (ModelException e) { PHPUiPlugin.log(e); } } if (count == 0) { return new Status(IStatus.ERROR, PHPUiPlugin.ID, ""); //$NON-NLS-1$ } String message = MessageFormat.format(Messages.SourceActions_ValidatorText, new Object[] { String.valueOf(count), String.valueOf(fEntries) }); return new Status(IStatus.INFO, PHPUiPlugin.ID, message); } /** * Creates a key used in hash maps for a method signature * (gettersettername+arguments(fqn)). * * @param methodName * the method name * @param field * the filed * @return the signature * @throws ModelException * if getting the field's type signature fails */ private String createSignatureKey(String methodName, IField field) throws ModelException { StringBuilder buffer = new StringBuilder(); buffer.append(methodName); buffer.append("#"); //$NON-NLS-1$ String fieldType = field.getDeclaringType().getElementName(); buffer.append(fieldType); return buffer.toString(); } } public static class GetterSetterEntry { public final IField field; public final boolean isGetter; public final boolean isFinal; public final boolean isConstant; public GetterSetterEntry(IField field, boolean isGetterEntry, boolean isFinal, boolean isConstant) { this.field = field; this.isGetter = isGetterEntry; this.isFinal = isFinal; this.isConstant = isConstant; } } }