From d45d99f4633457559ba728d3d1b770c730585ca0 Mon Sep 17 00:00:00 2001 From: Chris Wiebe Date: Fri, 13 Aug 2004 21:47:11 +0000 Subject: [PATCH] 2004-08-012 Chris Wiebe Initial draft of new class wizard. * src/org/eclipse/cdt/ui/wizards/NewClassCreationWizard.java * src/org/eclipse/cdt/internal/ui/wizards/classwizard/* --- core/org.eclipse.cdt.ui/ChangeLog | 6 + core/org.eclipse.cdt.ui/plugin.xml | 15 + .../classwizard/AbstractMethodStub.java | 84 + .../ui/wizards/classwizard/BaseClassInfo.java | 48 + .../classwizard/BaseClassesLabelProvider.java | 96 ++ .../BaseClassesListDialogField.java | 168 ++ .../classwizard/ConstructorMethodStub.java | 67 + .../classwizard/DestructorMethodStub.java | 67 + .../EnclosingClassSelectionDialog.java | 30 + .../wizards/classwizard/IBaseClassInfo.java | 24 + .../ui/wizards/classwizard/IMethodStub.java | 37 + .../classwizard/MethodStubsLabelProvider.java | 84 + .../MethodStubsListDialogField.java | 189 +++ .../classwizard/NamespaceSelectionDialog.java | 30 + .../NewBaseClassSelectionDialog.java | 163 ++ .../classwizard/NewClassCodeGenerator.java | 461 ++++++ .../NewClassCreationWizardPage.java | 1439 +++++++++++++++++ .../classwizard/NewClassWizardMessages.java | 60 + .../NewClassWizardMessages.properties | 116 ++ .../classwizard/NewSourceFileGenerator.java | 150 ++ .../ui/wizards/NewClassCreationWizard.java | 93 ++ 21 files changed, 3427 insertions(+) create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/classwizard/AbstractMethodStub.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/classwizard/BaseClassInfo.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/classwizard/BaseClassesLabelProvider.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/classwizard/BaseClassesListDialogField.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/classwizard/ConstructorMethodStub.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/classwizard/DestructorMethodStub.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/classwizard/EnclosingClassSelectionDialog.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/classwizard/IBaseClassInfo.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/classwizard/IMethodStub.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/classwizard/MethodStubsLabelProvider.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/classwizard/MethodStubsListDialogField.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/classwizard/NamespaceSelectionDialog.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/classwizard/NewBaseClassSelectionDialog.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/classwizard/NewClassCodeGenerator.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/classwizard/NewClassCreationWizardPage.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/classwizard/NewClassWizardMessages.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/classwizard/NewClassWizardMessages.properties create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/classwizard/NewSourceFileGenerator.java create mode 100644 core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/wizards/NewClassCreationWizard.java diff --git a/core/org.eclipse.cdt.ui/ChangeLog b/core/org.eclipse.cdt.ui/ChangeLog index d4464b91d10..cfaa3e065ad 100644 --- a/core/org.eclipse.cdt.ui/ChangeLog +++ b/core/org.eclipse.cdt.ui/ChangeLog @@ -1,3 +1,9 @@ +2004-08-012 Chris Wiebe + + Initial draft of new class wizard. + * src/org/eclipse/cdt/ui/wizards/NewClassCreationWizard.java + * src/org/eclipse/cdt/internal/ui/wizards/classwizard/* + 2004-08-012 Chris Wiebe * src/org/eclipse/cdt/internal/ui/wizards/dialogsfields/ListDialogField.java diff --git a/core/org.eclipse.cdt.ui/plugin.xml b/core/org.eclipse.cdt.ui/plugin.xml index 2df802e3229..5cf6ae54247 100644 --- a/core/org.eclipse.cdt.ui/plugin.xml +++ b/core/org.eclipse.cdt.ui/plugin.xml @@ -324,6 +324,21 @@ %NewWizards.class.description + 0) { + text.append(" : "); //$NON-NLS-1$ + for (int i = 0; i < fBaseClasses.length; ++i) { + IBaseClassInfo baseClass = fBaseClasses[i]; + String baseClassName = baseClass.getType().getQualifiedTypeName().getFullyQualifiedName(); + if (i > 0) + text.append(", "); //$NON-NLS-1$ + if (baseClass.getAccess() == ASTAccessVisibility.PRIVATE) + text.append("private"); //$NON-NLS-1$ + else if (baseClass.getAccess() == ASTAccessVisibility.PROTECTED) + text.append("private"); //$NON-NLS-1$ + else + text.append("public"); //$NON-NLS-1$ + text.append(' '); + + if (baseClass.isVirtual()) + text.append("virtual "); //$NON-NLS-1$ + + text.append(baseClassName); + } + } + } + + private void addBaseClassIncludes(ITranslationUnit headerTU, StringBuffer text) { + if (fBaseClasses != null && fBaseClasses.length > 0) { + IProject project = headerTU.getCProject().getProject(); + IPath projectLocation = project.getLocation(); + IPath headerLocation = headerTU.getResource().getLocation(); + for (int i = 0; i < fBaseClasses.length; ++i) { + String baseClassFileName = null; + boolean isSystemIncludePath = false; + IBaseClassInfo baseClass = fBaseClasses[i]; + ITypeReference ref = baseClass.getType().getResolvedReference(); + if (ref != null) { + IPath baseClassLocation = ref.getLocation(); + IPath includePath = makeRelativePathToProjectIncludes(baseClassLocation, project); + if (includePath != null && !projectLocation.isPrefixOf(baseClassLocation)) { + isSystemIncludePath = true; + } else if (projectLocation.isPrefixOf(baseClassLocation) + && projectLocation.isPrefixOf(headerLocation)) { + includePath = makeRelativePath(baseClassLocation, headerLocation); + } + if (includePath == null) + includePath = baseClassLocation; + baseClassFileName = includePath.toString(); + } + if (baseClassFileName == null) { + baseClassFileName = NewSourceFileGenerator.generateHeaderFileNameFromClass(baseClass.getType().getName()); + } + + // add the include statement if we are extending a base class + // and we are not already in the base class header file + // (enclosing type) + if (!(headerTU.getElementName().equals(baseClassFileName))) { + String include = getIncludeString(baseClassFileName, isSystemIncludePath); + text.append(include); + text.append(fLineDelimiter); + } + } + text.append(fLineDelimiter); + } + } + + public String constructSourceFileContent(ITranslationUnit sourceTU, ITranslationUnit headerTU) { + //TODO should use code templates + StringBuffer text = new StringBuffer(); + + if (headerTU != null) { + addHeaderInclude(sourceTU, headerTU, text); + } + + //TODO sort methods (eg constructor always first?) + List publicMethods = getStubs(ASTAccessVisibility.PUBLIC, true); + List protectedMethods = getStubs(ASTAccessVisibility.PROTECTED, true); + List privateMethods = getStubs(ASTAccessVisibility.PRIVATE, true); + + if (publicMethods.isEmpty() + && protectedMethods.isEmpty() + && privateMethods.isEmpty()) { + text.append(' '); + } else { + addMethodBodies(publicMethods, protectedMethods, privateMethods, text); + } + + return text.toString(); + } + + private void addHeaderInclude(ITranslationUnit sourceTU, ITranslationUnit headerTU, StringBuffer text) { + IProject project = headerTU.getCProject().getProject(); + IPath projectLocation = project.getLocation(); + IPath headerLocation = headerTU.getResource().getLocation(); + IPath sourceLocation = sourceTU.getResource().getLocation(); + + IPath includePath = makeRelativePathToProjectIncludes(headerLocation, project); + boolean isSystemIncludePath = false; + if (includePath != null && !projectLocation.isPrefixOf(headerLocation)) { + isSystemIncludePath = true; + } else if (projectLocation.isPrefixOf(headerLocation) + && projectLocation.isPrefixOf(sourceLocation)) { + includePath = makeRelativePath(headerLocation, sourceLocation); + } + if (includePath == null) + includePath = headerLocation; + + String include = getIncludeString(includePath.toString(), isSystemIncludePath); + text.append(include); + text.append(fLineDelimiter); + } + + private void addMethodBodies(List publicMethods, List protectedMethods, List privateMethods, StringBuffer text) { + if (!publicMethods.isEmpty()) { + for (Iterator i = publicMethods.iterator(); i.hasNext();) { + IMethodStub stub = (IMethodStub) i.next(); + String code = stub.createMethodImplementation(fClassName, fBaseClasses, fLineDelimiter); + text.append(fLineDelimiter); + text.append(code); + text.append(fLineDelimiter); + } + } + + if (!protectedMethods.isEmpty()) { + for (Iterator i = protectedMethods.iterator(); i.hasNext();) { + IMethodStub stub = (IMethodStub) i.next(); + String code = stub.createMethodImplementation(fClassName, fBaseClasses, fLineDelimiter); + text.append(fLineDelimiter); + text.append(code); + text.append(fLineDelimiter); + } + } + + if (!privateMethods.isEmpty()) { + for (Iterator i = privateMethods.iterator(); i.hasNext();) { + IMethodStub stub = (IMethodStub) i.next(); + String code = stub.createMethodImplementation(fClassName, fBaseClasses, fLineDelimiter); + text.append(fLineDelimiter); + text.append(code); + text.append(fLineDelimiter); + } + } + } + + private IPath makeRelativePathToProjectIncludes(IPath fullPath, IProject project) { + IScannerInfoProvider provider = CCorePlugin.getDefault().getScannerInfoProvider(project); + if (provider != null) { + IScannerInfo info = provider.getScannerInformation(project); + if (info != null) { + String[] includePaths = info.getIncludePaths(); + IPath relativePath = null; + int mostSegments = 0; + for (int i = 0; i < includePaths.length; ++i) { + IPath includePath = new Path(includePaths[i]); + if (includePath.isPrefixOf(fullPath)) { + int segments = includePath.matchingFirstSegments(fullPath); + if (segments > mostSegments) { + relativePath = fullPath.removeFirstSegments(segments).setDevice(null); + mostSegments = segments; + } + } + } + if (relativePath != null) + return relativePath; + } + } + return null; + } + + private IPath makeRelativePath(IPath path, IPath relativeTo) { + int segments = relativeTo.matchingFirstSegments(path); + if (segments > 0) { + IPath prefix = relativeTo.removeFirstSegments(segments).removeLastSegments(1); + IPath suffix = path.removeFirstSegments(segments); + IPath relativePath = new Path(""); //$NON-NLS-1$ + for (int i = 0; i < prefix.segmentCount(); ++i) { + relativePath = relativePath.append(".." + IPath.SEPARATOR); //$NON-NLS-1$ + } + return relativePath.append(suffix); + } + return null; + } + + private String getIncludeString(String fileName, boolean isSystemInclude) { + StringBuffer buf = new StringBuffer(); + buf.append("#include "); //$NON-NLS-1$ + if (isSystemInclude) + buf.append('<'); //$NON-NLS-1$ + else + buf.append('\"'); //$NON-NLS-1$ + buf.append(fileName); + if (isSystemInclude) + buf.append('>'); //$NON-NLS-1$ + else + buf.append('\"'); //$NON-NLS-1$ + return buf.toString(); + } + } \ No newline at end of file diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/classwizard/NewClassCreationWizardPage.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/classwizard/NewClassCreationWizardPage.java new file mode 100644 index 00000000000..951f695f746 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/classwizard/NewClassCreationWizardPage.java @@ -0,0 +1,1439 @@ +/******************************************************************************* + * Copyright (c) 2004 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * QNX Software Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.internal.ui.wizards.classwizard; + +import java.lang.reflect.InvocationTargetException; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.cdt.core.CConventions; +import org.eclipse.cdt.core.browser.AllTypesCache; +import org.eclipse.cdt.core.browser.IQualifiedTypeName; +import org.eclipse.cdt.core.browser.ITypeInfo; +import org.eclipse.cdt.core.browser.ITypeSearchScope; +import org.eclipse.cdt.core.browser.QualifiedTypeName; +import org.eclipse.cdt.core.browser.TypeSearchScope; +import org.eclipse.cdt.core.model.CModelException; +import org.eclipse.cdt.core.model.CoreModel; +import org.eclipse.cdt.core.model.ICElement; +import org.eclipse.cdt.core.model.ICModel; +import org.eclipse.cdt.core.model.ICProject; +import org.eclipse.cdt.core.model.ISourceRoot; +import org.eclipse.cdt.core.model.ITranslationUnit; +import org.eclipse.cdt.core.parser.ast.ASTAccessVisibility; +import org.eclipse.cdt.internal.corext.util.CModelUtil; +import org.eclipse.cdt.internal.ui.dialogs.StatusInfo; +import org.eclipse.cdt.internal.ui.util.ExceptionHandler; +import org.eclipse.cdt.internal.ui.util.SWTUtil; +import org.eclipse.cdt.internal.ui.viewsupport.IViewPartInputProvider; +import org.eclipse.cdt.internal.ui.wizards.NewElementWizardPage; +import org.eclipse.cdt.internal.ui.wizards.TypedElementSelectionValidator; +import org.eclipse.cdt.internal.ui.wizards.TypedViewerFilter; +import org.eclipse.cdt.internal.ui.wizards.classwizard.NewBaseClassSelectionDialog.ITypeSelectionListener; +import org.eclipse.cdt.internal.ui.wizards.dialogfields.DialogField; +import org.eclipse.cdt.internal.ui.wizards.dialogfields.IDialogFieldListener; +import org.eclipse.cdt.internal.ui.wizards.dialogfields.IListAdapter; +import org.eclipse.cdt.internal.ui.wizards.dialogfields.IStringButtonAdapter; +import org.eclipse.cdt.internal.ui.wizards.dialogfields.LayoutUtil; +import org.eclipse.cdt.internal.ui.wizards.dialogfields.ListDialogField; +import org.eclipse.cdt.internal.ui.wizards.dialogfields.SelectionButtonDialogField; +import org.eclipse.cdt.internal.ui.wizards.dialogfields.Separator; +import org.eclipse.cdt.internal.ui.wizards.dialogfields.StringButtonDialogField; +import org.eclipse.cdt.internal.ui.wizards.dialogfields.StringDialogField; +import org.eclipse.cdt.ui.CElementContentProvider; +import org.eclipse.cdt.ui.CElementLabelProvider; +import org.eclipse.cdt.ui.CElementSorter; +import org.eclipse.cdt.ui.CUIPlugin; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Path; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.text.ITextSelection; +import org.eclipse.jface.viewers.ILabelProvider; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerFilter; +import org.eclipse.jface.window.Window; +import org.eclipse.swt.SWT; +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.Text; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.dialogs.ElementTreeSelectionDialog; +import org.eclipse.ui.views.contentoutline.ContentOutline; + +public class NewClassCreationWizardPage extends NewElementWizardPage { + + private final static String PAGE_NAME = "NewClassWizardPage"; //$NON-NLS-1$ + + private IWorkspaceRoot fWorkspaceRoot; + + /** ID of the source folder field */ + protected static final String SOURCE_FOLDER = PAGE_NAME + ".sourcefolder"; //$NON-NLS-1$ + private StringButtonDialogField fSourceFolderDialogField; + protected IStatus fSourceFolderStatus; + ISourceRoot fCurrentSourceFolder; + + /** ID of the namespace input field. */ + protected final static String NAMESPACE = PAGE_NAME + ".namespace"; //$NON-NLS-1$ + StringButtonDialogField fNamespaceDialogField; + private boolean fCanModifyNamespace; + protected IStatus fNamespaceStatus; + + /** ID of the enclosing class input field. */ + protected final static String ENCLOSING_CLASS = PAGE_NAME + ".enclosingclass"; //$NON-NLS-1$ + SelectionButtonDialogField fEnclosingClassSelection; + StringButtonDialogField fEnclosingClassDialogField; + private boolean fCanModifyEnclosingClass; + protected IStatus fEnclosingClassStatus; + ITypeInfo fCurrentEnclosingClass; + + /** Field ID of the class name input field. */ + protected final static String CLASSNAME = PAGE_NAME + ".typename"; //$NON-NLS-1$ + StringDialogField fClassNameDialogField; + protected IStatus fClassNameStatus; + + /** ID of the base classes input field. */ + protected final static String BASECLASSES = PAGE_NAME + ".baseclasses"; //$NON-NLS-1$ + BaseClassesListDialogField fBaseClassesDialogField; + protected IStatus fBaseClassesStatus; + + /** ID of the method stubs input field. */ + protected final static String METHODSTUBS = PAGE_NAME + ".methodstubs"; //$NON-NLS-1$ + MethodStubsListDialogField fMethodStubsDialogField; + protected IStatus fMethodStubsStatus; + + StringButtonDialogField fHeaderFileDialogField; + + StringButtonDialogField fSourceFileDialogField; + + private NewClassCodeGenerator fCodeGenerator = null; + + public NewClassCreationWizardPage() { + super(PAGE_NAME); + + setTitle(NewClassWizardMessages.getString("NewClassCreationWizardPage.title")); //$NON-NLS-1$ + setDescription(NewClassWizardMessages.getString("NewClassCreationWizardPage.description")); //$NON-NLS-1$ + + fWorkspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); + fCodeGenerator = null; + + SourceFolderFieldAdapter sourceFolderAdapter = new SourceFolderFieldAdapter(); + fSourceFolderDialogField = new StringButtonDialogField(sourceFolderAdapter); + fSourceFolderDialogField.setDialogFieldListener(sourceFolderAdapter); + fSourceFolderDialogField.setLabelText(NewClassWizardMessages.getString("NewClassCreationWizardPage.sourceFolder.label")); //$NON-NLS-1$ + fSourceFolderDialogField.setButtonLabel(NewClassWizardMessages.getString("NewClassCreationWizardPage.sourceFolder.button")); //$NON-NLS-1$ + + NamespaceFieldAdapter namespaceAdapter = new NamespaceFieldAdapter(); + fNamespaceDialogField = new StringButtonDialogField(namespaceAdapter); + fNamespaceDialogField.setDialogFieldListener(namespaceAdapter); + fNamespaceDialogField.setLabelText(NewClassWizardMessages.getString("NewClassCreationWizardPage.namespace.label")); //$NON-NLS-1$ + fNamespaceDialogField.setButtonLabel(NewClassWizardMessages.getString("NewClassCreationWizardPage.namespace.button")); //$NON-NLS-1$ + + EnclosingClassFieldAdapter enclosingClassAdapter = new EnclosingClassFieldAdapter(); + fEnclosingClassSelection = new SelectionButtonDialogField(SWT.CHECK); + fEnclosingClassSelection.setDialogFieldListener(enclosingClassAdapter); + fEnclosingClassSelection.setLabelText(NewClassWizardMessages.getString("NewClassCreationWizardPage.enclosingClass.label")); //$NON-NLS-1$ + fEnclosingClassDialogField = new StringButtonDialogField(enclosingClassAdapter); + fEnclosingClassDialogField.setDialogFieldListener(enclosingClassAdapter); + fEnclosingClassDialogField.setButtonLabel(NewClassWizardMessages.getString("NewClassCreationWizardPage.enclosingClass.button")); //$NON-NLS-1$ + + ClassNameFieldAdapter classAdapter = new ClassNameFieldAdapter(); + fClassNameDialogField = new StringDialogField(); + fClassNameDialogField.setDialogFieldListener(classAdapter); + fClassNameDialogField.setLabelText(NewClassWizardMessages.getString("NewClassCreationWizardPage.className.label")); //$NON-NLS-1$ + + BaseClassesFieldAdapter baseClassesAdapter = new BaseClassesFieldAdapter(); + fBaseClassesDialogField = new BaseClassesListDialogField(NewClassWizardMessages.getString("NewClassCreationWizardPage.baseClasses.label"), baseClassesAdapter); //$NON-NLS-1$ + + MethodStubsFieldAdapter methodStubsAdapter = new MethodStubsFieldAdapter(); + fMethodStubsDialogField = new MethodStubsListDialogField(NewClassWizardMessages.getString("NewClassCreationWizardPage.methodStubs.label"), methodStubsAdapter); //$NON-NLS-1$ + + HeaderFileFieldAdapter headerFileAdapter = new HeaderFileFieldAdapter(); + fHeaderFileDialogField = new StringButtonDialogField(headerFileAdapter); + fHeaderFileDialogField.setDialogFieldListener(headerFileAdapter); + fHeaderFileDialogField.setLabelText(NewClassWizardMessages.getString("NewClassCreationWizardPage.classDefinition.label")); //$NON-NLS-1$ + fHeaderFileDialogField.setButtonLabel(NewClassWizardMessages.getString("NewClassCreationWizardPage.classDefinition.button")); //$NON-NLS-1$ + + SourceFileFieldAdapter sourceFileAdapter = new SourceFileFieldAdapter(); + fSourceFileDialogField = new StringButtonDialogField(sourceFileAdapter); + fSourceFileDialogField.setDialogFieldListener(sourceFileAdapter); + fSourceFileDialogField.setLabelText(NewClassWizardMessages.getString("NewClassCreationWizardPage.classImplementation.label")); //$NON-NLS-1$ + fSourceFileDialogField.setButtonLabel(NewClassWizardMessages.getString("NewClassCreationWizardPage.classImplementation.button")); //$NON-NLS-1$ + + fSourceFolderStatus = new StatusInfo(); + fNamespaceStatus = new StatusInfo(); + fEnclosingClassStatus = new StatusInfo(); + fClassNameStatus = new StatusInfo(); + fBaseClassesStatus = new StatusInfo(); + fMethodStubsStatus = new StatusInfo(); + + fCurrentSourceFolder = null; + fCanModifyNamespace = true; + fCurrentEnclosingClass = null; + fCanModifyEnclosingClass = true; + updateEnableState(); + } + + // -------- UI Creation --------- + + public void createControl(Composite parent) { + initializeDialogUnits(parent); + + Composite composite = new Composite(parent, SWT.NONE); + int nColumns = 4; + + GridLayout layout = new GridLayout(); + layout.numColumns = nColumns; + composite.setLayout(layout); + composite.setLayoutData(new GridData(GridData.FILL_BOTH)); + composite.setFont(parent.getFont()); + + createSourceFolderControls(composite, nColumns); + createNamespaceControls(composite, nColumns); + createEnclosingClassControls(composite, nColumns); + + createSeparator(composite, nColumns); + + createClassNameControls(composite, nColumns); + createBaseClassesControls(composite, nColumns); + createMethodStubsControls(composite, nColumns); + + createSeparator(composite, nColumns); + + createHeaderFileControls(composite, nColumns); + createSourceFileControls(composite, nColumns); + + composite.layout(); + + setErrorMessage(null); + setMessage(null); + setControl(composite); + } + + /** + * Creates a separator line. Expects a GridLayout 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)); + } + + /** + * Creates the necessary controls (label, text field and browse button) to edit + * the source folder location. The method expects that the parent composite + * uses a GridLayout as its layout manager and that the + * grid layout has at least 3 columns. + * + * @param parent the parent composite + * @param nColumns the number of columns to span. This number must be + * greater or equal three + */ + protected void createSourceFolderControls(Composite parent, int nColumns) { + fSourceFolderDialogField.doFillIntoGrid(parent, nColumns); + LayoutUtil.setWidthHint(fSourceFolderDialogField.getTextControl(null), getMaxFieldWidth()); + } + + /** + * Creates the controls for the namespace field. Expects a GridLayout with at + * least 4 columns. + * + * @param composite the parent composite + * @param nColumns number of columns to span + */ + protected void createNamespaceControls(Composite composite, int nColumns) { + fNamespaceDialogField.doFillIntoGrid(composite, nColumns); + LayoutUtil.setWidthHint(fNamespaceDialogField.getTextControl(null), getMaxFieldWidth()); + } + + /** + * Creates the controls for the enclosing class name field. Expects a GridLayout with at + * least 4 columns. + * + * @param composite the parent composite + * @param nColumns number of columns to span + */ + protected void createEnclosingClassControls(Composite composite, int nColumns) { + Composite tabGroup = new Composite(composite, SWT.NONE); + GridLayout layout = new GridLayout(); + layout.marginWidth = 0; + layout.marginHeight = 0; + tabGroup.setLayout(layout); + + fEnclosingClassSelection.doFillIntoGrid(tabGroup, 1); + + Text text = fEnclosingClassDialogField.getTextControl(composite); + GridData gd = new GridData(GridData.FILL_HORIZONTAL); + gd.widthHint = getMaxFieldWidth(); + gd.horizontalSpan = 2; + text.setLayoutData(gd); + + Button button = fEnclosingClassDialogField.getChangeControl(composite); + gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL); + gd.heightHint = SWTUtil.getButtonHeigthHint(button); + gd.widthHint = SWTUtil.getButtonWidthHint(button); + button.setLayoutData(gd); +// ControlContentAssistHelper.createTextContentAssistant(text, fEnclosingTypeCompletionProcessor); + } + + /** + * Creates the controls for the type name field. Expects a GridLayout with at + * least 2 columns. + * + * @param composite the parent composite + * @param nColumns number of columns to span + */ + protected void createClassNameControls(Composite composite, int nColumns) { + fClassNameDialogField.doFillIntoGrid(composite, nColumns - 1); + DialogField.createEmptySpace(composite); + + LayoutUtil.setWidthHint(fClassNameDialogField.getTextControl(null), getMaxFieldWidth()); + } + + /** + * Creates the controls for the base classes field. Expects a GridLayout with + * at least 3 columns. + * + * @param composite the parent composite + * @param nColumns number of columns to span + */ + protected void createBaseClassesControls(Composite composite, int nColumns) { + fBaseClassesDialogField.doFillIntoGrid(composite, nColumns); + GridData gd = (GridData)fBaseClassesDialogField.getListControl(null).getLayoutData(); + gd.heightHint = convertHeightInCharsToPixels(5); + gd.grabExcessVerticalSpace = false; + gd.widthHint = getMaxFieldWidth(); + } + + /** + * Creates the controls for the base classes field. Expects a GridLayout with + * at least 4 columns. + * + * @param composite the parent composite + * @param nColumns number of columns to span + */ + protected void createMethodStubsControls(Composite composite, int nColumns) { + fMethodStubsDialogField.doFillIntoGrid(composite, nColumns); + GridData gd = (GridData)fMethodStubsDialogField.getListControl(null).getLayoutData(); + gd.heightHint = convertHeightInCharsToPixels(5); + gd.grabExcessVerticalSpace = false; + gd.widthHint = getMaxFieldWidth(); + } + + /** + * Creates the controls for the header file field. Expects a GridLayout with at + * least 4 columns. + * + * @param composite the parent composite + * @param nColumns number of columns to span + */ + protected void createHeaderFileControls(Composite composite, int nColumns) { + LayoutUtil.setHorizontalSpan(fHeaderFileDialogField.getLabelControl(composite), 1); + + Text text = fHeaderFileDialogField.getTextControl(composite); + GridData gd = new GridData(GridData.FILL_HORIZONTAL); + gd.widthHint = getMaxFieldWidth(); + gd.horizontalSpan = 2; + text.setLayoutData(gd); + + Button button = fHeaderFileDialogField.getChangeControl(composite); + gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL); + gd.heightHint = SWTUtil.getButtonHeigthHint(button); + gd.widthHint = SWTUtil.getButtonWidthHint(button); + button.setLayoutData(gd); + } + + /** + * Creates the controls for the source file field. Expects a GridLayout with at + * least 4 columns. + * + * @param composite the parent composite + * @param nColumns number of columns to span + */ + protected void createSourceFileControls(Composite composite, int nColumns) { + LayoutUtil.setHorizontalSpan(fSourceFileDialogField.getLabelControl(composite), 1); + + Text text = fSourceFileDialogField.getTextControl(composite); + GridData gd = new GridData(GridData.FILL_HORIZONTAL); + gd.widthHint = getMaxFieldWidth(); + gd.horizontalSpan = 2; + text.setLayoutData(gd); + + Button button = fSourceFileDialogField.getChangeControl(composite); + gd = new GridData(GridData.HORIZONTAL_ALIGN_FILL); + gd.heightHint = SWTUtil.getButtonHeigthHint(button); + gd.widthHint = SWTUtil.getButtonWidthHint(button); + button.setLayoutData(gd); + } + + /** + * The wizard owning this page is responsible for calling this method with the + * current selection. The selection is used to initialize the fields of the wizard + * page. + * + * @param selection used to initialize the fields + */ + public void init(IStructuredSelection selection) { + ICElement celem = getInitialCElement(selection); + initFields(celem); + doStatusUpdate(); + + //TODO restore dialog settings for method stubs + // IDialogSettings section = getDialogSettings().getSection(PAGE_NAME); + // if (section != null) { + // enabled = section.getBoolean(stubName); + // } + } + + /** + * Utility method to inspect a selection to find a C element. + * + * @param selection the selection to be inspected + * @return a C element to be used as the initial selection, or null, + * if no C element exists in the given selection + */ + protected ICElement getInitialCElement(IStructuredSelection selection) { + ICElement celem = null; + if (selection != null && !selection.isEmpty()) { + Object selectedElement = selection.getFirstElement(); + if (selectedElement instanceof IAdaptable) { + IAdaptable adaptable = (IAdaptable) selectedElement; + + celem = (ICElement) adaptable.getAdapter(ICElement.class); + if (celem == null) { + IResource resource = (IResource) adaptable.getAdapter(IResource.class); + if (resource != null && resource.getType() != IResource.ROOT) { + while (celem == null && resource.getType() != IResource.PROJECT) { + resource = resource.getParent(); + celem = (ICElement) resource.getAdapter(ICElement.class); + } + if (celem == null) { + celem = CoreModel.getDefault().create(resource); // c project + } + } + } + } + } + if (celem == null) { + IWorkbenchPart part = CUIPlugin.getActivePage().getActivePart(); + if (part instanceof ContentOutline) { + part = CUIPlugin.getActivePage().getActiveEditor(); + } + + if (part instanceof IViewPartInputProvider) { + Object elem = ((IViewPartInputProvider)part).getViewPartInput(); + if (elem instanceof ICElement) { + celem = (ICElement) elem; + } + } + } + + if (celem == null || celem.getElementType() == ICElement.C_MODEL) { + try { + ICProject[] projects = CoreModel.create(getWorkspaceRoot()).getCProjects(); + if (projects.length == 1) { + celem = projects[0]; + } + } catch (CModelException e) { + CUIPlugin.getDefault().log(e); + } + } + return celem; + } + + /** + * Initializes all fields provided by the page with a given selection. + * + * @param elem the selection used to initialize this page or + * null if no selection was available + */ + protected void initFields(ICElement elem) { + initSourceFolder(elem); + + ITypeInfo namespace = null; + ITypeInfo enclosingClass = null; + //TODO evaluate the enclosing class + + String className = ""; //$NON-NLS-1$ + + ITextSelection selection = getCurrentTextSelection(); + if (selection != null) { + String text = selection.getText(); + if (CConventions.validateClassName(text).isOK()) { + className = text; + } + } + + setNamespace(namespace, true); + setEnclosingClass(enclosingClass, true); + setEnclosingClassSelection(false, true); + + setClassName(className, true); + + addMethodStub(new ConstructorMethodStub(), true); + addMethodStub(new DestructorMethodStub(), true); + } + + /** + * Initializes the source folder field. + * + * @param elem the C element used to compute the initial folder + */ + protected void initSourceFolder(ICElement elem) { + ISourceRoot initRoot = null; + if (elem != null) { + initRoot = CModelUtil.getSourceRoot(elem); + if (initRoot == null) { + ICProject cproject = elem.getCProject(); + if (cproject != null) { + try { + initRoot = null; + if (cproject.exists()) { + ISourceRoot[] roots = cproject.getSourceRoots(); + if (roots != null && roots.length > 0) + initRoot = roots[0]; + } + } catch (CModelException e) { + CUIPlugin.getDefault().log(e); + } + if (initRoot == null) { + initRoot = cproject.findSourceRoot(cproject.getResource()); + } + } + } + } + setSourceFolder(initRoot, true); + } + + /** + * Returns the recommended maximum width for text fields (in pixels). This + * method requires that createContent has been called before this method is + * call. Subclasses may override to change the maximum width for text + * fields. + * + * @return the recommended maximum width for text fields. + */ + protected int getMaxFieldWidth() { + return convertWidthInCharsToPixels(60); + } + + /** + * Returns the test selection of the current editor. null is returned + * when the current editor does not have focus or does not return a text selection. + * @return Returns the test selection of the current editor or null. + * + * @since 3.0 + */ + protected ITextSelection getCurrentTextSelection() { + IWorkbenchPart part = CUIPlugin.getActivePage().getActivePart(); + if (part instanceof IEditorPart) { + ISelectionProvider selectionProvider = part.getSite().getSelectionProvider(); + if (selectionProvider != null) { + ISelection selection = selectionProvider.getSelection(); + if (selection instanceof ITextSelection) { + return (ITextSelection) selection; + } + } + } + return null; + } + + /** + * Sets the focus to the source folder's text field. + */ + protected void setFocusOnSourceFolder() { + fSourceFolderDialogField.setFocus(); + } + + private class SourceFolderFieldAdapter implements IStringButtonAdapter, IDialogFieldListener { + public void changeControlPressed(DialogField field) { + // take the current cproject as init element of the dialog + ISourceRoot folder = chooseSourceFolder(fCurrentSourceFolder); + if (folder != null) { + setSourceFolder(folder, true); + prepareTypeCache(); + } + } + + public void dialogFieldChanged(DialogField field) { + fSourceFolderStatus = sourceFolderChanged(); + // tell all others + handleFieldChanged(SOURCE_FOLDER); + } + } + + private class NamespaceFieldAdapter implements IStringButtonAdapter, IDialogFieldListener { + public void changeControlPressed(DialogField field) { + ITypeInfo namespace = chooseNamespace(); + if (namespace != null) { + String name = namespace.getQualifiedTypeName().getFullyQualifiedName(); + + // this will trigger dialogFieldChanged + fNamespaceDialogField.setText(name); + } + } + + public void dialogFieldChanged(DialogField field) { + fNamespaceStatus = namespaceChanged(); + updateEnclosingClassFromNamespace(); + // tell all others + updateEnableState(); + handleFieldChanged(NAMESPACE); + } + } + + private class EnclosingClassFieldAdapter implements IStringButtonAdapter, IDialogFieldListener { + public void changeControlPressed(DialogField field) { + ITypeInfo enclosingClass = chooseEnclosingClass(); + if (enclosingClass != null) { + fCurrentEnclosingClass = enclosingClass; + IQualifiedTypeName qualClassName = enclosingClass.getQualifiedTypeName(); + + // this will trigger dialogFieldChanged + fEnclosingClassDialogField.setText(qualClassName.getFullyQualifiedName()); + } + } + + public void dialogFieldChanged(DialogField field) { + if (field == fEnclosingClassSelection) { + boolean enclosing = isEnclosingClassSelected(); + fEnclosingClassDialogField.setEnabled(enclosing); + } else { + updateNamespaceFromEnclosingClass(); + } + fEnclosingClassStatus = enclosingClassChanged(); + // tell all others + updateEnableState(); + handleFieldChanged(ENCLOSING_CLASS); + } + } + + void updateEnclosingClassFromNamespace() { + fCurrentEnclosingClass = null; + fEnclosingClassDialogField.setTextWithoutUpdate(""); //$NON-NLS-1$ + } + + void updateNamespaceFromEnclosingClass() { + boolean enclosing = isEnclosingClassSelected(); + String name = ""; //$NON-NLS-1$ + if (enclosing && fCurrentEnclosingClass != null) { + ITypeInfo namespace = fCurrentEnclosingClass.getEnclosingNamespace(); + if (namespace != null) { + IQualifiedTypeName qualNSName = namespace.getQualifiedTypeName(); + name = qualNSName.getFullyQualifiedName(); + } + } + fNamespaceDialogField.setTextWithoutUpdate(name); + } + + private class ClassNameFieldAdapter implements IDialogFieldListener { + public void dialogFieldChanged(DialogField field) { + String className = fClassNameDialogField.getText(); + if (className.length() > 0) { + fHeaderFileDialogField.setText(NewSourceFileGenerator.generateHeaderFileNameFromClass(className)); + fSourceFileDialogField.setText(NewSourceFileGenerator.generateSourceFileNameFromClass(className)); + } else { + fHeaderFileDialogField.setText(""); //$NON-NLS-1$ + fSourceFileDialogField.setText(""); //$NON-NLS-1$ + } + fClassNameStatus = classNameChanged(); + // tell all others + handleFieldChanged(CLASSNAME); + } + } + + private final class BaseClassesFieldAdapter implements IListAdapter { + public void customButtonPressed(ListDialogField field, int index) { + if (index == 0) { + chooseBaseClasses(); + fBaseClassesStatus = baseClassesChanged(); + handleFieldChanged(BASECLASSES); + } + } + + public void selectionChanged(ListDialogField field) { + } + + public void doubleClicked(ListDialogField field) { + } + } + + private final class MethodStubsFieldAdapter implements IListAdapter { + + public void customButtonPressed(ListDialogField field, int index) { + } + + public void selectionChanged(ListDialogField field) { + } + + public void doubleClicked(ListDialogField field) { + } + } + + private class HeaderFileFieldAdapter implements IStringButtonAdapter, IDialogFieldListener { + public void changeControlPressed(DialogField field) { + } + + public void dialogFieldChanged(DialogField field) { + } + } + + private class SourceFileFieldAdapter implements IStringButtonAdapter, IDialogFieldListener { + public void changeControlPressed(DialogField field) { + } + + public void dialogFieldChanged(DialogField field) { + } + } + + // ----------- validation ---------- + + /** + * This method is a hook which gets called after the source folder's + * text input field has changed. This default implementation updates + * the model and returns an error status. The underlying model + * is only valid if the returned status is OK. + * + * @return the model's error status + */ + protected IStatus sourceFolderChanged() { + StatusInfo status = new StatusInfo(); + + fCurrentSourceFolder = null; + String str = getSourceFolderText(); + if (str.length() == 0) { + status.setError(NewClassWizardMessages.getString("NewClassCreationWizardPage.error.EnterSourceFolderName")); //$NON-NLS-1$ + return status; + } + IPath path = new Path(str); + IResource res = fWorkspaceRoot.findMember(path); + if (res != null) { + int resType = res.getType(); + if (resType == IResource.PROJECT || resType == IResource.FOLDER) { + IProject proj = res.getProject(); + if (!proj.isOpen()) { + status.setError(NewClassWizardMessages.getFormattedString("NewClassCreationWizardPage.error.ProjectClosed", proj.getFullPath().toString())); //$NON-NLS-1$ + return status; + } + ICProject cproject = CoreModel.getDefault().create(proj); + fCurrentSourceFolder = cproject.findSourceRoot(res); + //TODO check for null + if (res.exists()) { +// try { + if (!CoreModel.hasCCNature(proj) && !CoreModel.hasCNature(proj)) { +// if (!proj.hasNature(CoreModel.NATURE_ID)) { + if (resType == IResource.PROJECT) { + status.setError(NewClassWizardMessages.getString("NewClassCreationWizardPage.warning.NotACProject")); //$NON-NLS-1$ + } else { + status.setWarning(NewClassWizardMessages.getString("NewClassCreationWizardPage.warning.NotInACProject")); //$NON-NLS-1$ + } + return status; + } +// } catch (CoreException e) { +// status.setWarning(NewClassWizardMessages.getString("NewClassCreationWizardPage.warning.NotACProject")); //$NON-NLS-1$ +// } +// if (!cproject.isOnClasspath(fCurrRoot)) { +// if (!cproject.isOnSourceRoot(fCurrRoot)) { +// status.setWarning(NewClassWizardMessages.getFormattedString("NewClassCreationWizardPage.warning.NotOnClassPath", str)); //$NON-NLS-1$ +// } +// if (fCurrRoot.isArchive()) { +// status.setError(NewClassWizardMessages.getFormattedString("NewClassCreationWizardPage.error.ContainerIsBinary", str)); //$NON-NLS-1$ +// return status; +// } + } + return status; + } else { + status.setError(NewClassWizardMessages.getFormattedString("NewClassCreationWizardPage.error.NotAFolder", str)); //$NON-NLS-1$ + return status; + } + } else { + status.setError(NewClassWizardMessages.getFormattedString("NewClassCreationWizardPage.error.SourceFolderDoesNotExist", str)); //$NON-NLS-1$ + return status; + } + } + + /** + * This method is a hook which gets called after the namespace + * text input field has changed. This default implementation updates + * the model and returns an error status. The underlying model + * is only valid if the returned status is OK. + * + * @return the model's error status + */ + protected IStatus namespaceChanged() { + StatusInfo status = new StatusInfo(); + return status; + } + + /** + * This method is a hook which gets called after the enclosing class + * text input field has changed. This default implementation updates + * the model and returns an error status. The underlying model + * is only valid if the returned status is OK. + * + * @return the model's error status + */ + protected IStatus enclosingClassChanged() { + StatusInfo status = new StatusInfo(); + if (!isEnclosingClassSelected()) { + return status; + } + //TODO check if enclosing class exists + return status; + } + + /** + * Hook method that gets called when the class name has changed. The method validates the + * class name and returns the status of the validation. + * + * @return the status of the validation + */ + protected IStatus classNameChanged() { + StatusInfo status = new StatusInfo(); + String className = getClassName(); + // must not be empty + if (className.length() == 0) { + status.setError(NewClassWizardMessages.getString("NewClassCreationWizardPage.error.EnterClassName")); //$NON-NLS-1$ + return status; + } + if (className.indexOf("::") != -1) { //$NON-NLS-1$ + status.setError(NewClassWizardMessages.getString("NewClassCreationWizardPage.error.QualifiedName")); //$NON-NLS-1$ + return status; + } + + IStatus val = CConventions.validateClassName(className); + if (val.getSeverity() == IStatus.ERROR) { + status.setError(NewClassWizardMessages.getFormattedString("NewClassCreationWizardPage.error.InvalidClassName", val.getMessage())); //$NON-NLS-1$ + return status; + } else if (val.getSeverity() == IStatus.WARNING) { + status.setWarning(NewClassWizardMessages.getFormattedString("NewClassCreationWizardPage.warning.ClassNameDiscouraged", val.getMessage())); //$NON-NLS-1$ + // continue checking + } + + IQualifiedTypeName qualName = new QualifiedTypeName(className); + // must not exist + if (!isEnclosingClassSelected()) { + IProject project = getCurrentProject(); + if (project == null) + return null; + ITypeSearchScope scope = prepareTypeCache(); + if (scope == null) + return null; + + ITypeInfo[] types = AllTypesCache.getTypes(project, qualName, false); + if (types.length != 0) { + status.setError(NewClassWizardMessages.getString("NewClassCreationWizardPage.error.ClassNameExists")); //$NON-NLS-1$ + return status; + } + types = AllTypesCache.getTypes(project, qualName, true); + if (types.length != 0) { + status.setError(NewClassWizardMessages.getString("NewClassCreationWizardPage.error.ClassNameExistsDifferentCase")); //$NON-NLS-1$ + return status; + } + } else { + ITypeSearchScope scope = prepareTypeCache(); + if (scope == null) + return null; + + if (fCurrentEnclosingClass != null) { + ITypeInfo[] types = fCurrentEnclosingClass.getEnclosedTypes(); + for (int i = 0; i < types.length; ++i) { + ITypeInfo type = types[i]; + if (type.getQualifiedTypeName().equalsIgnoreCase(qualName)) { + if (type.getQualifiedTypeName().equals(qualName)) + status.setError(NewClassWizardMessages.getString("NewClassCreationWizardPage.error.ClassNameExists")); //$NON-NLS-1$ + else + status.setError(NewClassWizardMessages.getString("NewClassCreationWizardPage.error.ClassNameExistsDifferentCase")); //$NON-NLS-1$ + return status; + } + } + } + } + return status; + } + + /** + * Hook method that gets called when the list of base classes has changed. The method + * validates the base classes and returns the status of the validation. + *

