/*******************************************************************************
* Copyright (c) 2009 Benjamin Muskalla 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:
* Benjamin Muskalla - initial API and implementation
*******************************************************************************/
package edu.ohio_state.khatchad.refactoring.ui;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Plugin;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.internal.ui.dialogs.TextFieldNavigationHandler;
import org.eclipse.jdt.internal.ui.util.SWTUtil;
import org.eclipse.jdt.ui.JavaElementLabelProvider;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTableViewer;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.ltk.core.refactoring.Refactoring;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.ltk.ui.refactoring.UserInputWizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.Text;
import edu.ohio_state.khatchad.refactoring.ConvertConstantsToEnumRefactoring;
import edu.ohio_state.khatchad.refactoring.Messages;
import edu.ohio_state.khatchad.refactoring.core.Util;
public class ConvertToEnumTypePage extends UserInputWizardPage {
private Text fNameField;
private Label fLabel;
private Label fStatusLine;
private CheckboxTableViewer fTableViewer;
private final ILabelProvider fLabelProvider= new JavaElementLabelProvider(JavaElementLabelProvider.SHOW_DEFAULT | JavaElementLabelProvider.SHOW_SMALL_ICONS);;
public ConvertToEnumTypePage(String name) {
super(name);
setDescription(Messages.ConvertToEnumTypePage_Description);
}
/**
* {@inheritDoc}
*/
public void createControl(Composite parent) {
final Composite composite= new Composite(parent, SWT.NONE);
final GridLayout layout= new GridLayout();
layout.numColumns= 2;
composite.setLayout(layout);
createEnumTypeNameField(composite);
createSpacer(composite);
createFieldTableLabel(composite);
createFieldTableComposite(composite);
createStatusLine(composite);
setControl(composite);
TextFieldNavigationHandler.install(fNameField);
}
private void createEnumTypeNameField(final Composite parent) {
final Label label= new Label(parent, SWT.NONE);
label.setText(Messages.ConvertToEnumTypePage_EnumName);
label.setLayoutData(new GridData());
fNameField= new Text(parent, SWT.BORDER);
fNameField.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
handleNameChanged(fNameField.getText());
}
});
fNameField.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
IField[] fields = (IField[]) getConvertToEnumRefactoring().getFieldsToRefactor().toArray(new IField[] {});
List fieldList = new ArrayList(fields.length);
for (int i = 0; i < fields.length; i++) {
IField field = fields[i];
fieldList.add(field.getElementName());
}
String suggestedName = getSuggestedEnumTypeName((String[]) fieldList.toArray(new String[]{}));
fNameField.setText(suggestedName);
}
/**
* Handles the name changed event.
*
* @param name
* the name
*/
protected void handleNameChanged(final String name) {
if (name != null) {
String packageName = Util.getPackageName(name);
if ( packageName.isEmpty() && !getConvertToEnumRefactoring().getFieldsToRefactor().isEmpty() ) {
//assign package to be the package of the first constant.
//TODO [rk]: Done just to avoid default package for now.
IField field = (IField) getConvertToEnumRefactoring().getFieldsToRefactor().iterator().next();
IType parent = (IType) field.getParent();
String fullyQualifiedName = parent.getFullyQualifiedName();
packageName = Util.getPackageName(fullyQualifiedName);
}
getConvertToEnumRefactoring().setPackageName(packageName);
String simpleName = Util.getSimpleName(name);
getConvertToEnumRefactoring().setSimpleTypeName(simpleName);
}
checkPageCompletionStatus(true);
}
/**
* {@inheritDoc}
*/
protected void checkPageCompletionStatus(final boolean display) {
RefactoringStatus status = null;
try {
status = getConvertToEnumRefactoring().checkInitialConditions(new NullProgressMonitor());
} catch (OperationCanceledException e) {
e.printStackTrace();
} catch (CoreException e) {
e.printStackTrace();
}
setMessage(null);
if (display) {
setPageComplete(status);
} else {
setPageComplete(!status.hasFatalError());
}
}
protected void createFieldTableLabel(final Composite parent) {
fLabel= new Label(parent, SWT.NONE);
fLabel.setText(Messages.ConvertToEnumTypePage_ConstantsToExtract);
final GridData data= new GridData();
data.horizontalSpan= 2;
fLabel.setLayoutData(data);
}
protected void createFieldTableComposite(final Composite parent) {
final Composite composite= new Composite(parent, SWT.NONE);
final GridData data= new GridData(GridData.FILL_BOTH);
data.horizontalSpan= 2;
composite.setLayoutData(data);
final GridLayout layout= new GridLayout();
layout.numColumns= 1;
layout.marginWidth= 0;
layout.marginHeight= 0;
composite.setLayout(layout);
createMemberTable(composite);
}
private void createMemberTable(final Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
GridLayout layout = new GridLayout(1, false);
layout.marginWidth= 0;
layout.marginHeight= 0;
composite.setLayout(layout);
final Table table= new Table(composite, SWT.H_SCROLL | SWT.V_SCROLL | SWT.MULTI | SWT.BORDER | SWT.FULL_SELECTION | SWT.CHECK);
table.setLinesVisible(true);
GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
table.setLayoutData(gridData);
final GridData gd= new GridData(GridData.FILL_BOTH);
gd.heightHint= SWTUtil.getTableHeightHint(table, 6);
composite.setLayoutData(gd);
fTableViewer= new CheckboxTableViewer(table);
fTableViewer.setUseHashlookup(true);
fTableViewer.setContentProvider(new ArrayContentProvider());
fTableViewer.setLabelProvider(fLabelProvider);
fTableViewer.addCheckStateListener(new ICheckStateListener() {
public void checkStateChanged(final CheckStateChangedEvent event) {
updateWizardPage(null, true);
}
});
setTableInput();
}
private void setTableInput() {
fTableViewer.setInput(getConvertToEnumRefactoring().getFieldsToRefactor().toArray(new IField[]{}));
fTableViewer.setAllChecked(true);
updateStatusLine();
updateRefactoringInput();
}
private ConvertConstantsToEnumRefactoring getConvertToEnumRefactoring() {
return (ConvertConstantsToEnumRefactoring) getRefactoring();
}
protected void createSpacer(final Composite parent) {
final Label label= new Label(parent, SWT.NONE);
final GridData data= new GridData();
data.horizontalSpan= 2;
data.heightHint= convertHeightInCharsToPixels(1) / 2;
label.setLayoutData(data);
}
protected void createStatusLine(final Composite composite) {
fStatusLine= new Label(composite, SWT.NONE);
final GridData data= new GridData(SWT.FILL, SWT.TOP, false, false);
data.horizontalSpan= 2;
updateStatusLine();
fStatusLine.setLayoutData(data);
}
private void updateStatusLine() {
if (fStatusLine == null)
return;
final int selected= fTableViewer.getCheckedElements().length;
final String[] keys= { String.valueOf(selected)};
final String msg= MessageFormat.format(Messages.ConvertToEnumTypePage_CountMembersSelected, keys);
fStatusLine.setText(msg);
}
private void updateWizardPage(final ISelection selection, final boolean displayErrors) {
fTableViewer.refresh();
if (selection != null) {
fTableViewer.getControl().setFocus();
fTableViewer.setSelection(selection);
}
// checkPageCompletionStatus(displayErrors);
updateStatusLine();
updateRefactoringInput();
}
/**
* Updates the input to the refactoring to mirror the checked constants.
*/
private void updateRefactoringInput() {
Object[] checkedElements = this.fTableViewer.getCheckedElements();
List list = Arrays.asList(checkedElements);
ConvertConstantsToEnumRefactoring refactoring = (ConvertConstantsToEnumRefactoring) this
.getRefactoring();
refactoring.setFieldsToRefactor(list);
}
/* package */ String getSuggestedEnumTypeName(String[] fields) {
char[] suffix = getLongestCommonSuffix(fields).toLowerCase().toCharArray();
String suffixString = ""; //$NON-NLS-1$
if(suffix.length == 0) {
return suffixString;
}
suffix[0] = Character.toUpperCase(suffix[0]);
for (int i = 0; i < suffix.length; i++) {
if(suffix[i] == '_') {
if (i < suffix.length - 1) {
suffix[i+1] = Character.toUpperCase(suffix[i+1]);
}
} else {
suffixString += suffix[i];
}
}
return suffixString;
}
private String getLongestCommonSuffix(String[] strings) {
String currentSuffix = ""; //$NON-NLS-1$
if(strings == null || strings.length <= 1) {
return currentSuffix;
}
for (int i = 0; i < strings[0].length(); i++) {
char currentChar = strings[0].charAt(i);
for (int j = 1; j < strings.length; j++) {
if(strings[j].charAt(i) != currentChar) {
return currentSuffix;
}
}
currentSuffix += currentChar;
}
return currentSuffix;
}
/**
* {@inheritDoc}
*/
public void setVisible(final boolean visible) {
super.setVisible(visible);
if (visible) {
fNameField.setFocus();
}
}
}