blob: 940241cf7edc6f62ee047e52dff5ec9605e64672 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2005 IBM Corporation 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.ui.dialogs;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
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.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.resource.StringConverter;
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.jface.text.ITextSelection;
import org.eclipse.ui.dialogs.CheckedTreeSelectionDialog;
import org.eclipse.ui.dialogs.PreferencesUtil;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.ISourceReference;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.internal.corext.util.Messages;
import org.eclipse.jdt.ui.JavaElementLabels;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.actions.ActionMessages;
import org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitEditor;
import org.eclipse.jdt.internal.ui.preferences.CodeTemplatePreferencePage;
import org.eclipse.jdt.internal.ui.preferences.JavaPreferencesSettings;
import org.eclipse.jdt.internal.ui.refactoring.IVisibilityChangeListener;
/**
* An advanced version of CheckedTreeSelectionDialog with right-side button layout and
* extra buttons and composites.
*/
public class SourceActionDialog extends CheckedTreeSelectionDialog {
private List fInsertPositions;
private List fLabels;
private int fCurrentPositionIndex;
private IDialogSettings fSettings;
private CompilationUnitEditor fEditor;
private ITreeContentProvider fContentProvider;
private boolean fGenerateComment;
private IType fType;
private int fWidth, fHeight;
private String fCommentString;
private boolean fEnableInsertPosition= true;
private int fVisibilityModifier;
private boolean fFinal;
private boolean fSynchronized;
private final String SETTINGS_SECTION_METHODS= "SourceActionDialog.methods"; //$NON-NLS-1$
private final String SETTINGS_SECTION_CONSTRUCTORS= "SourceActionDialog.constructors"; //$NON-NLS-1$
private final String SETTINGS_INSERTPOSITION= "InsertPosition"; //$NON-NLS-1$
private final String SETTINGS_VISIBILITY_MODIFIER= "VisibilityModifier"; //$NON-NLS-1$
private final String SETTINGS_FINAL_MODIFIER= "FinalModifier"; //$NON-NLS-1$
private final String SETTINGS_SYNCHRONIZED_MODIFIER= "SynchronizedModifier"; //$NON-NLS-1$
private final String SETTINGS_COMMENTS= "Comments"; //$NON-NLS-1$
private Composite fInsertPositionComposite;
public SourceActionDialog(Shell parent, ILabelProvider labelProvider, ITreeContentProvider contentProvider, CompilationUnitEditor editor, IType type, boolean isConstructor) throws JavaModelException {
super(parent, labelProvider, contentProvider);
fEditor= editor;
fContentProvider= contentProvider;
fType= type;
fCommentString= ActionMessages.SourceActionDialog_createMethodComment;
setEmptyListMessage(ActionMessages.SourceActionDialog_no_entries);
fWidth= 60;
fHeight= 18;
int insertionDefault= isConstructor ? 0 : 1;
boolean generateCommentsDefault= JavaPreferencesSettings.getCodeGenerationSettings(type.getJavaProject()).createComments;
IDialogSettings dialogSettings= JavaPlugin.getDefault().getDialogSettings();
String sectionId= isConstructor ? SETTINGS_SECTION_CONSTRUCTORS : SETTINGS_SECTION_METHODS;
fSettings= dialogSettings.getSection(sectionId);
if (fSettings == null) {
fSettings= dialogSettings.addNewSection(sectionId);
}
fVisibilityModifier= asInt(fSettings.get(SETTINGS_VISIBILITY_MODIFIER), Modifier.PUBLIC);
fFinal= asBoolean(fSettings.get(SETTINGS_FINAL_MODIFIER), false);
fSynchronized= asBoolean(fSettings.get(SETTINGS_SYNCHRONIZED_MODIFIER), false);
fCurrentPositionIndex= asInt(fSettings.get(SETTINGS_INSERTPOSITION), insertionDefault);
fGenerateComment= asBoolean(fSettings.get(SETTINGS_COMMENTS), generateCommentsDefault);
fInsertPositions= new ArrayList();
fLabels= new ArrayList();
IJavaElement[] members= fType.getChildren();
IMethod[] methods= fType.getMethods();
fInsertPositions.add(methods.length > 0 ? methods[0]: null); // first
fInsertPositions.add(null); // last
fLabels.add(ActionMessages.SourceActionDialog_first_method);
fLabels.add(ActionMessages.SourceActionDialog_last_method);
if (hasCursorPositionElement(fEditor, members, fInsertPositions)) {
fLabels.add(ActionMessages.SourceActionDialog_cursor);
fCurrentPositionIndex= 2;
} else {
// code is needed to deal with bogus values already present in the dialog store.
fCurrentPositionIndex= Math.max(fCurrentPositionIndex, 0);
fCurrentPositionIndex= Math.min(fCurrentPositionIndex, 1);
}
for (int i = 0; i < methods.length; i++) {
IMethod curr= methods[i];
String methodLabel= JavaElementLabels.getElementLabel(curr, JavaElementLabels.M_PARAMETER_TYPES);
fLabels.add(Messages.format(ActionMessages.SourceActionDialog_after, methodLabel));
fInsertPositions.add(findSibling(curr, members));
}
fInsertPositions.add(null);
}
protected IType getType() {
return fType;
}
private boolean asBoolean(String string, boolean defaultValue) {
if (string != null) {
return StringConverter.asBoolean(string, defaultValue);
}
return defaultValue;
}
private int asInt(String string, int defaultValue) {
if (string != null) {
return StringConverter.asInt(string, defaultValue);
}
return defaultValue;
}
private IJavaElement findSibling(IMethod curr, IJavaElement[] members) throws JavaModelException {
IJavaElement res= null;
int methodStart= curr.getSourceRange().getOffset();
for (int i= members.length-1; i >= 0; i--) {
IMember member= (IMember) members[i];
if (methodStart >= member.getSourceRange().getOffset()) {
return res;
}
res= member;
}
return null;
}
private boolean hasCursorPositionElement(CompilationUnitEditor editor, IJavaElement[] members, List insertPositions) throws JavaModelException {
if (editor == null) {
return false;
}
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()) {
insertPositions.add(curr);
return true;
} else if (offset < range.getOffset() + range.getLength()) {
return false; // in the middle of a member
}
}
insertPositions.add(null);
return true;
}
/* (non-Javadoc)
* @see org.eclipse.jface.dialogs.Dialog#close()
*/
public boolean close() {
fSettings.put(SETTINGS_VISIBILITY_MODIFIER, StringConverter.asString(fVisibilityModifier));
fSettings.put(SETTINGS_FINAL_MODIFIER, StringConverter.asString(fFinal));
fSettings.put(SETTINGS_SYNCHRONIZED_MODIFIER, StringConverter.asString(fSynchronized));
if (fCurrentPositionIndex == 0 || fCurrentPositionIndex == 1) {
fSettings.put(SETTINGS_INSERTPOSITION, StringConverter.asString(fCurrentPositionIndex));
}
fSettings.put(SETTINGS_COMMENTS, fGenerateComment);
return super.close();
}
/**
* Sets the size of the tree in unit of characters.
* @param width the width of the tree.
* @param height the height of the tree.
*/
public void setSize(int width, int height) {
fWidth = width;
fHeight = height;
}
/***
* 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;
}
public void setCommentString(String string) {
fCommentString= string;
}
protected ITreeContentProvider getContentProvider() {
return fContentProvider;
}
public boolean getGenerateComment() {
return fGenerateComment;
}
public int getVisibilityModifier() {
return fVisibilityModifier;
}
public void setGenerateComment(boolean comment) {
fGenerateComment= comment;
}
protected void setVisibility(int visibility) {
fVisibilityModifier= visibility;
}
private void setFinal(boolean value) {
fFinal= value;
}
private void setSynchronized(boolean value) {
fSynchronized= value;
}
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 void buttonPressed(int buttonId) {
switch (buttonId) {
case IDialogConstants.OK_ID: {
okPressed();
break;
}
case IDialogConstants.CANCEL_ID: {
cancelPressed();
break;
}
}
}
/**
* Returns a composite containing the label created at the top of the dialog. Returns null if there is the
* message for the label is null.
*/
protected Label createMessageArea(Composite composite) {
if (getMessage() != null) {
Label label = new Label(composite,SWT.NONE);
label.setText(getMessage());
label.setFont(composite.getFont());
return label;
}
return null;
}
/*
* @see Dialog#createDialogArea(Composite)
*/
protected Control createDialogArea(Composite parent) {
initializeDialogUnits(parent);
Composite composite= new Composite(parent, SWT.NONE);
GridLayout layout= new GridLayout();
GridData gd= null;
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);
fInsertPositionComposite= createInsertPositionCombo(composite);
fInsertPositionComposite.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;
}
protected Control createLinkControl(Composite composite) {
return null; // No link as default
}
protected void openCodeTempatePage(String id) {
HashMap arg= new HashMap();
arg.put(CodeTemplatePreferencePage.DATA_SELECT_TEMPLATE, id);
PreferencesUtil.createPropertyDialogOn(getShell(), fType.getJavaProject().getProject(), CodeTemplatePreferencePage.PROP_ID, null, arg).open();
}
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() {
public void widgetSelected(SelectionEvent e) {
boolean isSelected= (((Button) e.widget).getSelection());
setGenerateComment(isSelected);
}
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;
}
protected Composite addVisibilityAndModifiersChoices(Composite buttonComposite) {
// Add visibility and modifiers buttons: http://bugs.eclipse.org/bugs/show_bug.cgi?id=35870
// Add persistence of options: http://bugs.eclipse.org/bugs/show_bug.cgi?id=38400
IVisibilityChangeListener visibilityChangeListener= new IVisibilityChangeListener(){
public void visibilityChanged(int newVisibility) {
setVisibility(newVisibility);
}
public void modifierChanged(int modifier, boolean isChecked) {
switch (modifier) {
case Modifier.FINAL: {
setFinal(isChecked);
return;
}
case Modifier.SYNCHRONIZED: {
setSynchronized(isChecked);
return;
}
default: return;
}
}
};
int initialVisibility= getVisibilityModifier();
int[] availableVisibilities= new int[]{Modifier.PUBLIC, Modifier.PROTECTED, Modifier.PRIVATE, Modifier.NONE};
Composite visibilityComposite= createVisibilityControlAndModifiers(buttonComposite, visibilityChangeListener, availableVisibilities, initialVisibility);
return visibilityComposite;
}
private List convertToIntegerList(int[] array) {
List result= new ArrayList(array.length);
for (int i= 0; i < array.length; i++) {
result.add(new Integer(array[i]));
}
return result;
}
/* (non-Javadoc)
* @see org.eclipse.ui.dialogs.CheckedTreeSelectionDialog#create()
*/
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 (int i= 0; i < items.length; i++) {
if (items[i].getChecked()) {
revealedElement= items[i].getData();
break;
}
}
treeViewer.setSelection(new StructuredSelection(revealedElement));
treeViewer.reveal(revealedElement);
}
}
protected Composite createVisibilityControl(Composite parent, final IVisibilityChangeListener visibilityChangeListener, int[] availableVisibilities, int correctVisibility) {
List allowedVisibilities= convertToIntegerList(availableVisibilities);
if (allowedVisibilities.size() == 1)
return null;
Group group= new Group(parent, SWT.NONE);
group.setText(ActionMessages.SourceActionDialog_modifier_group);
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[] {
ActionMessages.SourceActionDialog_modifier_public,
ActionMessages.SourceActionDialog_modifier_protected,
ActionMessages.SourceActionDialog_modifier_default,
ActionMessages.SourceActionDialog_modifier_private,
};
Integer[] data= new Integer[] {
new Integer(Modifier.PUBLIC),
new Integer(Modifier.PROTECTED),
new Integer(Modifier.NONE),
new Integer(Modifier.PRIVATE)};
Integer initialVisibility= new Integer(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() {
public void widgetSelected(SelectionEvent event) {
visibilityChangeListener.visibilityChanged(((Integer)event.widget.getData()).intValue());
}
});
}
return group;
}
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(ActionMessages.SourceActionDialog_modifier_final);
GridData gd= new GridData(GridData.HORIZONTAL_ALIGN_FILL);
finalCheckboxButton.setLayoutData(gd);
finalCheckboxButton.setData(new Integer(Modifier.FINAL));
finalCheckboxButton.setEnabled(true);
finalCheckboxButton.setSelection(isFinal());
finalCheckboxButton.addSelectionListener(new SelectionListener() {
public void widgetSelected(SelectionEvent event) {
visibilityChangeListener.modifierChanged(((Integer)event.widget.getData()).intValue(), ((Button) event.widget).getSelection());
}
public void widgetDefaultSelected(SelectionEvent event) {
widgetSelected(event);
}
});
Button syncCheckboxButton= new Button(visibilityComposite, SWT.CHECK);
syncCheckboxButton.setText(ActionMessages.SourceActionDialog_modifier_synchronized);
gd= new GridData(GridData.HORIZONTAL_ALIGN_FILL);
syncCheckboxButton.setLayoutData(gd);
syncCheckboxButton.setData(new Integer(Modifier.SYNCHRONIZED));
syncCheckboxButton.setEnabled(true);
syncCheckboxButton.setSelection(isSynchronized());
syncCheckboxButton.addSelectionListener(new SelectionListener() {
public void widgetSelected(SelectionEvent event) {
visibilityChangeListener.modifierChanged(((Integer)event.widget.getData()).intValue(), ((Button) event.widget).getSelection());
}
public void widgetDefaultSelected(SelectionEvent event) {
widgetSelected(event);
}
});
return visibilityComposite;
}
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(ActionMessages.SourceActionDialog_enterAt_label);
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(){
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);
}
});
return buttonComposite;
}
private void fillWithPossibleInsertPositions(Combo combo) {
combo.setItems((String[]) fLabels.toArray(new String[fLabels.size()]));
combo.select(fCurrentPositionIndex);
}
public boolean getFinal() {
return fFinal;
}
public boolean getSynchronized() {
return fSynchronized;
}
public boolean isFinal() {
return fFinal;
}
public boolean isSynchronized() {
return fSynchronized;
}
public void setElementPositionEnabled(boolean enabled) {
fEnableInsertPosition= enabled;
}
public boolean isElementPositionEnabled() {
return fEnableInsertPosition;
}
/*
* Determine where in the file to enter the newly created methods.
*/
public IJavaElement getElementPosition() {
return (IJavaElement) fInsertPositions.get(fCurrentPositionIndex);
}
public int getInsertOffset() throws JavaModelException {
IJavaElement elementPosition= getElementPosition();
if (elementPosition instanceof ISourceReference) {
return ((ISourceReference) elementPosition).getSourceRange().getOffset();
}
return -1;
}
}