+ * Subclasses may extend this method to perform their own validation. + *

+ * + * @return the status of the validation + */ + protected IStatus baseClassesChanged() { + StatusInfo status = new StatusInfo(); + return status; + } + + /** + * This method is a hook which gets called after the method stubs + * input field has changed. This default implementation updates + * the model and returns an error status. The underlying model + * is only valid if the returned status is OK. + * + * @return the model's error status + */ + protected IStatus methodStubsChanged() { + StatusInfo status = new StatusInfo(); + return status; + } + + /** + * Hook method that gets called when a field on this page has changed. For this page the + * method gets called when the source folder field changes. + *

+ * Every sub type is responsible to call this method when a field on its page has changed. + * Subtypes override (extend) the method to add verification when a own field has a + * dependency to an other field. For example the class name input must be verified + * again when the package field changes (check for duplicated class names). + * + * @param fieldName The name of the field that has changed (field id). For the + * source folder the field id is SOURCE_FOLDER + */ + protected void handleFieldChanged(String fieldName) { + if (fieldName == SOURCE_FOLDER) { + fNamespaceStatus = namespaceChanged(); + fEnclosingClassStatus = enclosingClassChanged(); + fClassNameStatus = classNameChanged(); + fBaseClassesStatus = baseClassesChanged(); + fMethodStubsStatus = methodStubsChanged(); + } + doStatusUpdate(); + } + + protected void doStatusUpdate() { + // status of all used components + IStatus[] status = new IStatus[] { + fSourceFolderStatus, + isEnclosingClassSelected() ? fEnclosingClassStatus : fNamespaceStatus, + fClassNameStatus, + fBaseClassesStatus, + fMethodStubsStatus, + }; + + // the mode severe status will be displayed and the ok button enabled/disabled. + updateStatus(status); + } + + /** + * Returns the current text of source folder text field. + * + * @return the text of the source folder text field + */ + public String getSourceFolderText() { + return fSourceFolderDialogField.getText(); + } + + /** + * Returns the selection state of the enclosing class checkbox. + * + * @return the selection state of the enclosing class checkbox + */ + public boolean isEnclosingClassSelected() { + return fEnclosingClassSelection.isSelected(); + } + + /** + * Returns the type name entered into the type input field. + * + * @return the type name + */ + public String getClassName() { + return fClassNameDialogField.getText(); + } + + /** + * Returns the chosen base classes. + * + * @return array of IBaseClassInfo + */ + public IBaseClassInfo[] getBaseClasses() { + List classesList = fBaseClassesDialogField.getElements(); + return (IBaseClassInfo[]) classesList.toArray(new IBaseClassInfo[classesList.size()]); + } + + /** + * Returns the chosen method stubs. + * + * @return array of IMethodStub or empty array if none selected. + */ + public IMethodStub[] getCheckedMethodStubs() { + return fMethodStubsDialogField.getCheckedMethodStubs(); + } + + /** + * Returns the file name entered into the class definition field. + * + * @return the file name + */ + public String getHeaderFileName() { + return fHeaderFileDialogField.getText(); + } + + /** + * Returns the type name entered into the type input field. + * + * @return the type name + */ + public String getSourceFileName() { + return fSourceFileDialogField.getText(); + } + + public IProject getCurrentProject() { + if (fCurrentSourceFolder != null) { + return fCurrentSourceFolder.getCProject().getProject(); + } + return null; + } + + /** + * Returns the workspace root. + * + * @return the workspace root + */ + protected IWorkspaceRoot getWorkspaceRoot() { + return fWorkspaceRoot; + } + + /* + * @see WizardPage#becomesVisible + */ + public void setVisible(boolean visible) { + super.setVisible(visible); + if (visible) { + setFocus(); + } + } + + /** + * Sets the focus on the type name input field. + */ + protected void setFocus() { + fClassNameDialogField.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 true the type name field is + * editable; otherwise it is read-only. + */ + public void setClassName(String name, boolean canBeModified) { + fClassNameDialogField.setText(name); + fClassNameDialogField.setEnabled(canBeModified); + } + + public void addBaseClass(ITypeInfo newBaseClass, ASTAccessVisibility access, boolean isVirtual) { + List baseClasses = fBaseClassesDialogField.getElements(); + boolean classExists = false; + if (baseClasses != null) { + for (Iterator i = baseClasses.iterator(); i.hasNext(); ) { + BaseClassInfo info = (BaseClassInfo) i.next(); + if (info.getType().equals(newBaseClass)) { + classExists = true; + break; + } + } + } + if (!classExists) { + prepareTypeCache(); + // resolve location of base class + if (newBaseClass.getResolvedReference() == null) { + final ITypeInfo[] typesToResolve = new ITypeInfo[] { newBaseClass }; + IRunnableWithProgress runnable = new IRunnableWithProgress() { + public void run(IProgressMonitor progressMonitor) throws InvocationTargetException, InterruptedException { + AllTypesCache.resolveTypeLocation(typesToResolve[0], progressMonitor); + if (progressMonitor.isCanceled()) { + throw new InterruptedException(); + } + } + }; + + try { + getContainer().run(true, true, runnable); + } catch (InvocationTargetException e) { + String title = NewClassWizardMessages.getString("NewClassCreationWizardPage.getClasses.exception.title"); //$NON-NLS-1$ + String message = NewClassWizardMessages.getString("NewClassCreationWizardPage.getClasses.exception.message"); //$NON-NLS-1$ + ExceptionHandler.handle(e, title, message); + return; + } catch (InterruptedException e) { + // cancelled by user + return; + } + } + fBaseClassesDialogField.addBaseClass(new BaseClassInfo(newBaseClass, access, isVirtual)); + } + } + + public void addMethodStub(IMethodStub methodStub, boolean checked) { + fMethodStubsDialogField.addMethodStub(methodStub, checked); + } + + ITypeSearchScope prepareTypeCache() { + IProject project = getCurrentProject(); + if (project == null) + return null; + + final ITypeSearchScope scope = new TypeSearchScope(); + scope.add(project); + + if (!AllTypesCache.isCacheUpToDate(scope)) { + IRunnableWithProgress runnable = new IRunnableWithProgress() { + public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { + AllTypesCache.updateCache(scope, monitor); + if (monitor.isCanceled()) { + throw new InterruptedException(); + } + } + }; + + try { + getContainer().run(true, true, runnable); + } catch (InvocationTargetException e) { + String title = NewClassWizardMessages.getString("NewClassCreationWizardPage.getClasses.exception.title"); //$NON-NLS-1$ + String message = NewClassWizardMessages.getString("NewClassCreationWizardPage.getClasses.exception.message"); //$NON-NLS-1$ + ExceptionHandler.handle(e, title, message); + return null; + } catch (InterruptedException e) { + // cancelled by user + return null; + } + } + return scope; + } + + /** + * Sets the current source folder (model and text field) to the given source folder. + * + * @param folder The new folder. + * @param canBeModified if false the source folder field can + * not be changed by the user. If true the field is editable + */ + public void setSourceFolder(ISourceRoot folder, boolean canBeModified) { + fCurrentSourceFolder = folder; + String str = (folder == null) ? "" : folder.getPath().makeRelative().toString(); //$NON-NLS-1$ + fSourceFolderDialogField.setText(str); + fSourceFolderDialogField.setEnabled(canBeModified); + } + + /** + * Sets the namespace to the given value. The method updates the model + * and the text of the control. + * + * @param namespace the namespace to be set + * @param canBeModified if true the namespace is + * editable; otherwise it is read-only. + */ + public void setNamespace(ITypeInfo namespace, boolean canBeModified) { +// fCurrNamespace = namespace; + fCanModifyNamespace = canBeModified; + if (namespace != null) { + String name = namespace.getQualifiedTypeName().getFullyQualifiedName(); + fNamespaceDialogField.setText(name); + } else { + fNamespaceDialogField.setText(""); //$NON-NLS-1$ + } + updateEnableState(); + } + + /** + * Sets the enclosing type. The method updates the underlying model + * and the text of the control. + * + * @param type the enclosing type + * @param canBeModified if true the enclosing type field is + * editable; otherwise it is read-only. + */ + public void setEnclosingClass(ITypeInfo enclosingClass, boolean canBeModified) { + fCurrentEnclosingClass = enclosingClass; + fCanModifyEnclosingClass = canBeModified; + if (enclosingClass != null) { + String name = enclosingClass.getQualifiedTypeName().getFullyQualifiedName(); + fEnclosingClassDialogField.setText(name); + } else { + fEnclosingClassDialogField.setText(""); //$NON-NLS-1$ + } + updateEnableState(); + } + + /** + * Sets the enclosing class checkbox's selection state. + * + * @param isSelected the checkbox's selection state + * @param canBeModified if true the enclosing class checkbox is + * modifiable; otherwise it is read-only. + */ + public void setEnclosingClassSelection(boolean isSelected, boolean canBeModified) { + fEnclosingClassSelection.setSelection(isSelected); + fEnclosingClassSelection.setEnabled(canBeModified); + updateEnableState(); + } + + /* + * Updates the enable state of buttons related to the enclosing class selection checkbox. + */ + void updateEnableState() { + boolean enclosing = isEnclosingClassSelected(); + fNamespaceDialogField.setEnabled(fCanModifyNamespace && !enclosing); + fEnclosingClassDialogField.setEnabled(fCanModifyEnclosingClass && enclosing); + } + + ISourceRoot chooseSourceFolder(ICElement initElement) { + Class[] acceptedClasses = new Class[] { ISourceRoot.class, ICProject.class }; + TypedElementSelectionValidator validator = new TypedElementSelectionValidator(acceptedClasses, false) { + public boolean isSelectedValid(Object element) { + if (element instanceof ICProject) { + ICProject cproject = (ICProject)element; + IPath path = cproject.getProject().getFullPath(); + return (cproject.findSourceRoot(path) != null); + } else if (element instanceof ISourceRoot) { + return true; + } + return false; + } + }; + + acceptedClasses = new Class[] { ICModel.class, ISourceRoot.class, ICProject.class }; + ViewerFilter filter = new TypedViewerFilter(acceptedClasses) { + public boolean select(Viewer viewer, Object parent, Object element) { + if (element instanceof ISourceRoot) { + return true; + } + return super.select(viewer, parent, element); + } + }; + + CElementContentProvider provider = new CElementContentProvider(); + ILabelProvider labelProvider = new CElementLabelProvider(CElementLabelProvider.SHOW_DEFAULT); + ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog(getShell(), labelProvider, provider); + dialog.setValidator(validator); + dialog.setSorter(new CElementSorter()); + dialog.setTitle(NewClassWizardMessages.getString("NewClassCreationWizardPage.ChooseSourceFolderDialog.title")); //$NON-NLS-1$ + dialog.setMessage(NewClassWizardMessages.getString("NewClassCreationWizardPage.ChooseSourceFolderDialog.description")); //$NON-NLS-1$ + dialog.addFilter(filter); + dialog.setInput(CoreModel.create(fWorkspaceRoot)); + dialog.setInitialSelection(initElement); + + if (dialog.open() == Window.OK) { + Object element = dialog.getFirstResult(); + if (element instanceof ICProject) { + ICProject cproject = (ICProject)element; + return cproject.findSourceRoot(cproject.getProject()); + } else if (element instanceof ISourceRoot) { + return (ISourceRoot)element; + } + return null; + } + return null; + } + + ITypeInfo chooseNamespace() { + ITypeSearchScope scope = prepareTypeCache(); + if (scope == null) + return null; + + ITypeInfo[] elements = AllTypesCache.getNamespaces(scope, false); + if (elements == null || elements.length == 0) { + String title = NewClassWizardMessages.getString("NewClassCreationWizardPage.getClasses.noclasses.title"); //$NON-NLS-1$ + String message = NewClassWizardMessages.getString("NewClassCreationWizardPage.getClasses.noclasses.message"); //$NON-NLS-1$ + MessageDialog.openInformation(getShell(), title, message); + return null; + } + + NamespaceSelectionDialog dialog = new NamespaceSelectionDialog(getShell()); + dialog.setElements(elements); + int result = dialog.open(); + if (result == IDialogConstants.OK_ID) { + ITypeInfo namespace = (ITypeInfo) dialog.getFirstResult(); +/* if (namespace != null) { + // resolve location of namespace + if (namespace.getResolvedReference() == null) { + final ITypeInfo[] typesToResolve = new ITypeInfo[] { namespace }; + IRunnableWithProgress runnable = new IRunnableWithProgress() { + public void run(IProgressMonitor progressMonitor) throws InvocationTargetException, InterruptedException { + AllTypesCache.resolveTypeLocation(typesToResolve[0], progressMonitor); + if (progressMonitor.isCanceled()) { + throw new InterruptedException(); + } + } + }; + + try { + getContainer().run(true, true, runnable); + } catch (InvocationTargetException e) { + String title = NewClassWizardMessages.getString("NewClassCreationWizardPage.getClasses.exception.title"); //$NON-NLS-1$ + String message = NewClassWizardMessages.getString("NewClassCreationWizardPage.getClasses.exception.message"); //$NON-NLS-1$ + ExceptionHandler.handle(e, title, message); + return null; + } catch (InterruptedException e) { + // cancelled by user + return null; + } + } + } +*/ return namespace; + } + + return null; + } + + private final int[] ENCLOSING_CLASS_TYPES = { ICElement.C_CLASS }; + + ITypeInfo chooseEnclosingClass() { + ITypeSearchScope scope = prepareTypeCache(); + if (scope == null) + return null; + + ITypeInfo[] elements = AllTypesCache.getTypes(scope, ENCLOSING_CLASS_TYPES); + if (elements == null || elements.length == 0) { + String title = NewClassWizardMessages.getString("NewClassCreationWizardPage.getClasses.noclasses.title"); //$NON-NLS-1$ + String message = NewClassWizardMessages.getString("NewClassCreationWizardPage.getClasses.noclasses.message"); //$NON-NLS-1$ + MessageDialog.openInformation(getShell(), title, message); + return null; + } + + EnclosingClassSelectionDialog dialog = new EnclosingClassSelectionDialog(getShell()); + dialog.setElements(elements); + int result = dialog.open(); + if (result == IDialogConstants.OK_ID) { + ITypeInfo enclosingClass = (ITypeInfo) dialog.getFirstResult(); + if (enclosingClass != null) { + // resolve location of class + if (enclosingClass.getResolvedReference() == null) { + final ITypeInfo[] typesToResolve = new ITypeInfo[] { enclosingClass }; + IRunnableWithProgress runnable = new IRunnableWithProgress() { + public void run(IProgressMonitor progressMonitor) throws InvocationTargetException, InterruptedException { + AllTypesCache.resolveTypeLocation(typesToResolve[0], progressMonitor); + if (progressMonitor.isCanceled()) { + throw new InterruptedException(); + } + } + }; + + try { + getContainer().run(true, true, runnable); + } catch (InvocationTargetException e) { + String title = NewClassWizardMessages.getString("NewClassCreationWizardPage.getClasses.exception.title"); //$NON-NLS-1$ + String message = NewClassWizardMessages.getString("NewClassCreationWizardPage.getClasses.exception.message"); //$NON-NLS-1$ + ExceptionHandler.handle(e, title, message); + return null; + } catch (InterruptedException e) { + // cancelled by user + return null; + } + } + } + return enclosingClass; + } + + return null; + } + + private final int[] CLASS_TYPES = { ICElement.C_CLASS, ICElement.C_STRUCT }; + + void chooseBaseClasses() { + ITypeSearchScope scope = prepareTypeCache(); + if (scope == null) + return; + + ITypeInfo[] elements = AllTypesCache.getTypes(scope, CLASS_TYPES); + if (elements == null || elements.length == 0) { + String title = NewClassWizardMessages.getString("NewClassCreationWizardPage.getClasses.noclasses.title"); //$NON-NLS-1$ + String message = NewClassWizardMessages.getString("NewClassCreationWizardPage.getClasses.noclasses.message"); //$NON-NLS-1$ + MessageDialog.openInformation(getShell(), title, message); + return; + } + + List oldContents = fBaseClassesDialogField.getElements(); + NewBaseClassSelectionDialog dialog = new NewBaseClassSelectionDialog(getShell()); + dialog.addListener(new ITypeSelectionListener() { + public void typeAdded(ITypeInfo newBaseClass) { + addBaseClass(newBaseClass, ASTAccessVisibility.PUBLIC, false); + } + }); + dialog.setElements(elements); + int result = dialog.open(); + if (result != IDialogConstants.OK_ID) { + // restore the old contents + fBaseClassesDialogField.setElements(oldContents); + } + } + + // ---- creation ---------------- + + /** + * Creates the new class 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 cancelled. + */ + public void createClass(IProgressMonitor monitor) throws CoreException, InterruptedException { + IPath containerPath = fCurrentSourceFolder.getPath(); + IPath headerPath = containerPath.append(getHeaderFileName()); + IPath sourcePath = containerPath.append(getSourceFileName()); + + fCodeGenerator = new NewClassCodeGenerator( + headerPath, + sourcePath, + getClassName(), + getBaseClasses(), + getCheckedMethodStubs()); + fCodeGenerator.createClass(monitor); + } + + /** + * Returns the created type. The method only returns a valid type + * after createType has been called. + * + * @return the created type + * @see #createClass(IProgressMonitor) + */ + public ICElement getCreatedClass() { + if (fCodeGenerator != null) { + return fCodeGenerator.getCreatedClass(); + } + return null; + } + + public ITranslationUnit getCreatedHeaderTU(){ + if (fCodeGenerator != null) { + return fCodeGenerator.getCreatedHeaderTU(); + } + return null; + } + + public ITranslationUnit getCreatedSourceTU(){ + if (fCodeGenerator != null) { + return fCodeGenerator.getCreatedSourceTU(); + } + return null; + } +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/classwizard/NewClassWizardMessages.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/classwizard/NewClassWizardMessages.java new file mode 100644 index 00000000000..e223ac7eb05 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/classwizard/NewClassWizardMessages.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2004 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * QNX Software Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.internal.ui.wizards.classwizard; + + +import java.text.MessageFormat; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + + +public class NewClassWizardMessages { + + private static final String RESOURCE_BUNDLE= NewClassWizardMessages.class.getName(); + private static ResourceBundle fgResourceBundle; + static { + try { + fgResourceBundle = ResourceBundle.getBundle(RESOURCE_BUNDLE); + } catch (MissingResourceException x) { + fgResourceBundle = null; + } + } + + private NewClassWizardMessages() { + } + + public static String getString(String key) { + try { + return fgResourceBundle.getString(key); + } catch (MissingResourceException e) { + return '!' + key + '!'; + } catch (NullPointerException e) { + return "#" + key + "#"; //$NON-NLS-1$ //$NON-NLS-2$ + } + } + + /** + * Gets a string from the resource bundle and formats it with the argument + * + * @param key the string used to get the bundle value, must not be null + */ + public static String getFormattedString(String key, Object arg) { + return MessageFormat.format(getString(key), new Object[] { arg }); + } + + /** + * Gets a string from the resource bundle and formats it with arguments + */ + public static String getFormattedString(String key, Object[] args) { + return MessageFormat.format(getString(key), args); + } + +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/classwizard/NewClassWizardMessages.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/classwizard/NewClassWizardMessages.properties new file mode 100644 index 00000000000..63dd9098a1f --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/classwizard/NewClassWizardMessages.properties @@ -0,0 +1,116 @@ +############################################################################### +# Copyright (c) 2004 QNX Software Systems and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Common Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/cpl-v10.html +# +# Contributors: +# QNX Software Systems - Initial API and implementation +############################################################################### + +# ------- NewClassCreationWizard ------- +NewClassCreationWizard.title=New C++ Class + +# -----------NewClassCreationWizardPage ------------- +NewClassCreationWizardPage.title=C++ Class +NewClassCreationWizardPage.description=Create a new C++ class. +NewClassCreationWizardPage.error.SelectedProjectError=Error in determining the selected project. +NewClassCreationWizardPage.error.DefaultSourceFolderError=Error in determining the default source folder. +NewClassCreationWizardPage.error.NotAvailableForNonCppProjects= The wizard is not available for non C++ projects. + +NewClassCreationWizardPage.getClasses.exception.title=Exception +NewClassCreationWizardPage.getClasses.exception.message=Unexpected exception. See log for details. +NewClassCreationWizardPage.getClasses.noclasses.title=Class Selection +NewClassCreationWizardPage.getClasses.noclasses.message=No classes available. + +NewClassCreationWizardPage.sourceFolder.label=Source &Folder: +NewClassCreationWizardPage.sourceFolder.button=Br&owse... +NewClassCreationWizardPage.ChooseSourceFolderDialog.title=Folder Selection +NewClassCreationWizardPage.ChooseSourceFolderDialog.description=&Choose a folder: +NewClassCreationWizardPage.error.EnterSourceFolderName=Folder name is empty. +NewClassCreationWizardPage.error.SourceFolderDoesNotExist=Folder ''{0}'' does not exist. +NewClassCreationWizardPage.error.NotAFolder=''{0}'' must be a project or folder. +NewClassCreationWizardPage.error.ProjectClosed=Project ''{0}'' must be accessible. +NewClassCreationWizardPage.warning.NotACProject=Folder is not a C/C++ project. +NewClassCreationWizardPage.warning.NotInACProject=Folder is not in a C/C++ project. + +NewClassCreationWizardPage.namespace.label=Namespace: +NewClassCreationWizardPage.namespace.button=Bro&wse... + +NewClassCreationWizardPage.enclosingClass.label=&Enclosing Class: +NewClassCreationWizardPage.enclosingClass.button=Br&owse... + +NewClassCreationWizardPage.className.label=Class &Name: +NewClassCreationWizardPage.error.EnterClassName=Class name is empty. +NewClassCreationWizardPage.error.ClassNameExists=Class already exists. +NewClassCreationWizardPage.error.ClassNameExistsDifferentCase=Class with same name but different case exists. +NewClassCreationWizardPage.error.InvalidClassName=Class name is not valid. {0} +NewClassCreationWizardPage.error.QualifiedName=Class name must not be qualified. +NewClassCreationWizardPage.warning.ClassNameDiscouraged=Class name is discouraged. {0} + +NewClassCreationWizardPage.baseClasses.label=&Base Classes: +NewClassCreationWizardPage.error.InvalidBaseClassName=Base class name is not valid. + +NewClassCreationWizardPage.methodStubs.label=Method &Stubs: + +NewClassCreationWizardPage.classDefinition.label=Class &Definition: +NewClassCreationWizardPage.classDefinition.button=Br&owse... + +NewClassCreationWizardPage.classImplementation.button=Br&owse... +NewClassCreationWizardPage.classImplementation.label=Class &Implementation: + +# -----------BaseClassesListDialogField ------------- +BaseClassesListDialogField.buttons.add=&Add... +BaseClassesListDialogField.buttons.remove=&Remove +BaseClassesListDialogField.buttons.up=&Up +BaseClassesListDialogField.buttons.down=&Down +BaseClassesListDialogField.headings.name=Name +BaseClassesListDialogField.headings.access=Access +BaseClassesListDialogField.headings.virtual=Virtual + +# -----------BaseClassesLabelProvider ------------- +BaseClassesLabelProvider.boolean.yes.label=yes +BaseClassesLabelProvider.boolean.no.label=no +BaseClassesLabelProvider.access.public.label=public +BaseClassesLabelProvider.access.protected.label=protected +BaseClassesLabelProvider.access.private.label=private + +# -----------MethodStubsDialogField ------------- +MethodStubsDialogField.headings.name=Name +MethodStubsDialogField.headings.access=Access +MethodStubsDialogField.headings.virtual=Virtual +MethodStubsDialogField.headings.inline=Inline + +# ------- NamespaceSelectionDialog ----- +NamespaceSelectionDialog.title=Choose Namespace +NamespaceSelectionDialog.message=&Choose a namespace (? = any character, * = any string): +NamespaceSelectionDialog.filter= + +# ------- EnclosingClassSelectionDialog ----- +EnclosingClassSelectionDialog.title=Choose Enclosing Class +EnclosingClassSelectionDialog.message=&Choose a class (? = any character, * = any string): +EnclosingClassSelectionDialog.filter= + +# ------- NewBaseClassSelectionDialog ----- +NewBaseClassSelectionDialog.title=Choose Base Class +NewBaseClassSelectionDialog.message=&Choose a class (? = any character, * = any string): +NewBaseClassSelectionDialog.filter= +NewBaseClassSelectionDialog.access.label=Access +NewBaseClassSelectionDialog.virtual.label=Virtual +NewBaseClassSelectionDialog.addButton.label=&Add +NewBaseClassSelectionDialog.classadded.info=''{0}'' added. +NewBaseClassSelectionDialog.classalreadyadded.info=''{0}'' already added. +NewBaseClassSelectionDialog.addingclass.info=Adding ''{0}''... +NewBaseClassSelectionDialog.error.classnotadded=''{0}'' could not be added. +NewBaseClassSelectionDialog.getClasses.exception.title=Exception +NewBaseClassSelectionDialog.getClasses.exception.message=Unexpected exception. See log for details. +NewBaseClassSelectionDialog.getClasses.noclasses.title=Class Selection +NewBaseClassSelectionDialog.getClasses.noclasses.message=No classes available. + +# -----------NewClassCodeGeneration ------------- +NewClassCodeGeneration.createType.task=Creating type.... +NewClassCodeGeneration.createFile.task=Creating +NewClassCodeGeneration.stub.constructor.name=Constructor +NewClassCodeGeneration.stub.destructor.name=Destructor +NewClassCodeGeneration.includeGuard.suffix=_H diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/classwizard/NewSourceFileGenerator.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/classwizard/NewSourceFileGenerator.java new file mode 100644 index 00000000000..ff5c8403c0b --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/wizards/classwizard/NewSourceFileGenerator.java @@ -0,0 +1,150 @@ +/******************************************************************************* + * Copyright (c) 2004 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * QNX Software Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.internal.ui.wizards.classwizard; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +import org.eclipse.cdt.ui.CUIPlugin; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceStatus; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.core.runtime.SubProgressMonitor; +import org.eclipse.ui.dialogs.ContainerGenerator; + +public class NewSourceFileGenerator { + + private static final String HEADER_EXT = ".h"; //$NON-NLS-1$ + private static final String SOURCE_EXT = ".cpp"; //$NON-NLS-1$ + private static boolean fUseIncludeGuard = true; + private static final String fLineDelimiter = System.getProperty("line.separator", "\n"); //$NON-NLS-1$ //$NON-NLS-2$ + + public static String getLineDelimiter() { + //TODO line delimiter part of code template prefs? + return fLineDelimiter; + } + + public static String generateHeaderFileNameFromClass(String className) { + //TODO eventually make this a prefs option - filename pattern + return className + HEADER_EXT; + } + + public static String generateSourceFileNameFromClass(String className) { + //TODO eventually make this a prefs option - filename pattern + return className + SOURCE_EXT; + } + + public static IFile createHeaderFile(IPath filePath, boolean force, IProgressMonitor monitor) throws CoreException { + //TODO should use code templates + ByteArrayInputStream stream; + if (fUseIncludeGuard) { + String includeGuardSymbol = generateIncludeGuardSymbol(filePath); + StringBuffer buf = new StringBuffer(); + buf.append("#ifndef "); //$NON-NLS-1$ + buf.append(includeGuardSymbol); + buf.append(fLineDelimiter); + buf.append("#define "); //$NON-NLS-1$ + buf.append(includeGuardSymbol); + buf.append(fLineDelimiter); + buf.append(fLineDelimiter); + buf.append("#endif //"); //$NON-NLS-1$ + buf.append(includeGuardSymbol); + buf.append(fLineDelimiter); + stream = new ByteArrayInputStream(buf.toString().getBytes()); + } else { + stream = new ByteArrayInputStream(new byte[0]); + } + return createNewFile(filePath, stream, force, monitor); + } + + private static String generateIncludeGuardSymbol(IPath headerPath) { + //TODO eventually make this a prefs option - filename pattern or + // unique id/incremental value + String name = headerPath.lastSegment(); + if (name != null) { + //convert to upper case and remove invalid characters + //eg convert foo.h --> _FOO_H_ + StringBuffer buf = new StringBuffer(); + buf.append('_'); + for (int i = 0; i < name.length(); ++i) { + char ch = name.charAt(i); + if (Character.isLetterOrDigit(ch)) { + buf.append(Character.toUpperCase(ch)); + } else if (ch == '.' || ch == '_') { + buf.append('_'); + } + } + buf.append('_'); + return buf.toString(); + } + return null; + } + + public static IFile createSourceFile(IPath filePath, boolean useIncludeGuard, boolean force, IProgressMonitor monitor) throws CoreException { + //TODO should use code templates + ByteArrayInputStream stream = new ByteArrayInputStream(new byte[0]); + return createNewFile(filePath, stream, force, monitor); + } + + private static IFile createNewFile(IPath newFilePath, InputStream contents, boolean force, IProgressMonitor monitor) throws CoreException { + int totalWork = 100; + int createFileWork = totalWork; + + monitor.beginTask(NewClassWizardMessages.getString("NewClassCodeGeneration.createFile.task"), totalWork); //$NON-NLS-1$ + + IWorkspaceRoot root = CUIPlugin.getWorkspace().getRoot(); + IFile newFile = root.getFileForLocation(newFilePath); + if (newFile == null) + newFile = root.getFile(newFilePath); + if (newFile.exists()) { + monitor.done(); + return newFile; + } + + if (newFilePath.segmentCount() > 1) { + IPath containerPath = newFilePath.removeLastSegments(1); + if (root.getContainerForLocation(containerPath) == null) { + int containerWork = totalWork / 2; + createFileWork = totalWork / 2; + ContainerGenerator generator = new ContainerGenerator(containerPath); + generator.generateContainer(new SubProgressMonitor(monitor, containerWork)); + } + } + + createFile(newFile, contents, force, new SubProgressMonitor(monitor, createFileWork)); + monitor.done(); + + return newFile; + } + + private static void createFile(IFile fileHandle, InputStream contents, boolean force, IProgressMonitor monitor) throws CoreException { + if (contents == null) + contents = new ByteArrayInputStream(new byte[0]); + + try { + fileHandle.create(contents, force, monitor); + } catch (CoreException e) { + // If the file already existed locally, just refresh to get contents + if (e.getStatus().getCode() == IResourceStatus.PATH_OCCUPIED) + fileHandle.refreshLocal(IResource.DEPTH_ZERO, null); + else + throw e; + } + + if (monitor.isCanceled()) + throw new OperationCanceledException(); + } +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/wizards/NewClassCreationWizard.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/wizards/NewClassCreationWizard.java new file mode 100644 index 00000000000..147db7454d6 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/wizards/NewClassCreationWizard.java @@ -0,0 +1,93 @@ +/******************************************************************************* + * Copyright (c) 2004 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * QNX Software Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.ui.wizards; + +import org.eclipse.cdt.core.model.ITranslationUnit; +import org.eclipse.cdt.internal.ui.CPluginImages; +import org.eclipse.cdt.internal.ui.wizards.NewElementWizard; +import org.eclipse.cdt.internal.ui.wizards.classwizard.NewClassCreationWizardPage; +import org.eclipse.cdt.internal.ui.wizards.classwizard.NewClassWizardMessages; +import org.eclipse.cdt.ui.CUIPlugin; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; + +public class NewClassCreationWizard extends NewElementWizard { + + private NewClassCreationWizardPage fPage; + + public NewClassCreationWizard() { + super(); + setDefaultPageImageDescriptor(CPluginImages.DESC_WIZBAN_NEWCLASS); + setDialogSettings(CUIPlugin.getDefault().getDialogSettings()); + setWindowTitle(NewClassWizardMessages.getString("NewClassCreationWizard.title")); //$NON-NLS-1$ + } + + /* + * @see Wizard#createPages + */ + public void addPages() { + super.addPages(); + fPage = new NewClassCreationWizardPage(); + addPage(fPage); + fPage.init(getSelection()); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.cdt.internal.ui.wizards.NewElementWizard#canRunForked() + */ + protected boolean canRunForked() { + return !fPage.isEnclosingClassSelected(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.cdt.internal.ui.wizards.NewElementWizard#finishPage(org.eclipse.core.runtime.IProgressMonitor) + */ + protected void finishPage(IProgressMonitor monitor) throws InterruptedException, CoreException { + fPage.createClass(monitor); // use the full progress monitor + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.wizard.IWizard#performFinish() + */ + public boolean performFinish() { + boolean res = super.performFinish(); + if (res) { + //TODO need prefs option for opening editor + boolean openInEditor = true; + + ITranslationUnit bodyTU = fPage.getCreatedSourceTU(); + if (bodyTU != null) { + IResource resource= bodyTU.getResource(); + selectAndReveal(resource); + if (openInEditor) { + openResource((IFile) resource); + } + } + ITranslationUnit headerTU = fPage.getCreatedHeaderTU(); + if (headerTU != null) { + IResource resource = headerTU.getResource(); + selectAndReveal(resource); + if (openInEditor) { + openResource((IFile) resource); + } + } + } + return res; + } +}