blob: 2955cf569f0c4ab316305f47ef358a7a1d0b444c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2014 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
* Lars Vogel <Lars.Vogel@gmail.com> - Bug 427883
*******************************************************************************/
package org.eclipse.jdt.internal.ui.refactoring;
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.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.fieldassist.ControlDecoration;
import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.CellLabelProvider;
import org.eclipse.jface.viewers.CheckboxTableViewer;
import org.eclipse.jface.viewers.ColumnViewer;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.EditingSupport;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.ViewerCell;
import org.eclipse.jface.window.Window;
import org.eclipse.ltk.core.refactoring.Refactoring;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.ltk.core.refactoring.RefactoringStatusEntry;
import org.eclipse.ltk.ui.refactoring.RefactoringWizard;
import org.eclipse.ltk.ui.refactoring.UserInputWizardPage;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.refactoring.descriptors.ExtractClassDescriptor;
import org.eclipse.jdt.core.refactoring.descriptors.ExtractClassDescriptor.Field;
import org.eclipse.jdt.internal.corext.refactoring.structure.ExtractClassRefactoring.ExtractClassDescriptorVerification;
import org.eclipse.jdt.internal.corext.util.JavaConventionsUtil;
import org.eclipse.jdt.internal.corext.util.Messages;
import org.eclipse.jdt.ui.JavaElementLabels;
import org.eclipse.jdt.internal.ui.util.SWTUtil;
import org.eclipse.jdt.internal.ui.util.TableLayoutComposite;
public class ExtractClassWizard extends RefactoringWizard {
private ExtractClassDescriptor fDescriptor;
public ExtractClassWizard(ExtractClassDescriptor descriptor, Refactoring refactoring) {
super(refactoring, DIALOG_BASED_USER_INTERFACE);
fDescriptor= descriptor;
setDefaultPageTitle(RefactoringMessages.ExtractClassWizard_page_title);
}
@Override
protected void addUserInputPages() {
addPage(new ExtractClassUserInputWizardPage());
}
private class ExtractClassUserInputWizardPage extends UserInputWizardPage {
private static final String CREATE_GETTER_SETTER= "CREATE_GETTER_SETTER"; //$NON-NLS-1$
private static final String CREATE_TOP_LEVEL_SETTING= "CREATE_TOPLEVEL"; //$NON-NLS-1$
private ControlDecoration fClassNameDecoration;
private ControlDecoration fParameterNameDecoration;
public ExtractClassUserInputWizardPage() {
super("ExtractClass"); //$NON-NLS-1$
setTitle(RefactoringMessages.ExtractClassWizard_page_title);
}
@Override
public void createControl(Composite parent) {
initializeDialogUnits(parent);
Composite result= new Composite(parent, SWT.NONE);
result.setLayout(new GridLayout(2, false));
createClassNameInput(result);
createLocationInput(result);
createTable(result);
createGetterSetterInput(result);
createParameterNameInput(result);
setControl(result);
validateRefactoring();
}
private void createLocationInput(Composite parent) {
Label l= new Label(parent, SWT.NONE);
l.setText(RefactoringMessages.ExtractClassWizard_label_destination);
Composite composite= new Composite(parent, SWT.None);
GridLayout gridLayout= new GridLayout(2, false);
gridLayout.marginHeight= 0;
gridLayout.marginWidth= 0;
composite.setLayout(gridLayout);
GridData gridData= new GridData(GridData.FILL_HORIZONTAL);
gridData.horizontalIndent= FieldDecorationRegistry.getDefault().getMaximumDecorationWidth();
composite.setLayoutData(gridData);
final Button topLvlRadio= new Button(composite, SWT.RADIO);
topLvlRadio.setText(RefactoringMessages.ExtractClassWizard_radio_top_level);
topLvlRadio.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
boolean fAsTopLevel= topLvlRadio.getSelection();
fDescriptor.setCreateTopLevel(fAsTopLevel);
validateRefactoring();
}
});
Button nestedRadio= new Button(composite, SWT.RADIO);
nestedRadio.setText(Messages.format(RefactoringMessages.ExtractClassWizard_radio_nested, JavaElementLabels.getElementLabel(fDescriptor.getType(), JavaElementLabels.ALL_DEFAULT)));
boolean createAsTopLevel= getBooleanSetting(CREATE_TOP_LEVEL_SETTING, fDescriptor.isCreateTopLevel());
fDescriptor.setCreateTopLevel(createAsTopLevel);
topLvlRadio.setSelection(createAsTopLevel);
nestedRadio.setSelection(!createAsTopLevel);
}
private void createGetterSetterInput(Composite result) {
final Button button= new Button(result, SWT.CHECK);
button.setText(RefactoringMessages.ExtractClassWizard_checkbox_create_gettersetter);
button.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
fDescriptor.setCreateGetterSetter(button.getSelection());
validateRefactoring();
}
});
button.setSelection(getBooleanSetting(CREATE_GETTER_SETTER, fDescriptor.isCreateGetterSetter()));
fDescriptor.setCreateGetterSetter(button.getSelection());
GridData gridData= new GridData();
gridData.horizontalSpan= 2;
button.setLayoutData(gridData);
}
private void createClassNameInput(Composite result) {
Label label= new Label(result, SWT.LEAD);
label.setText(RefactoringMessages.ExtractClassWizard_label_class_name);
final Text text= new Text(result, SWT.SINGLE | SWT.BORDER);
fClassNameDecoration= new ControlDecoration(text, SWT.TOP | SWT.LEAD);
text.setText(fDescriptor.getClassName());
text.selectAll();
text.setFocus();
text.addModifyListener(e -> {
fDescriptor.setClassName(text.getText());
validateRefactoring();
});
GridData gridData= new GridData(GridData.FILL_HORIZONTAL);
gridData.horizontalIndent= FieldDecorationRegistry.getDefault().getMaximumDecorationWidth();
text.setLayoutData(gridData);
}
protected void updateDecoration(ControlDecoration decoration, RefactoringStatus status) {
RefactoringStatusEntry highestSeverity= status.getEntryWithHighestSeverity();
if (highestSeverity != null) {
Image newImage= null;
FieldDecorationRegistry registry= FieldDecorationRegistry.getDefault();
switch (highestSeverity.getSeverity()) {
case RefactoringStatus.INFO:
newImage= registry.getFieldDecoration(FieldDecorationRegistry.DEC_INFORMATION).getImage();
break;
case RefactoringStatus.WARNING:
newImage= registry.getFieldDecoration(FieldDecorationRegistry.DEC_WARNING).getImage();
break;
case RefactoringStatus.FATAL:
case RefactoringStatus.ERROR:
newImage= registry.getFieldDecoration(FieldDecorationRegistry.DEC_ERROR).getImage();
}
decoration.setDescriptionText(highestSeverity.getMessage());
decoration.setImage(newImage);
decoration.show();
} else {
decoration.setDescriptionText(null);
decoration.hide();
}
}
private void createParameterNameInput(Composite group) {
Label l= new Label(group, SWT.NONE);
l.setText(RefactoringMessages.ExtractClassWizard_field_name);
final Text text= new Text(group, SWT.BORDER);
fParameterNameDecoration= new ControlDecoration(text, SWT.TOP | SWT.LEAD);
text.setText(fDescriptor.getFieldName());
text.addModifyListener(e -> {
fDescriptor.setFieldName(text.getText());
validateRefactoring();
});
GridData gridData= new GridData(GridData.FILL_HORIZONTAL);
gridData.horizontalIndent= FieldDecorationRegistry.getDefault().getMaximumDecorationWidth();
text.setLayoutData(gridData);
}
private void createTable(Composite parent) {
Composite result= new Composite(parent, SWT.NONE);
GridLayout layout= new GridLayout(2, false);
layout.marginHeight= 0;
layout.marginWidth= 0;
result.setLayout(layout);
GridData gridData= new GridData(GridData.FILL_BOTH);
gridData.horizontalSpan= 2;
result.setLayoutData(gridData);
Label l= new Label(result, SWT.NONE);
l.setText(RefactoringMessages.ExtractClassWizard_label_select_fields);
gridData= new GridData(GridData.FILL_HORIZONTAL);
gridData.horizontalSpan= 2;
gridData.verticalIndent= 5;
//gridData.horizontalIndent= FieldDecorationRegistry.getDefault().getMaximumDecorationWidth();
l.setLayoutData(gridData);
//fFieldDecoration= new ControlDecoration(l, SWT.TOP | SWT.LEAD);
TableLayoutComposite layoutComposite= new TableLayoutComposite(result, SWT.NONE);
layoutComposite.addColumnData(new ColumnWeightData(40, convertWidthInCharsToPixels(20), true));
layoutComposite.addColumnData(new ColumnWeightData(60, convertWidthInCharsToPixels(20), true));
final CheckboxTableViewer tv= CheckboxTableViewer.newCheckList(layoutComposite, SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER | SWT.FULL_SELECTION | SWT.MULTI);
tv.setContentProvider(ArrayContentProvider.getInstance());
createColumns(tv);
Table table= tv.getTable();
table.setLinesVisible(true);
table.setHeaderVisible(true);
gridData= new GridData(GridData.FILL_BOTH);
table.setLayoutData(gridData);
Field[] fields= fDescriptor.getFields();
tv.setInput(fields);
for (Field field : fields) {
tv.setChecked(field, field.isCreateField());
}
gridData= new GridData(GridData.FILL_BOTH);
gridData.heightHint= SWTUtil.getTableHeightHint(table, Math.max(fields.length,5));
gridData.widthHint= convertWidthInCharsToPixels(50);
layoutComposite.setLayoutData(gridData);
Composite controls= new Composite(result, SWT.NONE);
gridData= new GridData(GridData.FILL, GridData.FILL, false, false);
controls.setLayoutData(gridData);
GridLayout gridLayout= new GridLayout();
gridLayout.marginHeight= 0;
gridLayout.marginWidth= 0;
controls.setLayout(gridLayout);
final Button editButton= new Button(controls, SWT.NONE);
editButton.setText(RefactoringMessages.ExtractClassWizard_button_edit);
editButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
editButton.setEnabled(!tv.getSelection().isEmpty());
SWTUtil.setButtonDimensionHint(editButton);
editButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
ISelection selection= tv.getSelection();
if (selection instanceof IStructuredSelection) {
IStructuredSelection ss= (IStructuredSelection) selection;
Field selected= (Field) ss.getFirstElement();
String message= RefactoringMessages.ExtractClassWizard_dialog_message;
String title= RefactoringMessages.ExtractClassWizard_dialog_title;
InputDialog inputDialog= new InputDialog(getShell(), title, message, selected.getNewFieldName(), newText -> {
IStatus status= JavaConventionsUtil.validateIdentifier(newText, fDescriptor.getType());
if (!status.isOK())
return status.getMessage();
return null;
});
if (inputDialog.open() == Window.OK) {
selected.setNewFieldName(inputDialog.getValue());
tv.refresh(selected);
}
}
}
});
tv.addCheckStateListener(event -> {
Field element= (Field) event.getElement();
element.setCreateField(event.getChecked());
validateRefactoring();
tv.refresh(element, true);
});
tv.addSelectionChangedListener(event -> {
IStructuredSelection selection= (IStructuredSelection) tv.getSelection();
Field field= (Field) selection.getFirstElement();
if (selection.isEmpty()) {
editButton.setEnabled(false);
} else {
editButton.setEnabled(tv.getChecked(field));
}
});
}
private abstract class FieldInfoLabelProvider extends CellLabelProvider {
@Override
public void update(ViewerCell cell) {
Field pi= (Field) cell.getElement();
cell.setText(doGetValue(pi));
}
protected abstract String doGetValue(Field pi);
}
private abstract class FieldInfoEditingSupport extends EditingSupport {
private CellEditor fTextEditor;
private FieldInfoEditingSupport(CellEditor textEditor, ColumnViewer tv) {
super(tv);
fTextEditor= textEditor;
}
@Override
protected void setValue(Object element, Object value) {
if (element instanceof Field) {
Field pi= (Field) element;
doSetValue(pi, value.toString());
getViewer().update(element, null);
}
validateRefactoring();
}
public abstract void doSetValue(Field pi, String string);
@Override
protected Object getValue(Object element) {
if (element instanceof Field) {
Field pi= (Field) element;
return doGetValue(pi);
}
return null;
}
public abstract String doGetValue(Field pi);
@Override
protected CellEditor getCellEditor(Object element) {
return fTextEditor;
}
@Override
protected boolean canEdit(Object element) {
if (element instanceof Field) {
return fTextEditor != null;
}
return false;
}
}
private void createColumns(final CheckboxTableViewer tv) {
TextCellEditor cellEditor= new TextCellEditor(tv.getTable());
TableViewerColumn viewerColumn= new TableViewerColumn(tv, SWT.LEAD);
viewerColumn.setLabelProvider(new FieldInfoLabelProvider() {
@Override
protected String doGetValue(Field pi) {
IField field= fDescriptor.getType().getField(pi.getFieldName());
try {
return Signature.toString(field.getTypeSignature());
} catch (JavaModelException e) {
return RefactoringMessages.ExtractClassWizard_not_available;
}
}
});
TableColumn column= viewerColumn.getColumn();
column.setText(RefactoringMessages.ExtractClassWizard_column_type);
viewerColumn= new TableViewerColumn(tv, SWT.LEAD);
viewerColumn.setLabelProvider(new FieldInfoLabelProvider() {
@Override
protected String doGetValue(Field pi) {
if (pi.isCreateField())
return pi.getNewFieldName();
else
return pi.getFieldName();
}
});
viewerColumn.setEditingSupport(new FieldInfoEditingSupport(cellEditor, tv) {
@Override
public String doGetValue(Field pi) {
return pi.getNewFieldName();
}
@Override
public void doSetValue(Field pi, String string) {
pi.setNewFieldName(string);
}
@Override
protected boolean canEdit(Object element) {
if (element instanceof Field) {
Field field= (Field) element;
return field.isCreateField();
}
return super.canEdit(element);
}
});
column= viewerColumn.getColumn();
column.setText(RefactoringMessages.ExtractClassWizard_column_name);
}
protected RefactoringStatus validateParameterName() {
RefactoringStatus status= new RefactoringStatus();
ExtractClassDescriptorVerification verification= getVerification();
status.merge(verification.validateParameterName());
updateDecoration(fParameterNameDecoration, status);
return status;
}
protected RefactoringStatus validateTopLevel() {
RefactoringStatus status= new RefactoringStatus();
ExtractClassDescriptorVerification verification= getVerification();
status.merge(verification.validateTopLevel());
updateDecoration(fClassNameDecoration, status);
return status;
}
protected RefactoringStatus validateClassName() {
RefactoringStatus status= new RefactoringStatus();
ExtractClassDescriptorVerification verification= getVerification();
status.merge(verification.validateClassName());
updateDecoration(fClassNameDecoration, status);
return status;
}
protected RefactoringStatus validateFields() {
RefactoringStatus status= new RefactoringStatus();
ExtractClassDescriptorVerification verification= getVerification();
status.merge(verification.validateFields());
return status;
}
protected RefactoringStatus validateRefactoring() {
RefactoringStatus status= new RefactoringStatus();
setErrorMessage(null);
setMessage(null);
setPageComplete(true);
status.merge(validateTopLevel());
status.merge(validateClassName());
status.merge(validateParameterName());
status.merge(validateFields());
RefactoringStatusEntry highestSeverity= status.getEntryWithHighestSeverity();
if (highestSeverity != null) {
switch (highestSeverity.getSeverity()) {
case RefactoringStatus.ERROR:
case RefactoringStatus.FATAL:
setErrorMessage(highestSeverity.getMessage());
setPageComplete(false);
break;
case RefactoringStatus.WARNING:
setMessage(highestSeverity.getMessage(), IMessageProvider.WARNING);
break;
case RefactoringStatus.INFO:
setMessage(highestSeverity.getMessage(), IMessageProvider.INFORMATION);
break;
}
}
return status;
}
protected boolean getBooleanSetting(String key, boolean defaultValue) {
String update= getRefactoringSettings().get(key);
if (update != null)
return Boolean.parseBoolean(update);
else
return defaultValue;
}
@Override
public void dispose() {
IDialogSettings settings= getRefactoringSettings();
settings.put(CREATE_GETTER_SETTER, fDescriptor.isCreateGetterSetter());
settings.put(CREATE_TOP_LEVEL_SETTING, fDescriptor.isCreateTopLevel());
super.dispose();
}
}
public ExtractClassDescriptorVerification getVerification() {
ExtractClassDescriptorVerification adapter= getRefactoring().getAdapter(ExtractClassDescriptorVerification.class);
return adapter;
}
}