/*******************************************************************************
* 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.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IProject;
import org.eclipse.dltk.core.*;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.resource.StringConverter;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.viewers.CheckboxTreeViewer;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.php.internal.ui.PHPUiPlugin;
import org.eclipse.php.internal.ui.preferences.PHPCodeTemplatePreferencePage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.*;
import org.eclipse.ui.dialogs.CheckedTreeSelectionDialog;
import org.eclipse.ui.dialogs.PreferencesUtil;
import org.eclipse.ui.editors.text.TextEditor;
import org.eclipse.wst.jsdt.internal.ui.refactoring.IVisibilityChangeListener;
/**
* This class is used for creating the dialog for Source actions (based on the
* JDT source dialog).
*
*/
public class PHPSourceActionDialog extends CheckedTreeSelectionDialog {
private static final String SETTINGS_SECTION_METHODS = "PHPSourceActionDialog.methods"; //$NON-NLS-1$
private static final String SETTINGS_VISIBILITY_MODIFIER = "PHPSourceActionDialog.VisibilityModifier"; //$NON-NLS-1$
private static final String SETTINGS_FINAL_MODIFIER = "PHPSourceActionDialog.FinalModifier"; //$NON-NLS-1$
private static final String SETTINGS_COMMENTS = "PHPSourceActionDialog.Comments"; //$NON-NLS-1$
private static final String SETTINGS_INSERT_POSITION = "PHPSourceActionDialog.InsertPosition"; //$NON-NLS-1$
private static final int INSERT_FIRST_INDEX = 0;
private static final int INSERT_LAST_INDEX = 1;
private static final int INSERT_POSITION_FROM_EDITOR = 2;
private final List<IMethod> fInsertPositions;
private final List<String> fLabels;
private int fCurrentPositionIndex;
ITreeContentProvider fContentProvider;
private int fVisibilityModifier;
private boolean fFinal;
private IProject fProject;
private boolean fGenerateComment;
private final int fWidth, fHeight;
private final String fCommentString;
private boolean fEnableInsertPosition = true;
protected IDialogSettings fSettings;
protected boolean fHasUserChangedPositionIndex;
private TextEditor fEditor;
public PHPSourceActionDialog(Shell parent, ILabelProvider labelProvider, ITreeContentProvider contentProvider,
IType type, TextEditor editor) {
super(parent, labelProvider, contentProvider);
fEditor = editor;
fContentProvider = contentProvider;
fCommentString = Messages.GettersSettersAction_27;
setEmptyListMessage(Messages.GettersSettersAction_28);
fWidth = 60;
fHeight = 18;
IDialogSettings dialogSettings = PHPUiPlugin.getDefault().getDialogSettings();
String sectionId = SETTINGS_SECTION_METHODS;
fSettings = dialogSettings.getSection(sectionId);
if (fSettings == null) {
fSettings = dialogSettings.addNewSection(sectionId);
}
fInsertPositions = new ArrayList<>();
fLabels = new ArrayList<>();
// generate a list of possible insertion locations
IMethod[] methods = null;
try {
methods = type.getMethods();
} catch (ModelException e1) {
}
if (methods == null) {
return;
}
fInsertPositions.add(methods.length > 0 ? methods[0] : null); // first
// //$NON-NLS-1$
fInsertPositions.add(null); // last
fLabels.add(Messages.GettersSettersAction_29);
fLabels.add(Messages.GettersSettersAction_30);
for (int i = 0; i < methods.length; i++) {
IMethod curr = methods[i];
StringBuilder methodLabel = new StringBuilder();
methodLabel.append(curr.getElementName());
methodLabel.append("("); //$NON-NLS-1$
String[] param = null;
try {
param = curr.getParameterNames();
} catch (ModelException e) {
PHPUiPlugin.log(e);
}
if (param != null) {
for (int j = 0; j < param.length; j++) {
methodLabel.append("$"); //$NON-NLS-1$
methodLabel.append(param[j]);
if (j < param.length - 1) {
methodLabel.append(", "); //$NON-NLS-1$
}
}
}
methodLabel.append(')');
fLabels.add(Messages.GettersSettersAction_31 + '\'' + methodLabel.toString() + '\'');
if (i < methods.length - 1) {
fInsertPositions.add(methods[i + 1]);
}
}
fInsertPositions.add(null);
try {
restoreWidgetsValue(methods);
} catch (ModelException e) {
}
}
public void setProject(IProject project) {
fProject = project;
}
public IProject getProject() {
return fProject;
}
protected void restoreWidgetsValue(IMethod[] methods) throws ModelException {
fVisibilityModifier = asInt(fSettings.get(SETTINGS_VISIBILITY_MODIFIER), Flags.AccPublic);
fFinal = asBoolean(fSettings.get(SETTINGS_FINAL_MODIFIER), false);
fGenerateComment = asBoolean(fSettings.get(SETTINGS_COMMENTS), true);
int storedPositionIndex = asInt(fSettings.get(SETTINGS_INSERT_POSITION), INSERT_POSITION_FROM_EDITOR);
if (storedPositionIndex == INSERT_POSITION_FROM_EDITOR) {
int indexAfterCursor = getElementAfterCursorPosition(fEditor, methods);
if (indexAfterCursor == -1 || indexAfterCursor == 0) {
fCurrentPositionIndex = INSERT_FIRST_INDEX;
} else if (indexAfterCursor > 0) {
fCurrentPositionIndex = indexAfterCursor + 1;
}
} else {
fCurrentPositionIndex = storedPositionIndex <= INSERT_FIRST_INDEX ? INSERT_FIRST_INDEX : INSERT_LAST_INDEX;
}
}
private int getElementAfterCursorPosition(TextEditor editor, IModelElement[] members) throws ModelException {
if (editor == null) {
return -1;
}
int offset = ((ITextSelection) editor.getSelectionProvider().getSelection()).getOffset();
for (int i = 0; i < members.length; i++) {
IMember curr = (IMember) members[i];
ISourceRange range = curr.getSourceRange();
if (offset < range.getOffset()) {
return i;
}
}
return members.length;
}
protected Composite addVisibilityAndModifiersChoices(Composite buttonComposite) {
// Add visibility and modifiers buttons
IVisibilityChangeListener visibilityChangeListener = new IVisibilityChangeListener() {
@Override
public void visibilityChanged(int newVisibility) {
setVisibility(newVisibility);
}
@Override
public void modifierChanged(int modifier, boolean isChecked) {
switch (modifier) {
case Flags.AccFinal: {
setFinal(isChecked);
return;
}
default:
return;
}
}
};
int initialVisibility = getVisibilityModifier();
int[] availableVisibilities = new int[] { Flags.AccPublic, Flags.AccProtected, Flags.AccPrivate };
return createVisibilityControlAndModifiers(buttonComposite, visibilityChangeListener, availableVisibilities,
initialVisibility);
}
protected Composite createVisibilityControlAndModifiers(Composite parent,
final IVisibilityChangeListener visibilityChangeListener, int[] availableVisibilities,
int correctVisibility) {
Composite visibilityComposite = createVisibilityControl(parent, visibilityChangeListener, availableVisibilities,
correctVisibility);
Button finalCheckboxButton = new Button(visibilityComposite, SWT.CHECK);
finalCheckboxButton.setText(Messages.GettersSettersAction_37);
GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
finalCheckboxButton.setLayoutData(gd);
finalCheckboxButton.setData(Flags.AccFinal);
finalCheckboxButton.setEnabled(true);
finalCheckboxButton.setSelection(isFinal());
finalCheckboxButton.addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent event) {
visibilityChangeListener.modifierChanged(((Integer) event.widget.getData()).intValue(),
((Button) event.widget).getSelection());
}
@Override
public void widgetDefaultSelected(SelectionEvent event) {
widgetSelected(event);
}
});
return visibilityComposite;
}
protected Composite createVisibilityControl(Composite parent,
final IVisibilityChangeListener visibilityChangeListener, int[] availableVisibilities,
int correctVisibility) {
List<Integer> allowedVisibilities = convertToIntegerList(availableVisibilities);
if (allowedVisibilities.size() == 1) {
return null;
}
Group group = new Group(parent, SWT.NONE);
group.setText(Messages.GettersSettersAction_33); // $NON-NLS-1$
GridData gd = new GridData(GridData.FILL_BOTH);
group.setLayoutData(gd);
GridLayout layout = new GridLayout();
layout.makeColumnsEqualWidth = true;
layout.numColumns = 4;
group.setLayout(layout);
String[] labels = new String[] { Messages.GettersSettersAction_34, Messages.GettersSettersAction_35,
Messages.GettersSettersAction_36, };
Integer[] data = new Integer[] { Flags.AccPublic, Flags.AccProtected, Flags.AccPrivate };
Integer initialVisibility = correctVisibility;
for (int i = 0; i < labels.length; i++) {
Button radio = new Button(group, SWT.RADIO);
Integer visibilityCode = data[i];
radio.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL));
radio.setText(labels[i]);
radio.setData(visibilityCode);
radio.setSelection(visibilityCode.equals(initialVisibility));
radio.setEnabled(allowedVisibilities.contains(visibilityCode));
radio.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
visibilityChangeListener.visibilityChanged(((Integer) event.widget.getData()).intValue());
}
});
}
return group;
}
private List<Integer> convertToIntegerList(int[] array) {
List<Integer> result = new ArrayList<>(array.length);
for (int element : array) {
result.add(element);
}
return result;
}
public boolean isFinal() {
return fFinal;
}
public int getVisibilityModifier() {
return fVisibilityModifier;
}
protected void setVisibility(int visibility) {
fVisibilityModifier = visibility;
}
private void setFinal(boolean value) {
fFinal = value;
}
protected boolean asBoolean(String string, boolean defaultValue) {
if (string != null) {
return StringConverter.asBoolean(string, defaultValue);
}
return defaultValue;
}
protected int asInt(String string, int defaultValue) {
if (string != null) {
return StringConverter.asInt(string, defaultValue);
}
return defaultValue;
}
@Override
public void create() {
super.create();
// select the first checked element, or if none are checked, the first
// element
CheckboxTreeViewer treeViewer = getTreeViewer();
TreeItem[] items = treeViewer.getTree().getItems();
if (items.length > 0) {
Object revealedElement = items[0];
for (TreeItem item : items) {
if (item.getChecked()) {
revealedElement = item.getData();
break;
}
}
treeViewer.setSelection(new StructuredSelection(revealedElement));
treeViewer.reveal(revealedElement);
}
}
public void setGenerateComment(boolean comment) {
fGenerateComment = comment;
}
public boolean getGenerateComment() {
return fGenerateComment;
}
protected ITreeContentProvider getContentProvider() {
return fContentProvider;
}
protected Control createLinkControl(Composite composite) {
return null; // No link as default
}
@Override
protected Control createDialogArea(Composite parent) {
initializeDialogUnits(parent);
Composite composite = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
GridData gd;
layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
composite.setLayout(layout);
Label messageLabel = createMessageArea(composite);
if (messageLabel != null) {
gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
gd.horizontalSpan = 2;
messageLabel.setLayoutData(gd);
}
Composite inner = new Composite(composite, SWT.NONE);
GridLayout innerLayout = new GridLayout();
innerLayout.numColumns = 2;
innerLayout.marginHeight = 0;
innerLayout.marginWidth = 0;
inner.setLayout(innerLayout);
inner.setFont(parent.getFont());
CheckboxTreeViewer treeViewer = createTreeViewer(inner);
gd = new GridData(GridData.FILL_BOTH);
gd.widthHint = convertWidthInCharsToPixels(fWidth);
gd.heightHint = convertHeightInCharsToPixels(fHeight);
treeViewer.getControl().setLayoutData(gd);
Composite buttonComposite = createSelectionButtons(inner);
gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_FILL);
buttonComposite.setLayoutData(gd);
gd = new GridData(GridData.FILL_BOTH);
inner.setLayoutData(gd);
Composite insertPositionComposite = createInsertPositionCombo(composite);
insertPositionComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
Composite commentComposite = createCommentSelection(composite);
commentComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
Control linkControl = createLinkControl(composite);
if (linkControl != null) {
linkControl.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
}
gd = new GridData(GridData.FILL_BOTH);
composite.setLayoutData(gd);
applyDialogFont(composite);
return composite;
}
@Override
protected Composite createSelectionButtons(Composite composite) {
Composite buttonComposite = super.createSelectionButtons(composite);
GridLayout layout = new GridLayout();
buttonComposite.setLayout(layout);
layout.marginHeight = 0;
layout.marginWidth = 0;
layout.numColumns = 1;
return buttonComposite;
}
protected Composite createInsertPositionCombo(Composite composite) {
Composite selectionComposite = new Composite(composite, SWT.NONE);
GridLayout layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
selectionComposite.setLayout(layout);
addOrderEntryChoices(selectionComposite);
return selectionComposite;
}
private Composite addOrderEntryChoices(Composite buttonComposite) {
Label enterLabel = new Label(buttonComposite, SWT.NONE);
enterLabel.setText(Messages.GettersSettersAction_32);
if (!fEnableInsertPosition) {
enterLabel.setEnabled(false);
}
GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
enterLabel.setLayoutData(gd);
final Combo enterCombo = new Combo(buttonComposite, SWT.READ_ONLY);
if (!fEnableInsertPosition) {
enterCombo.setEnabled(false);
}
fillWithPossibleInsertPositions(enterCombo);
gd = new GridData(GridData.FILL_BOTH);
gd.widthHint = convertWidthInCharsToPixels(fWidth);
enterCombo.setLayoutData(gd);
enterCombo.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
int index = enterCombo.getSelectionIndex();
// Add persistence only if first or last method:
// http://bugs.eclipse.org/bugs/show_bug.cgi?id=38400
setInsertPosition(index);
fHasUserChangedPositionIndex = true;
}
});
return buttonComposite;
}
private void fillWithPossibleInsertPositions(Combo combo) {
combo.setItems(fLabels.toArray(new String[fLabels.size()]));
combo.select(fCurrentPositionIndex);
}
protected void openCodeTempatePage(String id) {
Map<String, String> arg = new HashMap<>();
arg.put(PHPCodeTemplatePreferencePage.DATA_SELECT_TEMPLATE, id);
PreferencesUtil
.createPropertyDialogOn(getShell(), getProject(), PHPCodeTemplatePreferencePage.PROP_ID, null, arg)
.open();
}
/***
* Set insert position valid input is 0 for the first position, 1 for the
* last position, > 1 for all else.
*/
private void setInsertPosition(int insert) {
fCurrentPositionIndex = insert;
}
/*
* Determine where in the file to enter the newly created methods.
*/
public IMethod getElementPosition() {
return fInsertPositions.get(fCurrentPositionIndex);
}
public int getInsertOffset() throws ModelException {
IModelElement elementPosition = getElementPosition();
if (elementPosition instanceof ISourceReference) {
return ((ISourceReference) elementPosition).getSourceRange().getOffset();
}
return -1;
}
protected Composite createCommentSelection(Composite composite) {
Composite commentComposite = new Composite(composite, SWT.NONE);
GridLayout layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
commentComposite.setLayout(layout);
commentComposite.setFont(composite.getFont());
Button commentButton = new Button(commentComposite, SWT.CHECK);
commentButton.setText(fCommentString);
commentButton.addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent e) {
boolean isSelected = (((Button) e.widget).getSelection());
setGenerateComment(isSelected);
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {
widgetSelected(e);
}
});
commentButton.setSelection(getGenerateComment());
GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
gd.horizontalSpan = 2;
commentButton.setLayoutData(gd);
return commentComposite;
}
@Override
public boolean close() {
fSettings.put(SETTINGS_VISIBILITY_MODIFIER, StringConverter.asString(fVisibilityModifier));
fSettings.put(SETTINGS_FINAL_MODIFIER, StringConverter.asString(fFinal));
fSettings.put(SETTINGS_COMMENTS, fGenerateComment);
if (fHasUserChangedPositionIndex) {
if (fCurrentPositionIndex == INSERT_FIRST_INDEX || fCurrentPositionIndex == INSERT_LAST_INDEX) {
fSettings.put(SETTINGS_INSERT_POSITION, StringConverter.asString(fCurrentPositionIndex));
} else if (fEditor != null) {
fSettings.put(SETTINGS_INSERT_POSITION, StringConverter.asString(INSERT_POSITION_FROM_EDITOR));
}
}
return super.close();
}
}