package org.rubypeople.rdt.ui.wizards;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Text;
import org.rubypeople.rdt.core.IBuffer;
import org.rubypeople.rdt.core.IRubyElement;
import org.rubypeople.rdt.core.IRubyProject;
import org.rubypeople.rdt.core.IRubyScript;
import org.rubypeople.rdt.core.ISourceFolder;
import org.rubypeople.rdt.core.ISourceRange;
import org.rubypeople.rdt.core.IType;
import org.rubypeople.rdt.core.RubyConventions;
import org.rubypeople.rdt.core.RubyModelException;
import org.rubypeople.rdt.core.formatter.CodeFormatter;
import org.rubypeople.rdt.core.search.IRubySearchConstants;
import org.rubypeople.rdt.core.search.IRubySearchScope;
import org.rubypeople.rdt.core.search.SearchEngine;
import org.rubypeople.rdt.core.util.Util;
import org.rubypeople.rdt.internal.corext.codemanipulation.StubUtility;
import org.rubypeople.rdt.internal.corext.util.CodeFormatterUtil;
import org.rubypeople.rdt.internal.corext.util.RubyModelUtil;
import org.rubypeople.rdt.internal.ui.RubyPlugin;
import org.rubypeople.rdt.internal.ui.RubyPluginImages;
import org.rubypeople.rdt.internal.ui.dialogs.StatusInfo;
import org.rubypeople.rdt.internal.ui.dialogs.TextFieldNavigationHandler;
import org.rubypeople.rdt.internal.ui.dialogs.TypeSelectionDialog2;
import org.rubypeople.rdt.internal.ui.wizards.NewWizardMessages;
import org.rubypeople.rdt.internal.ui.wizards.SuperModuleSelectionDialog;
import org.rubypeople.rdt.internal.ui.wizards.dialogfields.DialogField;
import org.rubypeople.rdt.internal.ui.wizards.dialogfields.IDialogFieldListener;
import org.rubypeople.rdt.internal.ui.wizards.dialogfields.IListAdapter;
import org.rubypeople.rdt.internal.ui.wizards.dialogfields.IStringButtonAdapter;
import org.rubypeople.rdt.internal.ui.wizards.dialogfields.LayoutUtil;
import org.rubypeople.rdt.internal.ui.wizards.dialogfields.ListDialogField;
import org.rubypeople.rdt.internal.ui.wizards.dialogfields.Separator;
import org.rubypeople.rdt.internal.ui.wizards.dialogfields.StringButtonDialogField;
import org.rubypeople.rdt.internal.ui.wizards.dialogfields.StringDialogField;
public abstract class NewTypeWizardPage extends NewContainerWizardPage {
private static class InterfaceWrapper {
public String interfaceName;
public InterfaceWrapper(String interfaceName) {
this.interfaceName = interfaceName;
}
public int hashCode() {
return interfaceName.hashCode();
}
public boolean equals(Object obj) {
return obj != null
&& getClass().equals(obj.getClass())
&& ((InterfaceWrapper) obj).interfaceName
.equals(interfaceName);
}
}
private static class InterfacesListLabelProvider extends LabelProvider {
private Image fInterfaceImage;
public InterfacesListLabelProvider() {
fInterfaceImage = RubyPluginImages
.get(RubyPluginImages.IMG_OBJS_MODULE);
}
public String getText(Object element) {
return ((InterfaceWrapper) element).interfaceName;
}
public Image getImage(Object element) {
return fInterfaceImage;
}
}
private final static String PAGE_NAME = "NewTypeWizardPage"; //$NON-NLS-1$
/** Field ID of the package input field. */
protected final static String PACKAGE = PAGE_NAME + ".package"; //$NON-NLS-1$
/** Field ID of the enclosing type input field. */
protected final static String ENCLOSING = PAGE_NAME + ".enclosing"; //$NON-NLS-1$
/** Field ID of the enclosing type checkbox. */
protected final static String ENCLOSINGSELECTION = ENCLOSING + ".selection"; //$NON-NLS-1$
/** Field ID of the type name input field. */
protected final static String TYPENAME = PAGE_NAME + ".typename"; //$NON-NLS-1$
/** Field ID of the super type input field. */
protected final static String SUPER = PAGE_NAME + ".superclass"; //$NON-NLS-1$
/** Field ID of the super interfaces input field. */
protected final static String INTERFACES = PAGE_NAME + ".interfaces"; //$NON-NLS-1$
/** Field ID of the method stubs check boxes. */
protected final static String METHODS = PAGE_NAME + ".methods"; //$NON-NLS-1$
/**
* a handle to the type to be created (does usually not exist, can be null)
*/
private IType fCurrType;
private StringDialogField fTypeNameDialogField;
private StringButtonDialogField fSuperClassDialogField;
private ListDialogField fSuperModulesDialogField;
private IType fCreatedType;
protected IStatus fTypeNameStatus;
protected IStatus fSuperClassStatus;
protected IStatus fSuperModulesStatus;
private int fTypeKind;
/**
* Constant to signal that the created type is a class.
*
* @since 0.9.0
*/
public static final int CLASS_TYPE = 1;
/**
* Constant to signal that the created type is a interface.
*
* @since 0.9.0
*/
public static final int INTERFACE_TYPE = 2;
/**
* Creates a new <code>NewTypeWizardPage</code>.
*
* @param isClass
* <code>true</code> if a new class is to be created; otherwise
* an interface is to be created
* @param pageName
* the wizard page's name
*/
public NewTypeWizardPage(boolean isClass, String pageName) {
this(isClass ? CLASS_TYPE : INTERFACE_TYPE, pageName);
}
/**
* Creates a new <code>NewTypeWizardPage</code>.
*
* @param typeKind
* Signals the kind of the type to be created. Valid kinds are
* {@link #CLASS_TYPE}, {@link #INTERFACE_TYPE}
* @param pageName
* the wizard page's name
* @since 3.1
*/
public NewTypeWizardPage(int typeKind, String pageName) {
super(pageName);
fTypeKind = typeKind;
fCreatedType = null;
TypeFieldsAdapter adapter = new TypeFieldsAdapter();
fTypeNameDialogField = new StringDialogField();
fTypeNameDialogField.setDialogFieldListener(adapter);
fTypeNameDialogField.setLabelText(getTypeNameLabel());
fSuperClassDialogField = new StringButtonDialogField(adapter);
fSuperClassDialogField.setDialogFieldListener(adapter);
fSuperClassDialogField.setLabelText(getSuperClassLabel());
fSuperClassDialogField
.setButtonLabel(NewWizardMessages.NewTypeWizardPage_superclass_button);
String[] addButtons = new String[] {
NewWizardMessages.NewTypeWizardPage_interfaces_add,
/* 1 */null,
NewWizardMessages.NewTypeWizardPage_interfaces_remove };
fSuperModulesDialogField = new ListDialogField(adapter, addButtons,
new InterfacesListLabelProvider());
fSuperModulesDialogField.setDialogFieldListener(adapter);
fSuperModulesDialogField
.setTableColumns(new ListDialogField.ColumnsDescription(1,
false));
fSuperModulesDialogField.setLabelText(getSuperModulesLabel());
fSuperModulesDialogField.setRemoveButtonIndex(2);
fTypeNameStatus = new StatusInfo();
fSuperClassStatus = new StatusInfo();
fSuperModulesStatus = new StatusInfo();
}
/**
* Returns the label that is used for the package input field.
*
* @return the label that is used for the package input field.
* @since 3.2
*/
protected String getSourceFolderLabel() {
return NewWizardMessages.NewTypeWizardPage_package_label;
}
/**
* Creates the controls for the type name field. Expects a
* <code>GridLayout</code> with at least 2 columns.
*
* @param composite
* the parent composite
* @param nColumns
* number of columns to span
*/
protected void createTypeNameControls(Composite composite, int nColumns) {
fTypeNameDialogField.doFillIntoGrid(composite, nColumns - 1);
DialogField.createEmptySpace(composite);
Text text = fTypeNameDialogField.getTextControl(null);
LayoutUtil.setWidthHint(text, getMaxFieldWidth());
TextFieldNavigationHandler.install(text);
}
/**
* Sets the focus on the type name input field.
*/
protected void setFocus() {
fTypeNameDialogField.setFocus();
}
/**
* Sets the type name input field's text to the given value. Method doesn't
* update the model.
*
* @param name
* the new type name
* @param canBeModified
* if <code>true</code> the type name field is editable;
* otherwise it is read-only.
*/
public void setTypeName(String name, boolean canBeModified) {
fTypeNameDialogField.setText(name);
fTypeNameDialogField.setEnabled(canBeModified);
}
/**
* Creates a separator line. Expects a <code>GridLayout</code> with at least
* 1 column.
*
* @param composite
* the parent composite
* @param nColumns
* number of columns to span
*/
protected void createSeparator(Composite composite, int nColumns) {
(new Separator(SWT.SEPARATOR | SWT.HORIZONTAL)).doFillIntoGrid(
composite, nColumns, convertHeightInCharsToPixels(1));
}
/**
* Returns the label that is used for the super interfaces input field.
*
* @return the label that is used for the super interfaces input field.
* @since 3.2
*/
protected String getSuperModulesLabel() {
if (fTypeKind != INTERFACE_TYPE)
return NewWizardMessages.NewTypeWizardPage_interfaces_class_label;
return NewWizardMessages.NewTypeWizardPage_interfaces_ifc_label;
}
/**
* Returns the label that is used for the type name input field.
*
* @return the label that is used for the type name input field.
* @since 3.2
*/
protected String getTypeNameLabel() {
return NewWizardMessages.NewTypeWizardPage_typename_label;
}
/**
* Returns the label that is used for the super class input field.
*
* @return the label that is used for the super class input field.
* @since 3.2
*/
protected String getSuperClassLabel() {
return NewWizardMessages.NewTypeWizardPage_superclass_label;
}
/**
* Creates the controls for the superclass name field. Expects a
* <code>GridLayout</code> with at least 3 columns.
*
* @param composite
* the parent composite
* @param nColumns
* number of columns to span
*/
protected void createSuperClassControls(Composite composite, int nColumns) {
fSuperClassDialogField.doFillIntoGrid(composite, nColumns);
Text text = fSuperClassDialogField.getTextControl(null);
LayoutUtil.setWidthHint(text, getMaxFieldWidth());
// RubyTypeCompletionProcessor superClassCompletionProcessor= new
// RubyTypeCompletionProcessor(false, false);
// superClassCompletionProcessor.setCompletionContextRequestor(new
// CompletionContextRequestor() {
// public StubTypeContext getStubTypeContext() {
// return getSuperClassStubTypeContext();
// }
// });
//
// ControlContentAssistHelper.createTextContentAssistant(text,
// superClassCompletionProcessor);
// TextFieldNavigationHandler.install(text);
}
// -------- TypeFieldsAdapter --------
private class TypeFieldsAdapter implements IStringButtonAdapter,
IDialogFieldListener, IListAdapter, SelectionListener {
// -------- IStringButtonAdapter
public void changeControlPressed(DialogField field) {
typePageChangeControlPressed(field);
}
// -------- IListAdapter
public void customButtonPressed(ListDialogField field, int index) {
typePageCustomButtonPressed(field, index);
}
public void selectionChanged(ListDialogField field) {
}
// -------- IDialogFieldListener
public void dialogFieldChanged(DialogField field) {
typePageDialogFieldChanged(field);
}
public void doubleClicked(ListDialogField field) {
}
public void widgetSelected(SelectionEvent e) {
typePageLinkActivated(e);
}
public void widgetDefaultSelected(SelectionEvent e) {
typePageLinkActivated(e);
}
}
private void typePageLinkActivated(SelectionEvent e) {
ISourceFolder root = getSourceFolder();
if (root != null) {
// TODO Uncomment!
// PreferenceDialog dialog=
// PreferencesUtil.createPropertyDialogOn(getShell(),
// root.getProject(), CodeTemplatePreferencePage.PROP_ID, null,
// null);
// dialog.open();
} else {
String title = NewWizardMessages.NewTypeWizardPage_configure_templates_title;
String message = NewWizardMessages.NewTypeWizardPage_configure_templates_message;
MessageDialog.openInformation(getShell(), title, message);
}
}
private void typePageChangeControlPressed(DialogField field) {
if (field == fSuperClassDialogField) {
IType type = chooseSuperClass();
if (type != null) {
// TODO Spit out fully qualified name?!
fSuperClassDialogField.setText(type.getElementName());
}
}
}
private void typePageCustomButtonPressed(DialogField field, int index) {
if (field == fSuperModulesDialogField) {
chooseSuperModules();
List interfaces = fSuperModulesDialogField.getElements();
if (!interfaces.isEmpty()) {
Object element = interfaces.get(interfaces.size() - 1);
fSuperModulesDialogField.editElement(element);
}
}
}
/**
* Sets the super class name.
*
* @param name
* the new superclass name
* @param canBeModified
* if <code>true</code> the superclass name field is editable;
* otherwise it is read-only.
*/
public void setSuperClass(String name, boolean canBeModified) {
fSuperClassDialogField.setText(name);
fSuperClassDialogField.setEnabled(canBeModified);
}
/**
* Hook method that gets called from <code>createType</code> to support
* adding of unanticipated methods, fields, and inner types to the created
* type.
* <p>
* Implementers can use any methods defined on <code>IType</code> to
* manipulate the new type.
* </p>
* <p>
* The source code of the new type will be formatted using the platform's
* formatter. Needed imports are added by the wizard at the end of the type
* creation process using the given import manager.
* </p>
*
* @param newType
* the new type created via <code>createType</code>
* @param monitor
* a progress monitor to report progress. Must not be
* <code>null</code>
*
* @see #createType(IProgressMonitor)
*/
protected void createTypeMembers(IType newType, IProgressMonitor monitor)
throws CoreException {
}
/**
* Hook method that is called when evaluating the name of the compilation
* unit to create. By default, a file extension <code>rb</code> is added to
* the given type name, but implementors can override this behavior.
*
* @param typeName
* the name of the type to create the compilation unit for.
* @return the name of the compilation unit to be created for the given name
*
* @since 0.9.0
*/
protected String getRubyScriptName(String typeName) {
int index = typeName.lastIndexOf("::");
// TODO If they have set up namespace, should we offer to build nested
// folders? A::B::C -> a/b/c.rb
if (index != -1) {
typeName = typeName.substring(index + 2);
}
return Util.camelCaseToUnderscores(typeName)
+ RubyModelUtil.DEFAULT_SCRIPT_SUFFIX;
}
/**
* Creates the new type using the entered field values.
*
* @param monitor
* a progress monitor to report progress.
* @throws CoreException
* Thrown when the creation failed.
* @throws InterruptedException
* Thrown when the operation was canceled.
*/
public void createType(IProgressMonitor monitor) throws CoreException,
InterruptedException {
if (monitor == null) {
monitor = new NullProgressMonitor();
}
monitor.beginTask(NewWizardMessages.NewTypeWizardPage_operationdesc, 8);
ISourceFolder pack = getSourceFolder();
// if (!pack.exists()) {
// String packName= pack.getElementName();
// pack= root.createSourceFolder(packName, true, new
// SubProgressMonitor(monitor, 1));
// } else {
monitor.worked(1);
// }
boolean needsSave;
IRubyScript connectedCU = null;
try {
String typeName = getTypeName();
IType createdType;
int indent = 0;
String lineDelimiter = StubUtility.getLineDelimiterUsed(pack
.getRubyProject());
String cuName = getRubyScriptName(typeName);
IRubyScript parentCU = pack.createRubyScript(cuName,
"", false, new SubProgressMonitor(monitor, 2)); //$NON-NLS-1$
// create a working copy with a new owner
needsSave = true;
parentCU
.becomeWorkingCopy(null, new SubProgressMonitor(monitor, 1)); // cu
// is
// now
// a
// (
// primary
// )
// working
// copy
connectedCU = parentCU;
IBuffer buffer = parentCU.getBuffer();
String cuContent = constructSimpleTypeStub(lineDelimiter);
buffer.setContents(cuContent);
createdType = parentCU.getType(typeName);
if (monitor.isCanceled()) {
throw new InterruptedException();
}
IRubyScript cu = createdType.getRubyScript();
RubyModelUtil.reconcile(cu);
if (monitor.isCanceled()) {
throw new InterruptedException();
}
createTypeMembers(createdType, new SubProgressMonitor(monitor, 1));
RubyModelUtil.reconcile(cu);
ISourceRange range = createdType.getSourceRange(); // FIXME The
// source range
// seems to be
// off by one...
// We have a
// workaround
// here, but
// need to fix
// it in IType
int length = range.getLength() + 1;
if (lineDelimiter.length() > 1)
length++;
IBuffer buf = cu.getBuffer();
int offset = range.getOffset();
if (offset < 0)
offset = 0;
if (offset + length > buf.getLength())
{
length = buf.getLength() - offset;
}
String originalContent = buf.getText(range.getOffset(), length);
String formattedContent = CodeFormatterUtil.format(
CodeFormatter.K_CLASS_BODY_DECLARATIONS, originalContent,
indent, null, lineDelimiter, pack.getRubyProject());
// formattedContent=
// Strings.trimLeadingTabsAndSpaces(formattedContent);
buf.replace(range.getOffset(), length, formattedContent);
fCreatedType = createdType;
if (needsSave) {
cu.commitWorkingCopy(true, new SubProgressMonitor(monitor, 1));
} else {
monitor.worked(1);
}
} finally {
if (connectedCU != null) {
connectedCU.discardWorkingCopy();
}
monitor.done();
}
}
private String constructSimpleTypeStub(String lineDelimiter) {
StringBuffer buf = new StringBuffer(); //$NON-NLS-1$
List<String> imports = addImports();
if (imports != null) {
for (String string : imports) {
buf.append("require \"");
buf.append(string);
buf.append('"');
buf.append(lineDelimiter);
}
}
buf.append("class "); //$NON-NLS-1$
buf.append(getTypeName());
String superclass = getSuperClass();
if (superclass != null && superclass.trim().length() > 0
&& !superclass.trim().equals("Object")) {
buf.append(" < ");
buf.append(superclass.trim());
}
buf.append(lineDelimiter);
buf.append("end"); //$NON-NLS-1$
return buf.toString();
}
protected List<String> addImports() {
// This is an ugly hack since we don't have an Iportsmanager or
// ImportRewrite yet.
return null;
}
/**
* Opens a selection dialog that allows to select the super interfaces. The
* selected interfaces are directly added to the wizard page using
* {@link #addSuperModule(String)}.
*
* <p>
* Clients can override this method if they want to offer a different
* dialog.
* </p>
*
* @since 1.0
*/
protected void chooseSuperModules() {
ISourceFolder root = getSourceFolder();
if (root == null) {
return;
}
IRubyProject project = root.getRubyProject();
SuperModuleSelectionDialog dialog = new SuperModuleSelectionDialog(
getShell(), getWizard().getContainer(), this, project);
dialog.setTitle(getModuleDialogTitle());
dialog
.setMessage(NewWizardMessages.NewTypeWizardPage_InterfacesDialog_message);
dialog.open();
}
/**
* Sets the super interfaces.
*
* @param interfacesNames
* a list of super interface. The method requires that the list's
* elements are of type <code>String</code>
* @param canBeModified
* if <code>true</code> the super interface field is editable;
* otherwise it is read-only.
*/
public void setSuperModules(List interfacesNames, boolean canBeModified) {
ArrayList interfaces = new ArrayList(interfacesNames.size());
for (Iterator iter = interfacesNames.iterator(); iter.hasNext();) {
interfaces.add(new InterfaceWrapper((String) iter.next()));
}
fSuperModulesDialogField.setElements(interfaces);
fSuperModulesDialogField.setEnabled(canBeModified);
}
/**
* Returns the chosen super interfaces.
*
* @return a list of chosen super interfaces. The list's elements are of
* type <code>String</code>
*/
public List getSuperModules() {
List interfaces = fSuperModulesDialogField.getElements();
ArrayList result = new ArrayList(interfaces.size());
for (Iterator iter = interfaces.iterator(); iter.hasNext();) {
InterfaceWrapper wrapper = (InterfaceWrapper) iter.next();
result.add(wrapper.interfaceName);
}
return result;
}
/**
* Adds a super interface to the end of the list and selects it if it is not
* in the list yet.
*
* @param superInterface
* the fully qualified type name of the interface.
* @return returns <code>true</code>if the interfaces has been added,
* <code>false</code> if the interface already is in the list.
* @since 1.0
*/
public boolean addSuperModule(String superInterface) {
return fSuperModulesDialogField.addElement(new InterfaceWrapper(
superInterface));
}
private String getModuleDialogTitle() {
if (fTypeKind == INTERFACE_TYPE)
return NewWizardMessages.NewTypeWizardPage_InterfacesDialog_interface_title;
return NewWizardMessages.NewTypeWizardPage_InterfacesDialog_class_title;
}
/**
* Returns the resource handle that corresponds to the ruby script that was
* or will be created or modified.
*
* @return A resource or null if the page contains illegal values.
* @since 1.0
*/
public IResource getModifiedResource() {
ISourceFolder pack = getSourceFolder();
if (pack != null) {
String cuName = getRubyScriptName(getTypeName());
return pack.getRubyScript(cuName).getResource();
}
return null;
}
/*
* A field on the type has changed. The fields' status and all dependent
* status are updated.
*/
private void typePageDialogFieldChanged(DialogField field) {
String fieldName = null;
if (field == fTypeNameDialogField) {
fTypeNameStatus = typeNameChanged();
fieldName = TYPENAME;
} else if (field == fSuperClassDialogField) {
fSuperClassStatus = superClassChanged();
fieldName = SUPER;
} else if (field == fSuperModulesDialogField) {
fSuperModulesStatus = superInterfacesChanged();
fieldName = INTERFACES;
} else {
fieldName = METHODS;
}
// tell all others
handleFieldChanged(fieldName);
}
/**
* Returns the content of the superclass input field.
*
* @return the superclass name
*/
public String getSuperClass() {
return fSuperClassDialogField.getText();
}
/**
* Hook method that gets called when the superclass name has changed. The
* method validates the superclass name and returns the status of the
* validation.
* <p>
* Subclasses may extend this method to perform their own validation.
* </p>
*
* @return the status of the validation
*/
protected IStatus superClassChanged() {
StatusInfo status = new StatusInfo();
ISourceFolder root = getSourceFolder();
fSuperClassDialogField.enableButton(root != null);
String sclassName = getSuperClass();
if (sclassName.length() == 0) {
// accept the empty field (stands for Object)
return status;
}
if (root != null) {
// TODO Check to make sure super class exists and is valid
} else {
status.setError(""); //$NON-NLS-1$
}
return status;
}
/**
* Returns the type name entered into the type input field.
*
* @return the type name
*/
public String getTypeName() {
return fTypeNameDialogField.getText();
}
private IStatus typeNameChanged() {
StatusInfo status = new StatusInfo();
fCurrType = null;
String typeName = getTypeName();
if (typeName.length() == 0) {
status
.setError(NewWizardMessages.NewTypeWizardPage_error_EnterTypeName);
return status;
}
if (!isConstant(typeName)) {
status
.setError("Class name must be a constant. It must begin with a capital letter, and contain only letters, digits, or underscores.");
return status;
}
return status;
}
// ------ validation --------
protected void doStatusUpdate() {
// status of all used components
IStatus[] status = new IStatus[] { fContainerStatus, fTypeNameStatus,
fSuperClassStatus, fSuperModulesStatus };
// the mode severe status will be displayed and the OK button
// enabled/disabled.
updateStatus(status);
}
/*
* @see NewContainerWizardPage#handleFieldChanged
*/
protected void handleFieldChanged(String fieldName) {
super.handleFieldChanged(fieldName);
if (fieldName == CONTAINER) {
// /*fPackageStatus=*/ packageChanged();
// fEnclosingTypeStatus= enclosingTypeChanged();
fTypeNameStatus = typeNameChanged();
fSuperClassStatus = superClassChanged();
fSuperModulesStatus = superInterfacesChanged();
}
doStatusUpdate();
}
/**
* Initializes all fields provided by the page with a given selection.
*
* @param elem
* the selection used to initialize this page or <code>
* null</code> if
* no selection was available
*/
protected void initTypePage(IRubyElement elem) {
String initSuperclass = "Object"; //$NON-NLS-1$
ArrayList initSuperinterfaces = new ArrayList(5);
IRubyProject project = null;
ISourceFolder folder = getSourceFolder();
IType enclosingType = null;
if (elem != null) {
// evaluate the enclosing type
project = elem.getRubyProject();
IType typeInCU = (IType) elem.getAncestor(IRubyElement.TYPE);
if (typeInCU != null) {
if (typeInCU.getRubyScript() != null) {
enclosingType = typeInCU;
}
} else {
IRubyScript cu = (IRubyScript) elem
.getAncestor(IRubyElement.SCRIPT);
if (cu != null) {
enclosingType = cu.findPrimaryType();
}
}
}
String typeName = ""; //$NON-NLS-1$
ITextSelection selection = getCurrentTextSelection();
if (selection != null) {
String text = selection.getText();
if (text != null
&& RubyConventions.validateRubyTypeName(text).isOK()) {
typeName = text;
}
}
if (enclosingType != null) {
typeName = enclosingType.getElementName();
try {
initSuperclass = enclosingType.getSuperclassName();
initSuperinterfaces.addAll(Arrays.asList(enclosingType
.getIncludedModuleNames()));
} catch (RubyModelException e) {
RubyPlugin.log(e);
}
}
setSourceFolder(folder, true);
setTypeName(typeName, true);
setSuperClass(initSuperclass, true);
// setSuperInterfaces(initSuperinterfaces, true);
// setAddComments(StubUtility.doAddComments(project), true); // from
// project or workspace
}
private boolean isConstant(String className) {
if (className == null || className.length() == 0)
return false;
int namespaceDelimeterIndex = className.indexOf("::");
if (namespaceDelimeterIndex != -1) {
return isConstant(className.substring(0, namespaceDelimeterIndex))
&& isConstant(className
.substring(namespaceDelimeterIndex + 2));
}
return className.matches("^[A-Z]\\w*");
}
/**
* Hook method that gets called when the list of super interface has
* changed. The method validates the super interfaces and returns the status
* of the validation.
* <p>
* Subclasses may extend this method to perform their own validation.
* </p>
*
* @return the status of the validation
*/
protected IStatus superInterfacesChanged() {
StatusInfo status = new StatusInfo();
ISourceFolder root = getSourceFolder();
fSuperModulesDialogField.enableButton(0, root != null);
if (root != null) {
List elements = fSuperModulesDialogField.getElements();
int nElements = elements.size();
for (int i = 0; i < nElements; i++) {
// TODO Check to make sure each interface exists and is valid
// String intfname= ((InterfaceWrapper)
// elements.get(i)).interfaceName;
// Type type= TypeContextChecker.parseSuperInterface(intfname);
// if (type == null) {
// status.setError(Messages.format(NewWizardMessages.
// NewTypeWizardPage_error_InvalidSuperInterfaceName,
// intfname));
// return status;
// }
}
}
return status;
}
/**
* Opens a selection dialog that allows to select a super class.
*
* @return returns the selected type or <code>null</code> if the dialog has
* been canceled. The caller typically sets the result to the super
* class input field.
* <p>
* Clients can override this method if they want to offer a
* different dialog.
* </p>
*
* @since 0.9
*/
protected IType chooseSuperClass() {
ISourceFolder root = getSourceFolder();
if (root == null) {
return null;
}
IRubyElement[] elements = new IRubyElement[] { root.getRubyProject() };
IRubySearchScope scope = SearchEngine.createRubySearchScope(elements);
TypeSelectionDialog2 dialog = new TypeSelectionDialog2(getShell(),
false, getWizard().getContainer(), scope,
IRubySearchConstants.CLASS);
dialog
.setTitle(NewWizardMessages.NewTypeWizardPage_SuperClassDialog_title);
dialog
.setMessage(NewWizardMessages.NewTypeWizardPage_SuperClassDialog_message);
dialog.setFilter(getSuperClass());
if (dialog.open() == Window.OK) {
return (IType) dialog.getFirstResult();
}
return null;
}
/**
* Returns the created type or <code>null</code> is the type has not been
* created yet. The method only returns a valid type after
* <code>createType</code> has been called.
*
* @return the created type
* @see #createType(IProgressMonitor)
*/
public IType getCreatedType() {
return fCreatedType;
}
}