/******************************************************************************* * Copyright (c) 2007, 2008 Edgar Espina. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * *******************************************************************************/ package org.deved.antlride.internal.ui.wizards; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.text.MessageFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.deved.antlride.core.AntlrConstants; import org.deved.antlride.core.AntlrCore; import org.deved.antlride.core.AntlrLanguageTargetName; import org.deved.antlride.core.build.AntlrBuildUnit; import org.deved.antlride.core.model.GrammarType; import org.deved.antlride.core.resources.AntlrResourceFinder; import org.deved.antlride.core.util.AntlrTextHelper; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceVisitor; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; 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.dltk.ui.DLTKUIPlugin; import org.eclipse.dltk.ui.dialogs.StatusInfo; import org.eclipse.jface.dialogs.IMessageProvider; import org.eclipse.jface.window.Window; import org.eclipse.jface.wizard.WizardPage; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; import org.eclipse.swt.widgets.Widget; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.PartInitException; import org.eclipse.ui.dialogs.ContainerSelectionDialog; import org.eclipse.ui.ide.IDE; public abstract class AntlrGrammarPage extends WizardPage { private static final String PROTOTYPE = "prototype"; private class ValidationListener implements ModifyListener { public void modifyText(ModifyEvent e) { validate(getFolder(), getGrammarName(), getLanguage(), getTokenVocab()); } } private class TokenVocabSelectionListener implements SelectionListener { public void widgetSelected(SelectionEvent e) { AntlrTokenVocabSelectionDialog dialog = new AntlrTokenVocabSelectionDialog( getShell()); // dialog.addFilter(filter); IContainer container = ResourcesPlugin.getWorkspace().getRoot(); // getProject(getFolder()); final List<IResource> resources = new ArrayList<IResource>(); try { container.accept(new IResourceVisitor() { public boolean visit(IResource resource) throws CoreException { if (AntlrConstants.ANTLR_GRAMMAR_FILE_EXTENSION .equals(resource.getFileExtension())) { GrammarType grammarType = AntlrResourceFinder .getGrammarType(resource); if (grammarType == GrammarType.COMBINED || grammarType == GrammarType.PARSER || grammarType == GrammarType.LEXER) { resources.add(resource); } } return true; } }); } catch (CoreException ex) { AntlrCore.error(ex); } dialog.setElements(resources); if (dialog.open() == Window.OK) { Object selection = dialog.getFirstResult(); if (selection != null) { tokenVocabText .setText(resourceToString(((IFile) selection))); } } } public void widgetDefaultSelected(SelectionEvent e) { } } private class ProperyChangeListener implements SelectionListener { public void widgetDefaultSelected(SelectionEvent e) { } public void widgetSelected(SelectionEvent e) { Widget widget = e.widget; String property = (String) widget.getData(PROPERTY_NAME); String value = (String) widget.getData(property); if ((widget.getStyle() & SWT.CHECK) == SWT.CHECK) { value = "" + !Boolean.valueOf(value).booleanValue(); widget.setData(property, value); } setProperty(property, value); } } private class ChooseFolderListener implements SelectionListener { public void widgetSelected(SelectionEvent e) { ContainerSelectionDialog dialog = new ContainerSelectionDialog( getShell(), folder, true, "Select a grammar container: "); if (dialog.open() == Window.OK) { Object[] selection = dialog.getResult(); if (selection != null && selection.length > 0) { IPath path = (IPath) selection[0]; folderText.setText(resourceToString(path)); } } } public void widgetDefaultSelected(SelectionEvent e) { } } protected static final String FILE_PATH = "path"; protected static final String LANGUAGE = "language"; protected static final String GRAMMAR_NAME = "name"; private static final String PROPERTY_NAME = "keyName"; protected static final String OUTPUT = "output"; private Map<String, String> properties; private Text folderText; private IContainer folder; private Text nameText; private Combo languageCombo; private Text tokenVocabText; private Button tokenVocabButton; public AntlrGrammarPage(String pageName) { super(pageName); properties = new HashMap<String, String>(); setTitle(getPageTitle()); setDescription(getPageDescription()); } protected String getProperty(String property) { return properties.get(property); } protected void setProperty(String property, String value) { properties.put(property, value); } protected abstract String getPageDescription(); protected abstract String getPageTitle(); public void createControl(Composite parent) { initializeDialogUnits(parent); Composite composite = new Composite(parent, SWT.NONE); GridLayout gridLayout = new GridLayout(3, false); gridLayout.verticalSpacing = 10; composite.setLayout(gridLayout); Label label = null; GridData gd = null; ValidationListener validator = new ValidationListener(); label = new Label(composite, SWT.NONE); label.setText("Container:"); folderText = new Text(composite, SWT.BORDER); folderText.setText(resourceToString(folder)); folderText.addModifyListener(validator); gd = new GridData(GridData.FILL_HORIZONTAL); folderText.setLayoutData(gd); Button browse = new Button(composite, SWT.PUSH); browse.addSelectionListener(new ChooseFolderListener()); browse.setText(" Browse... "); label = new Label(composite, SWT.NONE); label.setText("Name:"); nameText = new Text(composite, SWT.BORDER); nameText.addModifyListener(validator); gd = new GridData(GridData.FILL_HORIZONTAL); gd.horizontalSpan = 2; nameText.setLayoutData(gd); label = new Label(composite, SWT.SEPARATOR | SWT.HORIZONTAL); gd = new GridData(GridData.FILL_HORIZONTAL); gd.horizontalSpan = 3; label.setLayoutData(gd); if (hasOutputSection()) { createOutputSection(composite); } // language section label = new Label(composite, SWT.NONE); label.setText("Language:"); Composite langSection = new Composite(composite, SWT.NONE); langSection.setLayout(new GridLayout(3, true)); gd = new GridData(GridData.FILL_HORIZONTAL); gd.horizontalSpan = 2; langSection.setLayoutData(gd); String[] languages = AntlrLanguageTargetName.names(); languageCombo = (Combo) addComboBox(langSection, "Language:", LANGUAGE, languages, languages, AntlrLanguageTargetName.Java.ordinal())[0]; languageCombo.addModifyListener(validator); // Dependent section if (hasDependentSection()) { label = new Label(composite, SWT.NONE); label.setText("Dependent:"); Button dependentButton = addCheckButton(composite, PROTOTYPE, "false", false); gd = new GridData(GridData.FILL_HORIZONTAL); gd.horizontalSpan = 2; dependentButton.setLayoutData(gd); } if (hasTokenVocabSection()) { createTokenVocabSection(composite); } setControl(composite); validate(getFolder(), getGrammarName(), getLanguage(), getTokenVocab()); if (getFolder().length() > 0) { Display.getDefault().asyncExec(new Runnable() { public void run() { nameText.setFocus(); } }); } } protected boolean hasOutputSection() { return false; } protected void createTokenVocabSection(Composite composite) { Label label; GridData gd; label = new Label(composite, SWT.NONE); label.setText("Token Vocabulary:"); tokenVocabText = new Text(composite, SWT.BORDER); tokenVocabText.addModifyListener(new ValidationListener()); gd = new GridData(GridData.FILL_HORIZONTAL); tokenVocabText.setLayoutData(gd); tokenVocabButton = new Button(composite, SWT.PUSH); tokenVocabButton .addSelectionListener(new TokenVocabSelectionListener()); tokenVocabButton.setText(" Browse... "); } protected void createOutputSection(Composite composite) { Label label = new Label(composite, SWT.NONE); label.setText("Output:"); Composite outputSection = new Composite(composite, SWT.NONE); outputSection.setLayout(new GridLayout(3, true)); GridData gd = new GridData(GridData.FILL_HORIZONTAL); gd.horizontalSpan = 2; outputSection.setLayoutData(gd); addRadioButton(outputSection, AntlrWizardMessages.NewGrammarFilePage_NoneOutput, OUTPUT, null, true); addRadioButton(outputSection, AntlrWizardMessages.NewGrammarFilePage_ASTOutput, OUTPUT, "AST", false);//$NON-NLS-1$ addRadioButton(outputSection, AntlrWizardMessages.NewGrammarFilePage_TemplateOutput, OUTPUT, "template", false);//$NON-NLS-1$ } protected Control[] addComboBox(Composite parent, String label, String key, String[] items, String[] values, int selected) { GridData gd = null; Combo combo = new Combo(parent, SWT.SINGLE); gd = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING); combo.setFont(parent.getFont()); combo.setItems(items); combo.setLayoutData(gd); combo.select(selected); return new Control[] { combo }; } protected Button addCheckButton(Composite parent, String key, String value, boolean selected) { Button checkbox = new Button(parent, SWT.CHECK); checkbox.setData(key, value); checkbox.setData(PROPERTY_NAME, key); checkbox.setSelection(selected); checkbox.addSelectionListener(new ProperyChangeListener()); return checkbox; } protected Button addRadioButton(Composite parent, String label, String key, String value, boolean selected) { Button radio = new Button(parent, SWT.RADIO); radio.setData(key, value); radio.setData(PROPERTY_NAME, key); radio.setSelection(selected); radio.setText(label); radio.addSelectionListener(new ProperyChangeListener()); return radio; } protected Composite createSubsection(Composite parent, String label, int align) { Group group = new Group(parent, SWT.SHADOW_NONE); group.setLayout(new FillLayout(align)); group.setText(label); if (parent.getLayout() instanceof GridLayout) { GridData data = new GridData(SWT.FILL, SWT.CENTER, true, false); data.horizontalSpan = 3; group.setLayoutData(data); } return group; } public void init(IResource resource) { folder = null; if (resource != null) { if (resource instanceof IContainer) { folder = (IContainer) resource; } else { folder = resource.getParent(); } } } protected void updateStatus(IStatus status) { setPageComplete(status.isOK()); int severity = status.getSeverity(); if (severity == IStatus.OK) { setMessage(status.getMessage(), IMessageProvider.NONE); setErrorMessage(null); } else { setMessage(null); setErrorMessage(status.getMessage()); } } protected void validate(String folder, String name, String language, String tokenVocab) { enableTokenVocab(false); IStatus status = validateFolder(folder); if (status != null) { updateStatus(status); return; } status = validateGrammar(folder, name); if (status != null) { updateStatus(status); return; } status = validateLanguage(getLanguage()); if (status != null) { updateStatus(status); return; } boolean dependent = Boolean.valueOf(getProperty(PROTOTYPE)) .booleanValue(); if (!dependent) { enableTokenVocab(true); status = validateTokenVocab(tokenVocab); if (status != null) { updateStatus(status); return; } } updateStatus(new StatusInfo(StatusInfo.OK, getPageDescription())); } private void enableTokenVocab(boolean enabled) { if (hasTokenVocabSection()) { tokenVocabButton.setEnabled(enabled); tokenVocabText.setEditable(enabled); } } protected boolean hasTokenVocabSection() { return false; } protected IStatus validateTokenVocab(String tokenVocab) { if (hasTokenVocabSection()) { if (tokenVocab == null || tokenVocab.length() == 0) { return createErrorStatus("Token Vocabulary is empty"); } IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); IFile tokenVocabFile = root.getFile(new Path(tokenVocab)); if (tokenVocabFile == null || !tokenVocabFile.exists()) { return createErrorStatus("Token Vocabulary does not exist"); } } return null; } protected IStatus validateFolder(String folder) { if (folder == null || folder.length() == 0) { return createErrorStatus("Container is empty"); } IContainer container = getContainer(folder); if (container == null || !container.exists()) { return createErrorStatus("Container does not exist"); } return null; } protected IStatus validateLanguage(String language) { if (language == null || language.length() == 0) { return createErrorStatus("Language is empty"); } return null; } private String getLanguage() { return languageCombo.getText(); } private IContainer getContainer(String path) { IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); IPath containerPath = new Path(path); if (containerPath.segmentCount() == 1) { // is a project String projectName = containerPath.lastSegment(); return root.getProject(projectName); } return root.getFolder(containerPath); } protected IStatus validateGrammar(String folder, String name) { if (name == null || name.length() == 0) { return createErrorStatus(AntlrWizardMessages.NewGrammarFilePage_Error_EmptyGrammarName); } else { if (!AntlrTextHelper.isGrammarName(name)) { return createErrorStatus(MessageFormat .format( AntlrWizardMessages.NewGrammarFilePage_Error_InvalidGrammarName, name)); } IPath path = new Path(folder).append(name).addFileExtension("g"); IWorkspaceRoot ws = ResourcesPlugin.getWorkspace().getRoot(); IFile file = ws.getFile(path); if (file.exists()) { return createErrorStatus(MessageFormat .format( AntlrWizardMessages.NewGrammarFilePage_Error_GrammarAlreadyExist, name)); } } return null; } protected IStatus createErrorStatus(String message) { StatusInfo status = new StatusInfo(StatusInfo.ERROR, message); return status; } private String getFolder() { return folderText.getText(); } private String getTokenVocab() { if (hasTokenVocabSection()) return tokenVocabText.getText(); return null; } private String getGrammarName() { return nameText.getText(); } protected String resourceToString(IResource resource) { if (resource == null) { return ""; } return resourceToString(resource.getFullPath()); } protected String resourceToString(IPath fullpath) { if (fullpath == null) { return ""; } return fullpath.makeRelative().toString(); } public final IFile createGrammar(IProgressMonitor monitor) { InputStream contents = null; try { IContainer folder = getContainer(getFolder()); IFile file = folder .getFile(new Path(getGrammarName()) .addFileExtension(AntlrConstants.ANTLR_GRAMMAR_FILE_EXTENSION)); // set all options setProperty(GRAMMAR_NAME, getGrammarName()); setProperty(AntlrConstants.ANTLR_GRAMMAR_TYPE, getGrammarType()); setProperty(LANGUAGE, getLanguage()); setProperty(FILE_PATH, file.getFullPath().toString()); setProperty("tokenVocab", getTokenVocab()); contents = new ByteArrayInputStream(getContents().getBytes()); file.create(contents, IResource.FORCE, monitor); file.setPersistentProperty(AntlrConstants.Q_ANTLR_GRAMMAR_TYPE, getGrammarType()); fileCreated(file); return file; } catch (CoreException ex) { AntlrCore.error(ex); } finally { if (contents != null) { try { contents.close(); } catch (IOException ex) { ex.printStackTrace(); } } } return null; } protected abstract String getGrammarType(); protected void fileCreated(IFile file) throws CoreException { if (hasDependentSection()) { String prototype = Boolean.valueOf(getProperty(PROTOTYPE)) .toString(); file.setPersistentProperty(AntlrBuildUnit.DEPENDENT_GRAMMAR, prototype); } } protected boolean hasDependentSection() { return true; } public void openGrammar(final IFile resource) { final IWorkbenchPage activePage = DLTKUIPlugin.getActivePage(); if (activePage != null) { final Display display = getShell().getDisplay(); if (display != null) { display.syncExec(new Runnable() { public void run() { try { IDE.openEditor(activePage, resource, true); } catch (PartInitException e) { DLTKUIPlugin.log(e); } } }); } } } protected abstract String getContents(); }