diff options
373 files changed, 60632 insertions, 0 deletions
diff --git a/bundles/org.eclipse.wst.xml.core/.classpath b/bundles/org.eclipse.wst.xml.core/.classpath new file mode 100644 index 0000000000..df094ee4a7 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/.classpath @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" path="src"/> + <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/bundles/org.eclipse.wst.xml.core/.compatibility b/bundles/org.eclipse.wst.xml.core/.compatibility new file mode 100644 index 0000000000..750d7ddfe6 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/.compatibility @@ -0,0 +1,2 @@ +#Wed Mar 24 13:53:52 EST 2004
+.project=12259
diff --git a/bundles/org.eclipse.wst.xml.core/.cvsignore b/bundles/org.eclipse.wst.xml.core/.cvsignore new file mode 100644 index 0000000000..e19f198e8f --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/.cvsignore @@ -0,0 +1,7 @@ +bin +temp.folder +xmlmodel.jar +.project +org.eclipse.wst.xml.core_6.0.0.jar +dev.properties +build.xml diff --git a/bundles/org.eclipse.wst.xml.core/.options b/bundles/org.eclipse.wst.xml.core/.options new file mode 100644 index 0000000000..e80df84bc6 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/.options @@ -0,0 +1,2 @@ +org.eclipse.wst.xml.core/debug=true +org.eclipse.wst.xml.core/debug/tracefilter= diff --git a/bundles/org.eclipse.wst.xml.core/build.properties b/bundles/org.eclipse.wst.xml.core/build.properties new file mode 100644 index 0000000000..8441d64567 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/build.properties @@ -0,0 +1,24 @@ +############################################################################### +# Copyright (c) 2001, 2004 IBM Corporation and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# IBM Corporation - initial API and implementation +# Jens Lukowski/Innoopract - initial renaming/restructuring +# +############################################################################### +bin.includes = plugin.xml,\ + *.jar,\ + xml.jar,\ + .options,\ + extensions.xml,\ + plugin.properties +src.includes = plugin.xml,\ + plugin.properties,\ + extensions.xml,\ + build.xml,\ + .options +source.xmlmodel.jar = src/ diff --git a/bundles/org.eclipse.wst.xml.core/plugin.properties b/bundles/org.eclipse.wst.xml.core/plugin.properties new file mode 100644 index 0000000000..6f5d373732 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/plugin.properties @@ -0,0 +1,14 @@ +############################################################################### +# Copyright (c) 2001, 2004 IBM Corporation and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# IBM Corporation - initial API and implementation +# Jens Lukowski/Innoopract - initial renaming/restructuring +# +############################################################################### +Structured_Source_XML_Model.name=Structured Source XML Model +Structured_Source_XML_Model_NL_Support.name=Structured Source XML Model NL Support diff --git a/bundles/org.eclipse.wst.xml.core/plugin.xml b/bundles/org.eclipse.wst.xml.core/plugin.xml new file mode 100644 index 0000000000..f172ba456c --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/plugin.xml @@ -0,0 +1,116 @@ +<?xml version="1.0" encoding="UTF-8"?> +<?eclipse version="3.0"?> +<plugin + id="org.eclipse.wst.xml.core" + name="%Structured_Source_XML_Model.name" + version="1.0.0" + provider-name="IBM" + class="org.eclipse.wst.xml.core.XMLModelPlugin"> + + <runtime> + <library name="xmlmodel.jar"> + <export name="*"/> + </library> + </runtime> + <requires> + <import plugin="org.eclipse.core.runtime.compatibility"/> + <import plugin="org.eclipse.wst.common.encoding"/> + <import plugin="org.eclipse.wst.sse.core"/> + <import plugin="org.eclipse.wst.common.contentmodel"/> + <import plugin="org.eclipse.core.resources"/> + <import plugin="org.eclipse.core.runtime"/> + <import plugin="org.eclipse.core.filebuffers"/> + <import plugin="org.eclipse.text"/> + <import plugin="org.eclipse.wst.xml.uriresolver.ui"/> + <import plugin="org.eclipse.wst.xml.uriresolver"/> + </requires> + + + <extension + point="org.eclipse.wst.sse.core.modelHandler"> + <modelHandler + default="true" + class="org.eclipse.wst.xml.core.modelhandler.ModelHandlerForXML" + associatedContentTypeId="org.eclipse.core.runtime.xml" + id="org.eclipse.wst.sse.core.handler.xml"> + </modelHandler> + </extension> + <extension + point="org.eclipse.wst.sse.core.embeddedTypeHandler"> + <embeddedTypeHandler + class="org.eclipse.wst.xml.core.modelhandler.EmbeddedXML"> + </embeddedTypeHandler> + </extension> + + <extension + id="org.eclipse.wst.xml.core.builderdelegate.todo" + point="org.eclipse.wst.sse.core.builderdelegate"> + <participant + class="org.eclipse.wst.xml.core.builder.delegates.XMLTaskTagSeeker" + contentType="org.eclipse.core.runtime.xml,org.eclipse.wst.xml.core.xmlsource"> + </participant> + </extension> + + <extension point="org.eclipse.core.filebuffers.documentCreation" + id="org.eclipse.wst.xml.core.documentfactories" + name="Structured XML Document Factory"> + <factory + contentTypeId="org.eclipse.core.runtime.xml" + class="org.eclipse.wst.sse.core.filebuffers.BasicStructuredDocumentFactory:org.eclipse.core.runtime.xml"/> + </extension> + + <extension + point="org.eclipse.team.core.fileTypes"> + <fileTypes + type="text" + extension="xsl"> + </fileTypes> + <fileTypes + type="text" + extension="xslt"> + </fileTypes> + <fileTypes + type="text" + extension="dadx"> + </fileTypes> + <fileTypes + type="text" + extension="wsdl"> + </fileTypes> + <fileTypes + type="text" + extension="nst"> + </fileTypes> + <fileTypes + type="text" + extension="xmi"> + </fileTypes> + <fileTypes + type="text" + extension="xsd"> + </fileTypes> + </extension> + <extension + point="org.eclipse.wst.sse.core.formatProcessors"> + <processor + class="org.eclipse.wst.xml.core.format.FormatProcessorXML" + contentTypeId="org.eclipse.core.runtime.xml"> + </processor> + </extension> + + <extension + point="org.eclipse.core.runtime.contentTypes"> + <content-type + priority="high" + name="XML Content Type" + id="xmlsource" + base-type="org.eclipse.core.runtime.xml" + default-charset="UTF-8"> + <describer class="org.eclipse.wst.xml.core.contenttype.ContentDescriberForXML"/> + </content-type> + <file-association + content-type="org.eclipse.core.runtime.xml" + file-extensions="xsl,xslt,dadx,wsdl,nst,xmi,xsd,exsd"/> + </extension> + +</plugin> diff --git a/bundles/org.eclipse.wst.xml.core/src/.cvsignore b/bundles/org.eclipse.wst.xml.core/src/.cvsignore new file mode 100644 index 0000000000..101c29e19d --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/.cvsignore @@ -0,0 +1 @@ +notebook.jpage diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/Logger.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/Logger.java new file mode 100644 index 0000000000..0e727bc4b3 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/Logger.java @@ -0,0 +1,153 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core; + +import java.util.StringTokenizer; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Plugin; +import org.eclipse.core.runtime.Status; + +/** + * Small convenience class to log messages to plugin's log file and also, if + * desired, the console. This class should only be used by classes in this + * plugin. Other plugins should make their own copy, with appropriate ID. + */ +public class Logger { + public static final int ERROR = IStatus.ERROR; // 4 + public static final int ERROR_DEBUG = 200 + ERROR; + private static Plugin fPlugin = XMLModelPlugin.getDefault(); + private static final String fPluginId = fPlugin.getDescriptor().getUniqueIdentifier(); + public static final int INFO = IStatus.INFO; // 1 + public static final int INFO_DEBUG = 200 + INFO; + + public static final int OK = IStatus.OK; // 0 + + public static final int OK_DEBUG = 200 + OK; + + private static final String TRACEFILTER_LOCATION = "/debug/tracefilter"; //$NON-NLS-1$ + public static final int WARNING = IStatus.WARNING; // 2 + public static final int WARNING_DEBUG = 200 + WARNING; + + /** + * Adds message to log. + * + * @param level + * severity level of the message (OK, INFO, WARNING, ERROR, + * OK_DEBUG, INFO_DEBUG, WARNING_DEBUG, ERROR_DEBUG) + * @param message + * text to add to the log + * @param exception + * exception thrown + */ + protected static void _log(int level, String message, Throwable exception) { + if (level == OK_DEBUG || level == INFO_DEBUG || level == WARNING_DEBUG || level == ERROR_DEBUG) { + if (!isDebugging()) + return; + } + + int severity = IStatus.OK; + switch (level) { + case INFO_DEBUG : + case INFO : + severity = IStatus.INFO; + break; + case WARNING_DEBUG : + case WARNING : + severity = IStatus.WARNING; + break; + case ERROR_DEBUG : + case ERROR : + severity = IStatus.ERROR; + } + message = (message != null) ? message : "null"; //$NON-NLS-1$ + Status statusObj = new Status(severity, fPluginId, severity, message, exception); + fPlugin.getLog().log(statusObj); + } + + /** + * Prints message to log if category matches /debug/tracefilter option. + * + * @param message + * text to print + * @param category + * category of the message, to be compared with + * /debug/tracefilter + */ + protected static void _trace(String category, String message, Throwable exception) { + if (isTracing(category)) { + message = (message != null) ? message : "null"; //$NON-NLS-1$ + Status statusObj = new Status(IStatus.OK, fPluginId, IStatus.OK, message, exception); + fPlugin.getLog().log(statusObj); + } + } + + /** + * @return true if the plugin for this logger is debugging + */ + public static boolean isDebugging() { + return fPlugin.isDebugging(); + } + + /** + * Determines if currently tracing a category + * + * @param category + * @return true if tracing category, false otherwise + */ + public static boolean isTracing(String category) { + if (!isDebugging()) + return false; + + String traceFilter = Platform.getDebugOption(fPluginId + TRACEFILTER_LOCATION); + if (traceFilter != null) { + StringTokenizer tokenizer = new StringTokenizer(traceFilter, ","); //$NON-NLS-1$ + while (tokenizer.hasMoreTokens()) { + String cat = tokenizer.nextToken().trim(); + if (category.equals(cat)) { + return true; + } + } + } + return false; + } + + public static void log(int level, String message) { + _log(level, message, null); + } + + public static void log(int level, String message, Throwable exception) { + _log(level, message, exception); + } + + public static void logException(String message, Throwable exception) { + _log(ERROR, message, exception); + } + + public static void logException(Throwable exception) { + _log(ERROR, exception.getMessage(), exception); + } + + public static void trace(String category, String message) { + _trace(category, message, null); + } + + public static void traceException(String category, String message, Throwable exception) { + _trace(category, message, exception); + } + + public static void traceException(String category, Throwable exception) { + _trace(category, exception.getMessage(), exception); + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/NameValidator.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/NameValidator.java new file mode 100644 index 0000000000..a0d564be80 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/NameValidator.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core; + +import java.io.Reader; + +import org.eclipse.wst.xml.core.internal.parser.XML10Names; + + + +public final class NameValidator { + + private static XML10Names charChecker = new XML10Names((Reader) null); + + public synchronized static final boolean isValid(String name) { + + return charChecker.isValidXML10Name(name); + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/XMLModelPlugin.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/XMLModelPlugin.java new file mode 100644 index 0000000000..c531d0baf7 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/XMLModelPlugin.java @@ -0,0 +1,118 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core; + +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +import org.eclipse.core.resources.IWorkspace; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.IPluginDescriptor; +import org.eclipse.core.runtime.Plugin; +import org.eclipse.core.runtime.Preferences; +import org.eclipse.wst.common.encoding.CommonEncodingPreferenceNames; +import org.eclipse.wst.sse.core.preferences.CommonModelPreferenceNames; + + +/** + * The main plugin class to be used in the desktop. + */ +public class XMLModelPlugin extends Plugin { + //The shared instance. + private static XMLModelPlugin plugin; + + /** + * Returns the shared instance. + */ + public static XMLModelPlugin getDefault() { + return plugin; + } + + /** + * Returns the string from the plugin's resource bundle, or 'key' if not + * found. + */ + public static String getResourceString(String key) { + ResourceBundle bundle = XMLModelPlugin.getDefault().getResourceBundle(); + try { + return bundle.getString(key); + } catch (MissingResourceException e) { + return key; + } + } + + /** + * Returns the workspace instance. + */ + public static IWorkspace getWorkspace() { + return ResourcesPlugin.getWorkspace(); + } + + //Resource bundle. + private ResourceBundle resourceBundle; + + /** + * The constructor. + */ + public XMLModelPlugin(IPluginDescriptor descriptor) { + super(descriptor); + plugin = this; + try { + resourceBundle = ResourceBundle.getBundle("org.eclipse.wst.xml.core.XmlPluginResources"); //$NON-NLS-1$ + } catch (MissingResourceException x) { + resourceBundle = null; + } + } + + /** + * Returns the plugin's resource bundle, + */ + public ResourceBundle getResourceBundle() { + return resourceBundle; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.Plugin#initializeDefaultPluginPreferences() + */ + protected void initializeDefaultPluginPreferences() { + super.initializeDefaultPluginPreferences(); + Preferences prefs = getDefault().getPluginPreferences(); + // set model preference defaults + prefs.setDefault(CommonModelPreferenceNames.CLEANUP_TAG_NAME_CASE, CommonModelPreferenceNames.ASIS); + prefs.setDefault(CommonModelPreferenceNames.CLEANUP_ATTR_NAME_CASE, CommonModelPreferenceNames.ASIS); + prefs.setDefault(CommonModelPreferenceNames.COMPRESS_EMPTY_ELEMENT_TAGS, true); + prefs.setDefault(CommonModelPreferenceNames.INSERT_REQUIRED_ATTRS, true); + prefs.setDefault(CommonModelPreferenceNames.INSERT_MISSING_TAGS, true); + prefs.setDefault(CommonModelPreferenceNames.QUOTE_ATTR_VALUES, true); + prefs.setDefault(CommonModelPreferenceNames.FORMAT_SOURCE, true); + prefs.setDefault(CommonModelPreferenceNames.CONVERT_EOL_CODES, false); + + prefs.setDefault(CommonEncodingPreferenceNames.INPUT_CODESET, ""); //$NON-NLS-1$ + prefs.setDefault(CommonEncodingPreferenceNames.OUTPUT_CODESET, CommonModelPreferenceNames.UTF_8); + prefs.setDefault(CommonEncodingPreferenceNames.END_OF_LINE_CODE, ""); //$NON-NLS-1$ + + prefs.setDefault(CommonModelPreferenceNames.TAB_WIDTH, 4); + + prefs.setDefault(CommonModelPreferenceNames.FORMATTING_SUPPORTED, true); + prefs.setDefault(CommonModelPreferenceNames.LINE_WIDTH, 72); + prefs.setDefault(CommonModelPreferenceNames.SPLIT_MULTI_ATTRS, false); + prefs.setDefault(CommonModelPreferenceNames.INDENT_USING_TABS, true); + prefs.setDefault(CommonModelPreferenceNames.CLEAR_ALL_BLANK_LINES, false); + + prefs.setDefault(CommonModelPreferenceNames.PREFERRED_MARKUP_CASE_SUPPORTED, false); + prefs.setDefault(CommonModelPreferenceNames.TAG_NAME_CASE, CommonModelPreferenceNames.LOWER); + prefs.setDefault(CommonModelPreferenceNames.ATTR_NAME_CASE, CommonModelPreferenceNames.LOWER); + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/XMLPreferenceNames.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/XMLPreferenceNames.java new file mode 100644 index 0000000000..4df06f069f --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/XMLPreferenceNames.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core; + + + +public interface XMLPreferenceNames { + String CLEANUP_ATTR_NAME_CASE = "cleanupAttrNameCase";//$NON-NLS-1$ + String CLEANUP_EOL_CODE = "cleanupEOLCode";//$NON-NLS-1$ + // cleanup preference names + String CLEANUP_TAG_NAME_CASE = "cleanupTagNameCase";//$NON-NLS-1$ + String CONVERT_EOL_CODES = "convertEOLCodes";//$NON-NLS-1$ + String FORMAT_SOURCE = "formatSource";//$NON-NLS-1$ + String INSERT_MISSING_TAGS = "insertMissingTags";//$NON-NLS-1$ + + // others + String LAST_ACTIVE_PAGE = "lastActivePage";//$NON-NLS-1$ + String QUOTE_ATTR_VALUES = "quoteAttrValues";//$NON-NLS-1$ + + /* + * not used for now // highlighting types String COMMENT_BORDER = + * "commentBorder";//$NON-NLS-1$ String COMMENT_TEXT = + * "commentText";//$NON-NLS-1$ String CDATA_BORDER = + * "cdataBorder";//$NON-NLS-1$ String CDATA_TEXT = + * "cdataText";//$NON-NLS-1$ String PI_BORDER = "piBorder";//$NON-NLS-1$ + * String PI_CONTENT = "piContent";//$NON-NLS-1$ String TAG_BORDER = + * "tagBorder";//$NON-NLS-1$ String TAG_NAME = "tagName";//$NON-NLS-1$ + * String TAG_ATTRIBUTE_NAME = "tagAttributeName";//$NON-NLS-1$ String + * TAG_ATTRIBUTE_VALUE = "tagAttributeValue";//$NON-NLS-1$ String + * DECL_BORDER = "declBoder";//$NON-NLS-1$ String DOCTYPE_NAME = + * "doctypeName";//$NON-NLS-1$ String DOCTYPE_EXTERNAL_ID = + * "doctypeExternalId";//$NON-NLS-1$ String DOCTYPE_EXTERNAL_ID_PUBREF = + * "doctypeExternalPubref";//$NON-NLS-1$ String DOCTYPE_EXTERNAL_ID_SYSREF = + * "doctypeExtrenalSysref";//$NON-NLS-1$ String XML_CONTENT = + * "xmlContent";//$NON-NLS-1$ // highlighting preferences String COMMA = + * ",";//$NON-NLS-1$ String COLOR = "color";//$NON-NLS-1$ String NAME = + * "name";//$NON-NLS-1$ String FOREGROUND = "foreground";//$NON-NLS-1$ + * String BACKGROUND = "background";//$NON-NLS-1$ String BOLD = + * "bold";//$NON-NLS-1$ String ITALIC = "italic";//$NON-NLS-1$ + */ +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/builder/delegates/XMLTaskTagSeeker.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/builder/delegates/XMLTaskTagSeeker.java new file mode 100644 index 0000000000..a9bba3b35f --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/builder/delegates/XMLTaskTagSeeker.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.builder.delegates; + +import org.eclipse.wst.sse.core.participants.TaskTagSeeker; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; + + +public class XMLTaskTagSeeker extends TaskTagSeeker { + + /** + * + */ + public XMLTaskTagSeeker() { + super(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.core.participants.TaskTagSeeker#isCommentRegion(org.eclipse.wst.sse.core.text.IStructuredDocumentRegion, + * org.eclipse.wst.sse.core.text.ITextRegion) + */ + protected boolean isCommentRegion(IStructuredDocumentRegion region, ITextRegion textRegion) { + return textRegion.getType().equals(XMLRegionContext.XML_COMMENT_TEXT); + + } + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/builder/participants/XMLTaskTagParticipant.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/builder/participants/XMLTaskTagParticipant.java new file mode 100644 index 0000000000..0c7774ddd9 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/builder/participants/XMLTaskTagParticipant.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.builder.participants; + +import org.eclipse.wst.sse.core.participants.TaskTagParticipant; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; + + +public class XMLTaskTagParticipant extends TaskTagParticipant { + protected boolean isCommentRegion(IStructuredDocumentRegion region, ITextRegion textRegion) { + return textRegion.getType().equals(XMLRegionContext.XML_COMMENT_TEXT); + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/cleanup/CleanupProcessorXML.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/cleanup/CleanupProcessorXML.java new file mode 100644 index 0000000000..6e69a59cde --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/cleanup/CleanupProcessorXML.java @@ -0,0 +1,90 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.cleanup; + +import org.eclipse.core.runtime.Preferences; +import org.eclipse.wst.common.encoding.content.IContentTypeIdentifier; +import org.eclipse.wst.sse.core.cleanup.AbstractStructuredCleanupProcessor; +import org.eclipse.wst.sse.core.cleanup.IStructuredCleanupHandler; +import org.eclipse.wst.sse.core.cleanup.IStructuredCleanupPreferences; +import org.eclipse.wst.sse.core.cleanup.StructuredCleanupPreferences; +import org.eclipse.wst.sse.core.format.IStructuredFormatProcessor; +import org.eclipse.wst.sse.core.preferences.CommonModelPreferenceNames; +import org.eclipse.wst.xml.core.XMLModelPlugin; +import org.eclipse.wst.xml.core.format.FormatProcessorXML; +import org.w3c.dom.Node; + + +public class CleanupProcessorXML extends AbstractStructuredCleanupProcessor { + protected IStructuredCleanupPreferences fCleanupPreferences = null; + + protected IStructuredCleanupHandler getCleanupHandler(Node node) { + short nodeType = node.getNodeType(); + IStructuredCleanupHandler cleanupHandler = null; + switch (nodeType) { + case Node.ELEMENT_NODE : { + cleanupHandler = new ElementNodeCleanupHandler(); + break; + } + case Node.TEXT_NODE : { + cleanupHandler = new NodeCleanupHandler(); + break; + } + default : { + cleanupHandler = new NodeCleanupHandler(); + } + } + + // init CleanupPreferences + cleanupHandler.setCleanupPreferences(getCleanupPreferences()); + + return cleanupHandler; + } + + public IStructuredCleanupPreferences getCleanupPreferences() { + if (fCleanupPreferences == null) { + fCleanupPreferences = new StructuredCleanupPreferences(); + + Preferences preferences = getModelPreferences(); + if (preferences != null) { + fCleanupPreferences.setTagNameCase(preferences.getInt(CommonModelPreferenceNames.CLEANUP_TAG_NAME_CASE)); + fCleanupPreferences.setAttrNameCase(preferences.getInt(CommonModelPreferenceNames.CLEANUP_ATTR_NAME_CASE)); + fCleanupPreferences.setCompressEmptyElementTags(preferences.getBoolean(CommonModelPreferenceNames.COMPRESS_EMPTY_ELEMENT_TAGS)); + fCleanupPreferences.setInsertRequiredAttrs(preferences.getBoolean(CommonModelPreferenceNames.INSERT_REQUIRED_ATTRS)); + fCleanupPreferences.setInsertMissingTags(preferences.getBoolean(CommonModelPreferenceNames.INSERT_MISSING_TAGS)); + fCleanupPreferences.setQuoteAttrValues(preferences.getBoolean(CommonModelPreferenceNames.QUOTE_ATTR_VALUES)); + fCleanupPreferences.setFormatSource(preferences.getBoolean(CommonModelPreferenceNames.FORMAT_SOURCE)); + fCleanupPreferences.setConvertEOLCodes(preferences.getBoolean(CommonModelPreferenceNames.CONVERT_EOL_CODES)); + fCleanupPreferences.setEOLCode(preferences.getString(CommonModelPreferenceNames.CLEANUP_EOL_CODE)); + } + } + + return fCleanupPreferences; + } + + protected String getContentType() { + return IContentTypeIdentifier.ContentTypeID_SSEXML; + } + + protected IStructuredFormatProcessor getFormatProcessor() { + return new FormatProcessorXML(); + } + + protected Preferences getModelPreferences() { + return XMLModelPlugin.getDefault().getPluginPreferences(); + } + + protected void refreshCleanupPreferences() { + fCleanupPreferences = null; + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/cleanup/ElementNodeCleanupHandler.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/cleanup/ElementNodeCleanupHandler.java new file mode 100644 index 0000000000..39f4e31b3a --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/cleanup/ElementNodeCleanupHandler.java @@ -0,0 +1,556 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.cleanup; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.text.edits.InsertEdit; +import org.eclipse.text.edits.MultiTextEdit; +import org.eclipse.wst.common.contentmodel.CMAttributeDeclaration; +import org.eclipse.wst.common.contentmodel.CMElementDeclaration; +import org.eclipse.wst.common.contentmodel.CMNamedNodeMap; +import org.eclipse.wst.common.contentmodel.modelquery.ModelQuery; +import org.eclipse.wst.sse.core.cleanup.IStructuredCleanupHandler; +import org.eclipse.wst.sse.core.exceptions.SourceEditingRuntimeException; +import org.eclipse.wst.sse.core.text.IStructuredDocument; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.core.text.ITextRegionList; +import org.eclipse.wst.sse.core.util.StringUtils; +import org.eclipse.wst.xml.core.document.XMLAttr; +import org.eclipse.wst.xml.core.document.XMLDocument; +import org.eclipse.wst.xml.core.document.XMLElement; +import org.eclipse.wst.xml.core.document.XMLGenerator; +import org.eclipse.wst.xml.core.document.XMLModel; +import org.eclipse.wst.xml.core.document.XMLNode; +import org.eclipse.wst.xml.core.modelquery.ModelQueryUtil; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + + +public class ElementNodeCleanupHandler extends NodeCleanupHandler { + protected static final char DOUBLE_QUOTE = '\"'; //$NON-NLS-1$ + protected static final String DOUBLE_QUOTES = "\"\""; //$NON-NLS-1$ + protected static final String EMPTY_TAG_CLOSE = "/>"; //$NON-NLS-1$ + protected static final String END_TAG_OPEN = "</"; //$NON-NLS-1$ + protected static final char SINGLE_QUOTE = '\''; //$NON-NLS-1$ + protected static final String SINGLE_QUOTES = "''"; //$NON-NLS-1$ + + /** Non-NLS strings */ + protected static final String START_TAG_OPEN = "<"; //$NON-NLS-1$ + protected static final String TAG_CLOSE = ">"; //$NON-NLS-1$ + + public Node cleanup(Node node) { + Node newNode = cleanupChildren(node); + XMLNode renamedNode = newNode instanceof XMLNode ? (XMLNode) newNode : null; + + // call quoteAttrValue() first so it will close any unclosed attr + // quoteAttrValue() will return the new start tag if there is a + // structure change + renamedNode = quoteAttrValue(renamedNode); + + // insert tag close if missing + // if node is not comment tag + // and not implicit tag + if (!isCommentTag(renamedNode) && !isImplicitTag(renamedNode)) { + XMLModel structuredModel = renamedNode.getModel(); + + // save start offset before insertTagClose() + // or else renamedNode.getStartOffset() will be zero if + // renamedNode replaced by insertTagClose() + int startTagStartOffset = renamedNode.getStartOffset(); + + // for start tag + IStructuredDocumentRegion startTagStructuredDocumentRegion = renamedNode.getStartStructuredDocumentRegion(); + insertTagClose(structuredModel, startTagStructuredDocumentRegion); + + // update renamedNode and startTagStructuredDocumentRegion after + // insertTagClose() + renamedNode = (XMLNode) structuredModel.getIndexedRegion(startTagStartOffset); + startTagStructuredDocumentRegion = renamedNode.getStartStructuredDocumentRegion(); + + // for end tag + IStructuredDocumentRegion endTagStructuredDocumentRegion = renamedNode.getEndStructuredDocumentRegion(); + if (endTagStructuredDocumentRegion != startTagStructuredDocumentRegion) + insertTagClose(structuredModel, endTagStructuredDocumentRegion); + } + + // call insertMissingTags() next, it will generate implicit tags if + // there are any + // insertMissingTags() will return the new missing start tag if one is + // missing + renamedNode = insertMissingTags(renamedNode); + + renamedNode = compressEmptyElementTag(renamedNode); + + renamedNode = insertRequiredAttrs(renamedNode); + + return renamedNode; + } + + protected Node cleanupChildren(Node node) { + Node parentNode = node; + + if (node != null) { + Node childNode = node.getFirstChild(); + while (childNode != null) { + // get cleanup handler + IStructuredCleanupHandler cleanupHandler = getCleanupHandler(childNode); + + // cleanup each child + childNode = cleanupHandler.cleanup(childNode); + + // get new parent node + parentNode = (XMLNode) childNode.getParentNode(); + + // get next child node + childNode = (XMLNode) childNode.getNextSibling(); + } + } + + return parentNode; + } + + private XMLNode compressEmptyElementTag(XMLNode node) { + boolean compressEmptyElementTags = getCleanupPreferences().getCompressEmptyElementTags(); + XMLNode newNode = node; + + IStructuredDocumentRegion startTagStructuredDocumentRegion = newNode.getFirstStructuredDocumentRegion(); + IStructuredDocumentRegion endTagStructuredDocumentRegion = newNode.getLastStructuredDocumentRegion(); + + if (compressEmptyElementTags && startTagStructuredDocumentRegion != endTagStructuredDocumentRegion && startTagStructuredDocumentRegion != null) { + ITextRegionList regions = startTagStructuredDocumentRegion.getRegions(); + ITextRegion lastRegion = regions.get(regions.size() - 1); + // format children and end tag if not empty element tag + if (lastRegion.getType() != XMLRegionContext.XML_EMPTY_TAG_CLOSE) { + NodeList childNodes = newNode.getChildNodes(); + if (childNodes == null || childNodes.getLength() == 0 || (childNodes.getLength() == 1 && (childNodes.item(0)).getNodeType() == Node.TEXT_NODE && ((childNodes.item(0)).getNodeValue().trim().length() == 0))) { + XMLModel structuredModel = newNode.getModel(); + IStructuredDocument structuredDocument = structuredModel.getStructuredDocument(); + + int startTagStartOffset = newNode.getStartOffset(); + int offset = endTagStructuredDocumentRegion.getStart(); + int length = endTagStructuredDocumentRegion.getLength(); + structuredDocument.replaceText(structuredDocument, offset, length, ""); //$NON-NLS-1$ + newNode = (XMLNode) structuredModel.getIndexedRegion(startTagStartOffset); // save + + offset = startTagStructuredDocumentRegion.getStart() + lastRegion.getStart(); + structuredDocument.replaceText(structuredDocument, offset, 0, "/"); //$NON-NLS-1$ + newNode = (XMLNode) structuredModel.getIndexedRegion(startTagStartOffset); // save + } + } + } + + return newNode; + } + + protected IStructuredCleanupHandler getCleanupHandler(Node node) { + short nodeType = node.getNodeType(); + IStructuredCleanupHandler cleanupHandler = null; + switch (nodeType) { + case org.w3c.dom.Node.ELEMENT_NODE : { + cleanupHandler = new ElementNodeCleanupHandler(); + break; + } + case org.w3c.dom.Node.TEXT_NODE : { + cleanupHandler = new NodeCleanupHandler(); + break; + } + default : { + cleanupHandler = new NodeCleanupHandler(); + } + } + + // init CleanupPreferences + cleanupHandler.setCleanupPreferences(getCleanupPreferences()); + + return cleanupHandler; + } + + + protected ModelQuery getModelQuery(Node node) { + if (node.getNodeType() == Node.DOCUMENT_NODE) { + return ModelQueryUtil.getModelQuery((Document) node); + } else { + return ModelQueryUtil.getModelQuery(node.getOwnerDocument()); + } + } + + protected List getRequiredAttrs(Node node) { + List result = new ArrayList(); + + ModelQuery modelQuery = getModelQuery(node); + if (modelQuery != null) { + CMElementDeclaration elementDecl = modelQuery.getCMElementDeclaration((Element) node); + if (elementDecl != null) { + CMNamedNodeMap attrMap = elementDecl.getAttributes(); + Iterator it = attrMap.iterator(); + CMAttributeDeclaration attr = null; + while (it.hasNext()) { + attr = (CMAttributeDeclaration) it.next(); + if (attr.getUsage() == CMAttributeDeclaration.REQUIRED) { + result.add(attr); + } + } + } + } + + return result; + } + + private XMLNode insertEndTag(XMLNode node) { + XMLNode newNode = node; + XMLElement element = (XMLElement) node; + if (element.isCommentTag()) + return node; // do nothing + + int startTagStartOffset = node.getStartOffset(); + XMLModel structuredModel = node.getModel(); + + if (isEmptyElement(element)) { + IStructuredDocument structuredDocument = structuredModel.getStructuredDocument(); + IStructuredDocumentRegion startStructuredDocumentRegion = node.getStartStructuredDocumentRegion(); + ITextRegionList regions = startStructuredDocumentRegion.getRegions(); + ITextRegion lastRegion = regions.get(regions.size() - 1); + structuredDocument.replaceText(structuredDocument, startStructuredDocumentRegion.getStartOffset(lastRegion), lastRegion.getLength(), EMPTY_TAG_CLOSE); + + if (regions.size() > 1) { + ITextRegion regionBeforeTagClose = regions.get(regions.size() - 1 - 1); + + // insert a space separator before tag close if the previous + // region does not have extra spaces + if (regionBeforeTagClose.getTextLength() == regionBeforeTagClose.getLength()) + structuredDocument.replaceText(structuredDocument, startStructuredDocumentRegion.getStartOffset(lastRegion), 0, " "); //$NON-NLS-1$ + } + } else { + String tagName = node.getNodeName(); + String endTag = END_TAG_OPEN.concat(tagName).concat(TAG_CLOSE); + + XMLNode lastChild = (XMLNode) node.getLastChild(); + int endTagStartOffset = 0; + if (lastChild != null) + // if this node has children, insert the end tag after the + // last child + endTagStartOffset = lastChild.getEndOffset(); + else + // if this node does not has children, insert the end tag + // after the start tag + endTagStartOffset = node.getEndOffset(); + + IStructuredDocument structuredDocument = structuredModel.getStructuredDocument(); + structuredDocument.replaceText(structuredDocument, endTagStartOffset, 0, endTag); + } + + newNode = (XMLNode) structuredModel.getIndexedRegion(startTagStartOffset); // save + // new + // node + + return newNode; + } + + private XMLNode insertMissingTags(XMLNode node) { + boolean insertMissingTags = getCleanupPreferences().getInsertMissingTags(); + XMLNode newNode = node; + + if (insertMissingTags) { + IStructuredDocumentRegion startTagStructuredDocumentRegion = node.getStartStructuredDocumentRegion(); + if (startTagStructuredDocumentRegion == null) { + // implicit start tag; generate tag for it + newNode = insertStartTag(node); + startTagStructuredDocumentRegion = newNode.getStartStructuredDocumentRegion(); + } + + IStructuredDocumentRegion endTagStructuredDocumentRegion = newNode.getEndStructuredDocumentRegion(); + ITextRegionList startStructuredDocumentRegionRegions = startTagStructuredDocumentRegion.getRegions(); + if (startTagStructuredDocumentRegion != null && startStructuredDocumentRegionRegions != null && (startStructuredDocumentRegionRegions.get(startStructuredDocumentRegionRegions.size() - 1)).getType() == XMLRegionContext.XML_EMPTY_TAG_CLOSE) { + + } else { + if (startTagStructuredDocumentRegion == null) { + // start tag missing + if (isStartTagRequired(newNode)) + newNode = insertStartTag(newNode); + } else if (endTagStructuredDocumentRegion == null) { + // end tag missing + if (isEndTagRequired(newNode)) + newNode = insertEndTag(newNode); + } + } + } + + return newNode; + } + + private XMLNode insertRequiredAttrs(XMLNode node) { + boolean insertRequiredAttrs = getCleanupPreferences().getInsertRequiredAttrs(); + XMLNode newNode = node; + + if (insertRequiredAttrs) { + List requiredAttrs = getRequiredAttrs(newNode); + if (requiredAttrs.size() > 0) { + NamedNodeMap currentAttrs = node.getAttributes(); + List insertAttrs = new ArrayList(); + if (currentAttrs.getLength() == 0) + insertAttrs.addAll(requiredAttrs); + else { + for (int i = 0; i < requiredAttrs.size(); i++) { + String requiredAttrName = ((CMAttributeDeclaration) requiredAttrs.get(i)).getAttrName(); + boolean found = false; + for (int j = 0; j < currentAttrs.getLength(); j++) { + String currentAttrName = currentAttrs.item(j).getNodeName(); + if (requiredAttrName.compareToIgnoreCase(currentAttrName) == 0) { + found = true; + break; + } + } + if (!found) + insertAttrs.add(requiredAttrs.get(i)); + } + } + if (insertAttrs.size() > 0) { + IStructuredDocumentRegion startStructuredDocumentRegion = newNode.getStartStructuredDocumentRegion(); + int index = startStructuredDocumentRegion.getEndOffset(); + ITextRegion lastRegion = startStructuredDocumentRegion.getLastRegion(); + if (lastRegion.getType() == XMLRegionContext.XML_TAG_CLOSE) { + index--; + lastRegion = startStructuredDocumentRegion.getRegionAtCharacterOffset(index - 1); + } else if (lastRegion.getType() == XMLRegionContext.XML_EMPTY_TAG_CLOSE) { + index = index - 2; + lastRegion = startStructuredDocumentRegion.getRegionAtCharacterOffset(index - 1); + } + MultiTextEdit multiTextEdit = new MultiTextEdit(); + try { + for (int i = insertAttrs.size() - 1; i >= 0; i--) { + CMAttributeDeclaration attrDecl = (CMAttributeDeclaration) insertAttrs.get(i); + String requiredAttributeName = attrDecl.getAttrName(); + String defaultValue = attrDecl.getDefaultValue(); + if (defaultValue == null) + defaultValue = ""; //$NON-NLS-1$ + String nameAndDefaultValue = " "; //$NON-NLS-1$ + if (i == 0 && lastRegion.getLength() > lastRegion.getTextLength()) + nameAndDefaultValue = ""; //$NON-NLS-1$ + nameAndDefaultValue += requiredAttributeName + "=\"" + defaultValue + "\""; //$NON-NLS-1$ //$NON-NLS-2$ + multiTextEdit.addChild(new InsertEdit(index, nameAndDefaultValue)); + // BUG3381: MultiTextEdit applies all child + // TextEdit's basing on offsets + // in the document before the first TextEdit, not + // after each + // child TextEdit. Therefore, do not need to + // advance the index. + //index += nameAndDefaultValue.length(); + } + multiTextEdit.apply(newNode.getStructuredDocument()); + } catch (BadLocationException e) { + throw new SourceEditingRuntimeException(e); + } + } + } + } + + return newNode; + } + + private XMLNode insertStartTag(XMLNode node) { + XMLNode newNode = node; + + if (isCommentTag(node)) + return node; // do nothing + + String tagName = node.getNodeName(); + String startTag = START_TAG_OPEN.concat(tagName).concat(TAG_CLOSE); + int startTagStartOffset = node.getStartOffset(); + + XMLModel structuredModel = node.getModel(); + IStructuredDocument structuredDocument = structuredModel.getStructuredDocument(); + structuredDocument.replaceText(structuredDocument, startTagStartOffset, 0, startTag); + newNode = (XMLNode) structuredModel.getIndexedRegion(startTagStartOffset); // save + // new + // node + + return newNode; + } + + private void insertTagClose(XMLModel structuredModel, IStructuredDocumentRegion flatNode) { + if (flatNode != null) { + ITextRegionList flatnodeRegions = flatNode.getRegions(); + if (flatnodeRegions != null) { + ITextRegion lastRegion = flatnodeRegions.get(flatnodeRegions.size() - 1); + if (lastRegion != null) { + String regionType = lastRegion.getType(); + if ((regionType != XMLRegionContext.XML_EMPTY_TAG_CLOSE) && (regionType != XMLRegionContext.XML_TAG_CLOSE)) { + IStructuredDocument structuredDocument = structuredModel.getStructuredDocument(); + + // insert ">" after lastRegion of flatNode + // as in "<a</a>" if flatNode is for start tag, or in + // "<a></a" if flatNode is for end tag + structuredDocument.replaceText(structuredDocument, flatNode.getTextEndOffset(lastRegion), 0, ">"); //$NON-NLS-1$ + } + } + } + } + } + + /** + * @param renamedNode + * @return + */ + private boolean isCommentTag(Node renamedNode) { + boolean result = false; + if (renamedNode instanceof XMLElement) { + XMLElement element = (XMLElement) renamedNode; + result = element.isCommentTag(); + } + return result; + } + + private boolean isEmptyElement(XMLElement element) { + Document document = element.getOwnerDocument(); + if (document == null) + // undefined tag, return default + return false; + + ModelQuery modelQuery = ModelQueryUtil.getModelQuery(document); + if (modelQuery == null) + // undefined tag, return default + return false; + + CMElementDeclaration decl = modelQuery.getCMElementDeclaration(element); + if (decl == null) + // undefined tag, return default + return false; + + return (decl.getContentType() == CMElementDeclaration.EMPTY); + } + + private boolean isEndTagRequired(XMLNode node) { + if (node == null) + return false; + return node.isContainer(); + } + + /** + * A tag is implicit if it has not corresponding region in document. + * + * @param renamedNode + * @return + */ + private boolean isImplicitTag(XMLNode renamedNode) { + return renamedNode.getStartStructuredDocumentRegion() == null; + } + + /** + * The end tags of HTML EMPTY content type, such as IMG, and HTML + * undefined tags are parsed separately from the start tags. So inserting + * the missing start tag is useless and even harmful. + */ + private boolean isStartTagRequired(XMLNode node) { + if (node == null) + return false; + return node.isContainer(); + } + + private boolean isXMLType(XMLModel structuredModel) { + boolean result = false; + + if (structuredModel != null && structuredModel != null) { + XMLDocument document = structuredModel.getDocument(); + + if (document != null) + result = document.isXMLType(); + } + + return result; + } + + private XMLNode quoteAttrValue(XMLNode node) { + XMLNode newNode = node; + //XMLElement element = (XMLElement) node; + if (isCommentTag(node)) + return node; // do nothing + + boolean quoteAttrValues = getCleanupPreferences().getQuoteAttrValues(); + + if (quoteAttrValues) { + NamedNodeMap attributes = newNode.getAttributes(); + if (attributes != null) { + int attributesLength = attributes.getLength(); + XMLGenerator generator = node.getModel().getGenerator(); + + for (int i = 0; i < attributesLength; i++) { + attributes = newNode.getAttributes(); + attributesLength = attributes.getLength(); + XMLAttr eachAttr = (XMLAttr) attributes.item(i); + //ITextRegion oldAttrValueRegion = + // eachAttr.getValueRegion(); + String oldAttrValue = eachAttr.getValueRegionText(); + if (oldAttrValue == null) { + XMLModel structuredModel = node.getModel(); + if (isXMLType(structuredModel)) { + String newAttrValue = "\"" + eachAttr.getNameRegionText() + "\""; //$NON-NLS-1$ //$NON-NLS-2$ + + IStructuredDocument structuredDocument = structuredModel.getStructuredDocument(); + if (eachAttr.getEqualRegion() != null) + // equal region exists + structuredDocument.replaceText(structuredDocument, eachAttr.getEndOffset(), 0, newAttrValue); + else + // no equal region + structuredDocument.replaceText(structuredDocument, eachAttr.getNameRegionTextEndOffset(), 0, "=".concat(newAttrValue)); //$NON-NLS-1$ + newNode = (XMLNode) structuredModel.getIndexedRegion(node.getStartOffset()); // save + // new + // node + } + } else { + //String oldAttrValue = oldAttrValueRegion.getText(); + char quote = StringUtils.isQuoted(oldAttrValue) ? oldAttrValue.charAt(0) : DOUBLE_QUOTE; + String newAttrValue = generator.generateAttrValue(eachAttr, quote); + + // There is a problem in + // StructuredDocumentRegionUtil.getAttrValue(ITextRegion) + // when the region is instanceof ContextRegion. + // Workaround for now... + if (oldAttrValue.length() == 1) { + char firstChar = oldAttrValue.charAt(0); + if (firstChar == SINGLE_QUOTE) + newAttrValue = SINGLE_QUOTES; + else if (firstChar == DOUBLE_QUOTE) + newAttrValue = DOUBLE_QUOTES; + } + + if (newAttrValue != null) { + if (newAttrValue.compareTo(oldAttrValue) != 0) { + int attrValueStartOffset = eachAttr.getValueRegionStartOffset(); + int attrValueLength = oldAttrValue.length(); + int startTagStartOffset = node.getStartOffset(); + + XMLModel structuredModel = node.getModel(); + IStructuredDocument structuredDocument = structuredModel.getStructuredDocument(); + structuredDocument.replaceText(structuredDocument, attrValueStartOffset, attrValueLength, newAttrValue); + newNode = (XMLNode) structuredModel.getIndexedRegion(startTagStartOffset); // save + // new + // node + } + } + } + } + } + } + + return newNode; + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/cleanup/NodeCleanupHandler.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/cleanup/NodeCleanupHandler.java new file mode 100644 index 0000000000..ffdb1977d4 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/cleanup/NodeCleanupHandler.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.cleanup; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.Preferences; +import org.eclipse.wst.sse.core.cleanup.IStructuredCleanupHandler; +import org.eclipse.wst.sse.core.cleanup.IStructuredCleanupPreferences; +import org.eclipse.wst.sse.core.cleanup.StructuredCleanupPreferences; +import org.eclipse.wst.sse.core.preferences.CommonModelPreferenceNames; +import org.eclipse.wst.xml.core.XMLModelPlugin; +import org.w3c.dom.Node; + + +public class NodeCleanupHandler implements IStructuredCleanupHandler { + + protected IStructuredCleanupPreferences fCleanupPreferences = null; + protected IProgressMonitor fProgressMonitor = null; + + /** + * @see com.ibm.sed.partitionCleanup.CleanupHandler#cleanup(com.ibm.sed.model.xml.XMLNode) + */ + public Node cleanup(Node node) { + + return node; + } + + /** + * @see com.ibm.sed.partitionCleanup.CleanupHandler#getCleanupPreferences() + */ + public IStructuredCleanupPreferences getCleanupPreferences() { + if (fCleanupPreferences == null) { + fCleanupPreferences = new StructuredCleanupPreferences(); + + Preferences preferences = getModelPreferences(); + if (preferences != null) { + fCleanupPreferences.setTagNameCase(preferences.getInt(CommonModelPreferenceNames.CLEANUP_TAG_NAME_CASE)); + fCleanupPreferences.setAttrNameCase(preferences.getInt(CommonModelPreferenceNames.CLEANUP_ATTR_NAME_CASE)); + fCleanupPreferences.setCompressEmptyElementTags(preferences.getBoolean(CommonModelPreferenceNames.COMPRESS_EMPTY_ELEMENT_TAGS)); + fCleanupPreferences.setInsertRequiredAttrs(preferences.getBoolean(CommonModelPreferenceNames.INSERT_REQUIRED_ATTRS)); + fCleanupPreferences.setInsertMissingTags(preferences.getBoolean(CommonModelPreferenceNames.INSERT_MISSING_TAGS)); + fCleanupPreferences.setQuoteAttrValues(preferences.getBoolean(CommonModelPreferenceNames.QUOTE_ATTR_VALUES)); + fCleanupPreferences.setFormatSource(preferences.getBoolean(CommonModelPreferenceNames.FORMAT_SOURCE)); + fCleanupPreferences.setConvertEOLCodes(preferences.getBoolean(CommonModelPreferenceNames.CONVERT_EOL_CODES)); + fCleanupPreferences.setEOLCode(preferences.getString(CommonModelPreferenceNames.CLEANUP_EOL_CODE)); + } + } + + return fCleanupPreferences; + } + + protected Preferences getModelPreferences() { + return XMLModelPlugin.getDefault().getPluginPreferences(); + } + + public void setCleanupPreferences(IStructuredCleanupPreferences cleanupPreferences) { + + fCleanupPreferences = cleanupPreferences; + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/cleanup/XMLCleanupPreferences.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/cleanup/XMLCleanupPreferences.java new file mode 100644 index 0000000000..6bae47a150 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/cleanup/XMLCleanupPreferences.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.cleanup; + +import org.eclipse.core.runtime.Preferences; + +/** + * @deprecated renamed to IStructuredCleanupPreferences + * + * TODO will delete in C5 + */ +public interface XMLCleanupPreferences { + + int getAttrNameCase(); + + boolean getConvertEOLCodes(); + + String getEOLCode(); + + boolean getFormatSource(); + + boolean getInsertMissingTags(); + + boolean getQuoteAttrValues(); + + int getTagNameCase(); + + void setAttrNameCase(int attrNameCase); + + void setConvertEOLCodes(boolean convertEOLCodes); + + void setEOLCode(String EOLCode); + + void setFormatSource(boolean formatSource); + + void setInsertMissingTags(boolean insertMissingTags); + + //void setPreferenceStore(IPreferenceStore preferenceStore); + void setPreferences(Preferences preferences); + + void setQuoteAttrValues(boolean quoteAttrValues); + + void setTagNameCase(int tagNameCase); +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/cleanup/XMLCleanupPreferencesImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/cleanup/XMLCleanupPreferencesImpl.java new file mode 100644 index 0000000000..6dccbc1302 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/cleanup/XMLCleanupPreferencesImpl.java @@ -0,0 +1,150 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.cleanup; + +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Preferences; +import org.eclipse.wst.sse.core.IModelManagerPlugin; +import org.eclipse.wst.xml.core.XMLPreferenceNames; + + +/** + * @deprecated renamed to StructuredCleanupPreferences + * + * TODO will delete in C5 + */ +public class XMLCleanupPreferencesImpl implements XMLCleanupPreferences { + + private static XMLCleanupPreferencesImpl fInstance; + + public synchronized static XMLCleanupPreferencesImpl getInstance() { + + // added for one method in CleanupDialog ... may be better way + if (fInstance == null) { + fInstance = new XMLCleanupPreferencesImpl(); + } + return fInstance; + } + + private int fAttrNameCase; + private boolean fConvertEOLCodes; + private String fEOLCode; + private boolean fFormatSource; + private boolean fInsertMissingTags; + //private IPreferenceStore fPreferenceStore = null; + private Preferences fPreferences = null; + private boolean fQuoteAttrValues; + private int fTagNameCase; + + public int getAttrNameCase() { + + return fAttrNameCase; + } + + public boolean getConvertEOLCodes() { + + return fConvertEOLCodes; + } + + public String getEOLCode() { + + return fEOLCode; + } + + public boolean getFormatSource() { + + return fFormatSource; + } + + public boolean getInsertMissingTags() { + + return fInsertMissingTags; + } + + private IModelManagerPlugin getModelManagerPlugin() { + + IModelManagerPlugin plugin = (IModelManagerPlugin) Platform.getPlugin(IModelManagerPlugin.ID); + return plugin; + } + + public Preferences getPreferences() { + + if (fPreferences == null) { + fPreferences = getModelManagerPlugin().getPluginPreferences(); + } + return fPreferences; + } + + public boolean getQuoteAttrValues() { + + return fQuoteAttrValues; + } + + public int getTagNameCase() { + + return fTagNameCase; + } + + public void setAttrNameCase(int attrNameCase) { + + fAttrNameCase = attrNameCase; + } + + public void setConvertEOLCodes(boolean convertEOLCodes) { + + fConvertEOLCodes = convertEOLCodes; + } + + public void setEOLCode(String EOLCode) { + + fEOLCode = EOLCode; + } + + public void setFormatSource(boolean formatSource) { + + fFormatSource = formatSource; + } + + public void setInsertMissingTags(boolean insertMissingTags) { + + fInsertMissingTags = insertMissingTags; + } + + public void setPreferences(Preferences prefs) { + + fPreferences = prefs; + updateOptions(); + } + + public void setQuoteAttrValues(boolean quoteAttrValues) { + + fQuoteAttrValues = quoteAttrValues; + } + + public void setTagNameCase(int tagNameCase) { + + fTagNameCase = tagNameCase; + } + + protected void updateOptions() { + + Preferences p = getPreferences(); + fTagNameCase = p.getInt(XMLPreferenceNames.CLEANUP_TAG_NAME_CASE); + fAttrNameCase = p.getInt(XMLPreferenceNames.CLEANUP_ATTR_NAME_CASE); + fInsertMissingTags = p.getBoolean(XMLPreferenceNames.INSERT_MISSING_TAGS); + fQuoteAttrValues = p.getBoolean(XMLPreferenceNames.QUOTE_ATTR_VALUES); + fFormatSource = p.getBoolean(XMLPreferenceNames.FORMAT_SOURCE); + fConvertEOLCodes = p.getBoolean(XMLPreferenceNames.CONVERT_EOL_CODES); + fEOLCode = p.getString(XMLPreferenceNames.CLEANUP_EOL_CODE); + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/CommentElementAdapter.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/CommentElementAdapter.java new file mode 100644 index 0000000000..ae18f47946 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/CommentElementAdapter.java @@ -0,0 +1,123 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.commentelement; + + + +import org.eclipse.core.runtime.IPluginDescriptor; +import org.eclipse.wst.sse.core.INodeNotifier; +import org.eclipse.wst.xml.core.commentelement.impl.CommentElementConfiguration; +import org.eclipse.wst.xml.core.document.TagAdapter; +import org.eclipse.wst.xml.core.document.XMLElement; + + +/** + */ +public class CommentElementAdapter implements TagAdapter { + private CommentElementConfiguration fConfiguration; + + private boolean fEndTag; + private CommentElementHandler fHandler; + + public CommentElementAdapter(boolean isEndTag, CommentElementHandler handler) { + fEndTag = isEndTag; + fHandler = handler; + } + + private String generateCommentClose(XMLElement element) { + return (element.isJSPTag()) ? "--%>" : "-->"; //$NON-NLS-1$ //$NON-NLS-2$ + } + + private String generateCommentOpen(XMLElement element) { + return (element.isJSPTag()) ? "<%--" : "<!--"; //$NON-NLS-1$ //$NON-NLS-2$ + } + + private CommentElementConfiguration getConfiguration() { + return fConfiguration; + } + + /** + * @see com.ibm.sed.model.xml.TagAdapter#getEndTag(XMLElement) + */ + public String getEndTag(XMLElement element) { + String content = fHandler.generateEndTagContent(element); + if (content == null) { + return null; + } + StringBuffer buffer = new StringBuffer(); + + buffer.append(generateCommentOpen(element)); + buffer.append(content); + buffer.append(generateCommentClose(element)); + + return buffer.toString(); + } + + public String getHandlerID() { + return getConfiguration().getHandlerID(); + } + + public IPluginDescriptor getHandlerPluginDescriptor() { + return fConfiguration.getHandlerPluginDescriptor(); + } + + public String getProperty(String name) { + return getConfiguration().getProperty(name); + } + + /** + * @see com.ibm.sed.model.xml.TagAdapter#getStartTag(XMLElement) + */ + public String getStartTag(XMLElement element) { + String content = fHandler.generateStartTagContent(element); + if (content == null) { + return null; + } + StringBuffer buffer = new StringBuffer(); + + buffer.append(generateCommentOpen(element)); + buffer.append(content); + buffer.append(generateCommentClose(element)); + + return buffer.toString(); + } + + /** + * @see com.ibm.sed.model.INodeAdapter#isAdapterForType(Object) + */ + public boolean isAdapterForType(Object type) { + return (type == CommentElementAdapter.class || type == TagAdapter.class); + } + + public boolean isContainer() { + return (!fHandler.isEmpty()); + } + + /** + * @see com.ibm.sed.model.xml.TagAdapter#isEndTag() + */ + public boolean isEndTag() { + return fEndTag; + } + + /** + * @see com.ibm.sed.model.INodeAdapter#notifyChanged(INodeNotifier, int, + * Object, Object, Object, int) + */ + public void notifyChanged(INodeNotifier notifier, int eventType, Object changedFeature, Object oldValue, Object newValue, int pos) { + } + + public void setConfiguration(CommentElementConfiguration configuration) { + fConfiguration = configuration; + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/CommentElementHandler.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/CommentElementHandler.java new file mode 100644 index 0000000000..b5eae28068 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/CommentElementHandler.java @@ -0,0 +1,107 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.commentelement; + + + +import org.eclipse.wst.xml.core.document.XMLElement; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + + +/** + */ +public interface CommentElementHandler { + /** + * This method is called when the prefix of the comment content matches + * the string specified in <startswith prefix=""/> in plugin + * extension. Comment content is parsed and new DOM element is created in + * this method. Implementor has to do following: + * <li>For start tag : + * <ul> + * <li>parse comment content and create new element instance.</li> + * </ul> + * </li> + * <li>For end tag : + * <ul> + * <li>parse comment content and create new element instance.</li> + * <li>make isEndTag flag true.</li> + * <li>Parser framework searches mached start tag element instance after + * this createElement call, and new instance is just thrown away.</li> + * </ul> + * </li> + * <li>For empty tag : + * <ul> + * <li>parse comment content and create new element instance.</li> + * <li>make isEndTag flag true.</li> + * </ul> + * </li> + * + * @param document + * parent DOM document + * @param data + * comment content. comment prefix (<!-- or <%--), suffix + * (--> or --%>), and surrounding spaces are trimmed. + * @param isJSPTag + * true if the comment is JSP style comment. This information + * may be required by handler when the handler accepts both XML + * style and JSP style comment (namely, + * commenttype="both" in plugin.xml). + * @return comment element instance if the comment content is rightly + * parsed. if parse failed, returns null. + */ + Element createElement(Document document, String data, boolean isJSPTag); + + /** + * This method generates the source text of the end tag for the passed + * element. Do not generate comment prefix (<!-- or <%--) and suffix + * (--> or --%>). XMLGenerator uses this method to generate XML/HTML + * source for a comment element. + * + * @param element + * the comment element + * @return generated tag string + */ + String generateEndTagContent(XMLElement element); + + /** + * This method generates the source text of the start tag for the passed + * element. Do not generate comment prefix (<!-- or <%--) and suffix + * (--> or --%>). XMLGenerator uses this method to generate XML/HTML + * source for a comment element. + * + * @param element + * the comment element + * @return generated tag string + */ + String generateStartTagContent(XMLElement element); + + /** + * + * @param element + * the element + * @return boolean whether the element is comment element or not + */ + boolean isCommentElement(XMLElement element); + + /** + * + * @return boolean whether this element can have children or not + */ + boolean isEmpty(); + + /** + * @return String + */ + // String getElementPrefix(); +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/impl/BasicCommentElementHandler.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/impl/BasicCommentElementHandler.java new file mode 100644 index 0000000000..98efac0f7d --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/impl/BasicCommentElementHandler.java @@ -0,0 +1,153 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.commentelement.impl; + + + +import org.eclipse.wst.xml.core.commentelement.CommentElementHandler; +import org.eclipse.wst.xml.core.commentelement.util.CommentElementFactory; +import org.eclipse.wst.xml.core.commentelement.util.TagScanner; +import org.eclipse.wst.xml.core.document.XMLAttr; +import org.eclipse.wst.xml.core.document.XMLElement; +import org.eclipse.wst.xml.core.document.XMLGenerator; +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; + + +/** + */ +class BasicCommentElementHandler implements CommentElementHandler { + + private String elementName; + private boolean isEmpty; + + public BasicCommentElementHandler(String elementName, boolean isEmpty) { + super(); + this.elementName = elementName; + this.isEmpty = isEmpty; + } + + /** + * @see com.ibm.sed.model.commentelement.CommentElementHandler#createElement(Document, + * String, boolean) + */ + public Element createElement(Document document, String data, boolean isJSPTag) { + Element element = null; + String str = data.trim(); + CommentElementFactory factory = new CommentElementFactory(document, isJSPTag, this); + if (str.charAt(0) == '/') { // end tag + TagScanner scanner = new TagScanner(str, 1); // skip '/' + String name = scanner.nextName(); + if (name.equals(elementName)) { + element = factory.create(name, CommentElementFactory.IS_END); + } + } else { // start tag + TagScanner scanner = new TagScanner(str, 0); + String name = scanner.nextName(); + if (name.equals(elementName)) { + element = factory.create(name, (isEmpty) ? CommentElementFactory.IS_EMPTY : CommentElementFactory.IS_START); + // set attributes + String attrName = scanner.nextName(); + while (attrName != null) { + String attrValue = scanner.nextValue(); + Attr attr = document.createAttribute(attrName); + if (attr != null) { + if (attrValue != null) + ((XMLAttr) attr).setValueSource(attrValue); + element.setAttributeNode(attr); + } + attrName = scanner.nextName(); + } + } + } + return element; + } + + /** + * @see com.ibm.sed.model.commentelement.CommentElementHandler#getEndTag(XMLElement) + */ + public String generateEndTagContent(XMLElement element) { + if (isEmpty) { + return null; + } + XMLGenerator generator = element.getModel().getGenerator(); + StringBuffer buffer = new StringBuffer(); + + buffer.append(" /"); //$NON-NLS-1$ + String tagName = generator.generateTagName(element); + if (tagName != null) { + buffer.append(tagName); + } + buffer.append(' '); + + return buffer.toString(); + } + + /** + * @see com.ibm.sed.model.commentelement.CommentElementHandler#getStartTag(XMLElement) + */ + public String generateStartTagContent(XMLElement element) { + XMLGenerator generator = element.getModel().getGenerator(); + StringBuffer buffer = new StringBuffer(); + + buffer.append(' '); + String tagName = generator.generateTagName(element); + if (tagName != null) { + buffer.append(tagName); + } + + NamedNodeMap attributes = element.getAttributes(); + int length = attributes.getLength(); + for (int i = 0; i < length; i++) { + Attr attr = (Attr) attributes.item(i); + if (attr == null) { + continue; + } + buffer.append(' '); + String attrName = generator.generateAttrName(attr); + if (attrName != null) { + buffer.append(attrName); + } + String attrValue = generator.generateAttrValue(attr); + if (attrValue != null) { + // attr name only for HTML boolean and JSP + buffer.append('='); + buffer.append(attrValue); + } + } + + buffer.append(' '); + + return buffer.toString(); + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.model.commentelement.CommentElementHandler#isCommentElement(com.ibm.sed.model.xml.XMLElement) + */ + public boolean isCommentElement(XMLElement element) { + return (element != null && element.getTagName().equals(elementName)) ? true : false; + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.model.commentelement.CommentElementHandler#isEmpty() + */ + public boolean isEmpty() { + return isEmpty; + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/impl/CommentElementConfiguration.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/impl/CommentElementConfiguration.java new file mode 100644 index 0000000000..d4aac41461 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/impl/CommentElementConfiguration.java @@ -0,0 +1,226 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.commentelement.impl; + + + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IPluginDescriptor; +import org.eclipse.wst.xml.core.Logger; +import org.eclipse.wst.xml.core.commentelement.CommentElementAdapter; +import org.eclipse.wst.xml.core.commentelement.CommentElementHandler; +import org.eclipse.wst.xml.core.document.XMLElement; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + + +/** + */ +public class CommentElementConfiguration { + private Map fAttributes = null; + private boolean fCustom; + private IConfigurationElement fElement = null; + + private boolean fEmpty; + private CommentElementHandler fHandler = null; + private String fID = null; + private boolean fJSPComment; + private String[] fPrefix = null; + private boolean fXMLComment; + + CommentElementConfiguration() { + super(); + } + + CommentElementConfiguration(IConfigurationElement element) { + super(); + fElement = element; + fCustom = (element.getName().equalsIgnoreCase("handler-custom")) ? true : false; //$NON-NLS-1$ + + fillAttributes(element); + + fXMLComment = fJSPComment = false; + String commentType = getProperty("commenttype"); //$NON-NLS-1$ + if (commentType.equalsIgnoreCase("xml")) { //$NON-NLS-1$ + fXMLComment = true; + } else if (commentType.equalsIgnoreCase("jsp")) { //$NON-NLS-1$ + fJSPComment = true; + } else if (commentType.equalsIgnoreCase("both")) { //$NON-NLS-1$ + fXMLComment = fJSPComment = true; + } + String empty = getProperty("isempty"); //$NON-NLS-1$ + fEmpty = (empty != null && !empty.equals("false")) ? true : false; //$NON-NLS-1$ + } + + public boolean acceptJSPComment() { + return fJSPComment; + } + + public boolean acceptXMLComment() { + return fXMLComment; + } + + public Element createElement(Document document, String data, boolean isJSPTag) { + XMLElement element = (XMLElement) getHandler().createElement(document, data, isJSPTag); + if (element != null) { + CommentElementAdapter adapter = (CommentElementAdapter) element.getAdapterFor(CommentElementAdapter.class); + if (adapter != null) { + adapter.setConfiguration(this); + } + } + return element; + } + + private void fillAttributes(IConfigurationElement element) { + if (fAttributes == null) { + fAttributes = new HashMap(); + } else { + fAttributes.clear(); + } + String[] names = element.getAttributeNames(); + if (names == null) { + return; + } + int length = names.length; + for (int i = 0; i < length; i++) { + String name = names[i]; + fAttributes.put(name.toLowerCase(), element.getAttribute(name)); + } + } + + public CommentElementHandler getHandler() { + if (fHandler == null) { + if (fElement != null) { + try { + if (isCustom()) { + fHandler = (CommentElementHandler) fElement.createExecutableExtension("class"); //$NON-NLS-1$ + } else { + String elementName = getProperty("elementname"); //$NON-NLS-1$ + fHandler = new BasicCommentElementHandler(elementName, fEmpty); + } + // ((AbstractCommentElementHandler)fHandler).setElementPrefix(fElement.getAttribute("prefix")); + } catch (Exception e) { + // catch and log (and ignore) ANY exception created + // by executable extension. + Logger.logException(e); + fHandler = null; + } + } + if (fHandler == null) { + fHandler = new CommentElementHandler() { + public Element createElement(Document document, String data, boolean isJSPTag) { + return null; + } + + public String generateEndTagContent(XMLElement element) { + return null; + } + + public String generateStartTagContent(XMLElement element) { + return null; + } + + public String getElementPrefix() { + return null; + } + + public boolean isCommentElement(XMLElement element) { + return false; + } + + public boolean isEmpty() { + return false; + } + }; + } + } + return fHandler; + } + + public String getHandlerID() { + if (fID == null) { + fID = getProperty("id"); //$NON-NLS-1$ + if (fID == null) { + if (isCustom()) { + fID = getProperty("class"); //$NON-NLS-1$ + } else { + StringBuffer buf = new StringBuffer(); + buf.append(getHandlerPluginDescriptor().getUniqueIdentifier()); + buf.append('.'); + buf.append(getProperty("elementname")); //$NON-NLS-1$ + fID = buf.toString(); + } + } + } + return fID; + } + + public IPluginDescriptor getHandlerPluginDescriptor() { + return fElement.getDeclaringExtension().getDeclaringPluginDescriptor(); + } + + public String[] getPrefix() { + if (fPrefix == null) { + if (fElement != null) { + if (isCustom()) { // custom + IConfigurationElement[] prefixes = fElement.getChildren("startwith"); //$NON-NLS-1$ + if (prefixes != null) { + fPrefix = new String[prefixes.length]; + for (int i = 0; i < prefixes.length; i++) { + fPrefix[i] = prefixes[i].getAttribute("prefix"); //$NON-NLS-1$ + } + } + } else { // basic + String name = getProperty("elementname"); //$NON-NLS-1$ + if (name != null) { + if (isEmpty()) { + fPrefix = new String[1]; + fPrefix[0] = name; + } else { + fPrefix = new String[2]; + fPrefix[0] = name; + fPrefix[1] = '/' + name; + } + } + } + } + } + if (fPrefix == null) { + fPrefix = new String[1]; + fPrefix[0] = ""; //$NON-NLS-1$ + } + return fPrefix; + } + + public String getProperty(String name) { + return (fAttributes != null) ? (String) fAttributes.get(name) : null; + } + + private boolean isCustom() { + return fCustom; + } + + private boolean isEmpty() { + return fEmpty; + } + + void setupCommentElement(XMLElement element) { + element.setCommentTag(true); + CommentElementAdapter adapter = new CommentElementAdapter(false, fHandler); + adapter.setConfiguration(this); + element.addAdapter(adapter); + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/impl/CommentElementRegistry.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/impl/CommentElementRegistry.java new file mode 100644 index 0000000000..3245298479 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/impl/CommentElementRegistry.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.commentelement.impl; + + + +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExtensionPoint; +import org.eclipse.core.runtime.IPluginRegistry; +import org.eclipse.core.runtime.Platform; +import org.eclipse.wst.xml.core.commentelement.CommentElementHandler; +import org.eclipse.wst.xml.core.document.XMLElement; + + +/** + */ +public class CommentElementRegistry { + + private static CommentElementRegistry fInstance = null; + + public synchronized static CommentElementRegistry getInstance() { + if (fInstance == null) { + fInstance = new CommentElementRegistry(); + } + return fInstance; + } + + private String EXTENSION_POINT_ID = "commentElementHandler"; //$NON-NLS-1$ + private CommentElementConfiguration[] fConfigurations = null; + + private String PLUGIN_ID = "org.eclipse.wst.sse.core"; //$NON-NLS-1$ + + /** + * Constructor for CommentElementRegistry. + */ + private CommentElementRegistry() { + super(); + } + + public CommentElementConfiguration[] getConfigurations() { + if (fConfigurations == null) { + IPluginRegistry pluginRegistry = Platform.getPluginRegistry(); + IExtensionPoint point = pluginRegistry.getExtensionPoint(PLUGIN_ID, EXTENSION_POINT_ID); + if (point != null) { + IConfigurationElement[] elements = point.getConfigurationElements(); + fConfigurations = new CommentElementConfiguration[elements.length]; + for (int i = 0; i < elements.length; i++) { + fConfigurations[i] = new CommentElementConfiguration(elements[i]); + } + } + if (fConfigurations == null) { + fConfigurations = new CommentElementConfiguration[0]; + } + } + return fConfigurations; + } + + public boolean setupCommentElement(XMLElement element) { + CommentElementConfiguration configurations[] = getConfigurations(); + int length = configurations.length; + for (int i = 0; i < length; i++) { + CommentElementConfiguration conf = configurations[i]; + boolean isJSP = element.isJSPTag(); + if (isJSP && conf.acceptJSPComment() || !isJSP && conf.acceptXMLComment()) { + CommentElementHandler handler = conf.getHandler(); + if (handler.isCommentElement(element)) { + conf.setupCommentElement(element); + return true; + } + } + } + return false; + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/util/CommentElementFactory.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/util/CommentElementFactory.java new file mode 100644 index 0000000000..2ae4c84734 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/util/CommentElementFactory.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.commentelement.util; + + + +import org.eclipse.wst.xml.core.commentelement.CommentElementAdapter; +import org.eclipse.wst.xml.core.commentelement.CommentElementHandler; +import org.eclipse.wst.xml.core.document.XMLElement; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + + +/** + */ +public class CommentElementFactory { + public static final int IS_EMPTY = 4866; + public static final int IS_END = 1808; + + public static final int IS_START = 28011; + + private Document fDocument; + private CommentElementHandler fHandler; + private boolean fJSPTag; + + /** + * Constructor for CommentElementFactory. + */ + private CommentElementFactory() { + super(); + } + + public CommentElementFactory(Document document, boolean isJSPTag, CommentElementHandler handler) { + super(); + fDocument = document; + fJSPTag = isJSPTag; + fHandler = handler; + } + + public Element create(String name, int nodeType) { + XMLElement element = (XMLElement) fDocument.createElement(name); + if (element == null) + return null; + element.setCommentTag(true); + if (nodeType == IS_EMPTY) { + element.setEmptyTag(true); + } + element.setJSPTag(fJSPTag); + + CommentElementAdapter adapter = new CommentElementAdapter((nodeType == IS_END), fHandler); + element.addAdapter(adapter); + + return element; + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/util/TagScanner.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/util/TagScanner.java new file mode 100644 index 0000000000..a74fe0bb77 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/commentelement/util/TagScanner.java @@ -0,0 +1,196 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.commentelement.util; + + + +/** + */ +public class TagScanner { + + /** + */ + private static boolean isEqual(char c) { + return (c == '='); + } + + /** + */ + private static boolean isQuote(char c) { + return (c == '"' || c == '\''); + } + + /** + */ + private static boolean isSpace(char c) { + return Character.isWhitespace(c); + } + + private int length = 0; + private int memOffset = 0; + private int offset = 0; + private boolean oneLine = false; + + private String tag = null; + + /** + */ + public TagScanner(String tag, int offset) { + super(); + + this.tag = tag; + this.offset = offset; + this.memOffset = -1; + if (tag != null) + this.length = tag.length(); + } + + /** + */ + public TagScanner(String tag, int offset, boolean oneLine) { + this(tag, offset); + + this.oneLine = oneLine; + } + + /** + */ + public int getNextOffset() { + int i; + char c; + for (i = offset; i < length; i++) { + c = tag.charAt(i); + if (isEnd(c)) + break; + if (isQuote(c)) { + i++; + break; + } + if (!isSpace(c) && !isEqual(c)) + break; + } + return i; + } + + /** + */ + public int getOffset() { + return this.memOffset; + } + + /** + */ + private final boolean isEnd(char c) { + return (this.oneLine && (c == '\r' || c == '\n')); + } + + /** + */ + public boolean isNewLine() { + if (oneLine) + return false; + char c; + for (int i = memOffset - 1; 0 <= i; i--) { + c = tag.charAt(i); + if (c == '\r' || c == '\n') + return true; + if (!isSpace(c)) + return false; + } + return false; + } + + /** + */ + private char nextChar() { + for (; this.offset < this.length; this.offset++) { + char c = this.tag.charAt(this.offset); + if (isEnd(c)) + break; + if (!isSpace(c)) + return c; + } + return 0; + } + + /** + */ + public String nextName() { + if (this.tag == null) + return null; + if (this.offset >= this.length) + return null; + + if (nextChar() == 0) + return null; + + int nameOffset = this.offset; + for (; this.offset < this.length; this.offset++) { + char c = this.tag.charAt(this.offset); + if (isEnd(c) || isSpace(c)) + break; + if (isEqual(c) && this.offset > nameOffset) + break; + } + if (this.offset == nameOffset) + return null; + + this.memOffset = nameOffset; + return this.tag.substring(nameOffset, this.offset); + } + + /** + */ + public String nextValue() { + if (this.tag == null) + return null; + if (this.offset >= this.length) + return null; + + char seperator = nextChar(); + if (!isEqual(seperator)) + return null; + this.offset++; // skip '=' + char quote = nextChar(); + if (quote == 0) + return null; + if (isQuote(quote)) + this.offset++; + else + quote = 0; + + int valueOffset = this.offset; + for (; this.offset < this.length; this.offset++) { + char c = this.tag.charAt(this.offset); + if (isEnd(c)) { + quote = 0; + break; + } + if (quote == 0) { + if (isSpace(c)) + break; + } else { + if (c == quote) + break; + } + } + int valueEnd = this.offset; + if (quote != 0 && this.offset < this.length) + this.offset++; + if (valueEnd == valueOffset) + return null; + + this.memOffset = valueOffset; + return this.tag.substring(valueOffset, valueEnd); + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/contenttype/ContentDescriberForXML.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/contenttype/ContentDescriberForXML.java new file mode 100644 index 0000000000..a78089e004 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/contenttype/ContentDescriberForXML.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.contenttype; + +import org.eclipse.core.runtime.content.ITextContentDescriber; +import org.eclipse.wst.common.encoding.AbstractContentDescriber; +import org.eclipse.wst.common.encoding.IResourceCharsetDetector; + + +public class ContentDescriberForXML extends AbstractContentDescriber implements ITextContentDescriber { + protected IResourceCharsetDetector getDetector() { + return new XMLResourceEncodingDetector(); + } + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/contenttype/XMLHeadTokenizer.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/contenttype/XMLHeadTokenizer.java new file mode 100644 index 0000000000..35ca57cf57 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/contenttype/XMLHeadTokenizer.java @@ -0,0 +1,1226 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +/* The following code was generated by JFlex 1.2.2 on 4/6/04 11:13 PM */ + +/*nlsXXX*/ +package org.eclipse.wst.xml.core.contenttype; + +import java.io.IOException; +import java.io.Reader; + +import org.eclipse.wst.common.encoding.IntStack; +import org.eclipse.wst.xml.core.internal.contenttype.EncodingParserConstants; +import org.eclipse.wst.xml.core.internal.contenttype.HeadParserToken; + + + +/** + * This class is a scanner generated by <a + * href="http://www.informatik.tu-muenchen.de/~kleing/jflex/">JFlex </a> 1.2.2 + * on 4/6/04 11:13 PM from the specification file + * <tt>file:/D:/DevTimeSupport/HeadParsers/XMLHeadTokenizer/XMLHeadTokenizer.jflex</tt> + */ +public class XMLHeadTokenizer { + + /** this character denotes the end of file */ + final public static int YYEOF = -1; + + /** lexical states */ + final public static int YYINITIAL = 0; + final public static int UnDelimitedString = 10; + final public static int DQ_STRING = 6; + final public static int SQ_STRING = 8; + final public static int ST_XMLDecl = 2; + final public static int QuotedAttributeValue = 4; + + /** + * YY_LEXSTATE[l] is the state in the DFA for the lexical state l + * YY_LEXSTATE[l+1] is the state in the DFA for the lexical state l at the + * beginning of a line l is of the form l = 2*k, k a non negative integer + */ + private final static int YY_LEXSTATE[] = {0, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6}; + + /** + * Translates characters to character classes + */ + final private static String yycmap_packed = "\11\0\1\6\1\7\2\0\1\11\22\0\1\6\1\0\1\27\2\0" + "\1\31\1\0\1\30\24\0\1\12\1\10\1\26\1\13\3\0\1\21" + "\1\23\1\17\1\0\1\25\1\0\1\24\2\0\1\16\1\15\1\20" + "\1\22\10\0\1\14\12\0\1\21\1\23\1\17\1\0\1\25\1\0" + "\1\24\2\0\1\16\1\15\1\20\1\22\10\0\1\14\102\0\1\4" + "\3\0\1\5\17\0\1\3\16\0\1\1\20\0\1\3\16\0\1\1" + "\1\2\170\0\1\2\ufe87\0"; //$NON-NLS-2$//$NON-NLS-3$ + + /** + * Translates characters to character classes + */ + final private static char[] yycmap = yy_unpack_cmap(yycmap_packed); + + + /* error codes */ + final private static int YY_UNKNOWN_ERROR = 0; + final private static int YY_ILLEGAL_STATE = 1; + final private static int YY_NO_MATCH = 2; + final private static int YY_PUSHBACK_2BIG = 3; + + /* error messages for the codes above */ + final private static String YY_ERROR_MSG[] = {"Unkown internal scanner error", "Internal error: unknown state", "Error: could not match input", "Error: pushback value was too large"}; + + /** the input device */ + private java.io.Reader yy_reader; + + /** the current state of the DFA */ + private int yy_state; + + /** the current lexical state */ + private int yy_lexical_state = YYINITIAL; + + /** + * this buffer contains the current text to be matched and is the source + * of the yytext() string + */ + private char yy_buffer[] = new char[16384]; + + /** the textposition at the last accepting state */ + private int yy_markedPos; + + /** the textposition at the last state to be included in yytext */ + private int yy_pushbackPos; + + /** the current text position in the buffer */ + private int yy_currentPos; + + /** startRead marks the beginning of the yytext() string in the buffer */ + private int yy_startRead; + + /** + * endRead marks the last character in the buffer, that has been read from + * input + */ + private int yy_endRead; + + /** number of newlines encountered up to the start of the matched text */ + // future_TODO: remove from skeleton + // private int yyline; + /** the number of characters up to the start of the matched text */ + private int yychar; + + /** + * the number of characters from the last newline up to the start of the + * matched text + */ + // future_TODO: remove from skeleton + //private int yycolumn; + /** + * yy_atBOL == true <=>the scanner is currently at the beginning of a line + */ + private boolean yy_atBOL; + + /** yy_atEOF == true <=>the scanner has returned a value for EOF */ + private boolean yy_atEOF; + + /** denotes if the user-EOF-code has already been executed */ + private boolean yy_eof_done; + + /* user code: */ + + + private boolean hasMore = true; + private final static int MAX_TO_SCAN = 1000; + StringBuffer string = new StringBuffer(); + // state stack for easier state handling + private IntStack fStateStack = new IntStack(); + private String valueText = null; + + + public XMLHeadTokenizer() { + super(); + } + + public void reset(Reader in) { + /* the input device */ + yy_reader = in; + + /* the current state of the DFA */ + yy_state = 0; + + /* the current lexical state */ + yy_lexical_state = YYINITIAL; + + /* + * this buffer contains the current text to be matched and is the + * source of the yytext() string + */ + java.util.Arrays.fill(yy_buffer, (char) 0); + + /* the textposition at the last accepting state */ + yy_markedPos = 0; + + /* the textposition at the last state to be included in yytext */ + yy_pushbackPos = 0; + + /* the current text position in the buffer */ + yy_currentPos = 0; + + /* startRead marks the beginning of the yytext() string in the buffer */ + yy_startRead = 0; + + /** + * endRead marks the last character in the buffer, that has been read + * from input + */ + yy_endRead = 0; + + /* number of newlines encountered up to the start of the matched text */ + // future_TODO: remove from skeleton + //yyline = 0; + /* the number of characters up to the start of the matched text */ + yychar = 0; + + /** + * the number of characters from the last newline up to the start of + * the matched text + */ + // future_TODO: remove from skeleton + //yycolumn = 0; + /** + * yy_atBOL == true <=>the scanner is currently at the beginning of a + * line + */ + yy_atBOL = false; + + /* yy_atEOF == true <=> the scanner has returned a value for EOF */ + yy_atEOF = false; + + /* denotes if the user-EOF-code has already been executed */ + yy_eof_done = false; + + + fStateStack.clear(); + + hasMore = true; + + // its a little wasteful to "throw away" first char array generated + // by class init (via auto generated code), but we really do want + // a small buffer for our head parsers. + if (yy_buffer.length != MAX_TO_SCAN) { + yy_buffer = new char[MAX_TO_SCAN]; + } + + + } + + + public final HeadParserToken getNextToken() throws IOException { + String context = null; + context = primGetNextToken(); + HeadParserToken result = null; + if (valueText != null) { + result = createToken(context, yychar, valueText); + valueText = null; + } else { + result = createToken(context, yychar, yytext()); + } + return result; + } + + public final boolean hasMoreTokens() { + return hasMore && yychar < MAX_TO_SCAN; + } + + private void pushCurrentState() { + fStateStack.push(yystate()); + + } + + private void popState() { + yybegin(fStateStack.pop()); + } + + private HeadParserToken createToken(String context, int start, String text) { + return new HeadParserToken(context, start, text); + } + + + + /** + * Creates a new scanner There is also a java.io.InputStream version of + * this constructor. + * + * @param in + * the java.io.Reader to read input from. + */ + public XMLHeadTokenizer(java.io.Reader in) { + this.yy_reader = in; + } + + /** + * Creates a new scanner. There is also java.io.Reader version of this + * constructor. + * + * @param in + * the java.io.Inputstream to read input from. + */ + public XMLHeadTokenizer(java.io.InputStream in) { + this(new java.io.InputStreamReader(in)); + } + + /** + * Unpacks the compressed character translation table. + * + * @param packed + * the packed character translation table + * @return the unpacked character translation table + */ + private static char[] yy_unpack_cmap(String packed) { + char[] map = new char[0x10000]; + int i = 0; /* index in packed string */ + int j = 0; /* index in unpacked array */ + while (i < 128) { + int count = packed.charAt(i++); + char value = packed.charAt(i++); + do + map[j++] = value; + while (--count > 0); + } + return map; + } + + + /** + * Gets the next input character. + * + * @return the next character of the input stream, EOF if the end of the + * stream is reached. + * @exception IOException + * if any I/O-Error occurs + */ + private int yy_advance() throws java.io.IOException { + + /* standard case */ + if (yy_currentPos < yy_endRead) + return yy_buffer[yy_currentPos++]; + + /* if the eof is reached, we don't need to work hard */ + if (yy_atEOF) + return YYEOF; + + /* otherwise: need to refill the buffer */ + + /* first: make room (if you can) */ + if (yy_startRead > 0) { + System.arraycopy(yy_buffer, yy_startRead, yy_buffer, 0, yy_endRead - yy_startRead); + + /* translate stored positions */ + yy_endRead -= yy_startRead; + yy_currentPos -= yy_startRead; + yy_markedPos -= yy_startRead; + yy_pushbackPos -= yy_startRead; + yy_startRead = 0; + } + + /* is the buffer big enough? */ + if (yy_currentPos >= yy_buffer.length) { + /* if not: blow it up */ + char newBuffer[] = new char[yy_currentPos * 2]; + System.arraycopy(yy_buffer, 0, newBuffer, 0, yy_buffer.length); + yy_buffer = newBuffer; + } + + /* finally: fill the buffer with new input */ + int numRead = yy_reader.read(yy_buffer, yy_endRead, yy_buffer.length - yy_endRead); + + if (numRead == -1) + return YYEOF; + + yy_endRead += numRead; + + return yy_buffer[yy_currentPos++]; + } + + + /** + * Closes the input stream. + */ + final public void yyclose() throws java.io.IOException { + yy_atEOF = true; /* indicate end of file */ + yy_endRead = yy_startRead; /* invalidate buffer */ + yy_reader.close(); + } + + + /** + * Returns the current lexical state. + */ + final public int yystate() { + return yy_lexical_state; + } + + /** + * Enters a new lexical state + * + * @param newState + * the new lexical state + */ + final public void yybegin(int newState) { + yy_lexical_state = newState; + } + + + /** + * Returns the text matched by the current regular expression. + */ + final public String yytext() { + return new String(yy_buffer, yy_startRead, yy_markedPos - yy_startRead); + } + + /** + * Returns the length of the matched text region. + */ + final public int yylength() { + return yy_markedPos - yy_startRead; + } + + + /** + * Reports an error that occured while scanning. + * + * @param errorCode + * the code of the errormessage to display + */ + private void yy_ScanError(int errorCode) { + try { + System.out.println(YY_ERROR_MSG[errorCode]); + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println(YY_ERROR_MSG[YY_UNKNOWN_ERROR]); + } + + // System.exit(1); + } + + + /** + * Pushes the specified amount of characters back into the input stream. + * + * They will be read again by then next call of the scanning method + * + * @param number + * the number of characters to be read again. This number must + * not be greater than yylength()! + */ + private void yypushback(int number) { + if (number > yylength()) + yy_ScanError(YY_PUSHBACK_2BIG); + + yy_markedPos -= number; + } + + + /** + * Contains user EOF-code, which will be executed exactly once, when the + * end of file is reached + */ + private void yy_do_eof() { + if (!yy_eof_done) { + yy_eof_done = true; + hasMore = false; + + } + } + + + /** + * Resumes scanning until the next regular expression is matched, the end + * of input is encountered or an I/O-Error occurs. + * + * @return the next token + * @exception IOException + * if any I/O-Error occurs + */ + public String primGetNextToken() throws java.io.IOException { + int yy_input; + int yy_action; + + + while (true) { + + yychar += yylength(); + + yy_atBOL = yy_markedPos <= 0 || yy_buffer[yy_markedPos - 1] == '\n'; + if (!yy_atBOL && yy_buffer[yy_markedPos - 1] == '\r') { + yy_atBOL = yy_advance() != '\n'; + if (!yy_atEOF) + yy_currentPos--; + } + + yy_action = -1; + + yy_currentPos = yy_startRead = yy_markedPos; + + if (yy_atBOL) + yy_state = YY_LEXSTATE[yy_lexical_state + 1]; + else + yy_state = YY_LEXSTATE[yy_lexical_state]; + + + yy_forAction : { + while (true) { + + yy_input = yy_advance(); + + if (yy_input == YYEOF) + break yy_forAction; + + yy_input = yycmap[yy_input]; + + boolean yy_isFinal = false; + boolean yy_noLookAhead = false; + + yy_forNext : { + switch (yy_state) { + case 0 : + switch (yy_input) { + default : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 7; + break yy_forNext; + } + + case 1 : + switch (yy_input) { + case 1 : + yy_isFinal = true; + yy_state = 8; + break yy_forNext; + case 2 : + yy_isFinal = true; + yy_state = 9; + break yy_forNext; + case 3 : + yy_isFinal = true; + yy_state = 10; + break yy_forNext; + case 6 : + case 7 : + case 9 : + yy_isFinal = true; + yy_state = 11; + break yy_forNext; + case 10 : + yy_isFinal = true; + yy_state = 12; + break yy_forNext; + default : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 7; + break yy_forNext; + } + + case 2 : + switch (yy_input) { + case 11 : + yy_isFinal = true; + yy_state = 13; + break yy_forNext; + case 15 : + yy_isFinal = true; + yy_state = 14; + break yy_forNext; + default : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 7; + break yy_forNext; + } + + case 3 : + switch (yy_input) { + case 6 : + case 9 : + yy_isFinal = true; + yy_state = 16; + break yy_forNext; + case 7 : + yy_isFinal = true; + yy_state = 17; + break yy_forNext; + case 23 : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 18; + break yy_forNext; + case 24 : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 19; + break yy_forNext; + default : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 15; + break yy_forNext; + } + + case 4 : + switch (yy_input) { + case 7 : + case 9 : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 21; + break yy_forNext; + case 11 : + yy_isFinal = true; + yy_state = 22; + break yy_forNext; + case 23 : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 23; + break yy_forNext; + case 24 : + yy_isFinal = true; + yy_state = 24; + break yy_forNext; + default : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 20; + break yy_forNext; + } + + case 5 : + switch (yy_input) { + case 7 : + case 9 : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 21; + break yy_forNext; + case 24 : + yy_isFinal = true; + yy_state = 25; + break yy_forNext; + case 25 : + yy_isFinal = true; + yy_state = 26; + break yy_forNext; + default : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 20; + break yy_forNext; + } + + case 6 : + switch (yy_input) { + case 11 : + yy_isFinal = true; + yy_state = 26; + break yy_forNext; + case 6 : + case 7 : + case 9 : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 27; + break yy_forNext; + case 23 : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 28; + break yy_forNext; + case 24 : + yy_isFinal = true; + yy_state = 29; + break yy_forNext; + default : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 20; + break yy_forNext; + } + + case 8 : + switch (yy_input) { + case 2 : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 30; + break yy_forNext; + default : + break yy_forAction; + } + + case 9 : + switch (yy_input) { + case 1 : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 31; + break yy_forNext; + default : + break yy_forAction; + } + + case 10 : + switch (yy_input) { + case 4 : + yy_state = 32; + break yy_forNext; + default : + break yy_forAction; + } + + case 11 : + switch (yy_input) { + case 6 : + case 7 : + case 9 : + yy_state = 33; + break yy_forNext; + case 10 : + yy_state = 34; + break yy_forNext; + default : + break yy_forAction; + } + + case 12 : + switch (yy_input) { + case 11 : + yy_state = 35; + break yy_forNext; + default : + break yy_forAction; + } + + case 13 : + switch (yy_input) { + case 22 : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 36; + break yy_forNext; + default : + break yy_forAction; + } + + case 14 : + switch (yy_input) { + case 16 : + yy_state = 37; + break yy_forNext; + default : + break yy_forAction; + } + + case 16 : + switch (yy_input) { + case 6 : + case 9 : + yy_isFinal = true; + yy_state = 16; + break yy_forNext; + case 7 : + yy_state = 38; + break yy_forNext; + default : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 15; + break yy_forNext; + } + + case 17 : + switch (yy_input) { + case 6 : + case 9 : + yy_isFinal = true; + yy_state = 16; + break yy_forNext; + case 7 : + yy_state = 38; + break yy_forNext; + default : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 15; + break yy_forNext; + } + + case 22 : + switch (yy_input) { + case 22 : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 39; + break yy_forNext; + default : + break yy_forAction; + } + + case 24 : + switch (yy_input) { + case 10 : + yy_state = 40; + break yy_forNext; + default : + break yy_forAction; + } + + case 25 : + switch (yy_input) { + case 10 : + yy_state = 40; + break yy_forNext; + default : + break yy_forAction; + } + + case 26 : + switch (yy_input) { + case 22 : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 41; + break yy_forNext; + default : + break yy_forAction; + } + + case 29 : + switch (yy_input) { + case 10 : + yy_state = 40; + break yy_forNext; + default : + break yy_forAction; + } + + case 32 : + switch (yy_input) { + case 5 : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 42; + break yy_forNext; + default : + break yy_forAction; + } + + case 33 : + switch (yy_input) { + case 6 : + case 7 : + case 9 : + yy_state = 33; + break yy_forNext; + case 10 : + yy_state = 34; + break yy_forNext; + default : + break yy_forAction; + } + + case 34 : + switch (yy_input) { + case 11 : + yy_state = 35; + break yy_forNext; + default : + break yy_forAction; + } + + case 35 : + switch (yy_input) { + case 12 : + yy_state = 43; + break yy_forNext; + default : + break yy_forAction; + } + + case 37 : + switch (yy_input) { + case 17 : + yy_state = 44; + break yy_forNext; + default : + break yy_forAction; + } + + case 38 : + switch (yy_input) { + case 6 : + case 9 : + yy_isFinal = true; + yy_state = 16; + break yy_forNext; + case 7 : + yy_state = 38; + break yy_forNext; + default : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 15; + break yy_forNext; + } + + case 40 : + switch (yy_input) { + case 24 : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 21; + break yy_forNext; + default : + break yy_forAction; + } + + case 43 : + switch (yy_input) { + case 13 : + yy_state = 45; + break yy_forNext; + default : + break yy_forAction; + } + + case 44 : + switch (yy_input) { + case 18 : + yy_state = 46; + break yy_forNext; + default : + break yy_forAction; + } + + case 45 : + switch (yy_input) { + case 14 : + yy_state = 47; + break yy_forNext; + default : + break yy_forAction; + } + + case 46 : + switch (yy_input) { + case 19 : + yy_state = 48; + break yy_forNext; + default : + break yy_forAction; + } + + case 47 : + switch (yy_input) { + case 6 : + case 7 : + case 9 : + yy_isFinal = true; + yy_state = 49; + break yy_forNext; + default : + break yy_forAction; + } + + case 48 : + switch (yy_input) { + case 20 : + yy_state = 50; + break yy_forNext; + default : + break yy_forAction; + } + + case 49 : + switch (yy_input) { + case 6 : + case 7 : + case 9 : + yy_isFinal = true; + yy_state = 49; + break yy_forNext; + default : + break yy_forAction; + } + + case 50 : + switch (yy_input) { + case 16 : + yy_state = 51; + break yy_forNext; + default : + break yy_forAction; + } + + case 51 : + switch (yy_input) { + case 21 : + yy_state = 52; + break yy_forNext; + default : + break yy_forAction; + } + + case 52 : + switch (yy_input) { + case 6 : + case 7 : + case 9 : + yy_state = 52; + break yy_forNext; + case 8 : + yy_isFinal = true; + yy_state = 53; + break yy_forNext; + default : + break yy_forAction; + } + + case 53 : + switch (yy_input) { + case 6 : + case 7 : + case 9 : + yy_isFinal = true; + yy_state = 53; + break yy_forNext; + default : + break yy_forAction; + } + + default : + yy_ScanError(YY_ILLEGAL_STATE); + break; + } + } + + if (yy_isFinal) { + yy_action = yy_state; + yy_markedPos = yy_currentPos; + if (yy_noLookAhead) + break yy_forAction; + } + + } + } + + + switch (yy_action) { + + case 25 : { + popState(); + valueText = string.toString(); + return EncodingParserConstants.StringValue; + } + case 55 : + break; + case 21 : { + yypushback(1); + popState(); + valueText = string.toString(); + return EncodingParserConstants.InvalidTerminatedStringValue; + } + case 56 : + break; + case 15 : + case 16 : { + yypushback(1); + yybegin(UnDelimitedString); + string.setLength(0); + } + case 57 : + break; + case 28 : + case 29 : { + yypushback(1); + popState(); + valueText = string.toString(); + return EncodingParserConstants.InvalidTermintatedUnDelimitedStringValue; + } + case 58 : + break; + case 39 : { + yypushback(2); + popState(); + valueText = string.toString(); + return EncodingParserConstants.InvalidTerminatedStringValue; + } + case 59 : + break; + case 41 : { + yypushback(2); + popState(); + valueText = string.toString(); + return EncodingParserConstants.InvalidTerminatedStringValue; + } + case 60 : + break; + case 7 : + case 8 : + case 9 : + case 10 : + case 11 : + case 12 : + case 13 : + case 14 : + case 17 : { + if (yychar > MAX_TO_SCAN) { + hasMore = false; + return EncodingParserConstants.MAX_CHARS_REACHED; + } + } + case 61 : + break; + case 30 : { + if (yychar == 0) { + hasMore = false; + return EncodingParserConstants.UTF16BE; + } + } + case 62 : + break; + case 31 : { + if (yychar == 0) { + hasMore = false; + return EncodingParserConstants.UTF16LE; + } + } + case 63 : + break; + case 42 : { + if (yychar == 0) { + hasMore = false; + return EncodingParserConstants.UTF83ByteBOM; + } + } + case 64 : + break; + case 49 : { + if (yychar == 0) { + yybegin(ST_XMLDecl); + return XMLHeadTokenizerConstants.XMLDeclStart; + } + } + case 65 : + break; + case 36 : { + yybegin(YYINITIAL); + hasMore = false; + return XMLHeadTokenizerConstants.XMLDeclEnd; + } + case 66 : + break; + case 53 : { + pushCurrentState(); + yybegin(QuotedAttributeValue); + return XMLHeadTokenizerConstants.XMLDelEncoding; + } + case 67 : + break; + case 23 : { + popState(); + valueText = string.toString(); + return EncodingParserConstants.StringValue; + } + case 68 : + break; + case 20 : + case 22 : + case 24 : + case 26 : { + string.append(yytext()); + } + case 69 : + break; + case 19 : { + yybegin(SQ_STRING); + string.setLength(0); + } + case 70 : + break; + case 18 : { + yybegin(DQ_STRING); + string.setLength(0); + } + case 71 : + break; + case 27 : { + yypushback(1); + popState(); + valueText = string.toString(); + return EncodingParserConstants.UnDelimitedStringValue; + } + case 72 : + break; + default : + if (yy_input == YYEOF && yy_startRead == yy_currentPos) { + yy_atEOF = true; + yy_do_eof(); + { + hasMore = false; + return EncodingParserConstants.EOF; + } + } else { + yy_ScanError(YY_NO_MATCH); + } + } + } + } + + /** + * Runs the scanner on input files. + * + * This main method is the debugging routine for the scanner. It prints + * each returned token to System.out until the end of file is reached, or + * an error occured. + * + * @param argv + * the command line, contains the filenames to run the scanner + * on. + */ + public static void main(String argv[]) { + for (int i = 0; i < argv.length; i++) { + XMLHeadTokenizer scanner = null; + try { + scanner = new XMLHeadTokenizer(new java.io.FileReader(argv[i])); + } catch (java.io.FileNotFoundException e) { + System.out.println("File not found : \"" + argv[i] + "\""); + System.exit(1); + } + // catch (java.io.IOException e) { + // System.out.println("Error opening file \"" + argv[i] + "\""); + // System.exit(1); + // } + catch (ArrayIndexOutOfBoundsException e) { + System.out.println("Usage : java XMLHeadTokenizer <inputfile>"); + System.exit(1); + } + + try { + do { + System.out.println(scanner.primGetNextToken()); + } while (!scanner.yy_atEOF); + + } catch (java.io.IOException e) { + System.out.println("An I/O error occured while scanning :"); + System.out.println(e); + System.exit(1); + } catch (Exception e) { + e.printStackTrace(); + System.exit(1); + } + } + } + + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/contenttype/XMLHeadTokenizerConstants.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/contenttype/XMLHeadTokenizerConstants.java new file mode 100644 index 0000000000..1153d5fdfa --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/contenttype/XMLHeadTokenizerConstants.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.contenttype; + +import org.eclipse.wst.common.encoding.EncodingParserConstants;; + +public interface XMLHeadTokenizerConstants extends EncodingParserConstants { + + final String XMLDeclEnd = "XMLDeclEnd"; //$NON-NLS-1$ + final String XMLDeclStart = "XMLDeclStart"; //$NON-NLS-1$ + final String XMLDelEncoding = "XMLDelEncoding"; //$NON-NLS-1$ + // final String XMLDeclVersion = "XMLDeclVersion"; +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/contenttype/XMLResourceEncodingDetector.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/contenttype/XMLResourceEncodingDetector.java new file mode 100644 index 0000000000..0d9d0c75d1 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/contenttype/XMLResourceEncodingDetector.java @@ -0,0 +1,102 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.contenttype; + +import java.io.IOException; + +import org.eclipse.wst.common.encoding.AbstractResourceEncodingDetector; +import org.eclipse.wst.common.encoding.EncodingMemento; +import org.eclipse.wst.common.encoding.EncodingParserConstants; +import org.eclipse.wst.common.encoding.IResourceCharsetDetector; +import org.eclipse.wst.xml.core.internal.contenttype.HeadParserToken; + + +public class XMLResourceEncodingDetector extends AbstractResourceEncodingDetector implements IResourceCharsetDetector { + private XMLHeadTokenizer fTokenizer; + + private boolean canHandleAsUnicodeStream(String tokenType) { + boolean canHandleAsUnicodeStream = false; + if (tokenType == EncodingParserConstants.UTF83ByteBOM) { + canHandleAsUnicodeStream = true; + String enc = "UTF-8"; //$NON-NLS-1$ + createEncodingMemento(enc, EncodingMemento.DETECTED_STANDARD_UNICODE_BYTES); + fEncodingMemento.setUTF83ByteBOMUsed(true); + } + + else if (tokenType == EncodingParserConstants.UTF16BE) { + canHandleAsUnicodeStream = true; + String enc = "UTF-16BE"; //$NON-NLS-1$ + createEncodingMemento(enc, EncodingMemento.DETECTED_STANDARD_UNICODE_BYTES); + } else if (tokenType == EncodingParserConstants.UTF16LE) { + canHandleAsUnicodeStream = true; + String enc = "UTF-16"; //$NON-NLS-1$ + createEncodingMemento(enc, EncodingMemento.DETECTED_STANDARD_UNICODE_BYTES); + } + return canHandleAsUnicodeStream; + } + + public String getSpecDefaultEncoding() { + // by default, UTF-8 as per XML spec + final String enc = "UTF-8"; //$NON-NLS-1$ + return enc; + } + + /** + * @return Returns the tokenizer. + */ + private XMLHeadTokenizer getTokenizer() { + // TODO: need to work on 'reset' in tokenizer, so new instance isn't + // always needed + //if (fTokenizer == null) { + fTokenizer = new XMLHeadTokenizer(); + //} + return fTokenizer; + } + + private boolean isLegalString(String valueTokenType) { + if (valueTokenType == null) + return false; + else + return valueTokenType.equals(EncodingParserConstants.StringValue) || valueTokenType.equals(EncodingParserConstants.UnDelimitedStringValue) || valueTokenType.equals(EncodingParserConstants.InvalidTerminatedStringValue) || valueTokenType.equals(EncodingParserConstants.InvalidTermintatedUnDelimitedStringValue); + } + + protected void parseInput() throws IOException { + XMLHeadTokenizer tokenizer = getTokenizer(); + tokenizer.reset(fReader); + HeadParserToken token = null; + String tokenType = null; + do { + token = tokenizer.getNextToken(); + tokenType = token.getType(); + if (canHandleAsUnicodeStream(tokenType)) { + // side effect of canHandle is to create appropriate memento + } else { + if (tokenType == XMLHeadTokenizerConstants.XMLDelEncoding) { + if (tokenizer.hasMoreTokens()) { + token = tokenizer.getNextToken(); + tokenType = token.getType(); + if (isLegalString(tokenType)) { + String enc = token.getText(); + if (enc != null && enc.length() > 0) { + createEncodingMemento(enc, EncodingMemento.FOUND_ENCODING_IN_CONTENT); + } + + } + } + } + } + } while (tokenizer.hasMoreTokens()); + + } + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/DocumentLoaderForXML.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/DocumentLoaderForXML.java new file mode 100644 index 0000000000..0561e4c0f2 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/DocumentLoaderForXML.java @@ -0,0 +1,131 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.document; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.io.UnsupportedEncodingException; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jface.text.IDocumentPartitioner; +import org.eclipse.wst.common.encoding.CodedReaderCreator; +import org.eclipse.wst.common.encoding.EncodingMemento; +import org.eclipse.wst.common.encoding.EncodingRule; +import org.eclipse.wst.sse.core.document.IDocumentCharsetDetector; +import org.eclipse.wst.sse.core.document.IDocumentLoader; +import org.eclipse.wst.sse.core.document.IDocumentLoaderForFileBuffers; +import org.eclipse.wst.sse.core.document.IEncodedDocument; +import org.eclipse.wst.sse.core.document.StructuredDocumentLoader; +import org.eclipse.wst.xml.core.encoding.XMLDocumentCharsetDetector; +import org.eclipse.wst.xml.core.internal.filebuffers.DocumentFactoryForXML; +import org.eclipse.wst.xml.core.text.rules.StructuredTextPartitionerForXML; + + + +public class DocumentLoaderForXML extends StructuredDocumentLoader implements IDocumentLoader, IDocumentLoaderForFileBuffers { + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.core.document.IDocumentLoader#createNewStructuredDocument() + */ + public IEncodedDocument createNewStructuredDocument() { + DocumentFactoryForXML factory = new DocumentFactoryForXML(); + IEncodedDocument document = (IEncodedDocument) factory.createDocument(); + return document; + } + + public IEncodedDocument createNewStructuredDocument(Reader reader) throws UnsupportedEncodingException, IOException { + IEncodedDocument structuredDocument = createNewStructuredDocument(); + StringBuffer allText = readInputStream(reader); + structuredDocument.set(allText.toString()); + return structuredDocument; + + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.core.document.IDocumentLoader#createNewStructuredDocument(java.lang.String, + * java.io.InputStream) + */ + public IEncodedDocument createNewStructuredDocument(String filename, InputStream inputStream) throws IOException { + return createNewStructuredDocument(filename, inputStream, EncodingRule.CONTENT_BASED); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.core.document.IDocumentLoader#createNewStructuredDocument(java.lang.String, + * java.io.InputStream, com.ibm.encoding.resource.EncodingRule) + */ + public IEncodedDocument createNewStructuredDocument(String filename, InputStream inputStream, EncodingRule encodingRule) throws IOException { + if (filename == null && inputStream == null) { + throw new IllegalArgumentException("can not have both null filename and inputstream"); //$NON-NLS-1$ + } + CodedReaderCreator codedReaderCreator = new CodedReaderCreator(); + Reader fullPreparedReader = null; + IEncodedDocument structuredDocument = createNewStructuredDocument(); + try { + codedReaderCreator.set(filename, inputStream); + codedReaderCreator.setEncodingRule(encodingRule); + EncodingMemento encodingMemento = codedReaderCreator.getEncodingMemento(); + fullPreparedReader = codedReaderCreator.getCodedReader(); + structuredDocument.setEncodingMemento(encodingMemento); + StringBuffer allText = readInputStream(fullPreparedReader); + structuredDocument.set(allText.toString()); + } catch (CoreException e) { + // impossible in this context + throw new Error(e); + } finally { + if (fullPreparedReader != null) { + fullPreparedReader.close(); + } + } + + return structuredDocument; + } + + + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.core.document.IDocumentLoader#getDefaultDocumentPartitioner() + */ + public IDocumentPartitioner getDefaultDocumentPartitioner() { + return new StructuredTextPartitionerForXML(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.core.document.IDocumentLoader#getDocumentEncodingDetector() + */ + public IDocumentCharsetDetector getDocumentEncodingDetector() { + return new XMLDocumentCharsetDetector(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.core.document.IDocumentLoader#handleLineDelimiter(java.lang.StringBuffer, + * org.eclipse.wst.sse.core.document.IEncodedDocument) + */ + public StringBuffer handleLineDelimiter(StringBuffer originalString, IEncodedDocument theStructuredDocument) { + // TODO Auto-generated method stub + return originalString; + } + +} + diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/DocumentTypeAdapter.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/DocumentTypeAdapter.java new file mode 100644 index 0000000000..285ad87906 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/DocumentTypeAdapter.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.document; + + + +import org.eclipse.wst.sse.core.INodeAdapter; +import org.w3c.dom.DocumentType; + + +/** + */ +public interface DocumentTypeAdapter extends INodeAdapter { + static final int LOWER_CASE = 2; + static final int STRICT_CASE = 0; + static final int UPPER_CASE = 1; + + /** + */ + int getAttrNameCase(); + + /** + */ + DocumentType getDocumentType(); + + /** + */ + int getTagNameCase(); + + /** + */ + boolean hasFeature(String feature); + + /** + */ + boolean isXMLType(); + + /** + */ + void release(); +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/InvalidCharacterException.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/InvalidCharacterException.java new file mode 100644 index 0000000000..e0a7add83d --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/InvalidCharacterException.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.document; + + + +/** + * Thrown an invalid character is specified in : XMLNode#setSource(String) + */ +public class InvalidCharacterException extends Exception { + + private char invalidChar = 0; + private int offset = -1; + + /** + */ + public InvalidCharacterException() { + super(); + } + + /** + */ + public InvalidCharacterException(String s) { + super(s); + } + + /** + */ + public InvalidCharacterException(String s, char c) { + super(s); + this.invalidChar = c; + } + + /** + */ + public InvalidCharacterException(String s, char c, int offset) { + super(s); + this.invalidChar = c; + this.offset = offset; + } + + /** + */ + public char getInvalidChar() { + return this.invalidChar; + } + + /** + */ + public int getOffset() { + return this.offset; + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/JSPTag.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/JSPTag.java new file mode 100644 index 0000000000..b4398d9fa0 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/JSPTag.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.document; + + + +/** + * JSPTag interface + */ +public interface JSPTag { + static final String COMMENT_CLOSE = "--%>";//$NON-NLS-1$ + static final String COMMENT_OPEN = "<%--";//$NON-NLS-1$ + static final String DECLARATION_TOKEN = "!";//$NON-NLS-1$ + static final String DIRECTIVE_TOKEN = "@";//$NON-NLS-1$ + static final String EXPRESSION_TOKEN = "=";//$NON-NLS-1$ + static final String JSP_DECLARATION = "jsp:declaration";//$NON-NLS-1$ + static final String JSP_DIRECTIVE = "jsp:directive";//$NON-NLS-1$ + static final String JSP_EXPRESSION = "jsp:expression";//$NON-NLS-1$ + static final String JSP_ROOT = "jsp:root";//$NON-NLS-1$ + + static final String JSP_SCRIPTLET = "jsp:scriptlet";//$NON-NLS-1$ + static final String TAG_CLOSE = "%>";//$NON-NLS-1$ + static final String TAG_OPEN = "<%";//$NON-NLS-1$ +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/TagAdapter.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/TagAdapter.java new file mode 100644 index 0000000000..1c7d0c4f37 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/TagAdapter.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.document; + + + +import org.eclipse.wst.sse.core.INodeAdapter; + +/** + */ +public interface TagAdapter extends INodeAdapter { + + /** + */ + String getEndTag(XMLElement element); + + /** + */ + String getStartTag(XMLElement element); + + /** + */ + boolean isEndTag(); +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLAttr.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLAttr.java new file mode 100644 index 0000000000..60b804141b --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLAttr.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.document; + + + +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.w3c.dom.Attr; + + +/** + */ +public interface XMLAttr extends XMLNode, Attr { + + /** + */ + ITextRegion getEqualRegion(); + + /** + * @return + */ + int getNameRegionEndOffset(); + + int getNameRegionStartOffset(); + + String getNameRegionText(); + + /** + * @return + */ + int getNameRegionTextEndOffset(); + + int getValueRegionStartOffset(); + + String getValueRegionText(); + + /** + * Check if Attr has JSP in value + */ + boolean hasJSPValue(); + + /** + * Check if Attr has only name but not equal sign nor value + */ + boolean hasNameOnly(); + + /** + */ + boolean isGlobalAttr(); + + /** + */ + boolean isXMLAttr(); + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLCharEntity.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLCharEntity.java new file mode 100644 index 0000000000..d1984d9fa0 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLCharEntity.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.document; + + + +/** + * XML Namespace constants + */ +public interface XMLCharEntity { + static final String AMP_NAME = "amp";//$NON-NLS-1$ + static final String AMP_REF = "&";//$NON-NLS-1$ + static final String AMP_VALUE = "&";//$NON-NLS-1$ + static final String APOS_NAME = "apos";//$NON-NLS-1$ + static final String APOS_REF = "'";//$NON-NLS-1$ + static final String APOS_VALUE = "'";//$NON-NLS-1$ + static final String GT_NAME = "gt";//$NON-NLS-1$ + static final String GT_REF = ">";//$NON-NLS-1$ + static final String GT_VALUE = ">";//$NON-NLS-1$ + + static final String LT_NAME = "lt";//$NON-NLS-1$ + static final String LT_REF = "<";//$NON-NLS-1$ + static final String LT_VALUE = "<";//$NON-NLS-1$ + static final String QUOT_NAME = "quot";//$NON-NLS-1$ + static final String QUOT_REF = """;//$NON-NLS-1$ + static final String QUOT_VALUE = "\"";//$NON-NLS-1$ +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLDocument.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLDocument.java new file mode 100644 index 0000000000..a461cab1a7 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLDocument.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.document; + + + +import org.w3c.dom.DOMException; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.Element; +import org.w3c.dom.ranges.DocumentRange; +import org.w3c.dom.traversal.DocumentTraversal; + +/** + * This interface enables creation of DOCTYPE declaration and some DOM Level 2 + * interfaces. + */ +public interface XMLDocument extends XMLNode, Document, DocumentRange, DocumentTraversal { + + /** + * create comment element. tagName must be registered as comment element + * name in plugin.xml + * + * @param tagName + * the element name + * @param isJSPTag + * true if the element is JSP style comment (<%-- ... + * --%>) + * @return Element element instance + * @throws DOMException + * throwed if the element name is registered as comment + * element + */ + Element createCommentElement(String tagName, boolean isJSPTag) throws DOMException; + + /** + */ + DocumentType createDoctype(String name); + + /** + */ + String getDocumentTypeId(); + + /** + */ + boolean isJSPDocument(); + + /** + */ + boolean isJSPType(); + + /** + */ + boolean isXMLType(); + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLDocumentType.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLDocumentType.java new file mode 100644 index 0000000000..082d4ff41a --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLDocumentType.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.document; + + + +import org.w3c.dom.DocumentType; + +/** + * This interface enables setting of Public and System ID for DOCTYPE + * declaration. + */ +public interface XMLDocumentType extends XMLNode, DocumentType { + + /** + */ + void setPublicId(String publicId); + + /** + */ + void setSystemId(String systemId); +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLElement.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLElement.java new file mode 100644 index 0000000000..b983975138 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLElement.java @@ -0,0 +1,107 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.document; + + + +import org.w3c.dom.Element; + +/** + */ +public interface XMLElement extends XMLNode, Element { + + /** + * @deprecated this should probably not be public, but already implemented + */ + int getEndStartOffset(); + + /** + */ + String getEndTagName(); + + /** + * @deprecated this should probably not be public, but already implemented + * + */ + int getStartEndOffset(); + + /** + */ + boolean hasEndTag(); + + /** + */ + boolean hasStartTag(); + + /** + */ + boolean isCommentTag(); + + /** + * isEmptyTag method + * + * @return boolean + */ + boolean isEmptyTag(); + + /** + */ + boolean isEndTag(); + + /** + * Returns true for "global tag" (basically, without prefix) + */ + boolean isGlobalTag(); + + /** + * Returns true for no the start and the end tags + */ + boolean isImplicitTag(); + + /** + * isJSPTag method + * + * @return boolean + */ + boolean isJSPTag(); + + /** + */ + boolean isStartTagClosed(); + + /** + */ + boolean isXMLTag(); + + /** + * @deprecated this should probably not be public, but already implemented + */ + void notifyEndTagChanged(); + + /** + * @deprecated this should probably not be public, but already implemented + */ + void notifyStartTagChanged(); + + /** + */ + void setCommentTag(boolean isCommentTag); + + /** + */ + void setEmptyTag(boolean isEmptyTag); + + /** + */ + void setJSPTag(boolean isJSPTag); +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLGenerator.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLGenerator.java new file mode 100644 index 0000000000..5b9321bba0 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLGenerator.java @@ -0,0 +1,154 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.document; + + + +import org.w3c.dom.Attr; +import org.w3c.dom.CDATASection; +import org.w3c.dom.Comment; +import org.w3c.dom.DocumentType; +import org.w3c.dom.Element; +import org.w3c.dom.EntityReference; +import org.w3c.dom.Node; +import org.w3c.dom.ProcessingInstruction; +import org.w3c.dom.Text; + +public interface XMLGenerator { + + /** + */ + String generateAttrName(Attr attr); + + /** + */ + String generateAttrValue(Attr attr); + + /** + */ + String generateAttrValue(Attr attr, char quote); + + /** + */ + String generateAttrValue(String value, char quote); + + /** + * generateCDATASection method + * + * @return java.lang.String + * @param comment + * org.w3c.dom.CDATASection + */ + String generateCDATASection(CDATASection cdata); + + /** + * generateChild method + * + * @return java.lang.String + * @param org.w3c.dom.Node + */ + String generateChild(Node parentNode); + + /** + */ + String generateCloseTag(Node node); + + /** + * generateComment method + * + * @return java.lang.String + * @param comment + * org.w3c.dom.Comment + */ + String generateComment(Comment comment); + + /** + * generateDoctype method + * + * @return java.lang.String + * @param docType + * org.w3c.dom.DocumentType + */ + String generateDoctype(DocumentType docType); + + /** + * generateElement method + * + * @return java.lang.String + * @param element + * Element + */ + String generateElement(Element element); + + /** + * generateEndTag method + * + * @return java.lang.String + * @param element + * org.w3c.dom.Element + */ + String generateEndTag(Element element); + + /** + * generateEntityRef method + * + * @return java.lang.String + * @param entityRef + * org.w3c.dom.EntityReference + */ + String generateEntityRef(EntityReference entityRef); + + /** + * generatePI method + * + * @return java.lang.String + * @param pi + * org.w3c.dom.ProcessingInstruction + */ + String generatePI(ProcessingInstruction pi); + + /** + * generateSource method + * + * @return java.lang.String + * @param node + * org.w3c.dom.Node + */ + String generateSource(Node node); + + /** + * generateStartTag method + * + * @return java.lang.String + * @param element + * Element + */ + String generateStartTag(Element element); + + /** + */ + String generateTagName(Element element); + + /** + * generateText method + * + * @return java.lang.String + * @param text + * org.w3c.dom.Text + */ + String generateText(Text text); + + /** + */ + String generateTextData(Text text, String data); +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLModel.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLModel.java new file mode 100644 index 0000000000..f95cff4d25 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLModel.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.document; + +import org.eclipse.wst.sse.core.IStructuredModel; + + + +/** + */ +public interface XMLModel extends IStructuredModel { + + XMLDocument getDocument(); + + /** + */ + XMLGenerator getGenerator(); + + /** + */ + XMLModelNotifier getModelNotifier(); + + /** + */ + void setModelNotifier(XMLModelNotifier notifier); +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLModelNotifier.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLModelNotifier.java new file mode 100644 index 0000000000..1cee885546 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLModelNotifier.java @@ -0,0 +1,103 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.document; + + + +import org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +public interface XMLModelNotifier { + + /** + * attrReplaced method + * + * @param element + * org.w3c.dom.Element + * @param newAttr + * org.w3c.dom.Attr + * @param oldAttr + * org.w3c.dom.Attr + */ + void attrReplaced(Element element, Attr newAttr, Attr oldAttr); + + /** + */ + void beginChanging(); + + /** + */ + void beginChanging(boolean newModel); + + /** + * Cancel pending notifications. This is called in the context of + * "reinitialization" so is assumed ALL notifications can be safely + * canceled, assuming that once factories and adapters are re-initialized + * they will be re-notified as text is set in model, if still appropriate. + */ + void cancelPending(); + + /** + * childReplaced method + * + * @param parentNode + * org.w3c.dom.Node + * @param newChild + * org.w3c.dom.Node + * @param oldChild + * org.w3c.dom.Node + */ + void childReplaced(Node parentNode, Node newChild, Node oldChild); + + /** + */ + void editableChanged(Node node); + + /** + */ + void endChanging(); + + /** + */ + void endTagChanged(Element element); + + /** + */ + boolean hasChanged(); + + /** + */ + boolean isChanging(); + + /** + */ + void propertyChanged(Node node); + + /** + */ + void startTagChanged(Element element); + + /** + */ + void structureChanged(Node node); + + /** + * valueChanged method + * + * @param node + * org.w3c.dom.Node + */ + void valueChanged(Node node); + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLNamespace.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLNamespace.java new file mode 100644 index 0000000000..04188a6781 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLNamespace.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.document; + + + +/** + * XML Namespace constants + */ +public interface XMLNamespace { + + static final String XMLNS = "xmlns";//$NON-NLS-1$ + static final String XMLNS_PREFIX = "xmlns:";//$NON-NLS-1$ + static final String XMLNS_URI = "http://www.w3.org/2000/xmlns/";//$NON-NLS-1$ +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLNode.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLNode.java new file mode 100644 index 0000000000..b20058190c --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLNode.java @@ -0,0 +1,124 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.document; + + + +import org.eclipse.wst.sse.core.text.IStructuredDocument; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; + +/** + * A interface to make concept clearer, just to denote the combination of + * three other interfaces. + * + */ +public interface XMLNode extends org.eclipse.wst.sse.core.IndexedRegion, org.eclipse.wst.sse.core.INodeNotifier, org.w3c.dom.Node { + + /** + * + * @return com.ibm.sed.structuredDocument.IStructuredDocumentRegion + */ + IStructuredDocumentRegion getEndStructuredDocumentRegion(); + + /** + */ + IStructuredDocumentRegion getFirstStructuredDocumentRegion(); + + /** + */ + IStructuredDocumentRegion getLastStructuredDocumentRegion(); + + /** + */ + XMLModel getModel(); + + /** + */ + ITextRegion getNameRegion(); + + /** + */ + String getSource(); + + /** + * + * @return com.ibm.sed.structuredDocument.IStructuredDocumentRegion + */ + IStructuredDocumentRegion getStartStructuredDocumentRegion(); + + /** + * + * @return com.ibm.sed.structuredDocument.IStructuredDocument + */ + IStructuredDocument getStructuredDocument(); + + /** + */ + ITextRegion getValueRegion(); + + /** + */ + String getValueSource(); + + /** + * + * @return boolean Whether children of the element can be appended or + * removed. + */ + boolean isChildEditable(); + + /** + */ + boolean isClosed(); + + /** + * isContainer method + * + * @return boolean + */ + boolean isContainer(); + + /** + */ + boolean isDataEditable(); + + /** + */ + void setChildEditable(boolean editable); + + /** + */ + void setDataEditable(boolean editable); + + /** + * faster approach to set + */ + void setEditable(boolean editable, boolean deep); + + /** + * Sets the specified raw source to the Text node. Throws + * InvalidCharacterException when the specified raw source includes + * invalid characters, such as, ' <', '>' and '&'. Valid character + * entities, such as, "&lt;", are accepted. + */ + void setSource(String source) throws InvalidCharacterException; + + /** + * Sets the specified raw source to the Text or Attr node's value. When + * the specified raw source includes invalid characters, such as, ' <', + * '>' and '&', converts them. Valid character entities, such as, + * "&lt;", are accepted. + */ + void setValueSource(String source); +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLText.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLText.java new file mode 100644 index 0000000000..fe80a06a73 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/document/XMLText.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.document; + + + +import org.w3c.dom.Text; + +/** + */ +public interface XMLText extends XMLNode, Text { + + /** + * Appends the content of the text node + */ + void appendText(Text text); + + /** + * Inserts the content of the text node at the specified position + */ + void insertText(Text text, int offset); + + /** + */ + boolean isInvalid(); + + /** + */ + boolean isWhitespace(); +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/encoding/XMLDocumentCharsetDetector.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/encoding/XMLDocumentCharsetDetector.java new file mode 100644 index 0000000000..bdde4b27a0 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/encoding/XMLDocumentCharsetDetector.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.encoding; + +import org.eclipse.jface.text.IDocument; +import org.eclipse.wst.sse.core.document.DocumentReader; +import org.eclipse.wst.sse.core.document.IDocumentCharsetDetector; +import org.eclipse.wst.xml.core.contenttype.XMLResourceEncodingDetector; + + +/** + * This class reads and parses first of XML file to get encoding. + * + */ +public class XMLDocumentCharsetDetector extends XMLResourceEncodingDetector implements IDocumentCharsetDetector { + + /** + * XMLLoader constructor comment. + */ + public XMLDocumentCharsetDetector() { + super(); + } + + public void set(IDocument document) { + set(new DocumentReader(document, 0)); + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/encoding/XMLDocumentLoader.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/encoding/XMLDocumentLoader.java new file mode 100644 index 0000000000..a87b340a1b --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/encoding/XMLDocumentLoader.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.encoding; + +import org.eclipse.jface.text.IDocumentPartitioner; +import org.eclipse.wst.common.encoding.ContentTypeEncodingPreferences; +import org.eclipse.wst.common.encoding.content.IContentTypeIdentifier; +import org.eclipse.wst.sse.core.document.AbstractDocumentLoader; +import org.eclipse.wst.sse.core.document.IDocumentCharsetDetector; +import org.eclipse.wst.sse.core.document.IDocumentLoader; +import org.eclipse.wst.sse.core.document.IEncodedDocument; +import org.eclipse.wst.sse.core.document.StructuredDocumentFactory; +import org.eclipse.wst.sse.core.internal.text.BasicStructuredDocument; +import org.eclipse.wst.sse.core.parser.RegionParser; +import org.eclipse.wst.sse.core.text.IStructuredDocument; +import org.eclipse.wst.xml.core.internal.parser.XMLSourceParser; +import org.eclipse.wst.xml.core.internal.parser.XMLStructuredDocumentReParser; +import org.eclipse.wst.xml.core.text.rules.StructuredTextPartitionerForXML; + + +/** + * This class reads an XML file and creates an XML Structured Model. + * + */ +public class XMLDocumentLoader extends AbstractDocumentLoader { + + public XMLDocumentLoader() { + super(); + } + + public IDocumentPartitioner getDefaultDocumentPartitioner() { + return new StructuredTextPartitionerForXML(); + } + + public IDocumentCharsetDetector getDocumentEncodingDetector() { + if (fDocumentEncodingDetector == null) { + fDocumentEncodingDetector = new XMLDocumentCharsetDetector(); + } + return fDocumentEncodingDetector; + } + + public RegionParser getParser() { + return new XMLSourceParser(); + } + + protected String getPreferredNewLineDelimiter() { + return ContentTypeEncodingPreferences.getPreferredNewLineDelimiter(IContentTypeIdentifier.ContentTypeID_SSEXML); + } + + protected String getSpecDefaultEncoding() { + // by default, UTF-8 as per XML spec + final String enc = "UTF-8"; //$NON-NLS-1$ + return enc; + } + + protected IEncodedDocument newEncodedDocument() { + IStructuredDocument structuredDocument = StructuredDocumentFactory.getNewStructuredDocumentInstance(getParser()); + if (structuredDocument instanceof BasicStructuredDocument) { + ((BasicStructuredDocument) structuredDocument).setReParser(new XMLStructuredDocumentReParser()); + } + return structuredDocument; + } + + public IDocumentLoader newInstance() { + return new XMLDocumentLoader(); + } + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/CommentNodeFormatter.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/CommentNodeFormatter.java new file mode 100644 index 0000000000..f962f15db6 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/CommentNodeFormatter.java @@ -0,0 +1,99 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.format; + +import org.eclipse.wst.sse.core.format.IStructuredFormatContraints; +import org.eclipse.wst.sse.core.util.StringUtils; +import org.eclipse.wst.xml.core.document.XMLNode; +import org.w3c.dom.Node; + + +public class CommentNodeFormatter extends NodeFormatter { + + protected String adjustIndentations(String aString, String lineIndent, String singleIndent) { + String result = new String(); + + int indexOfLineDelimiter = StringUtils.indexOfLineDelimiter(aString); + result = aString.substring(0, indexOfLineDelimiter); + while (indexOfLineDelimiter != -1) { + // Before find the next LineDelimiter, we have to figure out the + // size of the current LineDelimiter + // so we can figure out how many bytes to skip before finding the + // next LineDelimiter. + // Otherwise, we may treat the LF in CRLF as the next + // LineDelimiter. + int lineDelimiterSize = 1; + if (aString.length() >= indexOfLineDelimiter + 2 && aString.substring(indexOfLineDelimiter, indexOfLineDelimiter + 1).compareTo(CR) == 0 && aString.substring(indexOfLineDelimiter + 1, indexOfLineDelimiter + 2).compareTo(LF) == 0) + lineDelimiterSize = 2; + + int indexOfNextLineDelimiter = StringUtils.indexOfLineDelimiter(aString, indexOfLineDelimiter + lineDelimiterSize); + int indexOfNonblank = StringUtils.indexOfNonblank(aString, indexOfLineDelimiter); + + if (indexOfNonblank != -1) { + if (indexOfNextLineDelimiter == -1) { + // last line; copy till the end + result += lineIndent + singleIndent + aString.substring(indexOfNonblank); + } else if (indexOfNextLineDelimiter != -1 && indexOfNextLineDelimiter < indexOfNonblank) { + // blank line; just add a indent + result += lineIndent + singleIndent; + } else { + // copy all text between indexOfNonblank and + // indexOfNextLineDelimiter + result += lineIndent + singleIndent + aString.substring(indexOfNonblank, indexOfNextLineDelimiter); + } + + indexOfLineDelimiter = indexOfNextLineDelimiter; + } else { + if (indexOfNextLineDelimiter == -1) { + result += lineIndent; + } else { + // blank line; just add a indent + result += lineIndent + singleIndent; + } + + indexOfLineDelimiter = indexOfNextLineDelimiter; + } + } + + return result; + } + + protected void formatNode(XMLNode node, IStructuredFormatContraints formatContraints) { + if (node != null) { + // lineDelimiterFound means multi line comment + String nodeValue = node.getNodeValue(); + boolean lineDelimiterFoundInComment = StringUtils.containsLineDelimiter(nodeValue); + + if (lineDelimiterFoundInComment) { + // format indentation before node + formatIndentationBeforeNode(node, formatContraints); + + // adjust indentations in multi line comment + String lineDelimiter = node.getModel().getStructuredDocument().getLineDelimiter(); + String lineIndent = formatContraints.getCurrentIndent(); + String singleIndent = getFormatPreferences().getIndent(); + String newNodevalue = adjustIndentations(nodeValue, lineDelimiter + lineIndent, singleIndent); + if (nodeValue.compareTo(newNodevalue) != 0) + node.setNodeValue(newNodevalue); + } + + if (!nodeHasSiblings(node) || (node.getPreviousSibling() != null && node.getPreviousSibling().getNodeType() == Node.TEXT_NODE && !StringUtils.containsLineDelimiter(node.getPreviousSibling().getNodeValue()) && node.getNextSibling() == null)) { + // single child + // or inline comment after text + // do nothing + } else + // format indentation after node + formatIndentationAfterNode(node, formatContraints); + } + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/DocumentNodeFormatter.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/DocumentNodeFormatter.java new file mode 100644 index 0000000000..ee671a9925 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/DocumentNodeFormatter.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.format; + +import org.eclipse.wst.sse.core.format.IStructuredFormatContraints; +import org.eclipse.wst.sse.core.format.IStructuredFormatter; +import org.eclipse.wst.xml.core.document.XMLNode; + + +public class DocumentNodeFormatter extends NodeFormatter { + protected void formatChildren(XMLNode node, IStructuredFormatContraints formatContraints) { + String singleIndent = getFormatPreferences().getIndent(); + String lineIndent = formatContraints.getCurrentIndent(); + + if (node != null && (fProgressMonitor == null || !fProgressMonitor.isCanceled())) { + // normalize node first to combine adjacent text nodes + node.normalize(); + + XMLNode nextChild = (XMLNode) node.getFirstChild(); + while (nextChild != null) { + XMLNode eachChildNode = nextChild; + nextChild = (XMLNode) eachChildNode.getNextSibling(); + IStructuredFormatter formatter = getFormatter(eachChildNode); + IStructuredFormatContraints childFormatContraints = formatter.getFormatContraints(); + String childIndent = lineIndent + singleIndent; + childFormatContraints.setCurrentIndent(childIndent); + childFormatContraints.setClearAllBlankLines(formatContraints.getClearAllBlankLines()); + + // format each child + formatter.format(eachChildNode, childFormatContraints); + + if (nextChild != null && nextChild.getParentNode() == null) + // nextNode is deleted during format + nextChild = (XMLNode) eachChildNode.getNextSibling(); + } + } + } + + protected void formatNode(XMLNode node, IStructuredFormatContraints formatContraints) { + if (node != null) + formatChildren(node, formatContraints); + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/ElementNodeFormatter.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/ElementNodeFormatter.java new file mode 100644 index 0000000000..52d63d9a81 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/ElementNodeFormatter.java @@ -0,0 +1,357 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.format; + +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.wst.common.contentmodel.CMAttributeDeclaration; +import org.eclipse.wst.common.contentmodel.CMElementDeclaration; +import org.eclipse.wst.sse.core.exceptions.SourceEditingRuntimeException; +import org.eclipse.wst.sse.core.format.IStructuredFormatContraints; +import org.eclipse.wst.sse.core.modelquery.ModelQueryAdapter; +import org.eclipse.wst.sse.core.text.IStructuredDocument; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.core.text.ITextRegionList; +import org.eclipse.wst.sse.core.util.StringUtils; +import org.eclipse.wst.xml.core.document.XMLDocument; +import org.eclipse.wst.xml.core.document.XMLGenerator; +import org.eclipse.wst.xml.core.document.XMLModel; +import org.eclipse.wst.xml.core.document.XMLNode; +import org.eclipse.wst.xml.core.internal.document.AttrImpl; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + + +public class ElementNodeFormatter extends DocumentNodeFormatter { + static protected final char DOUBLE_QUOTE = '"';//$NON-NLS-1$ + static protected final String DOUBLE_QUOTES = "\"\"";//$NON-NLS-1$ + static protected final char EQUAL_CHAR = '='; // equal sign$NON-NLS-1$ + static protected final String PRESERVE = "preserve";//$NON-NLS-1$ + static protected final String PRESERVE_QUOTED = "\"preserve\"";//$NON-NLS-1$ + static protected final char SINGLE_QUOTE = '\'';//$NON-NLS-1$ + static protected final String XML_SPACE = "xml:space";//$NON-NLS-1$ + + protected void formatEndTag(XMLNode node, IStructuredFormatContraints formatContraints) { + String tagName = node.getNodeName(); + + if (!isEndTagMissing(node)) { + // end tag exists + + IStructuredDocument structuredDocument = node.getModel().getStructuredDocument(); + String lineDelimiter = structuredDocument.getLineDelimiter(); + String nodeIndentation = getNodeIndent(node); + XMLNode lastChild = (XMLNode) node.getLastChild(); + if (lastChild != null && lastChild.getNodeType() != Node.TEXT_NODE) { + if (isEndTagMissing(lastChild)) { + // find deepest child + XMLNode deepestChild = (XMLNode) lastChild.getLastChild(); + while (deepestChild != null && deepestChild.getLastChild() != null && isEndTagMissing(deepestChild)) { + lastChild = deepestChild; + deepestChild = (XMLNode) deepestChild.getLastChild(); + } + + if (deepestChild != null) { + if (deepestChild.getNodeType() == Node.TEXT_NODE) { + // Special indentation handling if lastChild's end + // tag is missing and deepestChild is a text node. + String nodeText = deepestChild.getNodeValue(); + + if (!nodeText.endsWith(lineDelimiter + nodeIndentation)) { + nodeText = StringUtils.appendIfNotEndWith(nodeText, lineDelimiter); + nodeText = StringUtils.appendIfNotEndWith(nodeText, nodeIndentation); + } + + replaceNodeValue(deepestChild, nodeText); + } else + insertAfterNode(lastChild, lineDelimiter + nodeIndentation); + } + } else + // indent end tag + insertAfterNode(lastChild, lineDelimiter + nodeIndentation); + } else if (lastChild == null && firstStructuredDocumentRegionContainsLineDelimiters(node)) { + // indent end tag + replace(structuredDocument, node.getFirstStructuredDocumentRegion().getEndOffset(), 0, lineDelimiter + nodeIndentation); + } + + // format end tag name + IStructuredDocumentRegion endTagStructuredDocumentRegion = node.getLastStructuredDocumentRegion(); + if (endTagStructuredDocumentRegion.getRegions().size() >= 3) { + ITextRegion endTagNameRegion = endTagStructuredDocumentRegion.getRegions().get(1); + removeRegionSpaces(node, endTagStructuredDocumentRegion, endTagNameRegion); + } + } + } + + protected void formatNode(XMLNode node, IStructuredFormatContraints formatContraints) { + if (node != null) { + // format indentation before node + formatIndentationBeforeNode(node, formatContraints); + + // format start tag + XMLNode newNode = node; + int startTagStartOffset = node.getStartOffset(); + XMLModel structuredModel = node.getModel(); + + formatStartTag(node, formatContraints); + // save new node + newNode = (XMLNode) structuredModel.getIndexedRegion(startTagStartOffset); + + IStructuredDocumentRegion flatNode = newNode.getFirstStructuredDocumentRegion(); + if (flatNode != null) { + ITextRegionList regions = flatNode.getRegions(); + ITextRegion lastRegion = regions.get(regions.size() - 1); + // format children and end tag if not empty start tag + if (lastRegion.getType() != XMLRegionContext.XML_EMPTY_TAG_CLOSE) { + // format children + formatChildren(newNode, formatContraints); + + // save new node + newNode = (XMLNode) structuredModel.getIndexedRegion(startTagStartOffset); + + // format end tag + formatEndTag(newNode, formatContraints); + } + } + + // format indentation after node + formatIndentationAfterNode(newNode, formatContraints); + } + } + + /** + * This method formats the start tag name, and formats the attributes if + * available. + */ + protected void formatStartTag(XMLNode node, IStructuredFormatContraints formatContraints) { + String singleIndent = getFormatPreferences().getIndent(); + String lineIndent = formatContraints.getCurrentIndent(); + String attrIndent = lineIndent + singleIndent; + boolean splitMultiAttrs = ((IStructuredFormatPreferencesXML) fFormatPreferences).getSplitMultiAttrs(); + IStructuredDocumentRegion flatNode = node.getFirstStructuredDocumentRegion(); + NamedNodeMap attributes = node.getAttributes(); + String tagName = node.getNodeName(); + + // Note: attributes should not be null even if the node has no + // attributes. However, attributes.getLength() will be 0. But, check + // for null just in case. + if (attributes != null) { + // compute current available line width + int currentAvailableLineWidth = 0; + try { + // 1 is for "<" + int nodeNameOffset = node.getStartOffset() + 1 + node.getNodeName().length(); + int lineOffset = node.getStructuredDocument().getLineInformationOfOffset(nodeNameOffset).getOffset(); + String text = node.getStructuredDocument().get(lineOffset, nodeNameOffset - lineOffset); + int usedWidth = getIndentationLength(text); + currentAvailableLineWidth = getFormatPreferences().getLineWidth() - usedWidth; + } catch (BadLocationException exception) { + throw new SourceEditingRuntimeException(exception); + } + + StringBuffer stringBuffer = new StringBuffer(); + String lineDelimiter = node.getModel().getStructuredDocument().getLineDelimiter(); + int attrLength = attributes.getLength(); + int lastUndefinedRegionOffset = 0; + for (int i = 0; i < attrLength; i++) { + AttrImpl attr = (AttrImpl) attributes.item(i); + ITextRegion nameRegion = attr.getNameRegion(); + ITextRegion equalRegion = attr.getEqualRegion(); + ITextRegion valueRegion = attr.getValueRegion(); + + // append undefined regions + String undefinedRegion = getUndefinedRegions(node, lastUndefinedRegionOffset, attr.getStartOffset() - lastUndefinedRegionOffset); + stringBuffer.append(undefinedRegion); + lastUndefinedRegionOffset = attr.getStartOffset(); + + // check for xml:space attribute + if (flatNode.getText(nameRegion).compareTo(XML_SPACE) == 0) { + if (valueRegion == null) { + ModelQueryAdapter adapter = (ModelQueryAdapter) ((XMLDocument) node.getOwnerDocument()).getAdapterFor(ModelQueryAdapter.class); + CMElementDeclaration elementDeclaration = (CMElementDeclaration) adapter.getModelQuery().getCMNode(node); + if (elementDeclaration == null) + // CMElementDeclaration not found, default to + // PRESERVE + formatContraints.setClearAllBlankLines(false); + else { + CMAttributeDeclaration attributeDeclaration = (CMAttributeDeclaration) elementDeclaration.getAttributes().getNamedItem(XML_SPACE); + if (attributeDeclaration == null) + // CMAttributeDeclaration not found, default + // to PRESERVE + formatContraints.setClearAllBlankLines(false); + else { + String defaultValue = attributeDeclaration.getAttrType().getImpliedValue(); + + if (defaultValue.compareTo(PRESERVE) == 0) + formatContraints.setClearAllBlankLines(false); + else + formatContraints.setClearAllBlankLines(getFormatPreferences().getClearAllBlankLines()); + } + } + } else { + XMLGenerator generator = node.getModel().getGenerator(); + String newAttrValue = generator.generateAttrValue(attr); + + // There is a problem in + // StructuredDocumentRegionUtil.getAttrValue(ITextRegion) + // when the region is instanceof ContextRegion. + // Workaround for now. + if (flatNode.getText(valueRegion).length() == 1) { + char firstChar = flatNode.getText(valueRegion).charAt(0); + if ((firstChar == DOUBLE_QUOTE) || (firstChar == SINGLE_QUOTE)) + newAttrValue = DOUBLE_QUOTES; + } + + if (newAttrValue.compareTo(PRESERVE_QUOTED) == 0) + formatContraints.setClearAllBlankLines(false); + else + formatContraints.setClearAllBlankLines(getFormatPreferences().getClearAllBlankLines()); + } + } + + if (splitMultiAttrs && attrLength > 1) { + stringBuffer.append(lineDelimiter + attrIndent); + stringBuffer.append(flatNode.getText(nameRegion)); + if (valueRegion != null) { + // append undefined regions + undefinedRegion = getUndefinedRegions(node, lastUndefinedRegionOffset, flatNode.getStartOffset(equalRegion) - lastUndefinedRegionOffset); + stringBuffer.append(undefinedRegion); + lastUndefinedRegionOffset = flatNode.getStartOffset(equalRegion); + + stringBuffer.append(EQUAL_CHAR); + + // append undefined regions + undefinedRegion = getUndefinedRegions(node, lastUndefinedRegionOffset, flatNode.getStartOffset(valueRegion) - lastUndefinedRegionOffset); + stringBuffer.append(undefinedRegion); + lastUndefinedRegionOffset = flatNode.getStartOffset(valueRegion); + + // Note: trim() should not be needed for + // valueRegion.getText(). Just a workaround for a + // problem found in valueRegion for now. + stringBuffer.append(flatNode.getText(valueRegion).trim()); + } + } else { + if (valueRegion != null) { + int textLength = 1 + flatNode.getText(nameRegion).length() + 1 + flatNode.getText(valueRegion).length(); + if (i == attrLength - 1) { + if (flatNode != null) { + ITextRegionList regions = flatNode.getRegions(); + ITextRegion lastRegion = regions.get(regions.size() - 1); + if (lastRegion.getType() != XMLRegionContext.XML_EMPTY_TAG_CLOSE) + // 3 is for " />" + textLength += 3; + else + // 1 is for ">" + textLength++; + } + } + + if (currentAvailableLineWidth >= textLength) { + stringBuffer.append(SPACE_CHAR); + currentAvailableLineWidth--; + } else { + stringBuffer.append(lineDelimiter + attrIndent); + currentAvailableLineWidth = getFormatPreferences().getLineWidth() - attrIndent.length(); + } + + stringBuffer.append(flatNode.getText(nameRegion)); + + // append undefined regions + undefinedRegion = getUndefinedRegions(node, lastUndefinedRegionOffset, flatNode.getStartOffset(equalRegion) - lastUndefinedRegionOffset); + stringBuffer.append(undefinedRegion); + lastUndefinedRegionOffset = flatNode.getStartOffset(equalRegion); + + stringBuffer.append(EQUAL_CHAR); + + // append undefined regions + undefinedRegion = getUndefinedRegions(node, lastUndefinedRegionOffset, flatNode.getStartOffset(valueRegion) - lastUndefinedRegionOffset); + stringBuffer.append(undefinedRegion); + lastUndefinedRegionOffset = flatNode.getStartOffset(valueRegion); + + // Note: trim() should not be needed for + // valueRegion.getText(). Just a workaround for a + // problem found in valueRegion for now. + stringBuffer.append(flatNode.getText(valueRegion).trim()); + + currentAvailableLineWidth -= flatNode.getText(nameRegion).length(); + currentAvailableLineWidth--; + currentAvailableLineWidth -= flatNode.getText(valueRegion).trim().length(); + } else { + if (currentAvailableLineWidth >= 1 + flatNode.getText(nameRegion).length()) { + stringBuffer.append(SPACE_CHAR); + currentAvailableLineWidth--; + } else { + stringBuffer.append(lineDelimiter + attrIndent); + currentAvailableLineWidth = getFormatPreferences().getLineWidth() - attrIndent.length(); + } + + stringBuffer.append(flatNode.getText(nameRegion)); + + currentAvailableLineWidth -= flatNode.getText(nameRegion).length(); + } + } + } + + // append undefined regions + String undefinedRegion = getUndefinedRegions(node, lastUndefinedRegionOffset, node.getEndOffset() - lastUndefinedRegionOffset); + stringBuffer.append(undefinedRegion); + + XMLModel structuredModel = node.getModel(); + IStructuredDocument structuredDocument = structuredModel.getStructuredDocument(); + // 1 is for "<" + int offset = node.getStartOffset() + 1 + node.getNodeName().length(); + // 1 is for "<" + int length = node.getFirstStructuredDocumentRegion().getTextLength() - 1 - node.getNodeName().length(); + + if (flatNode != null) { + ITextRegionList regions = flatNode.getRegions(); + ITextRegion firstRegion = regions.get(0); + ITextRegion lastRegion = regions.get(regions.size() - 1); + + if (firstRegion.getType() == XMLRegionContext.XML_END_TAG_OPEN) + // skip formatting for end tags in this format: </tagName> + return; + else { + if (lastRegion.getType() == XMLRegionContext.XML_TAG_CLOSE || lastRegion.getType() == XMLRegionContext.XML_EMPTY_TAG_CLOSE) + length = length - lastRegion.getLength(); + + if (lastRegion.getType() == XMLRegionContext.XML_EMPTY_TAG_CLOSE) + // leave space before XML_EMPTY_TAG_CLOSE: <tagName /> + stringBuffer.append(SPACE_CHAR); + } + } + + replace(structuredDocument, offset, length, stringBuffer.toString()); + } + } + + protected String getUndefinedRegions(XMLNode node, int startOffset, int length) { + String result = new String(); + + IStructuredDocumentRegion flatNode = node.getFirstStructuredDocumentRegion(); + ITextRegionList regions = flatNode.getRegions(); + for (int i = 0; i < regions.size(); i++) { + ITextRegion region = regions.get(i); + String regionType = region.getType(); + int regionStartOffset = flatNode.getStartOffset(region); + + if (regionType.compareTo(XMLRegionContext.UNDEFINED) == 0 && regionStartOffset >= startOffset && regionStartOffset < startOffset + length) + result = result + flatNode.getFullText(region); + } + + if (result.length() > 0) + return SPACE + result.trim(); + else + return result; + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/FormatProcessorXML.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/FormatProcessorXML.java new file mode 100644 index 0000000000..d9f2b0df10 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/FormatProcessorXML.java @@ -0,0 +1,116 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.format; + +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Preferences; +import org.eclipse.wst.sse.core.IModelManagerPlugin; +import org.eclipse.wst.sse.core.format.AbstractStructuredFormatProcessor; +import org.eclipse.wst.sse.core.format.IStructuredFormatPreferences; +import org.eclipse.wst.sse.core.format.IStructuredFormatter; +import org.eclipse.wst.sse.core.preferences.CommonModelPreferenceNames; +import org.eclipse.wst.xml.core.XMLModelPlugin; +import org.eclipse.wst.xml.core.internal.document.CDATASectionImpl; +import org.w3c.dom.Node; + + +public class FormatProcessorXML extends AbstractStructuredFormatProcessor { + protected IStructuredFormatPreferences fFormatPreferences = null; + + protected String getFileExtension() { + return "xml"; //$NON-NLS-1$ + } + + public IStructuredFormatPreferences getFormatPreferences() { + if (fFormatPreferences == null) { + fFormatPreferences = new StructuredFormatPreferencesXML(); + + Preferences preferences = getModelPreferences(); + if (preferences != null) { + fFormatPreferences.setLineWidth(preferences.getInt(CommonModelPreferenceNames.LINE_WIDTH)); + ((IStructuredFormatPreferencesXML) fFormatPreferences).setSplitMultiAttrs(preferences.getBoolean(CommonModelPreferenceNames.SPLIT_MULTI_ATTRS)); + fFormatPreferences.setClearAllBlankLines(preferences.getBoolean(CommonModelPreferenceNames.CLEAR_ALL_BLANK_LINES)); + + if (preferences.getBoolean(CommonModelPreferenceNames.INDENT_USING_TABS)) + fFormatPreferences.setIndent("\t"); //$NON-NLS-1$ + else { + int tabWidth = getModelManagerPlugin().getPluginPreferences().getInt(CommonModelPreferenceNames.TAB_WIDTH); + String indent = ""; //$NON-NLS-1$ + for (int i = 0; i < tabWidth; i++) { + indent += " "; //$NON-NLS-1$ + } + fFormatPreferences.setIndent(indent); + } + } + } + + return fFormatPreferences; + } + + protected IStructuredFormatter getFormatter(Node node) { + // 262135 - NPE during format of empty document + if (node == null) + return null; + + short nodeType = node.getNodeType(); + IStructuredFormatter formatter = null; + switch (nodeType) { + case Node.ELEMENT_NODE : { + formatter = new ElementNodeFormatter(); + break; + } + case Node.TEXT_NODE : { + if (node instanceof CDATASectionImpl) + formatter = new NodeFormatter(); + else + formatter = new TextNodeFormatter(); + break; + } + case Node.COMMENT_NODE : { + formatter = new CommentNodeFormatter(); + break; + } + case Node.PROCESSING_INSTRUCTION_NODE : { + formatter = new NodeFormatter(); + break; + } + case Node.DOCUMENT_NODE : { + formatter = new DocumentNodeFormatter(); + break; + } + default : { + formatter = new NodeFormatter(); + } + } + + // init fomatter + formatter.setFormatPreferences(getFormatPreferences()); + formatter.setProgressMonitor(fProgressMonitor); + + return formatter; + } + + private IModelManagerPlugin getModelManagerPlugin() { + + IModelManagerPlugin plugin = (IModelManagerPlugin) Platform.getPlugin(IModelManagerPlugin.ID); + return plugin; + } + + protected Preferences getModelPreferences() { + return XMLModelPlugin.getDefault().getPluginPreferences(); + } + + protected void refreshFormatPreferences() { + fFormatPreferences = null; + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/IStructuredFormatPreferencesXML.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/IStructuredFormatPreferencesXML.java new file mode 100644 index 0000000000..bc3faccf25 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/IStructuredFormatPreferencesXML.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.format; + +import org.eclipse.wst.sse.core.format.IStructuredFormatPreferences; + +public interface IStructuredFormatPreferencesXML extends IStructuredFormatPreferences { + boolean getSplitMultiAttrs(); + + void setSplitMultiAttrs(boolean splitMultiAttrs); +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/NodeFormatter.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/NodeFormatter.java new file mode 100644 index 0000000000..1948cdfc87 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/NodeFormatter.java @@ -0,0 +1,775 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.format; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Preferences; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.wst.sse.core.IModelManagerPlugin; +import org.eclipse.wst.sse.core.exceptions.SourceEditingRuntimeException; +import org.eclipse.wst.sse.core.format.IStructuredFormatContraints; +import org.eclipse.wst.sse.core.format.IStructuredFormatPreferences; +import org.eclipse.wst.sse.core.format.IStructuredFormatter; +import org.eclipse.wst.sse.core.format.StructuredFormatContraints; +import org.eclipse.wst.sse.core.internal.parser.ContextRegion; +import org.eclipse.wst.sse.core.preferences.CommonModelPreferenceNames; +import org.eclipse.wst.sse.core.text.IStructuredDocument; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.core.text.ITextRegionList; +import org.eclipse.wst.sse.core.util.StringUtils; +import org.eclipse.wst.xml.core.XMLModelPlugin; +import org.eclipse.wst.xml.core.document.XMLModel; +import org.eclipse.wst.xml.core.document.XMLNode; +import org.eclipse.wst.xml.core.internal.document.CDATASectionImpl; +import org.eclipse.wst.xml.core.internal.parser.regions.TagNameRegion; +import org.eclipse.wst.xml.core.jsp.model.parser.temp.XMLJSPRegionContexts; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; +import org.w3c.dom.Node; + + +public class NodeFormatter implements IStructuredFormatter { + static protected final String CR = "\r"; //$NON-NLS-1$ + static protected final String CRLF = "\r\n"; //$NON-NLS-1$ + static protected final String DELIMITERS = " \t\n\r\f"; //$NON-NLS-1$ + static protected final String EMPTY_STRING = ""; //$NON-NLS-1$ + static protected final String FF = "\f"; //$NON-NLS-1$ + static protected final String LF = "\n"; //$NON-NLS-1$ + static protected final String SPACE = " "; //$NON-NLS-1$ + static protected final char SPACE_CHAR = ' '; //$NON-NLS-1$ + static protected final String TAB = "\t"; //$NON-NLS-1$ + static protected final char TAB_CHAR = '\t'; //$NON-NLS-1$ + protected IStructuredFormatContraints fFormatContraints = null; + protected IStructuredFormatPreferences fFormatPreferences = null; + protected IProgressMonitor fProgressMonitor = null; + + protected String compressSpaces(String string, IStructuredFormatContraints formatContraints) { + /* + * Note that the StructuredTextEditor supports mixed new line + * characters (CR, LF, CRLF) in one file. We have to handle that when + * we try to preserve blank lines. + */ + String[] stringArray = null; + boolean clearAllBlankLines = formatContraints.getClearAllBlankLines(); + + if (clearAllBlankLines) + stringArray = StringUtils.asArray(string); + else + stringArray = StringUtils.asArray(string, DELIMITERS, true); + + StringBuffer compressedString = new StringBuffer(); + if (stringArray.length > 0) { + boolean cr = false, lf = false, cr2 = false, nonSpace = true; + + if (stringArray[0].compareTo(CR) == 0) + cr = true; + else if (stringArray[0].compareTo(LF) == 0) + lf = true; + else if ((stringArray[0].compareTo(SPACE) != 0) && (stringArray[0].compareTo(TAB) != 0) && (stringArray[0].compareTo(FF) != 0)) { + compressedString.append(stringArray[0]); + nonSpace = true; + } + + for (int i = 1; i < stringArray.length; i++) { + if (stringArray[i].compareTo(CR) == 0) { + if (cr && lf) { + if (nonSpace) { + compressedString.append(CR + LF); + nonSpace = false; + } + compressedString.append(stringArray[i]); + cr2 = true; + } else if (cr) { + if (nonSpace) { + compressedString.append(CR); + nonSpace = false; + } + compressedString.append(stringArray[i]); + cr2 = true; + } else + cr = true; + } else if (stringArray[i].compareTo(LF) == 0) { + if (cr && lf && cr2) { + compressedString.append(stringArray[i]); + } else if (lf) { + if (nonSpace) { + compressedString.append(LF); + nonSpace = false; + } + compressedString.append(stringArray[i]); + } else + lf = true; + } else if ((stringArray[i].compareTo(SPACE) != 0) && (stringArray[i].compareTo(TAB) != 0) && (stringArray[i].compareTo(FF) != 0)) { + if (compressedString.length() > 0) + compressedString.append(SPACE); + compressedString.append(stringArray[i]); + + cr = false; + lf = false; + cr2 = false; + nonSpace = true; + } + } + } + + return compressedString.toString(); + } + + protected boolean firstStructuredDocumentRegionContainsLineDelimiters(XMLNode node) { + boolean result = false; + + if (node != null) { + IStructuredDocumentRegion firstStructuredDocumentRegion = node.getFirstStructuredDocumentRegion(); + if (firstStructuredDocumentRegion != null && firstStructuredDocumentRegion.getText() != null) { + String firstStructuredDocumentRegionText = firstStructuredDocumentRegion.getText(); + result = StringUtils.containsLineDelimiter(firstStructuredDocumentRegionText); + } + } + + return result; + } + + public void format(Node node) { + IStructuredFormatContraints formatContraints = getFormatContraints(); + + format(node, formatContraints); + } + + public void format(Node node, IStructuredFormatContraints formatContraints) { + if (formatContraints.getFormatWithSiblingIndent()) + formatContraints.setCurrentIndent(getSiblingIndent(node)); + + if (node instanceof XMLNode) + formatNode((XMLNode) node, formatContraints); + } + + protected void formatIndentationAfterNode(XMLNode node, IStructuredFormatContraints formatContraints) { + if (node != null) { + XMLNode nextSibling = (XMLNode) node.getNextSibling(); + IStructuredDocument doc = node.getModel().getStructuredDocument(); + int line = doc.getLineOfOffset(node.getEndOffset()); + String lineDelimiter = doc.getLineDelimiter(); + try { + lineDelimiter = doc.getLineDelimiter(line); + if (lineDelimiter == null) + lineDelimiter = ""; //$NON-NLS-1$ + } catch (BadLocationException exception) { + throw new SourceEditingRuntimeException(exception); + } + String tagName = node.getNodeName(); + + if (node.getParentNode() != null) { + if (node.getParentNode().getNodeType() == Node.DOCUMENT_NODE) + if (nextSibling != null) + if (nextSibling.getNodeType() == Node.TEXT_NODE) + getFormatter(nextSibling).format(nextSibling, formatContraints); + else if (nextSibling.getNodeType() == Node.COMMENT_NODE) { + // do nothing + } else { + String lineIndent = formatContraints.getCurrentIndent(); + insertAfterNode(node, lineDelimiter + lineIndent); + } + else { + } + + else if (nextSibling != null) + if (nextSibling.getNodeType() == Node.TEXT_NODE) + getFormatter(nextSibling).format(nextSibling, formatContraints); + else if (nextSibling.getNodeType() == Node.COMMENT_NODE) { + // do nothing + } else { + String lineIndent = formatContraints.getCurrentIndent(); + insertAfterNode(node, lineDelimiter + lineIndent); + } + else { + XMLNode indentNode = getParentIndentNode(node); + String lineIndent = getNodeIndent(indentNode); + XMLNode lastChild = getDeepestChildNode(node); + boolean clearAllBlankLines = formatContraints.getClearAllBlankLines(); + + if (lastChild != null) { + if ((lastChild.getNodeType() == Node.TEXT_NODE) && (lastChild.getNodeValue().endsWith(lineDelimiter + lineIndent))) { + // this text node already ends with the requested + // indentation + } + + else if ((lastChild.getNodeType() == Node.TEXT_NODE) && (lastChild.getNodeValue() != null && lastChild.getNodeValue().endsWith(lineDelimiter))) + if (clearAllBlankLines) { + replaceNodeValue(lastChild, lineDelimiter + lineIndent); + } else { + // append indentation + insertAfterNode(lastChild, lineIndent); + } + else if (lastChild.getNodeType() == Node.TEXT_NODE) + if (lastChild.getNodeValue().length() == 0) { + // replace + replaceNodeValue(lastChild, lineDelimiter + lineIndent); + } else { + // append indentation + insertAfterNode(lastChild, lineDelimiter + lineIndent); + } + else { + // append indentation + insertAfterNode(lastChild, lineDelimiter + lineIndent); + } + } + } + } + } + } + + protected void formatIndentationBeforeNode(XMLNode node, IStructuredFormatContraints formatContraints) { + if (node != null) { + XMLNode previousSibling = (XMLNode) node.getPreviousSibling(); + IStructuredDocument doc = node.getModel().getStructuredDocument(); + int line = doc.getLineOfOffset(node.getStartOffset()); + String lineDelimiter = doc.getLineDelimiter(); + try { + if (line > 0) { + lineDelimiter = doc.getLineDelimiter(line - 1); + if (lineDelimiter == null) + lineDelimiter = ""; //$NON-NLS-1$ + } + } catch (BadLocationException exception) { + throw new SourceEditingRuntimeException(exception); + } + String lineIndent = formatContraints.getCurrentIndent(); + String tagName = node.getNodeName(); + + if (node.getParentNode() != null) { + if (node.getParentNode().getNodeType() == Node.DOCUMENT_NODE) { + if (previousSibling != null) + if (previousSibling.getNodeType() == Node.TEXT_NODE) + getFormatter(previousSibling).format(previousSibling, formatContraints); + else { + insertBeforeNode(node, lineDelimiter + lineIndent); + } + } else { + if (previousSibling == null || previousSibling.getNodeType() != Node.TEXT_NODE) { + // 261968 - formatting tag without closing bracket: + // <t1><t1 + // 265673 - Null ptr in formatIndentationBeforeNode + int prevEndNodeOffset = -1; + int prevEndRegionOffset = -1; + if (previousSibling != null) { + prevEndNodeOffset = previousSibling.getEndOffset(); + IStructuredDocumentRegion endRegion = previousSibling.getEndStructuredDocumentRegion(); + if (endRegion != null) { + prevEndRegionOffset = endRegion.getTextEndOffset(); + } + } + if ((previousSibling == null) || (prevEndNodeOffset != -1 && prevEndNodeOffset == prevEndRegionOffset)) { + insertBeforeNode(node, lineDelimiter + lineIndent); + } + + } else { + if (previousSibling.getNodeValue().length() == 0) { + // replace + replaceNodeValue(previousSibling, lineDelimiter + lineIndent); + } else { + // append indentation + if (!previousSibling.getNodeValue().endsWith(lineDelimiter + lineIndent)) { + if (previousSibling.getNodeValue().endsWith(lineDelimiter)) { + insertAfterNode(previousSibling, lineIndent); + } else + getFormatter(previousSibling).format(previousSibling, formatContraints); + } + } + } + } + } + } + } + + protected void formatNode(XMLNode node, IStructuredFormatContraints formatContraints) { + if (node != null && (fProgressMonitor == null || !fProgressMonitor.isCanceled())) { + // format indentation before node + formatIndentationBeforeNode(node, formatContraints); + + // format indentation after node + formatIndentationAfterNode(node, formatContraints); + } + } + + /** + * This method will compute the correct indentation after this node + * depending on the indentations of its sibling nodes and parent node. Not + * needed anymore? + */ + protected void formatTrailingText(XMLNode node, IStructuredFormatContraints formatContraints) { + String lineDelimiter = node.getModel().getStructuredDocument().getLineDelimiter(); + String lineIndent = formatContraints.getCurrentIndent(); + String parentLineIndent = getNodeIndent(node.getParentNode()); + boolean clearAllBlankLines = formatContraints.getClearAllBlankLines(); + + if ((node != null) && (node.getNodeType() != Node.DOCUMENT_NODE)) { + XMLNode nextSibling = (XMLNode) node.getNextSibling(); + if ((nextSibling != null) && (nextSibling.getNodeType() == Node.TEXT_NODE)) { + String nextSiblingText = nextSibling.getNodeValue(); + if (nextSibling.getNextSibling() == null) + if ((nextSibling.getParentNode().getNodeType() == Node.DOCUMENT_NODE) && (nextSiblingText.trim().length() == 0)) + // delete spaces at the end of the document + replaceNodeValue(nextSibling, EMPTY_STRING); + else + // replace the text node with parent indentation + replaceNodeValue(nextSibling, lineDelimiter + parentLineIndent); + else + // replace the text node with indentation + replaceNodeValue(nextSibling, lineDelimiter + lineIndent); + } else { + if (nextSibling == null) { + lineIndent = parentLineIndent; + + if (node.getParentNode().getNodeType() != Node.DOCUMENT_NODE) + if ((node.getNodeType() == Node.TEXT_NODE) && (node.getNodeValue().endsWith(lineDelimiter + lineIndent))) { + // this text node already ends with the requested + // indentation + } + + else if ((node.getNodeType() == Node.TEXT_NODE) && (node.getNodeValue().endsWith(lineDelimiter))) + if (clearAllBlankLines) + replaceNodeValue(node, lineDelimiter + lineIndent); + else + // append indentation + insertAfterNode(node, lineIndent); + else if (node.getNodeType() == Node.TEXT_NODE) + if (node.getNodeValue().length() == 0) + // replace + replaceNodeValue(node, lineDelimiter + lineIndent); + else + // append indentation + if (!node.getNodeValue().endsWith(lineDelimiter + lineIndent)) + if (node.getNodeValue().endsWith(lineDelimiter)) + insertAfterNode(node, lineIndent); + else + insertAfterNode(node, lineDelimiter + lineIndent); + else + replaceNodeValue(node, lineDelimiter + lineIndent); + } else { + if ((node.getNodeType() == Node.TEXT_NODE) && (node.getNodeValue().endsWith(lineDelimiter + lineIndent))) { + // this text node already ends with the requested + // indentation + } + + else if ((node.getNodeType() == Node.TEXT_NODE) && (node.getNodeValue().endsWith(lineDelimiter))) + if (clearAllBlankLines) + replaceNodeValue(node, lineDelimiter + lineIndent); + else + // append indentation + insertAfterNode(node, lineIndent); + else if (node.getNodeType() == Node.TEXT_NODE) + if (node.getNodeValue().length() == 0) + // replace + replaceNodeValue(node, lineDelimiter + lineIndent); + else + // append indentation + insertAfterNode(node, lineDelimiter + lineIndent); + else + // append indentation + insertAfterNode(node, lineDelimiter + lineIndent); + } + } + } + } + + protected String getCompressedNodeText(XMLNode node, IStructuredFormatContraints formatContraints) { + return compressSpaces(getNodeText(node), formatContraints); + } + + protected XMLNode getDeepestChildNode(XMLNode node) { + XMLNode result = null; + XMLNode lastChild = (XMLNode) node.getLastChild(); + + if (lastChild == null) + result = node; + else { + result = getDeepestChildNode(lastChild); + + if ((result.getNodeType() == Node.TEXT_NODE || result.getNodeType() == Node.COMMENT_NODE) && !isEndTagMissing(node)) + result = node; + } + + return result; + } + + public IStructuredFormatContraints getFormatContraints() { + if (fFormatContraints == null) { + fFormatContraints = new StructuredFormatContraints(); + + fFormatContraints.setClearAllBlankLines(getFormatPreferences().getClearAllBlankLines()); + } + + return fFormatContraints; + } + + public IStructuredFormatPreferences getFormatPreferences() { + if (fFormatPreferences == null) { + fFormatPreferences = new StructuredFormatPreferencesXML(); + + Preferences preferences = getModelPreferences(); + if (preferences != null) { + fFormatPreferences.setLineWidth(preferences.getInt(CommonModelPreferenceNames.LINE_WIDTH)); + ((IStructuredFormatPreferencesXML) fFormatPreferences).setSplitMultiAttrs(preferences.getBoolean(CommonModelPreferenceNames.SPLIT_MULTI_ATTRS)); + fFormatPreferences.setClearAllBlankLines(preferences.getBoolean(CommonModelPreferenceNames.CLEAR_ALL_BLANK_LINES)); + + if (preferences.getBoolean(CommonModelPreferenceNames.INDENT_USING_TABS)) + fFormatPreferences.setIndent("\t"); //$NON-NLS-1$ + else { + int tabWidth = getModelManagerPlugin().getPluginPreferences().getInt(CommonModelPreferenceNames.TAB_WIDTH); + String indent = ""; //$NON-NLS-1$ + for (int i = 0; i < tabWidth; i++) { + indent += " "; //$NON-NLS-1$ + } + fFormatPreferences.setIndent(indent); + } + } + } + + return fFormatPreferences; + } + + protected IStructuredFormatter getFormatter(XMLNode node) { + // 262135 - NPE during format of empty document + if (node == null) + return null; + + short nodeType = ((Node) node).getNodeType(); + IStructuredFormatter formatter = null; + switch (nodeType) { + case Node.ELEMENT_NODE : { + formatter = new ElementNodeFormatter(); + break; + } + case Node.TEXT_NODE : { + if (node instanceof CDATASectionImpl) + formatter = new NodeFormatter(); + else + formatter = new TextNodeFormatter(); + break; + } + case Node.COMMENT_NODE : { + formatter = new CommentNodeFormatter(); + break; + } + case Node.PROCESSING_INSTRUCTION_NODE : { + formatter = new NodeFormatter(); + break; + } + case Node.DOCUMENT_NODE : { + formatter = new DocumentNodeFormatter(); + break; + } + default : { + formatter = new NodeFormatter(); + } + } + + // init fomatter + formatter.setFormatPreferences(getFormatPreferences()); + formatter.setProgressMonitor(fProgressMonitor); + + return formatter; + } + + protected int getIndentationLength(String indent) { + // TODO Kit : The calculation of IndentationLength is not correct + // here. + // nodeIndentation may contain tabs. Multiply by 4 temporarily to get + // approx. width. + // Need to re-work. + + int indentationLength = 0; + + for (int i = 0; i < indent.length(); i++) { + if (indent.substring(i, i + 1).compareTo(TAB) == 0) + indentationLength += 4; + else + indentationLength++; + } + + return indentationLength; + } + + private IModelManagerPlugin getModelManagerPlugin() { + + IModelManagerPlugin plugin = (IModelManagerPlugin) Platform.getPlugin(IModelManagerPlugin.ID); + return plugin; + } + + protected Preferences getModelPreferences() { + return XMLModelPlugin.getDefault().getPluginPreferences(); + } + + /** + * This method will find the indentation for this node. It will search + * backwards starting from the beginning of the node until a character + * other than a space or a tab is found. If this node is null or it's a + * document node or it's a first level node (node's parent is a document + * node) the default empty string will be returned as the indentation. + */ + protected String getNodeIndent(Node node) { + String result = EMPTY_STRING; + + if ((node != null) && (node.getNodeType() != Node.DOCUMENT_NODE) && (node.getParentNode() != null) && (node.getParentNode().getNodeType() != Node.DOCUMENT_NODE)) { + XMLNode siblingTextNode = (XMLNode) node.getPreviousSibling(); + if ((siblingTextNode != null) && (siblingTextNode.getNodeType() == Node.TEXT_NODE)) { + // find the indentation + String siblingText = siblingTextNode.getNodeValue(); + int siblingTextLength = siblingText.length(); + if ((siblingText != null) && (siblingTextLength > 0) && ((siblingText.charAt(siblingTextLength - 1) == SPACE_CHAR) || (siblingText.charAt(siblingTextLength - 1) == TAB_CHAR))) { + int searchIndex = siblingTextLength - 1; + while ((searchIndex >= 0) && ((siblingText.charAt(searchIndex) == SPACE_CHAR) || (siblingText.charAt(searchIndex) == TAB_CHAR))) + searchIndex--; + + if (searchIndex < siblingTextLength) + result = siblingText.substring(searchIndex + 1, siblingTextLength); + } + } + } + + return result; + } + + protected String getNodeName(XMLNode node) { + return node.getNodeName(); + } + + protected String getNodeText(XMLNode node) { + String text = null; + + if ((node instanceof org.eclipse.wst.xml.core.internal.document.CharacterDataImpl) && !(node instanceof org.eclipse.wst.xml.core.internal.document.CommentImpl) && !(node instanceof org.eclipse.wst.xml.core.internal.document.CDATASectionImpl) && !isJSPTag(node)) + text = ((org.eclipse.wst.xml.core.internal.document.CharacterDataImpl) node).getSource(); + else + text = node.getFirstStructuredDocumentRegion().getText(); + + return text; + } + + protected XMLNode getParentIndentNode(XMLNode node) { + XMLNode result = null; + XMLNode parentNode = (XMLNode) node.getParentNode(); + + if (parentNode.getNodeType() == Node.DOCUMENT_NODE) + result = parentNode; + else { + ITextRegion region = parentNode.getLastStructuredDocumentRegion().getFirstRegion(); + if (region.getType() == XMLRegionContext.XML_END_TAG_OPEN) + result = parentNode; + else + result = getParentIndentNode(parentNode); + } + + return result; + } + + /** + * This method will find the indentation for a node sibling to this node. + * It will try to find a sibling node before this node first. If there is + * no sibling node before this node, it will try to find a sibling node + * after this node. If still not found, we will check if this node is + * already indented from its parent. If yes, this node's indentation will + * be used. Otherwise, the parent node's indentation plus one indentation + * will be used. If this node is null or it's a document node or it's a + * first level node (node's parent is a document node) the default empty + * string will be returned as the indentation. + */ + protected String getSiblingIndent(Node node) { + String result = EMPTY_STRING; + + if ((node != null) && (node.getNodeType() != Node.DOCUMENT_NODE) && (node.getParentNode() != null) && (node.getParentNode().getNodeType() != Node.DOCUMENT_NODE)) { + // find the text node before the previous non-text sibling + // if that's not found, we will try the text node before the next + // non-text sibling + XMLNode sibling = (XMLNode) node.getPreviousSibling(); + while ((sibling != null) && (sibling.getNodeType() == Node.TEXT_NODE || sibling.getNodeType() == Node.COMMENT_NODE)) { + if (sibling.getNodeType() == Node.COMMENT_NODE && sibling.getPreviousSibling() != null && sibling.getPreviousSibling().getNodeType() == Node.TEXT_NODE && StringUtils.containsLineDelimiter(sibling.getPreviousSibling().getNodeValue())) + break; + sibling = (XMLNode) sibling.getPreviousSibling(); + } + if (sibling == null) { + sibling = (XMLNode) node.getNextSibling(); + while ((sibling != null) && (sibling.getNodeType() == Node.TEXT_NODE)) + sibling = (XMLNode) sibling.getNextSibling(); + } + String singleIndent = getFormatPreferences().getIndent(); + String parentLineIndent = getNodeIndent(node.getParentNode()); + + if (sibling != null) { + String siblingIndent = getNodeIndent(sibling); + if (siblingIndent.length() > 0) + result = siblingIndent; + else { + String nodeIndent = getNodeIndent(node); + if (nodeIndent.length() > parentLineIndent.length()) + // this node is indented from its parent, its + // indentation will be used + result = nodeIndent; + else + result = parentLineIndent + singleIndent; + } + } else { + String nodeIndent = getNodeIndent(node); + if (nodeIndent.length() > parentLineIndent.length()) + // this node is indented from its parent, its indentation + // will be used + result = nodeIndent; + else + result = parentLineIndent + singleIndent; + } + } + + return result; + } + + protected void insertAfterNode(XMLNode node, String string) { + XMLModel structuredModel = node.getModel(); + IStructuredDocument structuredDocument = structuredModel.getStructuredDocument(); + + int offset = node.getEndOffset(); + int length = 0; + + // 261968 - formatting tag without closing bracket: <t1><t1 + if (node.getEndStructuredDocumentRegion() != null) { + offset = node.getEndStructuredDocumentRegion().getTextEndOffset(); + length = node.getEndOffset() - offset; + } + replace(structuredDocument, offset, length, string); + } + + protected void insertBeforeNode(XMLNode node, String string) { + XMLModel structuredModel = node.getModel(); + IStructuredDocument structuredDocument = structuredModel.getStructuredDocument(); + + replace(structuredDocument, node.getStartOffset(), 0, string); + } + + /** + * Allowing the INodeAdapter to compare itself against the type allows it + * to return true in more than one case. + */ + public boolean isAdapterForType(Object type) { + return type.equals(IStructuredFormatter.class); + } + + protected boolean isEndTagMissing(XMLNode node) { + boolean result = false; + + if ((node != null) && (node.getNodeType() != Node.DOCUMENT_NODE) && !isJSPTag(node)) { + IStructuredDocumentRegion startTagStructuredDocumentRegion = node.getFirstStructuredDocumentRegion(); + IStructuredDocumentRegion endTagStructuredDocumentRegion = node.getLastStructuredDocumentRegion(); + + ITextRegion startTagNameRegion = null; + if (startTagStructuredDocumentRegion.getRegions().size() > 1) + startTagNameRegion = startTagStructuredDocumentRegion.getRegions().get(1); + ITextRegion endTagNameRegion = null; + if (endTagStructuredDocumentRegion.getRegions().size() > 1) + endTagNameRegion = endTagStructuredDocumentRegion.getRegions().get(1); + + ITextRegionList startTagRegions = startTagStructuredDocumentRegion.getRegions(); + if (startTagNameRegion == endTagNameRegion && startTagNameRegion != null && (startTagRegions.get(0)).getType() != XMLRegionContext.XML_END_TAG_OPEN && (startTagRegions.get(startTagRegions.size() - 1).getType()) != XMLRegionContext.XML_EMPTY_TAG_CLOSE) + // end tag missing + result = true; + } + + return result; + } + + protected boolean isJSPTag(XMLNode node) { + boolean result = false; + + IStructuredDocumentRegion flatNode = node.getFirstStructuredDocumentRegion(); + // in some cases, the nodes exists, but hasn't been associated with + // a flatnode yet (the screen updates can be initiated on a different + // thread, + // so the request for a flatnode can come in before the node is fully + // formed. + // if the flatnode is null, we'll just allow the defaults to apply. + // (html adapter in this case). + if (flatNode != null) { + String flatNodeType = flatNode.getType(); + if ((flatNodeType == XMLJSPRegionContexts.JSP_CONTENT) || (flatNodeType == XMLJSPRegionContexts.JSP_EXPRESSION_OPEN) || (flatNodeType == XMLJSPRegionContexts.JSP_SCRIPTLET_OPEN) || (flatNodeType == XMLJSPRegionContexts.JSP_DECLARATION_OPEN) || (flatNodeType == XMLJSPRegionContexts.JSP_DIRECTIVE_CLOSE) || (flatNodeType == XMLJSPRegionContexts.JSP_DIRECTIVE_NAME) || (flatNodeType == XMLJSPRegionContexts.JSP_DIRECTIVE_OPEN) || (flatNodeType == XMLJSPRegionContexts.JSP_CLOSE)) { + result = true; + } + } + + return result; + } + + protected boolean nodeHasSiblings(XMLNode node) { + return (node.getPreviousSibling() != null) || (node.getNextSibling() != null); + } + + /** + * Node changed. No format should be performed automatically. + */ + public void notifyChanged(org.eclipse.wst.sse.core.INodeNotifier notifier, int eventType, Object changedFeature, Object oldValue, Object newValue, int pos) { + } + + protected void removeRegionSpaces(XMLNode node, IStructuredDocumentRegion flatNode, ITextRegion region) { + if ((region != null) && (region instanceof ContextRegion || region instanceof TagNameRegion) && (flatNode.getEndOffset(region) > flatNode.getTextEndOffset(region))) { + XMLModel structuredModel = node.getModel(); + IStructuredDocument structuredDocument = structuredModel.getStructuredDocument(); + + replace(structuredDocument, flatNode.getTextEndOffset(region), flatNode.getEndOffset(region) - flatNode.getTextEndOffset(region), EMPTY_STRING); + } + } + + /** + * This method will replace the string at offset and length with a new + * string. If the string to be replaced is the same as the new string, the + * string will not be replaced. + */ + protected void replace(IStructuredDocument structuredDocument, int offset, int length, String string) { + try { + String structuredDocumentString = structuredDocument.get(offset, length); + if (structuredDocumentString.compareTo(string) != 0) + structuredDocument.replaceText(structuredDocument, offset, length, string); + } catch (BadLocationException exception) { + throw new SourceEditingRuntimeException(exception); + } + } + + /** + * This method will replace the node value with a new string. If the node + * value to be replaced is the same as the new string, the node value will + * not be replaced. + */ + protected void replaceNodeValue(XMLNode node, String string) { + XMLModel structuredModel = node.getModel(); + IStructuredDocument structuredDocument = structuredModel.getStructuredDocument(); + int offset = node.getStartOffset(); + int length = node.getEndOffset() - node.getStartOffset(); + + try { + String structuredDocumentString = structuredDocument.get(offset, length); + if (structuredDocumentString.compareTo(string) != 0) + replace(structuredDocument, offset, length, string); + } catch (BadLocationException exception) { + throw new SourceEditingRuntimeException(exception); + } + } + + public void setFormatPreferences(IStructuredFormatPreferences formatPreferences) { + fFormatPreferences = formatPreferences; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.core.format.IStructuredFormatter#setProgressMonitor(org.eclipse.core.runtime.IProgressMonitor) + */ + public void setProgressMonitor(IProgressMonitor monitor) { + fProgressMonitor = monitor; + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/StructuredFormatPreferencesXML.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/StructuredFormatPreferencesXML.java new file mode 100644 index 0000000000..079ae41c29 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/StructuredFormatPreferencesXML.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.format; + +import org.eclipse.wst.sse.core.format.StructuredFormatPreferences; + +public class StructuredFormatPreferencesXML extends StructuredFormatPreferences implements IStructuredFormatPreferencesXML { + private boolean fSplitMultiAttrs; + + public boolean getSplitMultiAttrs() { + return fSplitMultiAttrs; + } + + public void setSplitMultiAttrs(boolean splitMultiAttrs) { + fSplitMultiAttrs = splitMultiAttrs; + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/TextNodeFormatter.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/TextNodeFormatter.java new file mode 100644 index 0000000000..1d428e9de2 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/format/TextNodeFormatter.java @@ -0,0 +1,198 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.format; + +import java.util.Vector; + +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.wst.sse.core.exceptions.SourceEditingRuntimeException; +import org.eclipse.wst.sse.core.format.IStructuredFormatContraints; +import org.eclipse.wst.sse.core.text.IStructuredDocument; +import org.eclipse.wst.sse.core.util.StringUtils; +import org.eclipse.wst.xml.core.document.XMLNode; +import org.w3c.dom.Node; + + +public class TextNodeFormatter extends NodeFormatter { + protected void formatNode(XMLNode node, IStructuredFormatContraints formatContraints) { + if (node != null) { + IStructuredDocument doc = node.getModel().getStructuredDocument(); + int line = doc.getLineOfOffset(node.getStartOffset()); + String lineDelimiter = doc.getLineDelimiter(); + try { + lineDelimiter = doc.getLineDelimiter(line); + if (lineDelimiter == null) + lineDelimiter = ""; //$NON-NLS-1$ + } catch (BadLocationException exception) { + throw new SourceEditingRuntimeException(exception); + } + int lineWidth = getFormatPreferences().getLineWidth(); + XMLNode parentNode = (XMLNode) node.getParentNode(); + XMLNode nextSibling = (XMLNode) node.getNextSibling(); + String nodeIndentation = formatContraints.getCurrentIndent(); + + // compute current available line width + int currentAvailableLineWidth = 0; + try { + int nodeNameOffset = node.getStartOffset(); + int lineOffset = node.getStructuredDocument().getLineInformationOfOffset(nodeNameOffset).getOffset(); + String text = node.getStructuredDocument().get(lineOffset, nodeNameOffset - lineOffset); + int usedWidth = getIndentationLength(text); + currentAvailableLineWidth = getFormatPreferences().getLineWidth() - usedWidth; + } catch (BadLocationException exception) { + throw new SourceEditingRuntimeException(exception); + } + + String compressedText = getCompressedNodeText(node, formatContraints); + + if (((compressedText.length() <= (currentAvailableLineWidth - node.getParentNode().getNodeName().length() - 3) && !StringUtils.containsLineDelimiter(compressedText)) && (!nodeHasSiblings(node) || (!StringUtils.containsLineDelimiter(node.getNodeValue()) && node.getNextSibling() != null && node.getNextSibling().getNodeType() == Node.COMMENT_NODE && !StringUtils.containsLineDelimiter(node.getNextSibling().getNodeValue()))) && !firstStructuredDocumentRegionContainsLineDelimiters((XMLNode) node.getParentNode())) || node.getStartStructuredDocumentRegion().getStartOffset() == 0) { + // enough space + // and text has no line delimiters + // and (node has no siblings or followed by inline comment) + // and + // parentFirstStructuredDocumentRegionContainsLineDelimiters + + if (isEndTagMissing(parentNode)) { + parentNode = (XMLNode) parentNode.getParentNode(); + while (isEndTagMissing(parentNode)) + parentNode = (XMLNode) parentNode.getParentNode(); + + // add parent's indentation to end + nodeIndentation = getNodeIndent(parentNode); + + if (!compressedText.endsWith(lineDelimiter + nodeIndentation)) { + compressedText = StringUtils.appendIfNotEndWith(compressedText, lineDelimiter); + compressedText = StringUtils.appendIfNotEndWith(compressedText, nodeIndentation); + } + } + + if ((parentNode != null) && (parentNode.getNodeType() == Node.DOCUMENT_NODE) && (node.getNodeValue().length() > 0) && (node.getNodeValue().trim().length() == 0) && ((node.getPreviousSibling() == null) || (node.getNextSibling() == null))) + // delete spaces at the beginning or end of the document + compressedText = EMPTY_STRING; + + replaceNodeValue(node, compressedText); + } else { + // not enough space, need to reflow text + + currentAvailableLineWidth = lineWidth - getIndentationLength(nodeIndentation); + Vector vector = reflowText(compressedText, currentAvailableLineWidth); + int vectorSize = vector.size(); + String reflowedText = new String(); + + for (int i = 0; i < vectorSize; i++) { + if (((String) vector.elementAt(i)).trim().length() > 0) + reflowedText = reflowedText + lineDelimiter + nodeIndentation + (String) vector.elementAt(i); + else + reflowedText = reflowedText + lineDelimiter; + } + + if (node.getNextSibling() == null) { + if (isEndTagMissing(parentNode)) { + // don't add indentation to end if parent end tag is + // missing + } + + else { + // add parent's indentation to end + nodeIndentation = getNodeIndent(parentNode); + + if (!reflowedText.endsWith(lineDelimiter + nodeIndentation)) { + reflowedText = StringUtils.appendIfNotEndWith(reflowedText, lineDelimiter); + reflowedText = StringUtils.appendIfNotEndWith(reflowedText, nodeIndentation); + } + } + } else { + if (!reflowedText.endsWith(lineDelimiter + nodeIndentation)) { + // not already ended with the expected indentation + + if (node.getNextSibling().getNodeType() == Node.COMMENT_NODE) { + // add indentation to end if + // currentTextEndsWithLineDelimiter + // or followed by multiLineComment + + String nodeText = getNodeText(node); + int indexOfLastLineDelimiter = StringUtils.indexOfLastLineDelimiter(nodeText); + boolean currentTextEndsWithLineDelimiter = indexOfLastLineDelimiter != -1; + if (currentTextEndsWithLineDelimiter) { + // no more non blank character after the last + // line delimiter + currentTextEndsWithLineDelimiter = StringUtils.indexOfNonblank(nodeText, indexOfLastLineDelimiter) == -1; + } + + String nodeValue = node.getNextSibling().getNodeValue(); + boolean multiLineComment = StringUtils.containsLineDelimiter(nodeValue); + + if (currentTextEndsWithLineDelimiter || multiLineComment) { + reflowedText = StringUtils.appendIfNotEndWith(reflowedText, lineDelimiter); + reflowedText = StringUtils.appendIfNotEndWith(reflowedText, nodeIndentation); + } + } else { + // not a comment, just add add indentation to end + reflowedText = StringUtils.appendIfNotEndWith(reflowedText, lineDelimiter); + reflowedText = StringUtils.appendIfNotEndWith(reflowedText, nodeIndentation); + } + } + } + + replaceNodeValue(node, reflowedText); + } + + } + } + + protected Vector reflowText(String text, int availableWidth) { + String[] stringArray = null; + boolean clearAllBlankLines = getFormatPreferences().getClearAllBlankLines(); + + if (clearAllBlankLines) + stringArray = StringUtils.asArray(text); + else + stringArray = StringUtils.asArray(text, DELIMITERS, true); + + Vector output = new Vector(); + if ((stringArray != null) && (stringArray.length > 0)) { + StringBuffer buffer = new StringBuffer(); + if (stringArray[0].compareTo(CR) != 0) + buffer.append(stringArray[0]); + int bufferLength = stringArray[0].toString().length(); + boolean cr = stringArray[0].compareTo(CR) == 0; + + for (int i = 1; i < stringArray.length; i++) { + String eachString = stringArray[i]; + if ((eachString.compareTo(SPACE) != 0) && (eachString.compareTo(TAB) != 0) && (eachString.compareTo(FF) != 0)) { + if ((bufferLength + 1 + eachString.length() > availableWidth) || (eachString.compareTo(CR) == 0) || (eachString.compareTo(LF) == 0)) { + if ((eachString.compareTo(LF) == 0) && cr) { + // do nothing + } else { + output.add(buffer.toString()); + buffer = new StringBuffer(); + bufferLength = 0; + } + cr = eachString.compareTo(CR) == 0; + } else if (buffer.toString().trim().length() > 0) { + buffer.append(SPACE); + bufferLength++; + } + if ((eachString.compareTo(CR) != 0) && (eachString.compareTo(LF) != 0)) { + buffer.append(eachString); + bufferLength = bufferLength + eachString.length(); + } + } + } + output.add(buffer.toString()); + } else + output.add(text); + + return output; + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/DebugAdapterFactory.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/DebugAdapterFactory.java new file mode 100644 index 0000000000..4275c5047d --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/DebugAdapterFactory.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal; + +import java.util.ArrayList; + +import org.eclipse.wst.sse.core.AbstractAdapterFactory; +import org.eclipse.wst.sse.core.AdapterFactory; +import org.eclipse.wst.sse.core.INodeAdapter; +import org.eclipse.wst.sse.core.INodeNotifier; +import org.eclipse.wst.sse.core.PropagatingAdapterFactory; + + +public class DebugAdapterFactory extends AbstractAdapterFactory implements PropagatingAdapterFactory { + + /** + * Constructor for PageDirectiveWatcherFactory. + */ + public DebugAdapterFactory() { + this(IDebugAdapter.class, true); + } + + /** + * Constructor for PageDirectiveWatcherFactory. + * + * @param adapterKey + * @param registerAdapters + */ + public DebugAdapterFactory(Object adapterKey, boolean registerAdapters) { + super(adapterKey, registerAdapters); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.core.PropagatingAdapterFactory#addContributedFactories(org.eclipse.wst.sse.core.AdapterFactory) + */ + public void addContributedFactories(AdapterFactory factory) { + //none expected + } + + public AdapterFactory copy() { + return new DebugAdapterFactory(this.adapterKey, this.shouldRegisterAdapter); + } + + protected INodeAdapter createAdapter(INodeNotifier target) { + EveryNodeDebugAdapter result = null; + result = EveryNodeDebugAdapter.getInstance(); + return result; + + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.core.AdapterFactory#isFactoryForType(java.lang.Object) + */ + public boolean isFactoryForType(Object type) { + + return IDebugAdapter.class == type; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.core.PropagatingAdapterFactory#setContributedFactories(java.util.ArrayList) + */ + public void setContributedFactories(ArrayList list) { + // none expected + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/EveryNodeDebugAdapter.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/EveryNodeDebugAdapter.java new file mode 100644 index 0000000000..dc238974fc --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/EveryNodeDebugAdapter.java @@ -0,0 +1,274 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal; + +import org.eclipse.jface.text.DocumentEvent; +import org.eclipse.jface.text.IDocumentListener; +import org.eclipse.wst.sse.core.IModelStateListener; +import org.eclipse.wst.sse.core.INodeNotifier; +import org.eclipse.wst.sse.core.IStructuredModel; +import org.eclipse.wst.sse.core.events.AboutToBeChangeEvent; +import org.eclipse.wst.sse.core.events.IModelAboutToBeChangedListener; +import org.eclipse.wst.sse.core.events.IStructuredDocumentListener; +import org.eclipse.wst.sse.core.events.NewDocumentEvent; +import org.eclipse.wst.sse.core.events.NoChangeEvent; +import org.eclipse.wst.sse.core.events.RegionChangedEvent; +import org.eclipse.wst.sse.core.events.RegionsReplacedEvent; +import org.eclipse.wst.sse.core.events.StructuredDocumentRegionsReplacedEvent; +import org.eclipse.wst.sse.core.text.IStructuredDocument; +import org.eclipse.wst.sse.core.util.Debug; +import org.eclipse.wst.xml.core.document.XMLNode; + + +/** + * Purely for use in debugging + */ +public class EveryNodeDebugAdapter implements IDebugAdapter { + + static class InternalDocumentListener implements IDocumentListener { + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.IDocumentListener#documentAboutToBeChanged(org.eclipse.jface.text.DocumentEvent) + */ + public void documentAboutToBeChanged(DocumentEvent event) { + Debug.println("IdocumentAboutToBeChanged: " + event); //$NON-NLS-1$ + + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.IDocumentListener#documentChanged(org.eclipse.jface.text.DocumentEvent) + */ + public void documentChanged(DocumentEvent event) { + Debug.println("IdocumentChanged: " + event); //$NON-NLS-1$ + + } + + } + + static class InternalModelStateListener implements IModelStateListener { + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.core.IModelStateListener#modelAboutToBeChanged(org.eclipse.wst.sse.core.IStructuredModel) + */ + public void modelAboutToBeChanged(IStructuredModel model) { + Debug.println("modelAboutToBeChanged: " + model); //$NON-NLS-1$ + + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.core.IModelStateListener#modelChanged(org.eclipse.wst.sse.core.IStructuredModel) + */ + public void modelChanged(IStructuredModel model) { + Debug.println("modelChanged: " + model); //$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.core.IModelStateListener#modelDirtyStateChanged(org.eclipse.wst.sse.core.IStructuredModel, + * boolean) + */ + public void modelDirtyStateChanged(IStructuredModel model, boolean isDirty) { + Debug.println("modelDirtyStateChanged: " + model); //$NON-NLS-1$ + + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.core.IModelStateListener#modelResourceDeleted(org.eclipse.wst.sse.core.IStructuredModel) + */ + public void modelResourceDeleted(IStructuredModel model) { + Debug.println("modelResourceDeleted: " + model); //$NON-NLS-1$ + + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.core.IModelStateListener#modelResourceMoved(org.eclipse.wst.sse.core.IStructuredModel, + * org.eclipse.wst.sse.core.IStructuredModel) + */ + public void modelResourceMoved(IStructuredModel oldModel, IStructuredModel newModel) { + Debug.println("modelResourceMoved: " + "oldModel: " + oldModel + "newModel: " + newModel); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + } + + static class InternalStructuredDocumentAboutToChange implements IModelAboutToBeChangedListener { + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.core.events.IModelAboutToBeChangedListener#modelAboutToBeChanged(org.eclipse.wst.sse.core.events.AboutToBeChangeEvent) + */ + public void modelAboutToBeChanged(AboutToBeChangeEvent structuredDocumentEvent) { + Debug.println("structuredDocumentAboutToBeChanged: " + structuredDocumentEvent); //$NON-NLS-1$ + + } + + } + + static class InternalStructuredDocumentListener implements IStructuredDocumentListener { + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.core.events.IStructuredDocumentListener#newModel(org.eclipse.wst.sse.core.events.NewDocumentContentEvent) + */ + public void newModel(NewDocumentEvent structuredDocumentEvent) { + Debug.println("structuredDocumentChanged - newModel: " + structuredDocumentEvent); //$NON-NLS-1$ + + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.core.events.IStructuredDocumentListener#noChange(org.eclipse.wst.sse.core.events.NoChangeEvent) + */ + public void noChange(NoChangeEvent structuredDocumentEvent) { + Debug.println("structuredDocumentChanged - noChange: " + structuredDocumentEvent); //$NON-NLS-1$ + + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.core.events.IStructuredDocumentListener#nodesReplaced(org.eclipse.wst.sse.core.events.StructuredDocumentRegionsReplacedEvent) + */ + public void nodesReplaced(StructuredDocumentRegionsReplacedEvent structuredDocumentEvent) { + Debug.println("structuredDocumentChanged - nodesReplaced: " + structuredDocumentEvent); //$NON-NLS-1$ + + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.core.events.IStructuredDocumentListener#regionChanged(org.eclipse.wst.sse.core.events.RegionChangedEvent) + */ + public void regionChanged(RegionChangedEvent structuredDocumentEvent) { + Debug.println("structuredDocumentChanged - regionChanged: " + structuredDocumentEvent); //$NON-NLS-1$ + + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.core.events.IStructuredDocumentListener#regionsReplaced(org.eclipse.wst.sse.core.events.RegionsReplacedEvent) + */ + public void regionsReplaced(RegionsReplacedEvent structuredDocumentEvent) { + Debug.println("structuredDocumentChanged - regionsReplaced: " + structuredDocumentEvent); //$NON-NLS-1$ + + } + + } + + private static EveryNodeDebugAdapter singletonInstance; + + public static EveryNodeDebugAdapter getInstance() { + if (singletonInstance == null) { + singletonInstance = new EveryNodeDebugAdapter(); + } + return singletonInstance; + } + + InternalDocumentListener fInternalDocumentListener; + InternalModelStateListener fInternalModelStateListener; + InternalStructuredDocumentAboutToChange fInternalStructuredDocumentAboutToChange; + InternalStructuredDocumentListener fInternalStructuredDocumentListener; + IStructuredModel fModel; + + /** + * + */ + public EveryNodeDebugAdapter() { + super(); + fInternalDocumentListener = new InternalDocumentListener(); + fInternalStructuredDocumentAboutToChange = new InternalStructuredDocumentAboutToChange(); + fInternalStructuredDocumentListener = new InternalStructuredDocumentListener(); + fInternalModelStateListener = new InternalModelStateListener(); + } + + /** + * @param target + */ + public EveryNodeDebugAdapter(INodeNotifier target) { + this(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.core.INodeAdapter#isAdapterForType(java.lang.Object) + */ + public boolean isAdapterForType(Object type) { + return (type == IDebugAdapter.class); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.core.INodeAdapter#notifyChanged(org.eclipse.wst.sse.core.INodeNotifier, + * int, java.lang.Object, java.lang.Object, java.lang.Object, int) + */ + public void notifyChanged(INodeNotifier notifier, int eventType, Object changedFeature, Object oldValue, Object newValue, int pos) { + if (notifier instanceof XMLNode) { + setModel(((XMLNode) notifier).getModel()); + } + Debug.println("notifier: " + notifier + " " + INodeNotifier.EVENT_TYPE_STRINGS[eventType] + " changedFeature: " + changedFeature + " oldValue: " + oldValue + " newValue: " + newValue + " pos: " + pos); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ + + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.core.internal.IDebugAdapter#setDocument(org.eclipse.wst.sse.core.text.IStructuredDocument) + */ + private void setModel(IStructuredModel structuredModel) { + if (fModel == structuredModel) + return; + + if (fModel != null) { + fModel.removeModelStateListener(fInternalModelStateListener); + // + IStructuredDocument structuredDocument = fModel.getStructuredDocument(); + if (structuredDocument != null) { + structuredDocument.removeDocumentListener(fInternalDocumentListener); + structuredDocument.removeDocumentAboutToChangeListener(fInternalStructuredDocumentAboutToChange); + structuredDocument.removeDocumentChangedListener(fInternalStructuredDocumentListener); + } + } + fModel = structuredModel; + if (fModel != null) { + + fModel.addModelStateListener(fInternalModelStateListener); + // + IStructuredDocument structuredDocument = fModel.getStructuredDocument(); + if (structuredDocument != null) { + structuredDocument.addDocumentListener(fInternalDocumentListener); + structuredDocument.addDocumentAboutToChangeListener(fInternalStructuredDocumentAboutToChange); + structuredDocument.addDocumentChangedListener(fInternalStructuredDocumentListener); + } + } + + + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/IDebugAdapter.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/IDebugAdapter.java new file mode 100644 index 0000000000..50b902514e --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/IDebugAdapter.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal; + +import org.eclipse.wst.sse.core.INodeAdapter; + + +public interface IDebugAdapter extends INodeAdapter { +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/ByteReader.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/ByteReader.java new file mode 100644 index 0000000000..e5f04fa496 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/ByteReader.java @@ -0,0 +1,107 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.contenttype; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; + +/** + * This is an "adapter" class, simply to get in input stream to act like a + * reader. We could not use InputStreamReader directly because its internal + * buffers are not controllable, and it sometimes pulls too much out of input + * stream (even when it wasn't needed for our purposes). + * + * The use of this class is highly specialized and by not means meant to be + * general purpose. Its use is restricted to those cases where the input + * stream can be regarded as ascii just long enough to determine what the real + * encoding should be. + */ + +public class ByteReader extends Reader { + + /** Default byte buffer size (2048). */ + public static final int DEFAULT_BUFFER_SIZE = 2048; + + protected byte[] fBuffer; + + protected InputStream fInputStream; + + protected ByteReader() { + super(); + } + + public ByteReader(InputStream inputStream) { + this(inputStream, DEFAULT_BUFFER_SIZE); + if (!inputStream.markSupported()) { + throw new IllegalArgumentException("ByteReader is required to have a resettable stream"); //$NON-NLS-1$ + } + } + + public ByteReader(InputStream inputStream, int size) { + fInputStream = inputStream; + if (!inputStream.markSupported()) { + throw new IllegalArgumentException("ByteReader is required to have a resettable stream"); //$NON-NLS-1$ + } + fBuffer = new byte[size]; + + } + + public void close() throws IOException { + fInputStream.close(); + } + + public void mark(int readAheadLimit) throws IOException { + fInputStream.mark(readAheadLimit); + } + + public boolean markSupported() { + return true; + } + + public int read() throws IOException { + int b0 = fInputStream.read(); + return (b0 & 0x00FF); + } + + public int read(char ch[], int offset, int length) throws IOException { + if (length > fBuffer.length) { + length = fBuffer.length; + } + + int count = fInputStream.read(fBuffer, 0, length); + + for (int i = 0; i < count; i++) { + int b0 = fBuffer[i]; + // the 0x00FF is to "lose" the negative bits filled in the byte to + // int conversion + // (and which would be there if cast directly from byte to char). + char c0 = (char) (b0 & 0x00FF); + ch[i] = c0; + } + return count; + } + + public boolean ready() throws IOException { + return fInputStream.available() > 0; + } + + public void reset() throws IOException { + fInputStream.reset(); + } + + public long skip(long n) throws IOException { + return fInputStream.skip(n); + } + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/EncodingParserConstants.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/EncodingParserConstants.java new file mode 100644 index 0000000000..7e12f93503 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/EncodingParserConstants.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.contenttype; + + +public interface EncodingParserConstants { + + final String EOF = "EOF"; //$NON-NLS-1$ + final String InvalidTerminatedStringValue = "InvalidTerminatedStringValue"; //$NON-NLS-1$ + final String InvalidTermintatedUnDelimitedStringValue = "InvalidTermintatedUnDelimitedStringValue"; //$NON-NLS-1$ + final String MAX_CHARS_REACHED = "MAX_CHARS_REACHED"; //$NON-NLS-1$ + final String StringValue = "strval"; //$NON-NLS-1$ + final String UnDelimitedStringValue = "UnDelimitedStringValue"; //$NON-NLS-1$ + String UTF16BE = "UTF16BE"; //$NON-NLS-1$ + String UTF16LE = "UTF16LE"; //$NON-NLS-1$ + + + String UTF83ByteBOM = "UTF83ByteBOM"; //$NON-NLS-1$ + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/HeadParserToken.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/HeadParserToken.java new file mode 100644 index 0000000000..0f14b8b570 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/HeadParserToken.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.contenttype; + +public class HeadParserToken { + private int fStart; + + private String fText; + private String fType; + + protected HeadParserToken() { + super(); + } + + public HeadParserToken(String type, int start, String text) { + this(); + fType = type; + fStart = start; + fText = text; + + } + + public String getText() { + return fText; + } + + public String getType() { + return fType; + } + + public String toString() { + return ("text: " + fText + " offset: " + fStart + " type: " + fType); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/IntStack.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/IntStack.java new file mode 100644 index 0000000000..1d1052d850 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/IntStack.java @@ -0,0 +1,99 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.contenttype; + +/* + * + * A non-resizable class implementing the behavior of java.util.Stack, but + * directly for the <code> integer </code> primitive. + */ +import java.util.EmptyStackException; + +public class IntStack { + private int[] list = null; + + private int size = 0; + + public IntStack() { + this(100); + } + + public IntStack(int maxdepth) { + super(); + list = new int[maxdepth]; + initialize(); + } + + public void clear() { + initialize(); + } + + public boolean empty() { + return size == 0; + } + + public int get(int slot) { + return list[slot]; + } + + private void initialize() { + for (int i = 0; i < list.length; i++) + list[i] = -1; + } + + /** + * Returns the int at the top of the stack without removing it + * + * @return int at the top of this stack. + * @exception EmptyStackException + * when empty. + */ + public int peek() { + if (size == 0) + throw new EmptyStackException(); + return list[size - 1]; + } + + /** + * Removes and returns the int at the top of the stack + * + * @return int at the top of this stack. + * @exception EmptyStackException + * when empty. + */ + public int pop() { + int value = peek(); + list[size - 1] = -1; + size--; + return value; + } + + /** + * Pushes an item onto the top of this stack. + * + * @param newValue - + * the int to be pushed onto this stack. + * @return the <code>newValue</code> argument. + */ + public int push(int newValue) { + if (size == list.length) { + throw new StackOverflowError(); + } + list[size++] = newValue; + return newValue; + } + + public int size() { + return list.length; + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/XMLDeclDetector.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/XMLDeclDetector.java new file mode 100644 index 0000000000..5843f61c4f --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/XMLDeclDetector.java @@ -0,0 +1,156 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.contenttype; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.runtime.CoreException; + +public class XMLDeclDetector { + private static final int MAX_BUF_SIZE = 1024 * 2; + private static final int MAX_MARK_SIZE = 1024 * 2; + protected boolean fHeaderParsed; + private boolean fIsXML; + protected Reader fReader; + //private boolean DEBUG = false; + private XMLHeadTokenizer fTokenizer; + + private boolean canHandleAsUnicodeStream(String tokenType) { + boolean canHandleAsUnicodeStream = false; + if (tokenType == EncodingParserConstants.UTF83ByteBOM) { + canHandleAsUnicodeStream = true; + //fUnicode = "UTF-8"; //$NON-NLS-1$ + } else if (tokenType == EncodingParserConstants.UTF16BE) { + canHandleAsUnicodeStream = true; + //fUnicode = "UTF-16BE"; //$NON-NLS-1$ + } else if (tokenType == EncodingParserConstants.UTF16LE) { + canHandleAsUnicodeStream = true; + //fUnicode = "UTF-16"; //$NON-NLS-1$ + } + return canHandleAsUnicodeStream; + } + + final private void ensureInputSet() { + if (fReader == null) { + throw new IllegalStateException("input must be set before use"); //$NON-NLS-1$ + } + } + + //private String fUnicode; + + /** + * @return Returns the tokenizer. + */ + private XMLHeadTokenizer getTokenizer() { + if (fTokenizer == null) { + fTokenizer = new XMLHeadTokenizer(); + } + return fTokenizer; + } + + /** + * @return Returns the isXML. + */ + public boolean isXML() throws IOException { + ensureInputSet(); + if (!fHeaderParsed) { + parseInput(); + } + return fIsXML; + } + + private void parseInput() throws IOException { + XMLHeadTokenizer tokenizer = getTokenizer(); + tokenizer.reset(fReader); + HeadParserToken token = null; + String tokenType = null; + do { + token = tokenizer.getNextToken(); + tokenType = token.getType(); + if (canHandleAsUnicodeStream(tokenType)) { + fReader.reset(); + // this is (obviously) not always true. + // TODO: need to fix so we "remember" original iFile or + // inputstream, and + // create appropriate InputStreamReader. + // I'm not sure what to do for the set(reader) case ... if its + // even relevent. + // plus, ensure against infinite loops! + fIsXML = true; + //fReader = new InputStreamReader(fReader, fUnicode); + // parseInput(); + } else { + if (tokenType == XMLHeadTokenizerConstants.XMLDelEncoding) { + fIsXML = true; + } + } + } while (tokenizer.hasMoreTokens()); + + } + + private void resetAll() { + fReader = null; + fHeaderParsed = false; + fIsXML = false; + //fUnicode = null; + + } + + public void set(IFile iFile) throws CoreException { + resetAll(); + InputStream inputStream = iFile.getContents(true); + InputStream resettableStream = new BufferedInputStream(inputStream, MAX_BUF_SIZE); + resettableStream.mark(MAX_MARK_SIZE); + set(resettableStream); + } + + public void set(InputStream inputStream) { + resetAll(); + fReader = new ByteReader(inputStream); + try { + fReader.mark(MAX_MARK_SIZE); + } catch (IOException e) { + // impossible, since we know ByteReader supports marking + throw new Error(e); + } + } + + /** + * Note: this is not part of interface to help avoid confusion ... it + * expected this Reader is a well formed character reader ... that is, its + * all ready been determined to not be a unicode marked input stream. And, + * its assumed to be in the correct position, at position zero, ready to + * read first character. + */ + public void set(Reader reader) { + resetAll(); + fReader = reader; + if (!fReader.markSupported()) { + fReader = new BufferedReader(fReader); + } + + try { + fReader.mark(MAX_MARK_SIZE); + } catch (IOException e) { + // impossble, since we just checked if markable + throw new Error(e); + } + + } + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/XMLHeadTokenizer.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/XMLHeadTokenizer.java new file mode 100644 index 0000000000..b4a9b6ebba --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/XMLHeadTokenizer.java @@ -0,0 +1,1222 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +/* The following code was generated by JFlex 1.2.2 on 4/6/04 11:13 PM */ + +/*nlsXXX*/ +package org.eclipse.wst.xml.core.internal.contenttype; + +import java.io.IOException; +import java.io.Reader; + + + +/** + * This class is a scanner generated by <a + * href="http://www.informatik.tu-muenchen.de/~kleing/jflex/">JFlex </a> 1.2.2 + * on 4/6/04 11:13 PM from the specification file + * <tt>file:/D:/DevTimeSupport/HeadParsers/XMLHeadTokenizer/XMLHeadTokenizer.jflex</tt> + */ +public class XMLHeadTokenizer { + + /** this character denotes the end of file */ + final public static int YYEOF = -1; + + /** lexical states */ + final public static int YYINITIAL = 0; + final public static int UnDelimitedString = 10; + final public static int DQ_STRING = 6; + final public static int SQ_STRING = 8; + final public static int ST_XMLDecl = 2; + final public static int QuotedAttributeValue = 4; + + /** + * YY_LEXSTATE[l] is the state in the DFA for the lexical state l + * YY_LEXSTATE[l+1] is the state in the DFA for the lexical state l at the + * beginning of a line l is of the form l = 2*k, k a non negative integer + */ + private final static int YY_LEXSTATE[] = {0, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6}; + + /** + * Translates characters to character classes + */ + final private static String yycmap_packed = "\11\0\1\6\1\7\2\0\1\11\22\0\1\6\1\0\1\27\2\0" + "\1\31\1\0\1\30\24\0\1\12\1\10\1\26\1\13\3\0\1\21" + "\1\23\1\17\1\0\1\25\1\0\1\24\2\0\1\16\1\15\1\20" + "\1\22\10\0\1\14\12\0\1\21\1\23\1\17\1\0\1\25\1\0" + "\1\24\2\0\1\16\1\15\1\20\1\22\10\0\1\14\102\0\1\4" + "\3\0\1\5\17\0\1\3\16\0\1\1\20\0\1\3\16\0\1\1" + "\1\2\170\0\1\2\ufe87\0"; + + /** + * Translates characters to character classes + */ + final private static char[] yycmap = yy_unpack_cmap(yycmap_packed); + + + /* error codes */ + final private static int YY_UNKNOWN_ERROR = 0; + final private static int YY_ILLEGAL_STATE = 1; + final private static int YY_NO_MATCH = 2; + final private static int YY_PUSHBACK_2BIG = 3; + + /* error messages for the codes above */ + final private static String YY_ERROR_MSG[] = {"Unkown internal scanner error", "Internal error: unknown state", "Error: could not match input", "Error: pushback value was too large"}; + + /** the input device */ + private java.io.Reader yy_reader; + + /** the current state of the DFA */ + private int yy_state; + + /** the current lexical state */ + private int yy_lexical_state = YYINITIAL; + + /** + * this buffer contains the current text to be matched and is the source + * of the yytext() string + */ + private char yy_buffer[] = new char[16384]; + + /** the textposition at the last accepting state */ + private int yy_markedPos; + + /** the textposition at the last state to be included in yytext */ + private int yy_pushbackPos; + + /** the current text position in the buffer */ + private int yy_currentPos; + + /** startRead marks the beginning of the yytext() string in the buffer */ + private int yy_startRead; + + /** + * endRead marks the last character in the buffer, that has been read from + * input + */ + private int yy_endRead; + + /** number of newlines encountered up to the start of the matched text */ + int yyline; + + /** the number of characters up to the start of the matched text */ + private int yychar; + + /** + * the number of characters from the last newline up to the start of the + * matched text + */ + int yycolumn; + + /** + * yy_atBOL == true <=>the scanner is currently at the beginning of a line + */ + private boolean yy_atBOL; + + /** yy_atEOF == true <=>the scanner has returned a value for EOF */ + private boolean yy_atEOF; + + /** denotes if the user-EOF-code has already been executed */ + private boolean yy_eof_done; + + /* user code: */ + + + private boolean hasMore = true; + private final static int MAX_TO_SCAN = 1000; + StringBuffer string = new StringBuffer(); + // state stack for easier state handling + private IntStack fStateStack = new IntStack(); + private String valueText = null; + + + public XMLHeadTokenizer() { + super(); + } + + public void reset(Reader in) { + /* the input device */ + yy_reader = in; + + /* the current state of the DFA */ + yy_state = 0; + + /* the current lexical state */ + yy_lexical_state = YYINITIAL; + + /* + * this buffer contains the current text to be matched and is the + * source of the yytext() string + */ + java.util.Arrays.fill(yy_buffer, (char) 0); + + /* the textposition at the last accepting state */ + yy_markedPos = 0; + + /* the textposition at the last state to be included in yytext */ + yy_pushbackPos = 0; + + /* the current text position in the buffer */ + yy_currentPos = 0; + + /* startRead marks the beginning of the yytext() string in the buffer */ + yy_startRead = 0; + + /** + * endRead marks the last character in the buffer, that has been read + * from input + */ + yy_endRead = 0; + + /* number of newlines encountered up to the start of the matched text */ + yyline = 0; + + /* the number of characters up to the start of the matched text */ + yychar = 0; + + /** + * the number of characters from the last newline up to the start of + * the matched text + */ + yycolumn = 0; + + /** + * yy_atBOL == true <=>the scanner is currently at the beginning of a + * line + */ + yy_atBOL = false; + + /* yy_atEOF == true <=> the scanner has returned a value for EOF */ + yy_atEOF = false; + + /* denotes if the user-EOF-code has already been executed */ + yy_eof_done = false; + + + fStateStack.clear(); + + hasMore = true; + + // its a little wasteful to "throw away" first char array generated + // by class init (via auto generated code), but we really do want + // a small buffer for our head parsers. + if (yy_buffer.length != MAX_TO_SCAN) { + yy_buffer = new char[MAX_TO_SCAN]; + } + + + } + + + public final HeadParserToken getNextToken() throws IOException { + String context = null; + context = primGetNextToken(); + HeadParserToken result = null; + if (valueText != null) { + result = createToken(context, yychar, valueText); + valueText = null; + } else { + result = createToken(context, yychar, yytext()); + } + return result; + } + + public final boolean hasMoreTokens() { + return hasMore && yychar < MAX_TO_SCAN; + } + + private void pushCurrentState() { + fStateStack.push(yystate()); + + } + + private void popState() { + yybegin(fStateStack.pop()); + } + + private HeadParserToken createToken(String context, int start, String text) { + return new HeadParserToken(context, start, text); + } + + + + /** + * Creates a new scanner There is also a java.io.InputStream version of + * this constructor. + * + * @param in + * the java.io.Reader to read input from. + */ + public XMLHeadTokenizer(java.io.Reader in) { + this.yy_reader = in; + } + + /** + * Creates a new scanner. There is also java.io.Reader version of this + * constructor. + * + * @param in + * the java.io.Inputstream to read input from. + */ + public XMLHeadTokenizer(java.io.InputStream in) { + this(new java.io.InputStreamReader(in)); + } + + /** + * Unpacks the compressed character translation table. + * + * @param packed + * the packed character translation table + * @return the unpacked character translation table + */ + private static char[] yy_unpack_cmap(String packed) { + char[] map = new char[0x10000]; + int i = 0; /* index in packed string */ + int j = 0; /* index in unpacked array */ + while (i < 128) { + int count = packed.charAt(i++); + char value = packed.charAt(i++); + do + map[j++] = value; + while (--count > 0); + } + return map; + } + + + /** + * Gets the next input character. + * + * @return the next character of the input stream, EOF if the end of the + * stream is reached. + * @exception IOException + * if any I/O-Error occurs + */ + private int yy_advance() throws java.io.IOException { + + /* standard case */ + if (yy_currentPos < yy_endRead) + return yy_buffer[yy_currentPos++]; + + /* if the eof is reached, we don't need to work hard */ + if (yy_atEOF) + return YYEOF; + + /* otherwise: need to refill the buffer */ + + /* first: make room (if you can) */ + if (yy_startRead > 0) { + System.arraycopy(yy_buffer, yy_startRead, yy_buffer, 0, yy_endRead - yy_startRead); + + /* translate stored positions */ + yy_endRead -= yy_startRead; + yy_currentPos -= yy_startRead; + yy_markedPos -= yy_startRead; + yy_pushbackPos -= yy_startRead; + yy_startRead = 0; + } + + /* is the buffer big enough? */ + if (yy_currentPos >= yy_buffer.length) { + /* if not: blow it up */ + char newBuffer[] = new char[yy_currentPos * 2]; + System.arraycopy(yy_buffer, 0, newBuffer, 0, yy_buffer.length); + yy_buffer = newBuffer; + } + + /* finally: fill the buffer with new input */ + int numRead = yy_reader.read(yy_buffer, yy_endRead, yy_buffer.length - yy_endRead); + + if (numRead == -1) + return YYEOF; + + yy_endRead += numRead; + + return yy_buffer[yy_currentPos++]; + } + + + /** + * Closes the input stream. + */ + final public void yyclose() throws java.io.IOException { + yy_atEOF = true; /* indicate end of file */ + yy_endRead = yy_startRead; /* invalidate buffer */ + yy_reader.close(); + } + + + /** + * Returns the current lexical state. + */ + final public int yystate() { + return yy_lexical_state; + } + + /** + * Enters a new lexical state + * + * @param newState + * the new lexical state + */ + final public void yybegin(int newState) { + yy_lexical_state = newState; + } + + + /** + * Returns the text matched by the current regular expression. + */ + final public String yytext() { + return new String(yy_buffer, yy_startRead, yy_markedPos - yy_startRead); + } + + /** + * Returns the length of the matched text region. + */ + final public int yylength() { + return yy_markedPos - yy_startRead; + } + + + /** + * Reports an error that occured while scanning. + * + * @param errorCode + * the code of the errormessage to display + */ + private void yy_ScanError(int errorCode) { + try { + System.out.println(YY_ERROR_MSG[errorCode]); + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println(YY_ERROR_MSG[YY_UNKNOWN_ERROR]); + } + + // System.exit(1); + } + + + /** + * Pushes the specified amount of characters back into the input stream. + * + * They will be read again by then next call of the scanning method + * + * @param number + * the number of characters to be read again. This number must + * not be greater than yylength()! + */ + private void yypushback(int number) { + if (number > yylength()) + yy_ScanError(YY_PUSHBACK_2BIG); + + yy_markedPos -= number; + } + + + /** + * Contains user EOF-code, which will be executed exactly once, when the + * end of file is reached + */ + private void yy_do_eof() { + if (!yy_eof_done) { + yy_eof_done = true; + hasMore = false; + + } + } + + + /** + * Resumes scanning until the next regular expression is matched, the end + * of input is encountered or an I/O-Error occurs. + * + * @return the next token + * @exception IOException + * if any I/O-Error occurs + */ + public String primGetNextToken() throws java.io.IOException { + int yy_input; + int yy_action; + + + while (true) { + + yychar += yylength(); + + yy_atBOL = yy_markedPos <= 0 || yy_buffer[yy_markedPos - 1] == '\n'; + if (!yy_atBOL && yy_buffer[yy_markedPos - 1] == '\r') { + yy_atBOL = yy_advance() != '\n'; + if (!yy_atEOF) + yy_currentPos--; + } + + yy_action = -1; + + yy_currentPos = yy_startRead = yy_markedPos; + + if (yy_atBOL) + yy_state = YY_LEXSTATE[yy_lexical_state + 1]; + else + yy_state = YY_LEXSTATE[yy_lexical_state]; + + + yy_forAction : { + while (true) { + + yy_input = yy_advance(); + + if (yy_input == YYEOF) + break yy_forAction; + + yy_input = yycmap[yy_input]; + + boolean yy_isFinal = false; + boolean yy_noLookAhead = false; + + yy_forNext : { + switch (yy_state) { + case 0 : + switch (yy_input) { + default : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 7; + break yy_forNext; + } + + case 1 : + switch (yy_input) { + case 1 : + yy_isFinal = true; + yy_state = 8; + break yy_forNext; + case 2 : + yy_isFinal = true; + yy_state = 9; + break yy_forNext; + case 3 : + yy_isFinal = true; + yy_state = 10; + break yy_forNext; + case 6 : + case 7 : + case 9 : + yy_isFinal = true; + yy_state = 11; + break yy_forNext; + case 10 : + yy_isFinal = true; + yy_state = 12; + break yy_forNext; + default : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 7; + break yy_forNext; + } + + case 2 : + switch (yy_input) { + case 11 : + yy_isFinal = true; + yy_state = 13; + break yy_forNext; + case 15 : + yy_isFinal = true; + yy_state = 14; + break yy_forNext; + default : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 7; + break yy_forNext; + } + + case 3 : + switch (yy_input) { + case 6 : + case 9 : + yy_isFinal = true; + yy_state = 16; + break yy_forNext; + case 7 : + yy_isFinal = true; + yy_state = 17; + break yy_forNext; + case 23 : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 18; + break yy_forNext; + case 24 : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 19; + break yy_forNext; + default : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 15; + break yy_forNext; + } + + case 4 : + switch (yy_input) { + case 7 : + case 9 : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 21; + break yy_forNext; + case 11 : + yy_isFinal = true; + yy_state = 22; + break yy_forNext; + case 23 : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 23; + break yy_forNext; + case 24 : + yy_isFinal = true; + yy_state = 24; + break yy_forNext; + default : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 20; + break yy_forNext; + } + + case 5 : + switch (yy_input) { + case 7 : + case 9 : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 21; + break yy_forNext; + case 24 : + yy_isFinal = true; + yy_state = 25; + break yy_forNext; + case 25 : + yy_isFinal = true; + yy_state = 26; + break yy_forNext; + default : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 20; + break yy_forNext; + } + + case 6 : + switch (yy_input) { + case 11 : + yy_isFinal = true; + yy_state = 26; + break yy_forNext; + case 6 : + case 7 : + case 9 : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 27; + break yy_forNext; + case 23 : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 28; + break yy_forNext; + case 24 : + yy_isFinal = true; + yy_state = 29; + break yy_forNext; + default : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 20; + break yy_forNext; + } + + case 8 : + switch (yy_input) { + case 2 : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 30; + break yy_forNext; + default : + break yy_forAction; + } + + case 9 : + switch (yy_input) { + case 1 : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 31; + break yy_forNext; + default : + break yy_forAction; + } + + case 10 : + switch (yy_input) { + case 4 : + yy_state = 32; + break yy_forNext; + default : + break yy_forAction; + } + + case 11 : + switch (yy_input) { + case 6 : + case 7 : + case 9 : + yy_state = 33; + break yy_forNext; + case 10 : + yy_state = 34; + break yy_forNext; + default : + break yy_forAction; + } + + case 12 : + switch (yy_input) { + case 11 : + yy_state = 35; + break yy_forNext; + default : + break yy_forAction; + } + + case 13 : + switch (yy_input) { + case 22 : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 36; + break yy_forNext; + default : + break yy_forAction; + } + + case 14 : + switch (yy_input) { + case 16 : + yy_state = 37; + break yy_forNext; + default : + break yy_forAction; + } + + case 16 : + switch (yy_input) { + case 6 : + case 9 : + yy_isFinal = true; + yy_state = 16; + break yy_forNext; + case 7 : + yy_state = 38; + break yy_forNext; + default : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 15; + break yy_forNext; + } + + case 17 : + switch (yy_input) { + case 6 : + case 9 : + yy_isFinal = true; + yy_state = 16; + break yy_forNext; + case 7 : + yy_state = 38; + break yy_forNext; + default : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 15; + break yy_forNext; + } + + case 22 : + switch (yy_input) { + case 22 : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 39; + break yy_forNext; + default : + break yy_forAction; + } + + case 24 : + switch (yy_input) { + case 10 : + yy_state = 40; + break yy_forNext; + default : + break yy_forAction; + } + + case 25 : + switch (yy_input) { + case 10 : + yy_state = 40; + break yy_forNext; + default : + break yy_forAction; + } + + case 26 : + switch (yy_input) { + case 22 : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 41; + break yy_forNext; + default : + break yy_forAction; + } + + case 29 : + switch (yy_input) { + case 10 : + yy_state = 40; + break yy_forNext; + default : + break yy_forAction; + } + + case 32 : + switch (yy_input) { + case 5 : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 42; + break yy_forNext; + default : + break yy_forAction; + } + + case 33 : + switch (yy_input) { + case 6 : + case 7 : + case 9 : + yy_state = 33; + break yy_forNext; + case 10 : + yy_state = 34; + break yy_forNext; + default : + break yy_forAction; + } + + case 34 : + switch (yy_input) { + case 11 : + yy_state = 35; + break yy_forNext; + default : + break yy_forAction; + } + + case 35 : + switch (yy_input) { + case 12 : + yy_state = 43; + break yy_forNext; + default : + break yy_forAction; + } + + case 37 : + switch (yy_input) { + case 17 : + yy_state = 44; + break yy_forNext; + default : + break yy_forAction; + } + + case 38 : + switch (yy_input) { + case 6 : + case 9 : + yy_isFinal = true; + yy_state = 16; + break yy_forNext; + case 7 : + yy_state = 38; + break yy_forNext; + default : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 15; + break yy_forNext; + } + + case 40 : + switch (yy_input) { + case 24 : + yy_isFinal = true; + yy_noLookAhead = true; + yy_state = 21; + break yy_forNext; + default : + break yy_forAction; + } + + case 43 : + switch (yy_input) { + case 13 : + yy_state = 45; + break yy_forNext; + default : + break yy_forAction; + } + + case 44 : + switch (yy_input) { + case 18 : + yy_state = 46; + break yy_forNext; + default : + break yy_forAction; + } + + case 45 : + switch (yy_input) { + case 14 : + yy_state = 47; + break yy_forNext; + default : + break yy_forAction; + } + + case 46 : + switch (yy_input) { + case 19 : + yy_state = 48; + break yy_forNext; + default : + break yy_forAction; + } + + case 47 : + switch (yy_input) { + case 6 : + case 7 : + case 9 : + yy_isFinal = true; + yy_state = 49; + break yy_forNext; + default : + break yy_forAction; + } + + case 48 : + switch (yy_input) { + case 20 : + yy_state = 50; + break yy_forNext; + default : + break yy_forAction; + } + + case 49 : + switch (yy_input) { + case 6 : + case 7 : + case 9 : + yy_isFinal = true; + yy_state = 49; + break yy_forNext; + default : + break yy_forAction; + } + + case 50 : + switch (yy_input) { + case 16 : + yy_state = 51; + break yy_forNext; + default : + break yy_forAction; + } + + case 51 : + switch (yy_input) { + case 21 : + yy_state = 52; + break yy_forNext; + default : + break yy_forAction; + } + + case 52 : + switch (yy_input) { + case 6 : + case 7 : + case 9 : + yy_state = 52; + break yy_forNext; + case 8 : + yy_isFinal = true; + yy_state = 53; + break yy_forNext; + default : + break yy_forAction; + } + + case 53 : + switch (yy_input) { + case 6 : + case 7 : + case 9 : + yy_isFinal = true; + yy_state = 53; + break yy_forNext; + default : + break yy_forAction; + } + + default : + yy_ScanError(YY_ILLEGAL_STATE); + break; + } + } + + if (yy_isFinal) { + yy_action = yy_state; + yy_markedPos = yy_currentPos; + if (yy_noLookAhead) + break yy_forAction; + } + + } + } + + + switch (yy_action) { + + case 25 : { + popState(); + valueText = string.toString(); + return EncodingParserConstants.StringValue; + } + case 55 : + break; + case 21 : { + yypushback(1); + popState(); + valueText = string.toString(); + return EncodingParserConstants.InvalidTerminatedStringValue; + } + case 56 : + break; + case 15 : + case 16 : { + yypushback(1); + yybegin(UnDelimitedString); + string.setLength(0); + } + case 57 : + break; + case 28 : + case 29 : { + yypushback(1); + popState(); + valueText = string.toString(); + return EncodingParserConstants.InvalidTermintatedUnDelimitedStringValue; + } + case 58 : + break; + case 39 : { + yypushback(2); + popState(); + valueText = string.toString(); + return EncodingParserConstants.InvalidTerminatedStringValue; + } + case 59 : + break; + case 41 : { + yypushback(2); + popState(); + valueText = string.toString(); + return EncodingParserConstants.InvalidTerminatedStringValue; + } + case 60 : + break; + case 7 : + case 8 : + case 9 : + case 10 : + case 11 : + case 12 : + case 13 : + case 14 : + case 17 : { + if (yychar > MAX_TO_SCAN) { + hasMore = false; + return EncodingParserConstants.MAX_CHARS_REACHED; + } + } + case 61 : + break; + case 30 : { + if (yychar == 0) { + hasMore = false; + return EncodingParserConstants.UTF16BE; + } + } + case 62 : + break; + case 31 : { + if (yychar == 0) { + hasMore = false; + return EncodingParserConstants.UTF16LE; + } + } + case 63 : + break; + case 42 : { + if (yychar == 0) { + hasMore = false; + return EncodingParserConstants.UTF83ByteBOM; + } + } + case 64 : + break; + case 49 : { + if (yychar == 0) { + yybegin(ST_XMLDecl); + return XMLHeadTokenizerConstants.XMLDeclStart; + } + } + case 65 : + break; + case 36 : { + yybegin(YYINITIAL); + hasMore = false; + return XMLHeadTokenizerConstants.XMLDeclEnd; + } + case 66 : + break; + case 53 : { + pushCurrentState(); + yybegin(QuotedAttributeValue); + return XMLHeadTokenizerConstants.XMLDelEncoding; + } + case 67 : + break; + case 23 : { + popState(); + valueText = string.toString(); + return EncodingParserConstants.StringValue; + } + case 68 : + break; + case 20 : + case 22 : + case 24 : + case 26 : { + string.append(yytext()); + } + case 69 : + break; + case 19 : { + yybegin(SQ_STRING); + string.setLength(0); + } + case 70 : + break; + case 18 : { + yybegin(DQ_STRING); + string.setLength(0); + } + case 71 : + break; + case 27 : { + yypushback(1); + popState(); + valueText = string.toString(); + return EncodingParserConstants.UnDelimitedStringValue; + } + case 72 : + break; + default : + if (yy_input == YYEOF && yy_startRead == yy_currentPos) { + yy_atEOF = true; + yy_do_eof(); + { + hasMore = false; + return EncodingParserConstants.EOF; + } + } else { + yy_ScanError(YY_NO_MATCH); + } + } + } + } + + /** + * Runs the scanner on input files. + * + * This main method is the debugging routine for the scanner. It prints + * each returned token to System.out until the end of file is reached, or + * an error occured. + * + * @param argv + * the command line, contains the filenames to run the scanner + * on. + */ + public static void main(String argv[]) { + for (int i = 0; i < argv.length; i++) { + XMLHeadTokenizer scanner = null; + try { + scanner = new XMLHeadTokenizer(new java.io.FileReader(argv[i])); + } catch (java.io.FileNotFoundException e) { + System.out.println("File not found : \"" + argv[i] + "\""); + System.exit(1); + } + // catch (java.io.IOException e) { + // System.out.println("Error opening file \"" + argv[i] + "\""); + // System.exit(1); + // } + catch (ArrayIndexOutOfBoundsException e) { + System.out.println("Usage : java XMLHeadTokenizer <inputfile>"); + System.exit(1); + } + + try { + do { + System.out.println(scanner.primGetNextToken()); + } while (!scanner.yy_atEOF); + + } catch (java.io.IOException e) { + System.out.println("An I/O error occured while scanning :"); + System.out.println(e); + System.exit(1); + } catch (Exception e) { + e.printStackTrace(); + System.exit(1); + } + } + } + + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/XMLHeadTokenizerConstants.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/XMLHeadTokenizerConstants.java new file mode 100644 index 0000000000..3321348059 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/contenttype/XMLHeadTokenizerConstants.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.contenttype; + + +public interface XMLHeadTokenizerConstants extends EncodingParserConstants { + + final String XMLDeclEnd = "XMLDeclEnd"; //$NON-NLS-1$ + final String XMLDeclStart = "XMLDeclStart"; //$NON-NLS-1$ + final String XMLDelEncoding = "XMLDelEncoding"; //$NON-NLS-1$ + // final String XMLDeclVersion = "XMLDeclVersion"; +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/AttrImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/AttrImpl.java new file mode 100644 index 0000000000..959f512544 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/AttrImpl.java @@ -0,0 +1,756 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.document; + + + +import java.util.Iterator; + +import org.eclipse.wst.common.contentmodel.CMAttributeDeclaration; +import org.eclipse.wst.common.contentmodel.CMElementDeclaration; +import org.eclipse.wst.common.contentmodel.CMNamedNodeMap; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.core.text.ITextRegionContainer; +import org.eclipse.wst.sse.core.text.ITextRegionList; +import org.eclipse.wst.xml.core.document.XMLAttr; +import org.eclipse.wst.xml.core.document.XMLCharEntity; +import org.eclipse.wst.xml.core.document.XMLNamespace; +import org.eclipse.wst.xml.core.jsp.model.parser.temp.XMLJSPRegionContexts; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; +import org.w3c.dom.Attr; +import org.w3c.dom.DOMException; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + + +/** + * AttrImpl class + */ +public class AttrImpl extends NodeImpl implements XMLAttr { + private ITextRegion equalRegion = null; + + private String name = null; + private ITextRegion nameRegion = null; + private String namespaceURI = null; + private ElementImpl ownerElement = null; + private ITextRegion valueRegion = null; + private String valueSource = null; + + /** + * AttrImpl constructor + */ + protected AttrImpl() { + super(); + } + + /** + * AttrImpl constructor + * + * @param that + * AttrImpl + */ + protected AttrImpl(AttrImpl that) { + super(that); + + if (that != null) { + this.name = that.name; + this.valueSource = that.getValueSource(); + } + } + + /** + * cloneNode method + * + * @return org.w3c.dom.Node + */ + public Node cloneNode(boolean deep) { + AttrImpl cloned = new AttrImpl(this); + return cloned; + } + + /** + */ + protected CMAttributeDeclaration getDeclaration() { + ElementImpl element = (ElementImpl) getOwnerElement(); + if (element == null) + return null; + CMElementDeclaration elementDecl = element.getDeclaration(); + if (elementDecl == null) + return null; + CMNamedNodeMap attributes = elementDecl.getAttributes(); + if (attributes == null) + return null; + return (CMAttributeDeclaration) attributes.getNamedItem(getName()); + } + + /** + * getEndOffset method + * + * @return int + */ + public int getEndOffset() { + if (this.ownerElement == null) + return 0; + int offset = this.ownerElement.getStartOffset(); + if (this.valueRegion != null) { + return (offset + this.valueRegion.getEnd()); + } + if (this.equalRegion != null) { + return (offset + this.equalRegion.getEnd()); + } + if (this.nameRegion != null) { + return (offset + this.nameRegion.getEnd()); + } + return 0; + } + + /** + * getEqualRegion method + * + * @return com.ibm.sed.structuredDocument.ITextRegion + */ + public ITextRegion getEqualRegion() { + return this.equalRegion; + } + + /** + */ + public String getLocalName() { + if (this.name == null) + return null; + int index = this.name.indexOf(':'); + if (index < 0) + return this.name; + return this.name.substring(index + 1); + } + + /** + * getName method + * + * @return java.lang.String + */ + public String getName() { + if (this.name == null) + return new String(); + return this.name; + } + + /** + * getNameRegion method + * + * @return com.ibm.sed.structuredDocument.ITextRegion + */ + public ITextRegion getNameRegion() { + return this.nameRegion; + } + + public int getNameRegionEndOffset() { + if (this.ownerElement == null) + return 0; + // assuming the firstStructuredDocumentRegion is the one that contains + // attributes + IStructuredDocumentRegion flatNode = this.ownerElement.getFirstStructuredDocumentRegion(); + if (flatNode == null) + return 0; + return flatNode.getEndOffset(this.nameRegion); + } + + public int getNameRegionStartOffset() { + if (this.ownerElement == null) + return 0; + // assuming the firstStructuredDocumentRegion is the one that contains + // attributes + IStructuredDocumentRegion flatNode = this.ownerElement.getFirstStructuredDocumentRegion(); + if (flatNode == null) + return 0; + return flatNode.getStartOffset(this.nameRegion); + } + + public String getNameRegionText() { + if (this.ownerElement == null) + return null; + // assuming the firstStructuredDocumentRegion is the one that contains + // attributes + IStructuredDocumentRegion flatNode = this.ownerElement.getFirstStructuredDocumentRegion(); + if (flatNode == null) + return null; + return flatNode.getText(this.nameRegion); + } + + public int getNameRegionTextEndOffset() { + if (this.ownerElement == null) + return 0; + // assuming the firstStructuredDocumentRegion is the one that contains + // attributes + IStructuredDocumentRegion flatNode = this.ownerElement.getFirstStructuredDocumentRegion(); + if (flatNode == null) + return 0; + return flatNode.getTextEndOffset(this.nameRegion); + } + + /** + */ + public String getNamespaceURI() { + String nsAttrName = null; + String prefix = getPrefix(); + if (prefix != null && prefix.length() > 0) { + if (prefix.equals(XMLNamespace.XMLNS)) { + // fixed URI + return XMLNamespace.XMLNS_URI; + } + nsAttrName = XMLNamespace.XMLNS_PREFIX + prefix; + } else { + String name = getName(); + if (name != null && name.equals(XMLNamespace.XMLNS)) { + // fixed URI + return XMLNamespace.XMLNS_URI; + } + // does not inherit namespace from owner element + // if (this.ownerElement != null) return + // this.ownerElement.getNamespaceURI(); + return this.namespaceURI; + } + + for (Node node = this.ownerElement; node != null; node = node.getParentNode()) { + if (node.getNodeType() != ELEMENT_NODE) + break; + Element element = (Element) node; + Attr attr = element.getAttributeNode(nsAttrName); + if (attr != null) + return attr.getValue(); + } + + return this.namespaceURI; + } + + /** + * getNodeName method + * + * @return java.lang.String + */ + public String getNodeName() { + return getName(); + } + + /** + * getNodeType method + * + * @return short + */ + public short getNodeType() { + return ATTRIBUTE_NODE; + } + + /** + * getNodeValue method + * + * @return java.lang.String + */ + public String getNodeValue() { + return getValue(); + } + + /** + * getOwnerElement method + * + * @return org.w3c.dom.Element + */ + public Element getOwnerElement() { + return this.ownerElement; + } + + /** + */ + public String getPrefix() { + if (this.name == null) + return null; + int index = this.name.indexOf(':'); + if (index <= 0) + return null; + // exclude JSP tag in name + if (this.name.charAt(0) == '<') + return null; + return this.name.substring(0, index); + } + + /** + * getSpecified method + * + * @return boolean + */ + public boolean getSpecified() { + return true; + } + + /** + * getStartOffset method + * + * @return int + */ + public int getStartOffset() { + if (this.ownerElement == null) + return 0; + int offset = this.ownerElement.getStartOffset(); + if (this.nameRegion != null) { + return (offset + this.nameRegion.getStart()); + } + if (this.equalRegion != null) { + return (offset + this.equalRegion.getStart()); + } + if (this.valueRegion != null) { + return (offset + this.valueRegion.getStart()); + } + return 0; + } + + /** + * getValue method + * + * @return java.lang.String + */ + public String getValue() { + return getValue(getValueSource()); + } + + /** + * Returns value for the source + */ + private String getValue(String source) { + if (source == null) + return new String(); + if (source.length() == 0) + return source; + StringBuffer buffer = null; + int offset = 0; + int length = source.length(); + int ref = source.indexOf('&'); + while (ref >= 0) { + int end = source.indexOf(';', ref + 1); + if (end > ref + 1) { + String name = source.substring(ref + 1, end); + String value = getCharValue(name); + if (value != null) { + if (buffer == null) + buffer = new StringBuffer(length); + if (ref > offset) + buffer.append(source.substring(offset, ref)); + buffer.append(value); + offset = end + 1; + ref = end; + } + } + ref = source.indexOf('&', ref + 1); + } + if (buffer == null) + return source; + if (length > offset) + buffer.append(source.substring(offset)); + return buffer.toString(); + } + + /** + * getValueRegion method + * + * @return com.ibm.sed.structuredDocument.ITextRegion + */ + public ITextRegion getValueRegion() { + return this.valueRegion; + } + + public int getValueRegionStartOffset() { + if (this.ownerElement == null) + return 0; + // assuming the firstStructuredDocumentRegion is the one that contains + // attributes + IStructuredDocumentRegion flatNode = this.ownerElement.getFirstStructuredDocumentRegion(); + if (flatNode == null) + return 0; + return flatNode.getStartOffset(this.valueRegion); + } + + public String getValueRegionText() { + if (this.ownerElement == null) + return null; + // assuming the firstStructuredDocumentRegion is the one that contains + // attributes + IStructuredDocumentRegion flatNode = this.ownerElement.getFirstStructuredDocumentRegion(); + if (flatNode == null) + return null; + if (this.valueRegion == null) + return null; + return flatNode.getText(this.valueRegion); + } + + /** + */ + public String getValueSource() { + if (this.valueSource != null) + return this.valueSource; + // DW: 4/16/2003 due to change in structuredDocument ... we need a + // flatnode to + // get at region values. For now I'll assume this is always the first + // flatnode .. may need to make smarter later (e.g. to search for + // the flatnode that this.valueRegion belongs to. + // DW: 4/30/2003 For some reason, this method is getting called a lot + // Not sure if its a threading problem, or a fundamental error + // elsewhere. + // It needs more investigation, but in the use cases I've seen, + // doesn't + // seem to hurt to simply return null in those cases. I saw this null + // case, + // when tryint go format an XML file. + if (this.ownerElement == null) + return null; + IStructuredDocumentRegion ownerRegion = this.ownerElement.getFirstStructuredDocumentRegion(); + if (ownerRegion == null) + return null; + if (this.valueRegion != null) + return StructuredDocumentRegionUtil.getAttrValue(ownerRegion, this.valueRegion); + return new String(); + } + + private String getValueSource(ElementImpl ownerElement) { + if (this.valueSource != null) + return this.valueSource; + // DW: 4/16/2003 due to change in structuredDocument ... we need a + // flatnode to + // get at region values. For now I'll assume this is always the first + // flatnode .. may need to make smarter later (e.g. to search for + // the flatnode that this.valueRegion belongs to. + if (this.valueRegion != null) + return StructuredDocumentRegionUtil.getAttrValue(ownerElement.getStructuredDocumentRegion(), this.valueRegion); + return new String(); + } + + /** + */ + private String getValueSource(String value) { + if (value == null) + return null; + if (value.length() == 0) + return value; + StringBuffer buffer = null; + int offset = 0; + int length = value.length(); + int amp = value.indexOf('&'); + while (amp >= 0) { + if (buffer == null) + buffer = new StringBuffer(length + 4); + if (amp > offset) + buffer.append(value.substring(offset, amp)); + buffer.append(XMLCharEntity.AMP_REF); + offset = amp + 1; + amp = value.indexOf('&', offset); + } + if (buffer == null) + return value; + if (length > offset) + buffer.append(value.substring(offset)); + return buffer.toString(); + } + + /** + * Check if Attr has JSP in value + */ + public boolean hasJSPValue() { + if (this.valueRegion == null) + return false; + if (!(this.valueRegion instanceof ITextRegionContainer)) + return false; + ITextRegionList regions = ((ITextRegionContainer) this.valueRegion).getRegions(); + if (regions == null) + return false; + Iterator e = regions.iterator(); + while (e.hasNext()) { + ITextRegion region = (ITextRegion) e.next(); + if (region == null) + continue; + String regionType = region.getType(); + if (regionType == XMLRegionContext.XML_TAG_OPEN || regionType == XMLJSPRegionContexts.JSP_SCRIPTLET_OPEN || regionType == XMLJSPRegionContexts.JSP_EXPRESSION_OPEN || regionType == XMLJSPRegionContexts.JSP_DECLARATION_OPEN || regionType == XMLJSPRegionContexts.JSP_DIRECTIVE_OPEN) + return true; + } + return false; + } + + /** + * Check if Attr has only name but not equal sign nor value + */ + public boolean hasNameOnly() { + return (this.nameRegion != null && this.equalRegion == null && this.valueRegion == null); + } + + /** + */ + protected final boolean hasPrefix() { + if (this.name == null) + return false; + if (this.name.indexOf(':') <= 0) + return false; + // exclude JSP tag in name + if (this.name.charAt(0) == '<') + return false; + return true; + } + + /** + */ + protected final boolean ignoreCase() { + if (this.ownerElement != null) { + if (this.ownerElement.ignoreCase()) { + return !hasPrefix(); + } + } else { + DocumentImpl document = (DocumentImpl) getOwnerDocument(); + if (document != null && document.ignoreCase()) { + // even in case insensitive document, if having prefix, it's + // case sensitive + return !hasPrefix(); + } + } + return false; + } + + /** + */ + public boolean isGlobalAttr() { + if (hasPrefix()) + return false; + if (this.ownerElement == null) + return false; + return this.ownerElement.isGlobalTag(); + } + + /** + */ + public final boolean isXMLAttr() { + if (this.ownerElement != null) { + if (!this.ownerElement.isXMLTag()) { + return hasPrefix(); + } + } else { + DocumentImpl document = (DocumentImpl) getOwnerDocument(); + if (document != null && !document.isXMLType()) { + // even in non-XML document, if having prefix, it's XML tag + return hasPrefix(); + } + } + return true; + } + + /** + * matchName method + * + * @return boolean + * @param name + * java.lang.String + */ + protected boolean matchName(String name) { + if (name == null) + return (this.name == null); + if (this.name == null) + return false; + if (!ignoreCase()) + return this.name.equals(name); + return this.name.equalsIgnoreCase(name); + } + + /** + * notifyValueChanged method + */ + protected void notifyNameChanged() { + if (this.ownerElement == null) + return; + DocumentImpl document = (DocumentImpl) this.ownerElement.getContainerDocument(); + if (document == null) + return; + XMLModelImpl model = (XMLModelImpl) document.getModel(); + if (model == null) + return; + model.nameChanged(this); + } + + /** + * notifyValueChanged method + */ + protected void notifyValueChanged() { + if (this.ownerElement == null) + return; + DocumentImpl document = (DocumentImpl) this.ownerElement.getContainerDocument(); + if (document == null) + return; + XMLModelImpl model = (XMLModelImpl) document.getModel(); + if (model == null) + return; + model.valueChanged(this); + } + + /** + * removeRegions method + */ + void removeRegions() { + this.nameRegion = null; + this.valueRegion = null; + this.equalRegion = null; + } + + /** + */ + void resetRegions() { + this.valueSource = getValueSource(); + removeRegions(); + } + + /** + */ + void resetRegions(ElementImpl ownerElement) { + this.valueSource = getValueSource(ownerElement); + removeRegions(); + } + + /** + * setEqualRegion method + * + * @param equalRegion + * com.ibm.sed.structuredDocument.ITextRegion + */ + void setEqualRegion(ITextRegion equalRegion) { + this.equalRegion = equalRegion; + } + + /** + * setName method + * + * @param name + * java.lang.String + */ + protected void setName(String name) { + String value = null; + int startOffset = 0; + if (this.ownerElement != null) { + value = getValue(); + startOffset = this.ownerElement.getStartOffset(); + this.ownerElement.notify(CHANGE, this, value, null, startOffset); + } + this.name = name; + if (this.ownerElement != null) { + this.ownerElement.notify(CHANGE, this, null, value, startOffset); + } + } + + /** + * setNameRegion method + * + * @param nameRegion + * com.ibm.sed.structuredDocument.ITextRegion + */ + void setNameRegion(ITextRegion nameRegion) { + this.nameRegion = nameRegion; + } + + /** + */ + protected void setNamespaceURI(String namespaceURI) { + this.namespaceURI = namespaceURI; + } + + /** + * setNodeValue method + * + * @param nodeValue + * java.lang.String + */ + public void setNodeValue(String nodeValue) throws DOMException { + setValue(nodeValue); + } + + /** + * setOwnerElement method + * + * @param ownerElement + * org.w3c.dom.Element + */ + protected void setOwnerElement(Element ownerElement) { + this.ownerElement = (ElementImpl) ownerElement; + } + + /** + */ + public void setPrefix(String prefix) throws DOMException { + if (this.ownerElement != null && !this.ownerElement.isDataEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + int prefixLength = (prefix != null ? prefix.length() : 0); + String localName = getLocalName(); + if (prefixLength == 0) { + setName(localName); + return; + } + if (localName == null) + localName = new String(); + int localLength = localName.length(); + StringBuffer buffer = new StringBuffer(prefixLength + 1 + localLength); + buffer.append(prefix); + buffer.append(':'); + buffer.append(localName); + setName(buffer.toString()); + + notifyNameChanged(); + } + + /** + * setValue method + * + * @param value + * java.lang.String + */ + public void setValue(String value) { + // Remember: as we account for "floaters" in + // future, remember that some are created + // in the natural process of implementing + // DOM apis. + // this "self notification" of about/changed, + // is added for this case, because it known to + // be called from properties pages. Should be a + // added to all DOM Modifiying APIs eventually. + try { + getModel().aboutToChangeModel(); + setValueSource(getValueSource(value)); + } finally { + getModel().changedModel(); + } + } + + /** + * setValueRegion method + * + * @param newValueRegion + * com.ibm.sed.structuredDocument.ITextRegion + */ + void setValueRegion(ITextRegion valueRegion) { + this.valueRegion = valueRegion; + if (valueRegion != null) + this.valueSource = null; + } + + /** + */ + public void setValueSource(String source) { + if (this.ownerElement != null && !this.ownerElement.isDataEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + this.valueSource = source; + + notifyValueChanged(); + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/CDATASectionImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/CDATASectionImpl.java new file mode 100644 index 0000000000..3954ca2d40 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/CDATASectionImpl.java @@ -0,0 +1,140 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.document; + + + +import java.util.Iterator; + +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.core.text.ITextRegionList; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; +import org.w3c.dom.CDATASection; +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; + + +/** + * CDATASectionImpl class + */ +public class CDATASectionImpl extends TextImpl implements CDATASection { + + /** + * CDATASectionImpl constructor + */ + protected CDATASectionImpl() { + super(); + } + + /** + * CDATASectionImpl constructor + * + * @param that + * CDATASectionImpl + */ + protected CDATASectionImpl(CDATASectionImpl that) { + super(that); + } + + /** + * cloneNode method + * + * @return org.w3c.dom.Node + * @param deep + * boolean + */ + public Node cloneNode(boolean deep) { + CDATASectionImpl cloned = new CDATASectionImpl(this); + return cloned; + } + + /** + * getData method + * + * @return java.lang.String + */ + public String getData() throws DOMException { + // instead of super(TextImpl).getData(), call getCharacterData() + String data = getCharacterData(); + if (data == null) { + data = getData(getStructuredDocumentRegion()); + if (data == null) + data = new String(); + } + return data; + } + + /** + */ + private String getData(IStructuredDocumentRegion flatNode) { + if (flatNode == null) + return null; + ITextRegionList regions = flatNode.getRegions(); + if (regions == null) + return null; + + ITextRegion contentRegion = null; + StringBuffer buffer = null; + Iterator e = regions.iterator(); + while (e.hasNext()) { + ITextRegion region = (ITextRegion) e.next(); + String regionType = region.getType(); + if (regionType == XMLRegionContext.XML_CDATA_OPEN || regionType == XMLRegionContext.XML_CDATA_CLOSE) { + continue; + } + if (contentRegion == null) { // first content + contentRegion = region; + } else { // multiple contents + if (buffer == null) { + buffer = new StringBuffer(flatNode.getText(contentRegion)); + } + buffer.append(flatNode.getText(region)); + } + } + + if (buffer != null) + return buffer.toString(); + if (contentRegion != null) + return flatNode.getText(contentRegion); + return null; + } + + /** + * getNodeName method + * + * @return java.lang.String + */ + public String getNodeName() { + return "#cdata-section";//$NON-NLS-1$ + } + + /** + * getNodeType method + * + * @return short + */ + public short getNodeType() { + return CDATA_SECTION_NODE; + } + + /** + */ + public boolean isClosed() { + IStructuredDocumentRegion flatNode = getStructuredDocumentRegion(); + if (flatNode == null) + return true; // will be generated + String regionType = StructuredDocumentRegionUtil.getLastRegionType(flatNode); + return (regionType == XMLRegionContext.XML_CDATA_CLOSE); + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/CMNodeUtil.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/CMNodeUtil.java new file mode 100644 index 0000000000..44ecfabad5 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/CMNodeUtil.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.document; + + + +import org.eclipse.wst.common.contentmodel.CMAttributeDeclaration; +import org.eclipse.wst.common.contentmodel.CMElementDeclaration; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; + + +/** + */ +public class CMNodeUtil { + + /** + */ + public static CMAttributeDeclaration getAttributeDeclaration(Attr attr) { + if (attr == null) + return null; + return ((AttrImpl) attr).getDeclaration(); + } + + /** + */ + public static CMElementDeclaration getElementDeclaration(Element element) { + if (element == null) + return null; + return ((ElementImpl) element).getDeclaration(); + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/CharacterDataImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/CharacterDataImpl.java new file mode 100644 index 0000000000..4c4a2dbc72 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/CharacterDataImpl.java @@ -0,0 +1,353 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.document; + + + +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.xml.core.jsp.model.parser.temp.XMLJSPRegionContexts; +import org.w3c.dom.CharacterData; +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; + + +/** + * CharacterDataImpl class + */ +public abstract class CharacterDataImpl extends NodeImpl implements XMLJSPRegionContexts, CharacterData { + + private String data = null; + + /** + * CharacterDataImpl constructor + */ + protected CharacterDataImpl() { + super(); + } + + /** + * CharacterDataImpl constructor + * + * @param that + * CharacterDataImpl + */ + protected CharacterDataImpl(CharacterDataImpl that) { + super(that); + + if (that != null) { + this.data = that.getData(); + } + } + + /** + * appendData method + * + * @param arg + * java.lang.String + */ + public void appendData(String arg) throws DOMException { + if (arg == null) + return; + + String data = getData(); + if (data == null) + data = arg; + else + data += arg; + setData(data); + } + + /** + * deleteData method + * + * @param offset + * int + * @param count + * int + */ + public void deleteData(int offset, int count) throws DOMException { + if (count == 0) + return; + if (!isDataEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + + if (count < 0 || offset < 0) { + throw new DOMException(DOMException.INDEX_SIZE_ERR, new String()); + } + + String data = getData(); + if (data == null) { + throw new DOMException(DOMException.INDEX_SIZE_ERR, new String()); + } + int length = data.length(); + if (offset > length) { + throw new DOMException(DOMException.INDEX_SIZE_ERR, new String()); + } + if (offset == 0) { + if (count > length) { + throw new DOMException(DOMException.INDEX_SIZE_ERR, new String()); + } + if (count == length) + data = new String(); + else + data = data.substring(count); + } else { + int end = offset + count; + if (end > length) { + throw new DOMException(DOMException.INDEX_SIZE_ERR, new String()); + } + if (end == length) + data = data.substring(0, offset); + else + data = data.substring(0, offset) + data.substring(end); + } + setData(data); + } + + /** + */ + protected final String getCharacterData() { + return this.data; + } + + /** + * getData method + * + * @return java.lang.String + */ + public String getData() throws DOMException { + return getCharacterData(); + } + + /** + * getLength method + * + * @return int + */ + public int getLength() { + String data = getData(); + if (data == null) + return 0; + return data.length(); + } + + /** + * getNodeValue method + * + * @return java.lang.String + */ + public String getNodeValue() { + return getData(); + } + + /** + * insertData method + * + * @param offset + * int + * @param arg + * java.lang.String + */ + public void insertData(int offset, String arg) throws DOMException { + if (arg == null) + return; + + if (!isDataEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + + if (offset < 0) { + throw new DOMException(DOMException.INDEX_SIZE_ERR, new String()); + } + + String data = getData(); + if (data == null) { + if (offset > 0) { + throw new DOMException(DOMException.INDEX_SIZE_ERR, new String()); + } + data = arg; + } else if (offset == 0) { + data = arg + data; + } else { + int length = data.length(); + if (offset > length) { + throw new DOMException(DOMException.INDEX_SIZE_ERR, new String()); + } + if (offset == length) + data += arg; + else + data = data.substring(0, offset) + arg + data.substring(offset); + } + setData(data); + } + + /** + * isJSPContent method + * + * @return boolean + */ + public boolean isJSPContent() { + Node parent = getParentNode(); + if (parent == null || parent.getNodeType() != Node.ELEMENT_NODE) + return false; + ElementImpl element = (ElementImpl) parent; + return element.isJSPContainer(); + } + + /** + * replaceData method + * + * @param offset + * int + * @param count + * int + * @param arg + * java.lang.String + */ + public void replaceData(int offset, int count, String arg) throws DOMException { + if (!isDataEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + + if (arg == null) { + deleteData(offset, count); + return; + } + if (count == 0) { + insertData(offset, arg); + return; + } + if (offset < 0 || count < 0) { + throw new DOMException(DOMException.INDEX_SIZE_ERR, new String()); + } + + String data = getData(); + if (data == null) { + throw new DOMException(DOMException.INDEX_SIZE_ERR, new String()); + } else if (offset == 0) { + int length = data.length(); + if (count > length) { + throw new DOMException(DOMException.INDEX_SIZE_ERR, new String()); + } + if (count == length) + data = arg; + else + data = arg + data.substring(count); + } else { + int length = data.length(); + int end = offset + count; + if (end > length) { + throw new DOMException(DOMException.INDEX_SIZE_ERR, new String()); + } + if (end == length) + data = data.substring(0, offset) + arg; + else + data = data.substring(0, offset) + arg + data.substring(end); + } + setData(data); + } + + /** + */ + void resetStructuredDocumentRegions() { + this.data = getData(); + setStructuredDocumentRegion(null); + } + + /** + * setData method + * + * @param data + * java.lang.String + */ + public void setData(String data) throws DOMException { + if (!isDataEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + + this.data = data; + + notifyValueChanged(); + } + + /** + * setNodeValue method + * + * @param nodeValue + * java.lang.String + */ + public void setNodeValue(String nodeValue) throws DOMException { + setData(nodeValue); + } + + /** + */ + void setStructuredDocumentRegion(IStructuredDocumentRegion flatNode) { + super.setStructuredDocumentRegion(flatNode); + if (flatNode != null) + this.data = null; + } + + /** + * substringData method + * + * @return java.lang.String + * @param offset + * int + * @param count + * int + */ + public String substringData(int offset, int count) throws DOMException { + if (count == 0) + return new String(); + if (offset < 0 || count < 0) { + throw new DOMException(DOMException.INDEX_SIZE_ERR, new String()); + } + + String data = getData(); + if (data == null) { + throw new DOMException(DOMException.INDEX_SIZE_ERR, new String()); + } + int length = data.length(); + if (offset == 0 && count == length) + return data; + if (offset > length) { + throw new DOMException(DOMException.INDEX_SIZE_ERR, new String()); + } + int end = offset + count; + if (end > length) { + throw new DOMException(DOMException.INDEX_SIZE_ERR, new String()); + } + return data.substring(offset, end); + } + + /** + * toString method + * + * @return java.lang.String + */ + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append(getNodeName()); + buffer.append('('); + buffer.append(getData()); + buffer.append(')'); + IStructuredDocumentRegion flatNode = getStructuredDocumentRegion(); + if (flatNode != null) { + buffer.append('@'); + buffer.append(flatNode.toString()); + } + return buffer.toString(); + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/CommentImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/CommentImpl.java new file mode 100644 index 0000000000..2d8d257072 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/CommentImpl.java @@ -0,0 +1,183 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.document; + + + +import java.util.Iterator; + +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.core.text.ITextRegionList; +import org.eclipse.wst.xml.core.jsp.model.parser.temp.XMLJSPRegionContexts; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; +import org.w3c.dom.Comment; +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; + + +/** + * CommentImpl class + */ +public class CommentImpl extends CharacterDataImpl implements Comment { + + private boolean isJSPTag = false; + + /** + * CommentImpl constructor + */ + protected CommentImpl() { + super(); + } + + /** + * CommentImpl constructor + * + * @param that + * CommentImpl + */ + protected CommentImpl(CommentImpl that) { + super(that); + + if (that != null) { + this.isJSPTag = that.isJSPTag; + } + } + + /** + * cloneNode method + * + * @return org.w3c.dom.Node + * @param deep + * boolean + */ + public Node cloneNode(boolean deep) { + CommentImpl cloned = new CommentImpl(this); + return cloned; + } + + /** + * getData method + * + * @return java.lang.String + */ + public String getData() throws DOMException { + String data = getCharacterData(); + if (data == null) { + data = getData(getStructuredDocumentRegion()); + if (data == null) + data = new String(); + } + return data; + } + + /** + */ + private String getData(IStructuredDocumentRegion flatNode) { + if (flatNode == null) + return null; + ITextRegionList regions = flatNode.getRegions(); + if (regions == null) + return null; + + ITextRegion contentRegion = null; + StringBuffer buffer = null; + Iterator e = regions.iterator(); + while (e.hasNext()) { + ITextRegion region = (ITextRegion) e.next(); + String regionType = region.getType(); + if (regionType == XMLRegionContext.XML_COMMENT_OPEN || regionType == JSP_COMMENT_OPEN || regionType == XMLRegionContext.XML_COMMENT_CLOSE || regionType == JSP_COMMENT_CLOSE) { + continue; + } + if (contentRegion == null) { // first content + contentRegion = region; + } else { // multiple contents + if (buffer == null) { + buffer = new StringBuffer(flatNode.getText(contentRegion)); + } + buffer.append(flatNode.getText(region)); + } + } + + if (buffer != null) + return buffer.toString(); + if (contentRegion != null) + return flatNode.getText(contentRegion); + return null; + } + + /** + * getNodeName method + * + * @return java.lang.String + */ + public String getNodeName() { + return "#comment";//$NON-NLS-1$ + } + + /** + * getNodeType method + * + * @return short + */ + public short getNodeType() { + return COMMENT_NODE; + } + + /** + */ + public boolean isClosed() { + IStructuredDocumentRegion flatNode = getStructuredDocumentRegion(); + if (flatNode == null) + return true; // will be generated + String regionType = StructuredDocumentRegionUtil.getLastRegionType(flatNode); + return (regionType == XMLRegionContext.XML_COMMENT_CLOSE || regionType == XMLJSPRegionContexts.JSP_COMMENT_CLOSE); + } + + /** + * isJSP method + * + * @return boolean + */ + public boolean isJSPTag() { + return this.isJSPTag; + } + + /** + * setJSPTag method + * + * @param isJSPTag + * boolean + */ + public void setJSPTag(boolean isJSPTag) { + if (isJSPTag == this.isJSPTag) + return; + + if (!isDataEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + + DocumentImpl document = (DocumentImpl) getOwnerDocument(); + if (isJSPTag) { + if (document == null || !document.isJSPType()) + return; + } + + this.isJSPTag = isJSPTag; + + if (getContainerDocument() != null) { + // already in the tree, update IStructuredDocument + setData(getData()); // calls notifyValueChanged(); + } + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/DocumentFragmentImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/DocumentFragmentImpl.java new file mode 100644 index 0000000000..06058a549f --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/DocumentFragmentImpl.java @@ -0,0 +1,74 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.document; + + + +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.Node; + + +/** + * DocumentFragmentImpl class + */ +public class DocumentFragmentImpl extends NodeContainer implements DocumentFragment { + + /** + * DocumentFragmentImpl constructor + */ + protected DocumentFragmentImpl() { + super(); + } + + /** + * DocumentFragmentImpl constructor + * + * @param that + * DocumentFragmentImpl + */ + protected DocumentFragmentImpl(DocumentFragmentImpl that) { + super(that); + } + + /** + * cloneNode method + * + * @return org.w3c.dom.Node + * @param deep + * boolean + */ + public Node cloneNode(boolean deep) { + DocumentFragmentImpl cloned = new DocumentFragmentImpl(this); + if (deep) + cloneChildNodes(cloned, deep); + return cloned; + } + + /** + * getNodeName method + * + * @return java.lang.String + */ + public String getNodeName() { + return "#document-fragment";//$NON-NLS-1$ + } + + /** + * getNodeType method + * + * @return short + */ + public short getNodeType() { + return DOCUMENT_FRAGMENT_NODE; + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/DocumentImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/DocumentImpl.java new file mode 100644 index 0000000000..f4ca2cc236 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/DocumentImpl.java @@ -0,0 +1,1073 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.document; + + + +// for org.apache.xerces 3.2.1 +// import org.apache.xerces.utils.XMLCharacterProperties; +// DMW modified for XML4J 4.0.1 +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.wst.common.contentmodel.CMDocument; +import org.eclipse.wst.common.contentmodel.CMEntityDeclaration; +import org.eclipse.wst.common.contentmodel.CMNamedNodeMap; +import org.eclipse.wst.common.contentmodel.modelquery.ModelQuery; +import org.eclipse.wst.common.encoding.content.IContentTypeIdentifier; +import org.eclipse.wst.sse.core.modelhandler.IModelHandler; +import org.eclipse.wst.xml.core.NameValidator; +import org.eclipse.wst.xml.core.commentelement.impl.CommentElementRegistry; +import org.eclipse.wst.xml.core.document.DocumentTypeAdapter; +import org.eclipse.wst.xml.core.document.JSPTag; +import org.eclipse.wst.xml.core.document.XMLCharEntity; +import org.eclipse.wst.xml.core.document.XMLDocument; +import org.eclipse.wst.xml.core.document.XMLElement; +import org.eclipse.wst.xml.core.document.XMLModel; +import org.eclipse.wst.xml.core.modelquery.ModelQueryUtil; +import org.w3c.dom.Attr; +import org.w3c.dom.CDATASection; +import org.w3c.dom.Comment; +import org.w3c.dom.DOMException; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.DocumentType; +import org.w3c.dom.Element; +import org.w3c.dom.Entity; +import org.w3c.dom.EntityReference; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Notation; +import org.w3c.dom.ProcessingInstruction; +import org.w3c.dom.Text; +import org.w3c.dom.ranges.Range; +import org.w3c.dom.traversal.NodeFilter; +import org.w3c.dom.traversal.NodeIterator; +import org.w3c.dom.traversal.TreeWalker; + + +/** + * DocumentImpl class + */ +public class DocumentImpl extends NodeContainer implements XMLDocument { + + /** + * Internal-use only class. This class was added to better able to handle + * repetetive request for getElementsByTagName. The cache is cleared when + * ever the document changes at all, so still not real efficient, + */ + class TagNameCache { + + private boolean active = true; + + private Map cache; + + public TagNameCache() { + super(); + cache = new HashMap(); + } + + /** + * @param b + */ + public void activate(boolean b) { + active = b; + if (!b) + clear(); + } + + public void addItem(String tagname, NodeListImpl nodelist) { + if (tagname == null || nodelist == null) + return; + cache.put(tagname, nodelist); + } + + public void clear() { + cache.clear(); + } + + public NodeListImpl getItem(String tagName) { + NodeListImpl result = null; + if (active) { + result = (NodeListImpl) cache.get(tagName); + // if (result != null) { + // System.out.println("getElementsByTagname from cache: " + + // tagName); + // } + } + return result; + } + + } + + // this is a constant just to give compile-time control over + // whether or not to use the cache. If, in future, its found that + // there are no (or few) "duplicate requests" ... then this cache + // is not needed. + private static final boolean usetagnamecache = true; + private DocumentTypeAdapter documentTypeAdapter = null; + + private XMLModelImpl model = null; + private TagNameCache tagNameCache; + + /** + * DocumentImpl constructor + */ + protected DocumentImpl() { + super(); + if (usetagnamecache) { + tagNameCache = new TagNameCache(); + } + } + + /** + * DocumentImpl constructor + * + * @param that + * DocumentImpl + */ + protected DocumentImpl(DocumentImpl that) { + super(that); + if (usetagnamecache) { + tagNameCache = new TagNameCache(); + } + } + + /** + * @param b + */ + void activateTagNameCache(boolean b) { + tagNameCache.activate(b); + } + + /** + * <p> + * EXPERIMENTAL! Based on the <a + * href='http://www.w3.org/TR/2001/WD-DOM-Level-3-Core-20010605'>Document + * Object Model (DOM) Level 3 Core Working Draft of 5 June 2001. </a>. + * <p> + * Changes the <code>ownerDocument</code> of a node, its children, as + * well as the attached attribute nodes if there are any. If the node has + * a parent it is first removed from its parent child list. This + * effectively allows moving a subtree from one document to another. The + * following list describes the specifics for each type of node. + * <dl> + * <dt>ATTRIBUTE_NODE</dt> + * <dd>The <code>ownerElement</code> attribute is set to + * <code>null</code> and the <code>specified</code> flag is set to + * <code>true</code> on the adopted <code>Attr</code>. The + * descendants of the source <code>Attr</code> are recursively adopted. + * </dd> + * <dt>DOCUMENT_FRAGMENT_NODE</dt> + * <dd>The descendants of the source node are recursively adopted.</dd> + * <dt>DOCUMENT_NODE</dt> + * <dd><code>Document</code> nodes cannot be adopted.</dd> + * <dt>DOCUMENT_TYPE_NODE</dt> + * <dd><code>DocumentType</code> nodes cannot be adopted.</dd> + * <dt>ELEMENT_NODE</dt> + * <dd>Specified attribute nodes of the source element are adopted, and + * the generated <code>Attr</code> nodes. Default attributes are + * discarded, though if the document being adopted into defines default + * attributes for this element name, those are assigned. The descendants + * of the source element are recursively adopted.</dd> + * <dt>ENTITY_NODE</dt> + * <dd><code>Entity</code> nodes cannot be adopted.</dd> + * <dt>ENTITY_REFERENCE_NODE</dt> + * <dd>Only the <code>EntityReference</code> node itself is adopted, + * the descendants are discarded, since the source and destination + * documents might have defined the entity differently. If the document + * being imported into provides a definition for this entity name, its + * value is assigned.</dd> + * <dt>NOTATION_NODE</dt> + * <dd><code>Notation</code> nodes cannot be adopted.</dd> + * <dt>PROCESSING_INSTRUCTION_NODE, TEXT_NODE, CDATA_SECTION_NODE, + * COMMENT_NODE</dt> + * <dd>These nodes can all be adopted. No specifics.</dd> + * Should this method simply return null when it fails? How "exceptional" + * is failure for this method?Stick with raising exceptions only in + * exceptional circumstances, return null on failure (F2F 19 Jun 2000).Can + * an entity node really be adopted?No, neither can Notation nodes (Telcon + * 13 Dec 2000).Does this affect keys and hashCode's of the adopted + * subtree nodes?If so, what about readonly-ness of key and hashCode?if + * not, would appendChild affect keys/hashCodes or would it generate + * exceptions if key's are duplicate? Update: Hashcodes have been dropped. + * Given that the key is only unique within a document an adopted node + * needs to be given a new key, but what does it mean for the application? + * + * @param source + * The node to move into this document. + * @return The adopted node, or <code>null</code> if this operation + * fails, such as when the source node comes from a different + * implementation. + * @exception DOMException + * NOT_SUPPORTED_ERR: Raised if the source node is of type + * <code>DOCUMENT</code>,<code>DOCUMENT_TYPE</code>. + * <br> + * NO_MODIFICATION_ALLOWED_ERR: Raised when the source node + * is readonly. + * @since DOM Level 3 + */ + public org.w3c.dom.Node adoptNode(org.w3c.dom.Node source) throws org.w3c.dom.DOMException { + return null; + } + + /** + * @param tagName + */ + protected void checkTagNameValidity(String tagName) { + if (!isValidName(tagName)) { + throw new DOMException(DOMException.INVALID_CHARACTER_ERR, createDOMExceptionMessage(DOMException.INVALID_CHARACTER_ERR, tagName)); + } + } + + /** + * cloneNode method + * + * @return org.w3c.dom.Node + * @param deep + * boolean + */ + public Node cloneNode(boolean deep) { + DocumentImpl cloned = new DocumentImpl(this); + if (deep) + cloned.importChildNodes(this, true); + return cloned; + } + + /** + * createAttribute method + * + * @return org.w3c.dom.Attr + * @param name + * java.lang.String + */ + public Attr createAttribute(String name) throws DOMException { + AttrImpl attr = new AttrImpl(); + attr.setOwnerDocument(this); + attr.setName(name); + return attr; + } + + /** + */ + public Attr createAttributeNS(String uri, String name) throws DOMException { + AttrImpl attr = new AttrImpl(); + attr.setOwnerDocument(this); + attr.setName(name); + attr.setNamespaceURI(uri); + return attr; + } + + /** + * createCDATASection method + * + * @return org.w3c.dom.CDATASection + * @param data + * java.lang.String + */ + public CDATASection createCDATASection(String data) throws DOMException { + // allow CDATA section + // if (!isXMLType()) { + // throw new DOMException(DOMException.NOT_SUPPORTED_ERR, new + // String()); + // } + CDATASectionImpl cdata = new CDATASectionImpl(); + cdata.setOwnerDocument(this); + if (data != null) + cdata.setData(data); + return cdata; + } + + /** + * createComment method + * + * @return org.w3c.dom.Comment + * @param data + * java.lang.String + */ + public Comment createComment(String data) { + CommentImpl comment = new CommentImpl(); + comment.setOwnerDocument(this); + if (data != null) + comment.setData(data); + return comment; + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.model.xml.XMLDocument#createCommentElement(java.lang.String, + * boolean) + */ + public Element createCommentElement(String tagName, boolean isJSPTag) throws DOMException { + if (!isJSPType() && isJSPTag) { + throw new DOMException(DOMException.INVALID_MODIFICATION_ERR, new String()); + } + ElementImpl element = (ElementImpl) createElement(tagName); + element.setJSPTag(isJSPTag); + CommentElementRegistry registry = CommentElementRegistry.getInstance(); + if (registry.setupCommentElement(element)) { + return element; + } else { + throw new DOMException(DOMException.INVALID_CHARACTER_ERR, new String()); + } + } + + /** + * createDoctype method + * + * @return org.w3c.dom.DocumentType + * @param name + * java.lang.String + */ + public DocumentType createDoctype(String name) { + DocumentTypeImpl docType = new DocumentTypeImpl(); + docType.setOwnerDocument(this); + docType.setName(name); + return docType; + } + + /** + * createDocumentFragment method + * + * @return org.w3c.dom.DocumentFragment + */ + public DocumentFragment createDocumentFragment() { + DocumentFragmentImpl fragment = new DocumentFragmentImpl(); + fragment.setOwnerDocument(this); + return fragment; + } + + /** + * createElement method + * + * @return org.w3c.dom.Element + * @param tagName + * java.lang.String + */ + public Element createElement(String tagName) throws DOMException { + checkTagNameValidity(tagName); + + ElementImpl element = new ElementImpl(); + element.setOwnerDocument(this); + element.setTagName(tagName); + return element; + } + + /** + */ + public Element createElementNS(String uri, String tagName) throws DOMException { + if (!isValidName(tagName)) { + throw new DOMException(DOMException.INVALID_CHARACTER_ERR, new String()); + } + + ElementImpl element = new ElementImpl(); + element.setOwnerDocument(this); + element.setTagName(tagName); + element.setNamespaceURI(uri); + return element; + } + + /** + * createEntity method + * + * @return org.w3c.dom.Entity + * @param name + * java.lang.String + */ + public Entity createEntity(String name) { + EntityImpl entity = new EntityImpl(); + entity.setOwnerDocument(this); + entity.setName(name); + return entity; + } + + /** + * createEntityReference method + * + * @return org.w3c.dom.EntityReference + * @param name + * java.lang.String + */ + public EntityReference createEntityReference(String name) throws DOMException { + if (!isXMLType()) { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, new String()); + } + + EntityReferenceImpl ref = new EntityReferenceImpl(); + ref.setOwnerDocument(this); + ref.setName(name); + return ref; + } + + /** + */ + public NodeIterator createNodeIterator(Node root, int whatToShow, NodeFilter filter, boolean entityReferenceExpansion) { + if (root == null) + root = this; + return new NodeIteratorImpl(root, whatToShow, filter); + } + + /** + * createNotation method + * + * @return org.w3c.dom.Notation + * @param name + * java.lang.String + */ + public Notation createNotation(String name) { + NotationImpl notation = new NotationImpl(); + notation.setOwnerDocument(this); + notation.setName(name); + return notation; + } + + /** + * createProcessingInstruction method + * + * @return org.w3c.dom.ProcessingInstruction + * @param target + * java.lang.String + * @param data + * java.lang.String + */ + public ProcessingInstruction createProcessingInstruction(String target, String data) throws DOMException { + ProcessingInstructionImpl pi = new ProcessingInstructionImpl(); + pi.setOwnerDocument(this); + pi.setTarget(target); + if (data != null) + pi.setData(data); + return pi; + } + + /** + */ + public Range createRange() { + return new RangeImpl(); + } + + /** + * createTextNode method + * + * @return org.w3c.dom.Text + * @param data + * java.lang.String + */ + public Text createTextNode(String data) { + TextImpl text = new TextImpl(); + text.setOwnerDocument(this); + text.setData(data); + return text; + } + + /** + */ + public TreeWalker createTreeWalker(Node root, int whatToShow, NodeFilter filter, boolean entityReferenceExpansion) { + // not suppoerted + return null; + } + + private DocumentType findDoctype(Node node) { + for (Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) { + if (child.getNodeType() == DOCUMENT_TYPE_NODE && child instanceof DocumentType) { + return (DocumentType) child; + } else if (child.getNodeType() == ELEMENT_NODE && ((XMLElement) child).isCommentTag()) { + // search DOCTYPE inside of generic comment element + DocumentType docType = findDoctype(child); + if (docType != null) { + return docType; + } + } + } + + return null; + } + + private Element findDocumentElement(String docName, Node node, Node[] firstFound) { + for (Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) { + if (child.getNodeType() != ELEMENT_NODE) + continue; + ElementImpl element = (ElementImpl) child; + if (element.isCommentTag()) { + Element docElement = findDocumentElement(docName, element, firstFound); + if (docElement != null) { + return docElement; + } else { + // added 'else continue' to better handle cases where + // there is "more than one root" element + // especially complicated by CommentElements, which are + // sometimes treated as elements, but should + // be treated as comments in this context. + continue; + } + } + // note: the "name" won't match in the event of a jsp tag ... but + // incase + // the name is null, we do not want the jsp element returned as + // documentElement + if (element.isJSPTag()) + continue; + if (docName == null) + return element; + // use local name for namespace + String localName = element.getLocalName(); + if (localName == null) + continue; + if (isXMLType()) { + if (localName.equals(docName)) + return element; + } else { + if (localName.equalsIgnoreCase(docName)) + return element; + } + if (firstFound[0] == null) + firstFound[0] = element; + } + return null; + } + + /** + * getCharValue method + * + * @return java.lang.String + * @param name + * java.lang.String + */ + protected String getCharValue(String name) { + if (name == null) + return null; + int length = name.length(); + if (length == 0) + return null; + + if (name.charAt(0) == '#') { // character reference + if (length == 1) + return null; + int radix = 10; + String s = null; + // now allow hexadecimal also for non XML document + if (name.charAt(1) == 'x') { // hexadecimal + radix = 16; + s = name.substring(2); + } else { // decimal + s = name.substring(1); + } + if (s == null || s.length() == 0) + return null; + if (s.charAt(0) == '-') + return null; // no minus accepted + char c = 0; + try { + c = (char) Integer.parseInt(s, radix); + } catch (NumberFormatException ex) { + } + if (c == 0) + return null; + return String.valueOf(c); + } + + // implicit character entities for XML + if (name.equals(XMLCharEntity.LT_NAME)) + return XMLCharEntity.LT_VALUE; + if (name.equals(XMLCharEntity.GT_NAME)) + return XMLCharEntity.GT_VALUE; + if (name.equals(XMLCharEntity.AMP_NAME)) + return XMLCharEntity.AMP_VALUE; + if (name.equals(XMLCharEntity.QUOT_NAME)) + return XMLCharEntity.QUOT_VALUE; + if (isXMLType()) { + if (name.equals(XMLCharEntity.APOS_NAME)) + return XMLCharEntity.APOS_VALUE; + } + + CMDocument cm = getCMDocument(); + if (cm != null) { + CMNamedNodeMap map = cm.getEntities(); + if (map != null) { + CMEntityDeclaration decl = (CMEntityDeclaration) map.getNamedItem(name); + if (decl != null) { + String value = decl.getValue(); + if (value == null) + return null; + int valueLength = value.length(); + if (valueLength > 1 && value.charAt(0) == '&' && value.charAt(1) == '#' && value.charAt(valueLength - 1) == ';') { + // character reference + return getCharValue(value.substring(1, valueLength - 1)); + } + return value; + } + } + } + + return null; + } + + /** + */ + protected CMDocument getCMDocument() { + ModelQuery modelQuery = ModelQueryUtil.getModelQuery(this); + if (modelQuery == null) + return null; + return modelQuery.getCorrespondingCMDocument(this); + } + + /** + * getDoctype method + * + * @return org.w3c.dom.DocumentType + */ + public DocumentType getDoctype() { + return findDoctype(this); + } + + /** + * getDocumentElement + * + * @return org.w3c.dom.Element From DOM 2 Spec: documentElement of type + * Element [p.62] , readonly This is a convenience [p.119] + * attribute that allows direct access to the child node that is + * the root element of the document. For HTML documents, this is + * the element with the tagName "HTML". Note: we differ from this + * definition a little in that we don't necessarily take the first + * child but also look to match the name. In a well formed + * document, of course, the result is the same, but not + * necessarily the same in an ill-formed document. + */ + public Element getDocumentElement() { + String name = null; + DocumentType docType = getDocumentType(); + if (docType != null) { + name = docType.getName(); + } + + Element first[] = new Element[1]; + Element docElement = findDocumentElement(name, this, first); + if (docElement == null) { + docElement = first[0]; + } + + return docElement; + } + + /** + */ + protected DocumentType getDocumentType() { + DocumentTypeAdapter adapter = getDocumentTypeAdapter(); + if (adapter == null) + return getDoctype(); + return adapter.getDocumentType(); + } + + /** + */ + protected DocumentTypeAdapter getDocumentTypeAdapter() { + if (this.documentTypeAdapter == null) { + this.documentTypeAdapter = (DocumentTypeAdapter) getAdapterFor(DocumentTypeAdapter.class); + if (this.documentTypeAdapter == null) { + // add default adapter + this.documentTypeAdapter = new DocumentTypeAdapterImpl(this); + addAdapter(this.documentTypeAdapter); + } + } + return this.documentTypeAdapter; + } + + /** + */ + public String getDocumentTypeId() { + DocumentType docType = getDocumentType(); + if (docType == null) + return null; + String id = docType.getPublicId(); + if (id == null) + id = docType.getSystemId(); + return id; + } + + /** + */ + public Element getElementById(String id) { + if (id == null) + return null; + NodeIterator it = createNodeIterator(this, NodeFilter.SHOW_ALL, null, false); + if (it == null) + return null; + + for (Node node = it.nextNode(); node != null; node = it.nextNode()) { + if (node.getNodeType() != ELEMENT_NODE) + continue; + ElementImpl element = (ElementImpl) node; + String value = element.getAttribute("id");//$NON-NLS-1$ + if (value != null && value.equals(id)) + return element; + } + + return null; + } + + /** + * getElementsByTagName method + * + * @return org.w3c.dom.NodeList + * @param tagName + * java.lang.String + */ + public NodeList getElementsByTagName(String tagName) { + if (tagName == null) + return new NodeListImpl(); + + NodeListImpl elements = null; + + if (usetagnamecache) { + elements = tagNameCache.getItem(tagName); + } + + if (elements == null) { + elements = internalGetElementsByTagName(tagName); + + } + + return elements; + } + + /** + */ + public NodeList getElementsByTagNameNS(String uri, String tagName) { + if (tagName == null) + return new NodeListImpl(); + + NodeIterator it = createNodeIterator(this, NodeFilter.SHOW_ALL, null, false); + if (it == null) + return new NodeListImpl(); + NodeListImpl elements = new NodeListImpl(); + + if (uri != null && uri.length() == 1 && uri.charAt(0) == '*') { + uri = null; // do not care + } + if (tagName.length() == 1 && tagName.charAt(0) == '*') { + tagName = null; // do not care + } + + for (Node node = it.nextNode(); node != null; node = it.nextNode()) { + if (node.getNodeType() != ELEMENT_NODE) + continue; + ElementImpl element = (ElementImpl) node; + if (tagName != null) { + String localName = element.getLocalName(); + if (localName == null || !localName.equals(tagName)) + continue; + } + if (uri != null) { + String nsURI = element.getNamespaceURI(); + if (nsURI == null || !nsURI.equals(uri)) + continue; + } + elements.appendNode(element); + } + + return elements; + } + + /** + * <p> + * EXPERIMENTAL! Based on the <a + * href='http://www.w3.org/TR/2001/WD-DOM-Level-3-Core-20010605'>Document + * Object Model (DOM) Level 3 Core Working Draft of 5 June 2001. </a>. + * <p> + * An attribute specifying, as part of the XML declaration, the encoding + * of this document. This is <code>null</code> when unspecified. + * + * @since DOM Level 3 + */ + public java.lang.String getEncoding() { + return null; + } + + /** + */ + public DOMImplementation getImplementation() { + return model; + } + + /** + * other nodes will be referring to this one to get the owning model + */ + public XMLModel getModel() { + return model; + } + + /** + * getNodeName method + * + * @return java.lang.String + */ + public String getNodeName() { + return "#document";//$NON-NLS-1$ + } + + /** + * getNodeType method + * + * @return short + */ + public short getNodeType() { + return DOCUMENT_NODE; + } + + /** + * <p> + * EXPERIMENTAL! Based on the <a + * href='http://www.w3.org/TR/2001/WD-DOM-Level-3-Core-20010605'>Document + * Object Model (DOM) Level 3 Core Working Draft of 5 June 2001. </a>. + * <p> + * An attribute specifying, as part of the XML declaration, whether this + * document is standalone. + * + * @since DOM Level 3 + */ + public boolean getStandalone() { + return false; + } + + /** + * <p> + * EXPERIMENTAL! Based on the <a + * href='http://www.w3.org/TR/2001/WD-DOM-Level-3-Core-20010605'>Document + * Object Model (DOM) Level 3 Core Working Draft of 5 June 2001. </a>. + * <p> + * An attribute specifying whether errors checking is enforced or not. + * When set to <code>false</code>, the implementation is free to not + * test every possible error case normally defined on DOM operations, and + * not raise any <code>DOMException</code>. In case of error, the + * behavior is undefined. This attribute is <code>true</code> by + * defaults. + * + * @since DOM Level 3 + */ + public boolean getStrictErrorChecking() { + return false; + } + + /** + * <p> + * EXPERIMENTAL! Based on the <a + * href='http://www.w3.org/TR/2001/WD-DOM-Level-3-Core-20010605'>Document + * Object Model (DOM) Level 3 Core Working Draft of 5 June 2001. </a>. + * <p> + * An attribute specifying, as part of the XML declaration, the version + * number of this document. This is <code>null</code> when unspecified. + * + * @since DOM Level 3 + */ + public String getVersion() { + return null; + } + + /** + */ + protected boolean ignoreCase() { + DocumentTypeAdapter adapter = getDocumentTypeAdapter(); + if (adapter == null) + return false; + return (adapter.getTagNameCase() != DocumentTypeAdapter.STRICT_CASE); + } + + /** + */ + protected void importChildNodes(Node parent, boolean deep) { + if (parent == null) + return; + + removeChildNodes(); + + for (Node child = parent.getFirstChild(); child != null; child = child.getNextSibling()) { + Node imported = importNode(child, deep); + if (imported == null) + continue; + appendChild(imported); + } + } + + /** + */ + public Node importNode(Node node, boolean deep) throws DOMException { + if (node == null) + return null; + NodeImpl imported = (NodeImpl) node.cloneNode(deep); + if (imported == null) + return null; + imported.setOwnerDocument(this, deep); + return imported; + } + + private NodeListImpl internalGetElementsByTagName(String tagName) { + //System.out.println("getElementsByTagname: " + tagName); + NodeIterator it = createNodeIterator(this, NodeFilter.SHOW_ALL, null, false); + if (it == null) + return new NodeListImpl(); + NodeListImpl elements = new NodeListImpl(); + + if (tagName.length() == 1 && tagName.charAt(0) == '*') { + tagName = null; // do not care + } + + for (Node node = it.nextNode(); node != null; node = it.nextNode()) { + if (node.getNodeType() != ELEMENT_NODE) + continue; + if (tagName != null) { + ElementImpl element = (ElementImpl) node; + if (!element.matchTagName(tagName)) + continue; + } + elements.appendNode(node); + } + if (usetagnamecache) { + tagNameCache.addItem(tagName, elements); + } + return elements; + } + + /** + */ + public boolean isJSPDocument() { + Element element = getDocumentElement(); + if (element == null) + return false; + String tagName = element.getTagName(); + if (tagName == null) + return false; + return tagName.equals(JSPTag.JSP_ROOT); + } + + /** + */ + public boolean isJSPType() { + if (this.model == null) + return false; + IModelHandler handler = this.model.getModelHandler(); + if (handler == null) + return false; + String id = handler.getAssociatedContentTypeId(); + if (id == null) + return false; + // TODO: -- avoid this semi hardcoded string + return id.equals(IContentTypeIdentifier.ContentTypeID_JSP); + } + + /** + */ + protected boolean isValidName(String name) { + if (name == null || name.length() == 0) + return false; + // // DMW: modified for XML4J 4.0.1 + // if (XMLChar.isValidName(name)) return true; + if (NameValidator.isValid(name)) + return true; + // special for invalid declaration + if (name.length() == 1 && name.charAt(0) == '!') + return true; + // special for JSP tag in tag name + if (name.startsWith(JSPTag.TAG_OPEN)) + return true; + return false; + } + + /** + */ + public boolean isXMLType() { + DocumentTypeAdapter adapter = getDocumentTypeAdapter(); + if (adapter == null) + return true; + return adapter.isXMLType(); + } + + /** + */ + protected void releaseDocumentType() { + if (this.documentTypeAdapter == null) + return; + this.documentTypeAdapter.release(); + this.documentTypeAdapter = null; + } + + /** + * <p> + * EXPERIMENTAL! Based on the <a + * href='http://www.w3.org/TR/2001/WD-DOM-Level-3-Core-20010605'>Document + * Object Model (DOM) Level 3 Core Working Draft of 5 June 2001. </a>. + * <p> + * An attribute specifying, as part of the XML declaration, the encoding + * of this document. This is <code>null</code> when unspecified. + * + * @since DOM Level 3 + */ + public void setEncoding(java.lang.String encoding) { + } + + /** + * setModel method + * + * @param model + * XMLModel + */ + + protected void setModel(XMLModel model) { + this.model = (XMLModelImpl) model; + } + + /** + * <p> + * EXPERIMENTAL! Based on the <a + * href='http://www.w3.org/TR/2001/WD-DOM-Level-3-Core-20010605'>Document + * Object Model (DOM) Level 3 Core Working Draft of 5 June 2001. </a>. + * <p> + * An attribute specifying, as part of the XML declaration, whether this + * document is standalone. + * + * @since DOM Level 3 + */ + public void setStandalone(boolean standalone) { + } + + /** + * <p> + * EXPERIMENTAL! Based on the <a + * href='http://www.w3.org/TR/2001/WD-DOM-Level-3-Core-20010605'>Document + * Object Model (DOM) Level 3 Core Working Draft of 5 June 2001. </a>. + * <p> + * An attribute specifying whether errors checking is enforced or not. + * When set to <code>false</code>, the implementation is free to not + * test every possible error case normally defined on DOM operations, and + * not raise any <code>DOMException</code>. In case of error, the + * behavior is undefined. This attribute is <code>true</code> by + * defaults. + * + * @since DOM Level 3 + */ + public void setStrictErrorChecking(boolean strictErrorChecking) { + } + + /** + * <p> + * EXPERIMENTAL! Based on the <a + * href='http://www.w3.org/TR/2001/WD-DOM-Level-3-Core-20010605'>Document + * Object Model (DOM) Level 3 Core Working Draft of 5 June 2001. </a>. + * <p> + * An attribute specifying, as part of the XML declaration, the version + * number of this document. This is <code>null</code> when unspecified. + * + * @since DOM Level 3 + */ + public void setVersion(java.lang.String version) { + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/DocumentTypeAdapterImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/DocumentTypeAdapterImpl.java new file mode 100644 index 0000000000..8d63d99b79 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/DocumentTypeAdapterImpl.java @@ -0,0 +1,120 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.document; + + + +import org.eclipse.wst.sse.core.INodeNotifier; +import org.eclipse.wst.xml.core.document.DocumentTypeAdapter; +import org.eclipse.wst.xml.core.document.XMLDocument; +import org.eclipse.wst.xml.core.document.XMLModel; +import org.w3c.dom.DocumentType; + + +/** + */ +public class DocumentTypeAdapterImpl implements DocumentTypeAdapter { + + private XMLDocument document = null; + private DocumentType documentType = null; + + /** + */ + protected DocumentTypeAdapterImpl() { + super(); + } + + /** + */ + protected DocumentTypeAdapterImpl(XMLDocument document) { + this.document = document; + if (document != null) { + this.documentType = document.getDoctype(); + } + } + + /** + */ + public int getAttrNameCase() { + return STRICT_CASE; + } + + /** + */ + protected XMLDocument getDocument() { + return this.document; + } + + /** + */ + public DocumentType getDocumentType() { + return this.documentType; + } + + /** + */ + public int getTagNameCase() { + return STRICT_CASE; + } + + /** + */ + public boolean hasFeature(String feature) { + return false; + } + + /** + */ + public boolean isAdapterForType(Object type) { + return (type == DocumentTypeAdapter.class); + } + + /** + */ + public boolean isXMLType() { + return true; + } + + /** + */ + public void notifyChanged(INodeNotifier notifier, int eventType, Object changedFeature, Object oldValue, Object newValue, int pos) { + if (eventType != INodeNotifier.STRUCTURE_CHANGED) + return; + if (notifier == null || !(notifier instanceof XMLDocument)) + return; + this.documentType = ((XMLDocument) notifier).getDoctype(); + } + + /** + */ + protected void notifyDocumentTypeChanged() { + if (this.document == null) + return; + XMLModel model = this.document.getModel(); + if (model == null) + return; + ((XMLModelImpl) model).documentTypeChanged(); + } + + /** + */ + public void release() { + // nothing to do + } + + /** + */ + protected void setDocumentType(DocumentType documentType) { + this.documentType = documentType; + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/DocumentTypeImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/DocumentTypeImpl.java new file mode 100644 index 0000000000..c8137da34b --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/DocumentTypeImpl.java @@ -0,0 +1,222 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.document; + + + +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.xml.core.document.XMLDocumentType; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; +import org.w3c.dom.DOMException; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + + +/** + * DocumentType class + */ +public class DocumentTypeImpl extends NodeImpl implements XMLDocumentType { + private String internalSubset = null; + + private String name = null; + private String publicId = null; + private String systemId = null; + + /** + * DocumentTypeImpl constructor + */ + protected DocumentTypeImpl() { + super(); + } + + /** + * DocumentTypeImpl constructor + * + * @param that + * DocumentTypeImpl + */ + protected DocumentTypeImpl(DocumentTypeImpl that) { + super(that); + + if (that != null) { + this.name = that.name; + } + } + + /** + * cloneNode method + * + * @return org.w3c.dom.Node + * @param deep + * boolean + */ + public Node cloneNode(boolean deep) { + DocumentTypeImpl cloned = new DocumentTypeImpl(this); + return cloned; + } + + /** + * getEntities method + * + * @return org.w3c.dom.NamedNodeMap + */ + public NamedNodeMap getEntities() { + return null; + } + + /** + */ + public String getInternalSubset() { + return this.internalSubset; + } + + /** + * getName method + * + * @return java.lang.String + */ + public String getName() { + if (this.name == null) + return new String(); + return this.name; + } + + /** + * getNodeName + * + * @return java.lang.String + */ + public String getNodeName() { + return getName(); + } + + /** + * getNodeType method + * + * @return short + */ + public short getNodeType() { + return DOCUMENT_TYPE_NODE; + } + + /** + * getNotations method + * + * @return org.w3c.dom.NamedNodeMap + */ + public NamedNodeMap getNotations() { + return null; + } + + /** + * getPublicId method + * + * @return java.lang.String + */ + public String getPublicId() { + return this.publicId; + } + + /** + * getSystemId method + * + * @return java.lang.String + */ + public String getSystemId() { + return this.systemId; + } + + /** + */ + public boolean isClosed() { + IStructuredDocumentRegion flatNode = getStructuredDocumentRegion(); + if (flatNode == null) + return true; // will be generated + String regionType = StructuredDocumentRegionUtil.getLastRegionType(flatNode); + return (regionType == XMLRegionContext.XML_DOCTYPE_DECLARATION_CLOSE || regionType == XMLRegionContext.XML_DECLARATION_CLOSE); + } + + /** + */ + public void setInternalSubset(String internalSubset) { + if (!isDataEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + + this.internalSubset = internalSubset; + } + + /** + * setName method + * + * @param name + * java.lang.String + */ + protected void setName(String name) { + this.name = name; + } + + /** + * setPublicId method + * + * @param publicId + * java.lang.String + */ + public void setPublicId(String publicId) { + if (!isDataEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + + this.publicId = publicId; + + notifyValueChanged(); + } + + /** + * setSystemId method + * + * @param systemId + * java.lang.String + */ + public void setSystemId(String systemId) { + if (!isDataEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + + this.systemId = systemId; + + notifyValueChanged(); + } + + /** + * toString method + * + * @return java.lang.String + */ + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append(getName()); + buffer.append('('); + buffer.append(getPublicId()); + buffer.append(')'); + buffer.append('('); + buffer.append(getSystemId()); + buffer.append(')'); + IStructuredDocumentRegion flatNode = getStructuredDocumentRegion(); + if (flatNode != null) { + buffer.append('@'); + buffer.append(flatNode.toString()); + } + return buffer.toString(); + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/ElementImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/ElementImpl.java new file mode 100644 index 0000000000..fd8d27a8ce --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/ElementImpl.java @@ -0,0 +1,1421 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.document; + + + +import java.util.Iterator; + +import org.eclipse.wst.common.contentmodel.CMElementDeclaration; +import org.eclipse.wst.common.contentmodel.modelquery.ModelQuery; +import org.eclipse.wst.sse.core.parser.RegionParser; +import org.eclipse.wst.sse.core.text.IStructuredDocument; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.core.text.ITextRegionList; +import org.eclipse.wst.xml.core.commentelement.CommentElementAdapter; +import org.eclipse.wst.xml.core.document.JSPTag; +import org.eclipse.wst.xml.core.document.XMLElement; +import org.eclipse.wst.xml.core.document.XMLModel; +import org.eclipse.wst.xml.core.document.XMLNamespace; +import org.eclipse.wst.xml.core.document.XMLNode; +import org.eclipse.wst.xml.core.internal.parser.XMLSourceParser; +import org.eclipse.wst.xml.core.jsp.model.parser.temp.XMLJSPRegionContexts; +import org.eclipse.wst.xml.core.modelquery.ModelQueryUtil; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; +import org.w3c.dom.Attr; +import org.w3c.dom.DOMException; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.traversal.NodeFilter; +import org.w3c.dom.traversal.NodeIterator; + + +/** + * ElementImpl class + */ +public class ElementImpl extends NodeContainer implements XMLElement { + + private class Attributes implements NamedNodeMap { + Attributes() { + super(); + } + + public int getLength() { + if (attrNodes == null) + return 0; + return attrNodes.getLength(); + } + + public Node getNamedItem(String name) { + return getAttributeNode(name); + } + + public Node getNamedItemNS(String uri, String name) { + return getAttributeNodeNS(uri, name); + } + + public Node item(int index) { + if (attrNodes == null) + return null; + return attrNodes.item(index); + } + + public Node removeNamedItem(String name) throws DOMException { + return removeAttributeNode(name); + } + + public Node removeNamedItemNS(String uri, String name) throws DOMException { + return removeAttributeNodeNS(uri, name); + } + + public Node setNamedItem(Node arg) throws DOMException { + return setAttributeNode((AttrImpl) arg); + } + + public Node setNamedItemNS(Node arg) throws DOMException { + return setAttributeNodeNS((AttrImpl) arg); + } + } + + NodeListImpl attrNodes = null; + private IStructuredDocumentRegion endStructuredDocumentRegion = null; + private boolean isCommentTag = false; + private boolean isEmptyTag = false; + private boolean isJSPTag = false; + private String namespaceURI = null; + + private String tagName = null; + + /** + * ElementImpl constructor + */ + protected ElementImpl() { + super(); + } + + /** + * ElementImpl constructor + * + * @param that + * ElementImpl + */ + protected ElementImpl(ElementImpl that) { + super(that); + + if (that != null) { + this.tagName = that.tagName; + this.isEmptyTag = that.isEmptyTag; + this.isJSPTag = that.isJSPTag; + this.isCommentTag = that.isCommentTag; + + // clone attributes + that.cloneAttributes(this); + } + } + + /** + * addEndTag method + * + * @param end + * org.w3c.dom.Element + */ + protected void addEndTag(Element endTag) { + if (endTag == null) + return; + if (hasEndTag()) + return; + ElementImpl end = (ElementImpl) endTag; + + // move the end flat node from the end tag + IStructuredDocumentRegion flatNode = end.getEndStructuredDocumentRegion(); + if (flatNode == null) + return; + end.setEndStructuredDocumentRegion(null); + setEndStructuredDocumentRegion(flatNode); + } + + /** + * appendAttibuteNode method + * + * @return org.w3c.dom.Attr + * @param newAttr + * org.w3c.dom.Attr + */ + public Attr appendAttributeNode(Attr newAttr) { + if (newAttr == null) + return null; + AttrImpl attr = (AttrImpl) newAttr; + if (attr.getOwnerElement() != null) + return null; + + if (!isDataEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + + if (this.attrNodes == null) + this.attrNodes = new NodeListImpl(); + this.attrNodes.appendNode(attr); + attr.setOwnerElement(this); + + notifyAttrReplaced(attr, null); + return attr; + } + + /** + * cloneAttributes method + * + * @param newOwner + * org.w3c.dom.Element + */ + protected void cloneAttributes(Element newOwner) { + if (newOwner == null || newOwner == this) + return; + + ElementImpl element = (ElementImpl) newOwner; + element.removeAttributes(); + + if (this.attrNodes == null) + return; + + int length = this.attrNodes.getLength(); + for (int i = 0; i < length; i++) { + Node node = this.attrNodes.item(i); + if (node == null) + continue; + Attr cloned = (Attr) node.cloneNode(false); + if (cloned != null) + element.appendAttributeNode(cloned); + } + } + + /** + * cloneNode method + * + * @return org.w3c.dom.Node + * @param deep + * boolean + */ + public Node cloneNode(boolean deep) { + ElementImpl cloned = new ElementImpl(this); + if (deep) + cloneChildNodes(cloned, deep); + return cloned; + } + + /** + * getAttribute method + * + * @return java.lang.String + * @param name + * java.lang.String + */ + public String getAttribute(String name) { + Attr attr = getAttributeNode(name); + if (attr == null) + return null; + return attr.getValue(); + } + + /** + * getAttributeNode method + * + * @return org.w3c.dom.Attr + * @param name + * java.lang.String + */ + public Attr getAttributeNode(String name) { + if (name == null) + return null; // invalid parameter + if (this.attrNodes == null) + return null; // no attribute + + int length = this.attrNodes.getLength(); + for (int i = 0; i < length; i++) { + AttrImpl attr = (AttrImpl) this.attrNodes.item(i); + if (attr == null) + continue; + if (attr.matchName(name)) + return attr; // found + } + + return null; // not found + } + + /** + */ + public Attr getAttributeNodeNS(String uri, String name) { + if (name == null) + return null; // invalid parameter + if (this.attrNodes == null) + return null; // no attribute + + int length = this.attrNodes.getLength(); + for (int i = 0; i < length; i++) { + AttrImpl attr = (AttrImpl) this.attrNodes.item(i); + if (attr == null) + continue; + String localName = attr.getLocalName(); + if (localName == null || !localName.equals(name)) + continue; + String nsURI = attr.getNamespaceURI(); + if (uri == null) { + if (nsURI != null) + continue; + } else { + if (nsURI == null || !nsURI.equals(uri)) + continue; + } + + // found + return attr; + } + + return null; // not found + } + + /** + */ + public String getAttributeNS(String uri, String name) { + Attr attr = getAttributeNodeNS(uri, name); + if (attr == null) + return null; + return attr.getValue(); + } + + /** + * getAttributes method + * + * @return org.w3c.dom.NamedNodeMap + */ + public NamedNodeMap getAttributes() { + return new Attributes(); + } + + /** + */ + protected CMElementDeclaration getDeclaration() { + Document document = getOwnerDocument(); + if (document == null) + return null; + ModelQuery modelQuery = ModelQueryUtil.getModelQuery(document); + if (modelQuery == null) + return null; + return modelQuery.getCMElementDeclaration(this); + } + + /** + * getElementsByTagName method + * + * @return org.w3c.dom.NodeList + * @param tagName + * java.lang.String + */ + public NodeList getElementsByTagName(String tagName) { + if (tagName == null) + return new NodeListImpl(); + + DocumentImpl document = (DocumentImpl) getOwnerDocument(); + if (document == null) + return new NodeListImpl(); + NodeIterator it = document.createNodeIterator(this, NodeFilter.SHOW_ALL, null, false); + if (it == null) + return new NodeListImpl(); + NodeListImpl elements = new NodeListImpl(); + + if (tagName.length() == 1 && tagName.charAt(0) == '*') { + tagName = null; // do not care + } + + for (Node node = it.nextNode(); node != null; node = it.nextNode()) { + if (node.getNodeType() != ELEMENT_NODE) + continue; + if (tagName != null) { + ElementImpl element = (ElementImpl) node; + if (!element.matchTagName(tagName)) + continue; + } + elements.appendNode(node); + } + + return elements; + } + + /** + */ + public NodeList getElementsByTagNameNS(String uri, String tagName) { + if (tagName == null) + return new NodeListImpl(); + + DocumentImpl document = (DocumentImpl) getOwnerDocument(); + if (document == null) + return new NodeListImpl(); + NodeIterator it = document.createNodeIterator(this, NodeFilter.SHOW_ALL, null, false); + if (it == null) + return new NodeListImpl(); + NodeListImpl elements = new NodeListImpl(); + + if (uri != null && uri.length() == 1 && uri.charAt(0) == '*') { + uri = null; // do not care + } + if (tagName.length() == 1 && tagName.charAt(0) == '*') { + tagName = null; // do not care + } + + for (Node node = it.nextNode(); node != null; node = it.nextNode()) { + if (node.getNodeType() != ELEMENT_NODE) + continue; + ElementImpl element = (ElementImpl) node; + if (tagName != null) { + String localName = element.getLocalName(); + if (localName == null || !localName.equals(tagName)) + continue; + } + if (uri != null) { + String nsURI = element.getNamespaceURI(); + if (nsURI == null || !nsURI.equals(uri)) + continue; + } + elements.appendNode(element); + } + + return elements; + } + + /** + * getEndOffset method + * + * @return int + */ + public int getEndOffset() { + if (this.endStructuredDocumentRegion != null) + return this.endStructuredDocumentRegion.getEnd(); + return super.getEndOffset(); + } + + /** + * getEndStartOffset method + * + * @return int + */ + public int getEndStartOffset() { + if (this.endStructuredDocumentRegion != null) + return this.endStructuredDocumentRegion.getStart(); + return super.getEndOffset(); + } + + /** + * getEndStructuredDocumentRegion method + * + * @return com.ibm.sed.structuredDocument.IStructuredDocumentRegion + */ + public IStructuredDocumentRegion getEndStructuredDocumentRegion() { + return this.endStructuredDocumentRegion; + } + + /** + */ + public String getEndTagName() { + if (this.endStructuredDocumentRegion == null) + return null; + + ITextRegionList regions = this.endStructuredDocumentRegion.getRegions(); + if (regions == null) + return null; + Iterator e = regions.iterator(); + while (e.hasNext()) { + ITextRegion region = (ITextRegion) e.next(); + String regionType = region.getType(); + if (regionType == XMLRegionContext.XML_TAG_NAME || regionType == XMLJSPRegionContexts.JSP_ROOT_TAG_NAME || regionType == XMLJSPRegionContexts.JSP_DIRECTIVE_NAME) { + return this.endStructuredDocumentRegion.getText(region); + } + } + + return null; + } + + /** + * getFirstStructuredDocumentRegion method + * + * @return com.ibm.sed.structuredDocument.IStructuredDocumentRegion + */ + public IStructuredDocumentRegion getFirstStructuredDocumentRegion() { + IStructuredDocumentRegion flatNode = getStructuredDocumentRegion(); + if (flatNode != null) + return StructuredDocumentRegionUtil.getStructuredDocumentRegion(flatNode); + return StructuredDocumentRegionUtil.getStructuredDocumentRegion(this.endStructuredDocumentRegion); + } + + /** + * getLastStructuredDocumentRegion method + * + * @return com.ibm.sed.structuredDocument.IStructuredDocumentRegion + */ + public IStructuredDocumentRegion getLastStructuredDocumentRegion() { + if (this.endStructuredDocumentRegion != null) + return StructuredDocumentRegionUtil.getStructuredDocumentRegion(this.endStructuredDocumentRegion); + return StructuredDocumentRegionUtil.getStructuredDocumentRegion(getStructuredDocumentRegion()); + } + + /** + */ + public String getLocalName() { + if (this.tagName == null) + return null; + int index = this.tagName.indexOf(':'); + if (index < 0) + return this.tagName; + return this.tagName.substring(index + 1); + } + + /** + */ + public String getNamespaceURI() { + String nsAttrName = null; + String prefix = getPrefix(); + if (prefix != null && prefix.length() > 0) { + nsAttrName = XMLNamespace.XMLNS_PREFIX + prefix; + } else { + nsAttrName = XMLNamespace.XMLNS; + } + + for (Node node = this; node != null; node = node.getParentNode()) { + if (node.getNodeType() != ELEMENT_NODE) + break; + Element element = (Element) node; + Attr attr = element.getAttributeNode(nsAttrName); + if (attr != null) + return attr.getValue(); + } + + return this.namespaceURI; + } + + /** + * getNodeName method + * + * @return java.lang.String + */ + public String getNodeName() { + return getTagName(); + } + + /** + * getNodeType method + * + * @return short + */ + public short getNodeType() { + return ELEMENT_NODE; + } + + /** + */ + public String getPrefix() { + if (this.tagName == null) + return null; + int index = this.tagName.indexOf(':'); + if (index <= 0) + return null; + // exclude JSP tag in tag name + if (this.tagName.charAt(0) == '<') + return null; + return this.tagName.substring(0, index); + } + + /** + * getStartEndOffset method + * + * @return int + */ + public int getStartEndOffset() { + IStructuredDocumentRegion flatNode = getStructuredDocumentRegion(); + if (flatNode != null) + return flatNode.getEnd(); + return super.getStartOffset(); + } + + /** + * getStartOffset method + * + * @return int + */ + public int getStartOffset() { + if (getStartStructuredDocumentRegion() == null && this.endStructuredDocumentRegion != null && !hasChildNodes()) { + return this.endStructuredDocumentRegion.getStart(); + } + return super.getStartOffset(); + } + + /** + * getStartStructuredDocumentRegion method + * + * @return com.ibm.sed.structuredDocument.IStructuredDocumentRegion + */ + public IStructuredDocumentRegion getStartStructuredDocumentRegion() { + return getStructuredDocumentRegion(); + } + + /** + * getTagName method + * + * @return java.lang.String + */ + public String getTagName() { + if (this.tagName == null) + return new String(); + return this.tagName; + } + + /** + */ + public boolean hasAttribute(String name) { + return (getAttributeNode(name) != null); + } + + /** + */ + public boolean hasAttributeNS(String uri, String name) { + return (getAttributeNodeNS(uri, name) != null); + } + + /** + */ + public boolean hasAttributes() { + return (this.attrNodes != null && this.attrNodes.getLength() > 0); + } + + /** + * hasEndTag method + * + * @return boolean + */ + public boolean hasEndTag() { + return (this.endStructuredDocumentRegion != null); + } + + /** + */ + protected final boolean hasPrefix() { + if (this.tagName == null) + return false; + if (this.tagName.indexOf(':') <= 0) + return false; + // exclude JSP tag in tag name + if (this.tagName.charAt(0) == '<') + return false; + return true; + } + + /** + * hasStartTag method + * + * @return boolean + */ + public boolean hasStartTag() { + return (getStructuredDocumentRegion() != null); + } + + /** + */ + protected final boolean ignoreCase() { + DocumentImpl document = (DocumentImpl) getOwnerDocument(); + if (document != null && document.ignoreCase()) { + // even in case insensitive document, if having prefix, it's case + // sensitive tag + return !hasPrefix(); + } + return false; + } + + /** + */ + protected Attr insertAttributeNode(Attr newAttr, int index) { + if (newAttr == null) + return null; + AttrImpl attr = (AttrImpl) newAttr; + if (attr.getOwnerElement() != null) + return null; + + if (this.attrNodes == null) + this.attrNodes = new NodeListImpl(); + this.attrNodes.insertNode(attr, index); + attr.setOwnerElement(this); + + notifyAttrReplaced(attr, null); + return attr; + } + + /** + * insertBefore method + * + * @return org.w3c.dom.Node + * @param newChild + * org.w3c.dom.Node + * @param refChild + * org.w3c.dom.Node + */ + public Node insertBefore(Node newChild, Node refChild) throws DOMException { + // should throw DOMException instead of return null? + if (newChild == null) + return null; + if (!isContainer()) { // never be container + throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, new String()); + } + if (newChild.getNodeType() != TEXT_NODE) { + if (isJSPContainer() || isCDATAContainer()) { // accepts only Text + // child + throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, new String()); + } + } + return super.insertBefore(newChild, refChild); + } + + /** + */ + protected boolean isCDATAContainer() { + // use BlockMaker instead of CMElementDeclaration + // because <style> and <script> in XHTML is not CDATA content type + XMLModel model = getModel(); + if (model == null) + return false; // error + IStructuredDocument structuredDocument = model.getStructuredDocument(); + if (structuredDocument == null) + return false; // eror + RegionParser parser = structuredDocument.getParser(); + if (parser == null || !(parser instanceof XMLSourceParser)) + return false; + return (((XMLSourceParser) parser).getBlockMarker(this.tagName) != null); + /* + * CMElementDeclaration decl = getDeclaration(); if (decl == null) + * return false; if (decl instanceof CMNodeWrapper) { decl = + * (CMElementDeclaration)((CMNodeWrapper)decl).getOriginNode(); if + * (decl == null) return false; } if (decl instanceof + * TLDElementDeclaration) { String content = + * ((TLDElementDeclaration)decl).getBodycontent(); if (content == + * null) return false; return + * content.equals(JSP11TLDNames.CONTENT_TAGDEPENDENT); } if + * (!isGlobalTag()) return false; return (decl.getContentType() == + * CMElementDeclaration.CDATA); + */ + } + + /** + */ + public boolean isClosed() { + IStructuredDocumentRegion flatNode = null; + if (isEmptyTag() || !isContainer()) { + flatNode = getStructuredDocumentRegion(); + if (flatNode == null) + return true; // will be generated + } else { + flatNode = getEndStructuredDocumentRegion(); + if (flatNode == null) + return false; // must be generated + } + String regionType = StructuredDocumentRegionUtil.getLastRegionType(flatNode); + if (isCommentTag()) { + return (regionType == XMLJSPRegionContexts.JSP_COMMENT_CLOSE || regionType == XMLRegionContext.XML_COMMENT_CLOSE); + } + if (isJSPTag()) { + return (regionType == XMLJSPRegionContexts.JSP_CLOSE || regionType == XMLJSPRegionContexts.JSP_DIRECTIVE_CLOSE); + } + return (regionType == XMLRegionContext.XML_TAG_CLOSE || regionType == XMLRegionContext.XML_EMPTY_TAG_CLOSE || regionType == XMLRegionContext.XML_DECLARATION_CLOSE); + } + + /** + */ + public final boolean isCommentTag() { + return this.isCommentTag; + } + + /** + * isContainer method + * + * @return boolean + */ + public boolean isContainer() { + if (isCommentTag()) { + CommentElementAdapter adapter = (CommentElementAdapter) getAdapterFor(CommentElementAdapter.class); + if (adapter != null) { + return (adapter.isContainer()); + } + return (getDeclaration() == null); + } + if (isJSPTag()) { + // exclude JSP directive + return (matchTagName(JSPTag.JSP_SCRIPTLET) || matchTagName(JSPTag.JSP_DECLARATION) || matchTagName(JSPTag.JSP_EXPRESSION)); + } + if (!isXMLTag()) { // non-XML tag + CMElementDeclaration decl = getDeclaration(); + if (decl == null) + return false; // undefined tag + return (decl.getContentType() != CMElementDeclaration.EMPTY); + } + return true; + } + + /** + * isEmptyTag method + * + * @return boolean + */ + public boolean isEmptyTag() { + if (isJSPTag()) + return false; + if (isCommentTag()) + return false; + if (!isXMLTag()) + return false; + return this.isEmptyTag; + } + + /** + */ + public boolean isEndTag() { + return (hasEndTag() && !hasStartTag() && !hasChildNodes()); + } + + /** + */ + public boolean isGlobalTag() { + return !hasPrefix(); + } + + /** + */ + public boolean isImplicitTag() { + if (hasStartTag() || hasEndTag()) + return false; + // make sure this is in the document tree + // because if not in the document tree, no tags are generated yet + return (getContainerDocument() != null); + } + + /** + */ + public boolean isJSPContainer() { + return (isJSPTag() && !isCommentTag() && isContainer()); + } + + /** + * isJSPTag method + * + * @return boolean + */ + public final boolean isJSPTag() { + return this.isJSPTag; + } + + /** + */ + public boolean isStartTagClosed() { + IStructuredDocumentRegion flatNode = getStructuredDocumentRegion(); + if (flatNode == null) + return true; // will be generated + String regionType = StructuredDocumentRegionUtil.getLastRegionType(flatNode); + if (isCommentTag()) { + return (regionType == XMLJSPRegionContexts.JSP_COMMENT_CLOSE || regionType == XMLRegionContext.XML_COMMENT_CLOSE); + } + if (isJSPTag()) { + if (isContainer()) + return true; // start tag always has a single region + return (regionType == XMLJSPRegionContexts.JSP_DIRECTIVE_CLOSE); + } + return (regionType == XMLRegionContext.XML_TAG_CLOSE || regionType == XMLRegionContext.XML_EMPTY_TAG_CLOSE || regionType == XMLRegionContext.XML_DECLARATION_CLOSE); + } + + /** + */ + public final boolean isXMLTag() { + if (isJSPTag()) + return false; + if (isCommentTag()) + return false; + DocumentImpl document = (DocumentImpl) getOwnerDocument(); + if (document != null && !document.isXMLType()) { + // even in non-XML document, if having prefix, it's XML tag + return hasPrefix(); + } + return true; + } + + /** + */ + protected boolean matchEndTag(Element element) { + if (element == null) + return false; + ElementImpl impl = (ElementImpl) element; + if (isJSPTag() && !isCommentTag()) { + return (impl.isJSPTag() && !impl.isCommentTag()); + } + return matchTagName(element.getTagName()); + } + + /** + * matchTagName method + * + * @return boolean + * @param tagName + * java.lang.String + */ + public boolean matchTagName(String tagName) { + if (tagName == null) + return (this.tagName == null); + if (this.tagName == null) + return false; + if (!ignoreCase()) + return this.tagName.equals(tagName); + return this.tagName.equalsIgnoreCase(tagName); + } + + /** + * notifyAttrReplaced method + * + * @param newAttr + * org.w3c.dom.Attr + * @param oldAttr + * org.w3c.dom.Attr + */ + protected void notifyAttrReplaced(Attr newAttr, Attr oldAttr) { + DocumentImpl document = (DocumentImpl) getContainerDocument(); + if (document == null) + return; + XMLModelImpl model = (XMLModelImpl) document.getModel(); + if (model == null) + return; + model.attrReplaced(this, newAttr, oldAttr); + } + + /** + * notifyValueChanged method + */ + public void notifyEndTagChanged() { + DocumentImpl document = (DocumentImpl) getContainerDocument(); + if (document == null) + return; + XMLModelImpl model = (XMLModelImpl) document.getModel(); + if (model == null) + return; + model.endTagChanged(this); + } + + /** + */ + public void notifyStartTagChanged() { + DocumentImpl document = (DocumentImpl) getContainerDocument(); + if (document == null) + return; + XMLModelImpl model = (XMLModelImpl) document.getModel(); + if (model == null) + return; + model.startTagChanged(this); + } + + /** + */ + public boolean preferEmptyTag() { + if (hasChildNodes()) + return false; + if (isJSPTag()) + return false; + if (isCommentTag()) + return false; + if (!isXMLTag()) + return false; + CMElementDeclaration decl = getDeclaration(); + if (decl == null) + return false; + return (decl.getContentType() == CMElementDeclaration.EMPTY); + } + + /** + * removeAttribute method + * + * @param name + * java.lang.String + */ + public void removeAttribute(String name) throws DOMException { + removeAttributeNode(name); + } + + /** + * removeAttributeNode method + * + * @return org.w3c.dom.Attr + * @param oldAttr + * org.w3c.dom.Attr + */ + public Attr removeAttributeNode(Attr oldAttr) throws DOMException { + if (oldAttr == null) + return null; // invalid parameter + + if (!isDataEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + + if (this.attrNodes == null) { // no attribute + throw new DOMException(DOMException.NOT_FOUND_ERR, new String()); + } + + int length = this.attrNodes.getLength(); + for (int i = 0; i < length; i++) { + AttrImpl attr = (AttrImpl) this.attrNodes.item(i); + if (attr != oldAttr) + continue; + + // found + this.attrNodes.removeNode(i); + attr.setOwnerElement(null); + + notifyAttrReplaced(null, attr); + return attr; + } + + // not found + throw new DOMException(DOMException.NOT_FOUND_ERR, new String()); + } + + /** + * removeAttributeNode method + * + * @return org.w3c.dom.Attr + * @param name + * java.lang.String + */ + public Attr removeAttributeNode(String name) { + if (name == null) + return null; // invalid parameter + if (this.attrNodes == null) + return null; // no attribute + + if (!isDataEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + + int length = this.attrNodes.getLength(); + for (int i = 0; i < length; i++) { + AttrImpl attr = (AttrImpl) this.attrNodes.item(i); + if (attr == null) + continue; + if (!attr.matchName(name)) + continue; + + // found + this.attrNodes.removeNode(i); + attr.setOwnerElement(null); + + notifyAttrReplaced(null, attr); + return attr; + } + + return null; // not found + } + + /** + */ + public Attr removeAttributeNodeNS(String uri, String name) { + if (name == null) + return null; // invalid parameter + if (this.attrNodes == null) + return null; // no attribute + + if (!isDataEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + + int length = this.attrNodes.getLength(); + for (int i = 0; i < length; i++) { + AttrImpl attr = (AttrImpl) this.attrNodes.item(i); + if (attr == null) + continue; + String localName = attr.getLocalName(); + if (localName == null || !localName.equals(name)) + continue; + String nsURI = attr.getNamespaceURI(); + if (uri == null) { + if (nsURI != null) + continue; + } else { + if (nsURI == null || !nsURI.equals(uri)) + continue; + } + + // found + this.attrNodes.removeNode(i); + attr.setOwnerElement(null); + + notifyAttrReplaced(null, attr); + return attr; + } + + return null; // not found + } + + /** + */ + public void removeAttributeNS(String uri, String name) throws DOMException { + removeAttributeNodeNS(uri, name); + } + + /** + * removeAttributes method + */ + public void removeAttributes() { + if (this.attrNodes == null) + return; + + if (!isDataEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + + int length = this.attrNodes.getLength(); + for (int i = 0; i < length; i++) { + AttrImpl attr = (AttrImpl) this.attrNodes.item(i); + if (attr != null) { + attr.setOwnerElement(null); + notifyAttrReplaced(null, attr); + } + } + + this.attrNodes = null; + } + + /** + * removeEndTag method + * + * @return org.w3c.dom.Element + */ + protected Element removeEndTag() { + if (!hasEndTag()) + return null; + NodeListImpl attrNodes = this.attrNodes; + this.attrNodes = null; // not to copy attributes + ElementImpl end = (ElementImpl) cloneNode(false); + this.attrNodes = attrNodes; + if (end == null) + return null; + + // move the end flat node to the end tag + IStructuredDocumentRegion flatNode = getEndStructuredDocumentRegion(); + if (flatNode == null) + return null; + setEndStructuredDocumentRegion(null); + end.setEndStructuredDocumentRegion(flatNode); + return end; + } + + /** + */ + protected void removeStartTag() { + removeAttributes(); + } + + /** + * Resets attribute values from IStructuredDocumentRegion. + */ + void resetStructuredDocumentRegions() { + if (this.attrNodes != null) { + int length = this.attrNodes.getLength(); + for (int i = 0; i < length; i++) { + AttrImpl attr = (AttrImpl) this.attrNodes.item(i); + if (attr == null) + continue; + attr.resetRegions(); + } + } + + super.resetStructuredDocumentRegions(); // for children + + this.endStructuredDocumentRegion = null; + } + + /** + * setAttribute method + * + * @param name + * java.lang.String + * @param value + * java.lang.String + */ + public void setAttribute(String name, String value) throws DOMException { + if (name == null) + return; + + if (!isDataEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + + Attr attr = getAttributeNode(name); + if (attr != null) { + attr.setValue(value); // change value + return; + } + + // new attribute + Document doc = getOwnerDocument(); + if (doc == null) + return; + attr = doc.createAttribute(name); + if (attr == null) + return; + attr.setValue(value); + appendAttributeNode(attr); + } + + /** + * setAttributeNode method + * + * @return org.w3c.dom.Attr + * @param newAttr + * org.w3c.dom.Attr + */ + public Attr setAttributeNode(Attr newAttr) throws DOMException { + if (newAttr == null) + return null; // nothing to do + + if (!isDataEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + + AttrImpl attr = (AttrImpl) newAttr; + Element owner = attr.getOwnerElement(); + if (owner != null) { + if (owner == this) + return null; // nothing to do + throw new DOMException(DOMException.INUSE_ATTRIBUTE_ERR, new String()); + } + + Attr oldAttr = removeAttributeNode(newAttr.getName()); + appendAttributeNode(attr); + return oldAttr; + } + + /** + */ + public Attr setAttributeNodeNS(Attr newAttr) throws DOMException { + if (newAttr == null) + return null; // nothing to do + + if (!isDataEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + + AttrImpl attr = (AttrImpl) newAttr; + Element owner = attr.getOwnerElement(); + if (owner != null) { + if (owner == this) + return null; // nothing to do + throw new DOMException(DOMException.INUSE_ATTRIBUTE_ERR, new String()); + } + + String name = newAttr.getLocalName(); + String uri = newAttr.getNamespaceURI(); + Attr oldAttr = removeAttributeNodeNS(uri, name); + appendAttributeNode(attr); + return oldAttr; + } + + /** + */ + public void setAttributeNS(String uri, String name, String value) throws DOMException { + if (name == null) + return; + + if (!isDataEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + + Attr attr = getAttributeNodeNS(uri, name); + if (attr != null) { + attr.setValue(value); // change value + return; + } + + // new attribute + Document doc = getOwnerDocument(); + if (doc == null) + return; + attr = doc.createAttributeNS(uri, name); + if (attr == null) + return; + attr.setValue(value); + appendAttributeNode(attr); + } + + /** + */ + public void setCommentTag(boolean isCommentTag) { + XMLNode parent = (XMLNode) getParentNode(); + if (parent != null && !parent.isChildEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + + this.isCommentTag = isCommentTag; + } + + /** + * setEmptyTag method + * + * @param isEmptyTag + * boolean + */ + public void setEmptyTag(boolean isEmptyTag) { + XMLNode parent = (XMLNode) getParentNode(); + if (parent != null && !parent.isChildEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + + this.isEmptyTag = isEmptyTag; + } + + /** + * setEndStructuredDocumentRegion method + * + * @param flatNode + * com.ibm.sed.structuredDocument.IStructuredDocumentRegion + */ + void setEndStructuredDocumentRegion(IStructuredDocumentRegion flatNode) { + this.endStructuredDocumentRegion = flatNode; + + NodeContainer parent = (NodeContainer) getParentNode(); + if (parent != null) { + parent.syncChildEditableState(this); + } + } + + /** + * setJSPTag method + * + * @param isJSPTag + * boolean + */ + public void setJSPTag(boolean isJSPTag) { + XMLNode parent = (XMLNode) getParentNode(); + if (parent != null && !parent.isChildEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + + this.isJSPTag = isJSPTag; + } + + /** + */ + protected void setNamespaceURI(String namespaceURI) { + this.namespaceURI = namespaceURI; + } + + /** + */ + protected void setOwnerDocument(Document ownerDocument, boolean deep) { + super.setOwnerDocument(ownerDocument, deep); + + if (this.attrNodes == null) + return; + + int length = this.attrNodes.getLength(); + for (int i = 0; i < length; i++) { + AttrImpl attr = (AttrImpl) this.attrNodes.item(i); + if (attr == null) + continue; + attr.setOwnerDocument(ownerDocument); + } + } + + /** + */ + public void setPrefix(String prefix) throws DOMException { + XMLNode parent = (XMLNode) getParentNode(); + if (parent != null && !parent.isChildEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + + int prefixLength = (prefix != null ? prefix.length() : 0); + String localName = getLocalName(); + if (prefixLength == 0) { + if (localName == null || localName.length() == 0) { + // invalid local name + return; + } + setTagName(localName); + } else { + int localLength = (localName != null ? localName.length() : 0); + StringBuffer buffer = new StringBuffer(prefixLength + 1 + localLength); + buffer.append(prefix); + buffer.append(':'); + if (localName != null) + buffer.append(localName); + setTagName(buffer.toString()); + } + + boolean changeEndTag = hasEndTag(); + notifyStartTagChanged(); + if (changeEndTag) + notifyEndTagChanged(); + } + + /** + * setStartStructuredDocumentRegion method + * + * @param flatNode + * com.ibm.sed.structuredDocument.IStructuredDocumentRegion + */ + void setStartStructuredDocumentRegion(IStructuredDocumentRegion flatNode) { + setStructuredDocumentRegion(flatNode); + } + + /** + * setTagName method + * + * @param tagName + * java.lang.String + */ + protected void setTagName(String tagName) { + this.tagName = tagName; + } + + /** + * toString method + * + * @return java.lang.String + */ + public String toString() { + StringBuffer buffer = new StringBuffer(); + String tagName = getTagName(); + if (hasStartTag()) + buffer.append(tagName); + if (isEmptyTag()) + buffer.append('/'); + if (hasEndTag()) { + buffer.append('/'); + buffer.append(tagName); + } + if (buffer.length() == 0) + buffer.append(tagName); + + IStructuredDocumentRegion startStructuredDocumentRegion = getStartStructuredDocumentRegion(); + if (startStructuredDocumentRegion != null) { + buffer.append('@'); + buffer.append(startStructuredDocumentRegion.toString()); + } + IStructuredDocumentRegion endStructuredDocumentRegion = getEndStructuredDocumentRegion(); + if (endStructuredDocumentRegion != null) { + buffer.append('@'); + buffer.append(endStructuredDocumentRegion.toString()); + } + return buffer.toString(); + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/EntityImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/EntityImpl.java new file mode 100644 index 0000000000..80e5d6fdbd --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/EntityImpl.java @@ -0,0 +1,227 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.document; + + + +import org.w3c.dom.DOMException; +import org.w3c.dom.Entity; +import org.w3c.dom.Node; + +/** + * EntityImpl class + */ +public class EntityImpl extends NodeImpl implements Entity { + + private String name = null; + private String notationName = null; + private String publicId = null; + private String systemId = null; + + /** + * EntityImpl constructor + */ + protected EntityImpl() { + super(); + } + + /** + * EntityImpl constructor + * + * @param that + * EntityImpl + */ + protected EntityImpl(EntityImpl that) { + super(that); + + if (that != null) { + this.name = that.name; + this.publicId = that.publicId; + this.systemId = that.systemId; + this.notationName = that.notationName; + } + } + + /** + * cloneNode method + * + * @return org.w3c.dom.Node + * @param deep + * boolean + */ + public Node cloneNode(boolean deep) { + EntityImpl cloned = new EntityImpl(this); + return cloned; + } + + /** + * <p> + * EXPERIMENTAL! Based on the <a + * href='http://www.w3.org/TR/2001/WD-DOM-Level-3-Core-20010605'>Document + * Object Model (DOM) Level 3 Core Working Draft of 5 June 2001. </a>. + * <p> + * An attribute specifying, as part of the text declaration, the encoding + * of this entity, when it is an external parsed entity. This is + * <code>null</code> otherwise. + * + * @since DOM Level 3 + */ + public java.lang.String getEncoding() { + return null; + } + + /** + * getNodeName method + * + * @return java.lang.String + */ + public String getNodeName() { + if (this.name == null) + return new String(); + return this.name; + } + + /** + * getNodeType method + * + * @return short + */ + public short getNodeType() { + return ENTITY_NODE; + } + + /** + * getNotationName method + * + * @return java.lang.String + */ + public String getNotationName() { + return this.notationName; + } + + /** + * getPublicId method + * + * @return java.lang.String + */ + public String getPublicId() { + return this.publicId; + } + + /** + * getSystemId method + * + * @return java.lang.String + */ + public String getSystemId() { + return this.systemId; + } + + /** + * <p> + * EXPERIMENTAL! Based on the <a + * href='http://www.w3.org/TR/2001/WD-DOM-Level-3-Core-20010605'>Document + * Object Model (DOM) Level 3 Core Working Draft of 5 June 2001. </a>. + * <p> + * An attribute specifying, as part of the text declaration, the version + * number of this entity, when it is an external parsed entity. This is + * <code>null</code> otherwise. + * + * @since DOM Level 3 + */ + public java.lang.String getVersion() { + return null; + } + + /** + * <p> + * EXPERIMENTAL! Based on the <a + * href='http://www.w3.org/TR/2001/WD-DOM-Level-3-Core-20010605'>Document + * Object Model (DOM) Level 3 Core Working Draft of 5 June 2001. </a>. + * <p> + * An attribute specifying, as part of the text declaration, the encoding + * of this entity, when it is an external parsed entity. This is + * <code>null</code> otherwise. + * + * @since DOM Level 3 + */ + public void setEncoding(java.lang.String encoding) { + } + + /** + * setName method + * + * @param name + * java.lang.String + */ + protected void setName(String name) { + this.name = name; + } + + /** + * setNotationName method + * + * @param notationName + * java.lang.String + */ + public void setNotationName(String notationName) { + if (!isDataEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + + this.notationName = notationName; + } + + /** + * setPublicId method + * + * @param publicId + * java.lang.String + */ + public void setPublicId(String publicId) { + if (!isDataEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + + this.publicId = publicId; + } + + /** + * setSystemId method + * + * @param systemId + * java.lang.String + */ + public void setSystemId(String systemId) { + if (!isDataEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + + this.systemId = systemId; + } + + /** + * <p> + * EXPERIMENTAL! Based on the <a + * href='http://www.w3.org/TR/2001/WD-DOM-Level-3-Core-20010605'>Document + * Object Model (DOM) Level 3 Core Working Draft of 5 June 2001. </a>. + * <p> + * An attribute specifying, as part of the text declaration, the version + * number of this entity, when it is an external parsed entity. This is + * <code>null</code> otherwise. + * + * @since DOM Level 3 + */ + public void setVersion(java.lang.String version) { + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/EntityReferenceImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/EntityReferenceImpl.java new file mode 100644 index 0000000000..366ecc0dbd --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/EntityReferenceImpl.java @@ -0,0 +1,89 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.document; + + + +import org.w3c.dom.EntityReference; +import org.w3c.dom.Node; + +/** + * EntityReference class + */ +public class EntityReferenceImpl extends NodeImpl implements EntityReference { + + private String name = null; + + /** + * EntityReferenceImpl constructor + */ + protected EntityReferenceImpl() { + super(); + } + + /** + * EntityReferenceImpl constructor + * + * @param that + * EntityReferenceImpl + */ + protected EntityReferenceImpl(EntityReferenceImpl that) { + super(that); + + if (that != null) { + this.name = that.name; + } + } + + /** + * cloneNode method + * + * @return org.w3c.dom.Node + * @param deep + * boolean + */ + public Node cloneNode(boolean deep) { + EntityReferenceImpl cloned = new EntityReferenceImpl(this); + return cloned; + } + + /** + * getNodeName method + * + * @return java.lang.String + */ + public String getNodeName() { + if (this.name == null) + return new String(); + return this.name; + } + + /** + * getNodeType method + * + * @return short + */ + public short getNodeType() { + return ENTITY_REFERENCE_NODE; + } + + /** + * setName method + * + * @param name + * java.lang.String + */ + protected void setName(String name) { + this.name = name; + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/ModelParserAdapter.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/ModelParserAdapter.java new file mode 100644 index 0000000000..011079bc31 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/ModelParserAdapter.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.document; + + + +import org.eclipse.wst.sse.core.INodeAdapter; +import org.eclipse.wst.xml.core.document.XMLElement; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + + +/** + */ +public interface ModelParserAdapter extends INodeAdapter { + + /** + */ + public boolean canBeImplicitTag(Element element); + + /** + */ + public boolean canBeImplicitTag(Element element, Node child); + + /** + */ + public boolean canContain(Element element, Node child); + + /** + */ + public Element createCommentElement(Document document, String data, boolean isJSPTag); + + /** + */ + public Element createImplicitElement(Document document, Node parent, Node child); + + /** + */ + public String getFindRootName(String tagName); + + /** + */ + public boolean isEndTag(XMLElement element); +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/NodeContainer.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/NodeContainer.java new file mode 100644 index 0000000000..121d57cb17 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/NodeContainer.java @@ -0,0 +1,514 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.document; + + + +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.xml.core.document.XMLNode; +import org.w3c.dom.DOMException; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + + +/** + * NodeContainer class + */ +public abstract class NodeContainer extends NodeImpl implements Node, NodeList { + + /** + */ + private class ChildNodesCache implements NodeList { + private Node curChild = null; + private int curIndex = -1; + private int length = 0; + + ChildNodesCache() { + initializeCache(); + } + + public int getLength() { + // atomic + return this.length; + } + + private void initializeCache() { + // note we use the outter objects lockobject + // (since we are using their "children". + synchronized (lockObject) { + for (Node child = firstChild; child != null; child = child.getNextSibling()) { + this.length++; + } + } + } + + public Node item(int index) { + synchronized (lockObject) { + if (this.length == 0) + return null; + if (index < 0) + return null; + if (index >= this.length) + return null; + + if (this.curIndex < 0) { // first time + if (index * 2 >= this.length) { // search from the last + this.curIndex = this.length - 1; + this.curChild = lastChild; + } else { // search from the first + this.curIndex = 0; + this.curChild = firstChild; + } + } + + if (index == this.curIndex) + return this.curChild; + + if (index > this.curIndex) { + while (index > this.curIndex) { + this.curIndex++; + this.curChild = this.curChild.getNextSibling(); + } + } else { // index < this.curIndex + while (index < this.curIndex) { + this.curIndex--; + this.curChild = this.curChild.getPreviousSibling(); + } + } + + return this.curChild; + } + } + } + + private NodeList childNodesCache = null; + + private boolean fChildEditable = true; + NodeImpl firstChild = null; + NodeImpl lastChild = null; + + Object lockObject = new byte[0]; + + /** + * NodeContainer constructor + */ + protected NodeContainer() { + super(); + } + + /** + * NodeContainer constructor + * + * @param that + * NodeContainer + */ + protected NodeContainer(NodeContainer that) { + super(that); + } + + /** + * appendChild method + * + * @return org.w3c.dom.Node + * @param newChild + * org.w3c.dom.Node + */ + public Node appendChild(Node newChild) throws DOMException { + return insertBefore(newChild, null); + } + + /** + * cloneChildNodes method + * + * @param container + * org.w3c.dom.Node + * @param deep + * boolean + */ + protected void cloneChildNodes(Node newParent, boolean deep) { + if (newParent == null || newParent == this) + return; + if (!(newParent instanceof NodeContainer)) + return; + + NodeContainer container = (NodeContainer) newParent; + container.removeChildNodes(); + + for (Node child = getFirstChild(); child != null; child = child.getNextSibling()) { + Node cloned = child.cloneNode(deep); + if (cloned != null) + container.appendChild(cloned); + } + } + + /** + * getChildNodes method + * + * @return org.w3c.dom.NodeList + */ + public NodeList getChildNodes() { + return this; + } + + /** + * getFirstChild method + * + * @return org.w3c.dom.Node + */ + public Node getFirstChild() { + return this.firstChild; + } + + /** + * getLastChild method + * + * @return org.w3c.dom.Node + */ + public Node getLastChild() { + return this.lastChild; + } + + /** + * getLength method + * + * @return int + */ + public int getLength() { + if (this.firstChild == null) + return 0; + synchronized (lockObject) { + if (this.childNodesCache == null) + this.childNodesCache = new ChildNodesCache(); + return this.childNodesCache.getLength(); + } + } + + /** + */ + public String getSource() { + StringBuffer buffer = new StringBuffer(); + + IStructuredDocumentRegion startStructuredDocumentRegion = getStartStructuredDocumentRegion(); + if (startStructuredDocumentRegion != null) { + String source = startStructuredDocumentRegion.getText(); + if (source != null) + buffer.append(source); + } + + for (NodeImpl child = firstChild; child != null; child = (NodeImpl) child.getNextSibling()) { + String source = child.getSource(); + if (source != null) + buffer.append(source); + } + + IStructuredDocumentRegion endStructuredDocumentRegion = getEndStructuredDocumentRegion(); + if (endStructuredDocumentRegion != null) { + String source = endStructuredDocumentRegion.getText(); + if (source != null) + buffer.append(source); + } + + return buffer.toString(); + } + + /** + * hasChildNodes method + * + * @return boolean + */ + public boolean hasChildNodes() { + return (this.firstChild != null); + } + + /** + * insertBefore method + * + * @return org.w3c.dom.Node + * @param newChild + * org.w3c.dom.Node + * @param refChild + * org.w3c.dom.Node + */ + public Node insertBefore(Node newChild, Node refChild) throws DOMException { + if (newChild == null) + return null; // nothing to do + if (refChild != null && refChild.getParentNode() != this) { + throw new DOMException(DOMException.NOT_FOUND_ERR, new String()); + } + if (!isChildEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + if (newChild == refChild) + return newChild; // nothing to do + + if (newChild.getNodeType() == DOCUMENT_FRAGMENT_NODE) { + // insert child nodes instead + for (Node child = newChild.getFirstChild(); child != null; child = newChild.getFirstChild()) { + newChild.removeChild(child); + insertBefore(child, refChild); + } + return newChild; + } + // synchronized in case another thread is getting item, or length + synchronized (lockObject) { + this.childNodesCache = null; // invalidate child nodes cache + } + + NodeImpl child = (NodeImpl) newChild; + NodeImpl next = (NodeImpl) refChild; + NodeImpl prev = null; + Node oldParent = child.getParentNode(); + if (oldParent != null) + oldParent.removeChild(child); + if (next == null) { + prev = this.lastChild; + this.lastChild = child; + } else { + prev = (NodeImpl) next.getPreviousSibling(); + next.setPreviousSibling(child); + } + if (prev == null) + this.firstChild = child; + else + prev.setNextSibling(child); + child.setPreviousSibling(prev); + child.setNextSibling(next); + child.setParentNode(this); + // make sure having the same owner document + if (child.getOwnerDocument() == null) { + if (getNodeType() == DOCUMENT_NODE) { + child.setOwnerDocument((Document) this); + } else { + child.setOwnerDocument(getOwnerDocument()); + } + } + + notifyChildReplaced(child, null); + + return child; + } + + public boolean isChildEditable() { + if (!fChildEditable) { + XMLModelImpl model = (XMLModelImpl) getModel(); + if (model != null && model.isReparsing()) { + return true; + } + } + return fChildEditable; + } + + /** + * isContainer method + * + * @return boolean + */ + public boolean isContainer() { + return true; + } + + /** + * item method + * + * @return org.w3c.dom.Node + * @param index + * int + */ + public Node item(int index) { + if (this.firstChild == null) + return null; + synchronized (lockObject) { + if (this.childNodesCache == null) + this.childNodesCache = new ChildNodesCache(); + return this.childNodesCache.item(index); + } + } + + /** + * notifyChildReplaced method + * + * @param newChild + * org.w3c.dom.Node + * @param oldChild + * org.w3c.dom.Node + */ + protected void notifyChildReplaced(Node newChild, Node oldChild) { + DocumentImpl document = (DocumentImpl) getContainerDocument(); + if (document == null) + return; + + syncChildEditableState(newChild); + + XMLModelImpl model = (XMLModelImpl) document.getModel(); + if (model == null) + return; + model.childReplaced(this, newChild, oldChild); + } + + /** + * removeChild method + * + * @return org.w3c.dom.Node + * @param oldChild + * org.w3c.dom.Node + */ + public Node removeChild(Node oldChild) throws DOMException { + if (oldChild == null) + return null; + if (oldChild.getParentNode() != this) { + throw new DOMException(DOMException.NOT_FOUND_ERR, new String()); + } + + if (!isChildEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + + // synchronized in case another thread is getting item, or length + synchronized (lockObject) { + this.childNodesCache = null; // invalidate child nodes cache + } + + NodeImpl child = (NodeImpl) oldChild; + NodeImpl prev = (NodeImpl) child.getPreviousSibling(); + NodeImpl next = (NodeImpl) child.getNextSibling(); + + child.setEditable(true, true); // clear ReadOnly flags + + if (prev == null) + this.firstChild = next; + else + prev.setNextSibling(next); + if (next == null) + this.lastChild = prev; + else + next.setPreviousSibling(prev); + child.setPreviousSibling(null); + child.setNextSibling(null); + child.setParentNode(null); + + notifyChildReplaced(null, child); + + return child; + } + + /** + * removeChildNodes method + */ + public void removeChildNodes() { + if (!isChildEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + + Node nextChild = null; + for (Node child = getFirstChild(); child != null; child = nextChild) { + nextChild = child.getNextSibling(); + removeChild(child); + } + } + + /** + * removeChildNodes method + * + * @return org.w3c.dom.DocumentFragment + * @param firstChild + * org.w3c.dom.Node + * @param lastChild + * org.w3c.dom.Node + */ + public DocumentFragment removeChildNodes(Node firstChild, Node lastChild) { + if (!hasChildNodes()) + return null; + if (!isChildEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + + Document document = null; + if (getNodeType() == DOCUMENT_NODE) + document = (Document) this; + else + document = getOwnerDocument(); + if (document == null) + return null; + DocumentFragment fragment = document.createDocumentFragment(); + if (fragment == null) + return null; + + if (firstChild == null) + firstChild = getFirstChild(); + if (lastChild == null) + lastChild = getLastChild(); + Node nextChild = null; + for (Node child = firstChild; child != null; child = nextChild) { + nextChild = child.getNextSibling(); + removeChild(child); + fragment.appendChild(child); + if (child == lastChild) + break; + } + + return fragment; + } + + /** + * replaceChild method + * + * @return org.w3c.dom.Node + * @param newChild + * org.w3c.dom.Node + * @param oldChild + * org.w3c.dom.Node + */ + public Node replaceChild(Node newChild, Node oldChild) throws DOMException { + if (!isChildEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + + if (oldChild == null) + return newChild; + if (newChild != null) + insertBefore(newChild, oldChild); + return removeChild(oldChild); + } + + public void setChildEditable(boolean editable) { + if (fChildEditable == editable) { + return; + } + + ReadOnlyController roc = ReadOnlyController.getInstance(); + Node node; + if (editable) { + for (node = getFirstChild(); node != null; node = node.getNextSibling()) { + roc.unlockNode((XMLNode) node); + } + } else { + for (node = getFirstChild(); node != null; node = node.getNextSibling()) { + roc.lockNode((XMLNode) node); + } + } + + fChildEditable = editable; + notifyEditableChanged(); + } + + protected void syncChildEditableState(Node child) { + ReadOnlyController roc = ReadOnlyController.getInstance(); + if (fChildEditable) { + roc.unlockNode((NodeImpl) child); + } else { + roc.lockNode((NodeImpl) child); + } + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/NodeImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/NodeImpl.java new file mode 100644 index 0000000000..0ea5dde799 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/NodeImpl.java @@ -0,0 +1,809 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.document; + + + +import org.eclipse.wst.sse.core.AbstractNotifier; +import org.eclipse.wst.sse.core.IFactoryRegistry; +import org.eclipse.wst.sse.core.text.IStructuredDocument; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.xml.core.document.InvalidCharacterException; +import org.eclipse.wst.xml.core.document.XMLModel; +import org.eclipse.wst.xml.core.document.XMLNode; +import org.w3c.dom.DOMException; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; + + +/** + * NodeImpl class + */ +public abstract class NodeImpl extends AbstractNotifier implements XMLNode { + // define one empty nodelist, for repeated use + private final static NodeList EMPTY_NODE_LIST = new NodeListImpl(); + + private boolean fDataEditable = true; + private IStructuredDocumentRegion flatNode = null; + private NodeImpl nextSibling = null; + + private DocumentImpl ownerDocument = null; + private NodeImpl parentNode = null; + private NodeImpl previousSibling = null; + + /** + * NodeImpl constructor + */ + protected NodeImpl() { + super(); + } + + /** + * NodeImpl constructor + * + * @param that + * NodeImpl + */ + protected NodeImpl(NodeImpl that) { + if (that != null) { + this.ownerDocument = that.ownerDocument; + } + } + + /** + * appendChild method + * + * @return org.w3c.dom.Node + * @param newChild + * org.w3c.dom.Node + */ + public Node appendChild(Node newChild) throws DOMException { + throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, new String()); + } + + /** + * contains method + * + * @return boolean + * @param offset + * int + */ + public boolean contains(int offset) { + return (offset >= getStartOffset() && offset < getEndOffset()); + } + + /** + * @param s + * @param tagName + * @return + */ + protected String createDOMExceptionMessage(short s, String tagName) { + String result = null; + // TODO: Should localize these messages, and provide /u escaped + // version of tagName + result = lookupMessage(s) + " " + tagName; //$NON-NLS-1$ + return result; + } + + /** + * getAttributes method + * + * @return org.w3c.dom.NamedNodeMap + */ + public NamedNodeMap getAttributes() { + return null; + } + + /** + */ + protected String getCharValue(String name) { + DocumentImpl document = (DocumentImpl) getOwnerDocument(); + if (document == null) + return null; + return document.getCharValue(name); + } + + /** + * getChildNodes method + * + * @return org.w3c.dom.NodeList + */ + public NodeList getChildNodes() { + // As per DOM spec, correct behavior for getChildNodes is to return a + // zero length NodeList, not null, when there are no children. + // We'll use a common instance of an empty node list, just to prevent + // creating a trival object many many times. + + return EMPTY_NODE_LIST; + } + + /** + * getCommonAncestor method + * + * @return org.w3c.dom.Node + * @param node + * org.w3c.dom.Node + */ + public Node getCommonAncestor(Node node) { + if (node == null) + return null; + + for (Node na = node; na != null; na = na.getParentNode()) { + for (Node ta = this; ta != null; ta = ta.getParentNode()) { + if (ta == na) + return ta; + } + } + + return null; // not found + } + + /** + * getContainerDocument method + * + * @return org.w3c.dom.Document + */ + public Document getContainerDocument() { + for (Node node = this; node != null; node = node.getParentNode()) { + if (node.getNodeType() == Node.DOCUMENT_NODE) { + return (Document) node; + } + } + return null; + } + + /** + * getEndOffset method + * + * @return int + */ + public int getEndOffset() { + Node node = this; + while (node != null) { + if (node.getNodeType() == Node.ELEMENT_NODE) { + ElementImpl element = (ElementImpl) node; + IStructuredDocumentRegion endStructuredDocumentRegion = element.getEndStructuredDocumentRegion(); + if (endStructuredDocumentRegion != null) + return endStructuredDocumentRegion.getEnd(); + } + + Node last = node.getLastChild(); + if (last != null) { // dig into the last + node = last; + continue; + } + + IStructuredDocumentRegion lastStructuredDocumentRegion = ((NodeImpl) node).getStructuredDocumentRegion(); + if (lastStructuredDocumentRegion != null) + return lastStructuredDocumentRegion.getEnd(); + + Node prev = node.getPreviousSibling(); + if (prev != null) { // move to the previous + node = prev; + continue; + } + + Node parent = node.getParentNode(); + node = null; + while (parent != null) { + if (parent.getNodeType() == Node.ELEMENT_NODE) { + ElementImpl element = (ElementImpl) parent; + IStructuredDocumentRegion startStructuredDocumentRegion = element.getStartStructuredDocumentRegion(); + if (startStructuredDocumentRegion != null) + return startStructuredDocumentRegion.getEnd(); + } + Node parentPrev = parent.getPreviousSibling(); + if (parentPrev != null) { // move to the previous + node = parentPrev; + break; + } + parent = parent.getParentNode(); + } + } + return 0; + } + + public IStructuredDocumentRegion getEndStructuredDocumentRegion() { + return null; + } + + /** + */ + public IFactoryRegistry getFactoryRegistry() { + XMLModel model = getModel(); + if (model != null) { + IFactoryRegistry reg = model.getFactoryRegistry(); + if (reg != null) + return reg; + } + return null; + } + + /** + * getFirstChild method + * + * @return org.w3c.dom.Node + */ + public Node getFirstChild() { + return null; + } + + /** + * getFirstStructuredDocumentRegion method + * + * @return com.ibm.sed.structuredDocument.IStructuredDocumentRegion + */ + public IStructuredDocumentRegion getFirstStructuredDocumentRegion() { + return StructuredDocumentRegionUtil.getStructuredDocumentRegion(this.flatNode); + } + + /** + */ + public int getIndex() { + Node parent = getParentNode(); + if (parent == null) + return -1; // error + int index = 0; + for (Node child = parent.getFirstChild(); child != null; child = child.getNextSibling()) { + if (child == this) + return index; + index++; + } + return -1; // error + } + + /** + * getLastChild method + * + * @return org.w3c.dom.Node + */ + public Node getLastChild() { + return null; + } + + /** + * getLastStructuredDocumentRegion method + * + * @return com.ibm.sed.structuredDocument.IStructuredDocumentRegion + */ + public IStructuredDocumentRegion getLastStructuredDocumentRegion() { + return StructuredDocumentRegionUtil.getStructuredDocumentRegion(this.flatNode); + } + + /** + */ + public String getLocalName() { + return null; + } + + /** + * the default implementation can just refer to the owning document + */ + public XMLModel getModel() { + if (this.ownerDocument == null) + return null; + return this.ownerDocument.getModel(); + } + + /** + * all but attr return null + */ + public ITextRegion getNameRegion() { + return null; + } + + /** + */ + public String getNamespaceURI() { + return null; + } + + /** + * getNextSibling method + * + * @return org.w3c.dom.Node + */ + public Node getNextSibling() { + return this.nextSibling; + } + + /** + * getNodeAt method + * + * @return org.w3c.dom.Node + * @param offset + * int + */ + Node getNodeAt(int offset) { + XMLNode parent = this; + XMLNode child = (XMLNode) getFirstChild(); + while (child != null) { + if (child.getEndOffset() <= offset) { + child = (XMLNode) child.getNextSibling(); + continue; + } + if (child.getStartOffset() > offset) { + break; + } + + IStructuredDocumentRegion startStructuredDocumentRegion = child.getStartStructuredDocumentRegion(); + if (startStructuredDocumentRegion != null) { + if (startStructuredDocumentRegion.getEnd() > offset) + return child; + } + + // dig more + parent = child; + child = (XMLNode) parent.getFirstChild(); + } + + return parent; + } + + /** + * getNodeValue method + * + * @return java.lang.String + */ + public String getNodeValue() throws DOMException { + return null; + } + + /** + * getOwnerDocument method + * + * @return org.w3c.dom.Document + */ + public Document getOwnerDocument() { + return this.ownerDocument; + } + + /** + * getParentNode method + * + * @return org.w3c.dom.Node + */ + public Node getParentNode() { + return this.parentNode; + } + + /** + */ + public String getPrefix() { + return null; + } + + /** + * getPreviousSibling method + * + * @return org.w3c.dom.Node + */ + public Node getPreviousSibling() { + return this.previousSibling; + } + + /** + */ + public String getSource() { + if (this.flatNode == null) + return new String(); + return this.flatNode.getText(); + } + + /** + * getStartOffset method + * + * @return int + */ + public int getStartOffset() { + if (this.flatNode != null) + return this.flatNode.getStart(); + NodeImpl prev = (NodeImpl) getPreviousSibling(); + if (prev != null) + return prev.getEndOffset(); + Node parent = getParentNode(); + if (parent != null && parent.getNodeType() == Node.ELEMENT_NODE) { + ElementImpl element = (ElementImpl) parent; + if (element.hasStartTag()) + return element.getStartEndOffset(); + return element.getStartOffset(); + } + // final fallback to look into first child + NodeImpl child = (NodeImpl) getFirstChild(); + while (child != null) { + IStructuredDocumentRegion childStructuredDocumentRegion = child.getStructuredDocumentRegion(); + if (childStructuredDocumentRegion != null) + return childStructuredDocumentRegion.getStart(); + child = (NodeImpl) child.getFirstChild(); + } + return 0; + } + + public IStructuredDocumentRegion getStartStructuredDocumentRegion() { + return getFirstStructuredDocumentRegion(); + } + + /** + * Every node (indirectly) knows its structuredDocument + */ + public IStructuredDocument getStructuredDocument() { + return getModel().getStructuredDocument(); + } + + /** + */ + IStructuredDocumentRegion getStructuredDocumentRegion() { + return this.flatNode; + } + + /** + * all but attr return null + */ + public ITextRegion getValueRegion() { + return null; + } + + /** + */ + public String getValueSource() { + return getNodeValue(); + } + + /** + */ + public boolean hasAttributes() { + return false; + } + + /** + * hasChildNodes method + * + * @return boolean + */ + public boolean hasChildNodes() { + return false; + } + + /** + * hasProperties method + * + * @return boolean + */ + public boolean hasProperties() { + return false; + } + + /** + * insertBefore method + * + * @return org.w3c.dom.Node + * @param newChild + * org.w3c.dom.Node + * @param refChild + * org.w3c.dom.Node + */ + public Node insertBefore(Node newChild, Node refChild) throws DOMException { + throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, new String()); + } + + public boolean isChildEditable() { + return false; + } + + /** + */ + public boolean isClosed() { + return true; + } + + /** + * isContainer method + * + * @return boolean + */ + public boolean isContainer() { + return false; + } + + public boolean isDataEditable() { + if (!fDataEditable) { + XMLModelImpl model = (XMLModelImpl) getModel(); + if (model != null && model.isReparsing()) { + return true; + } + } + return fDataEditable; + } + + /** + */ + public boolean isSupported(String feature, String version) { + if (this.ownerDocument == null) + return false; + DOMImplementation impl = this.ownerDocument.getImplementation(); + if (impl == null) + return false; + return impl.hasFeature(feature, version); + } + + /** + * @param s + * @return + */ + private String lookupMessage(short s) { + // TODO: make localized version + String result = null; + switch (s) { + case DOMException.INVALID_CHARACTER_ERR : + result = "INVALID_CHARACTER_ERR"; //$NON-NLS-1$ + break; + + default : + result = new String(); + break; + } + return result; + } + + /** + * normalize method + */ + public void normalize() { + TextImpl prevText = null; + for (Node child = getFirstChild(); child != null; child = child.getNextSibling()) { + switch (child.getNodeType()) { + case TEXT_NODE : { + if (prevText == null) { + prevText = (TextImpl) child; + break; + } + Text text = (Text) child; + removeChild(text); + prevText.appendText(text); + child = prevText; + break; + } + case ELEMENT_NODE : { + Element element = (Element) child; + element.normalize(); + prevText = null; + break; + } + default : + prevText = null; + break; + } + } + } + + protected void notifyEditableChanged() { + DocumentImpl document = (DocumentImpl) getContainerDocument(); + if (document == null) + return; + XMLModelImpl model = (XMLModelImpl) document.getModel(); + if (model == null) + return; + model.editableChanged(this); + } + + /** + * notifyValueChanged method + */ + protected void notifyValueChanged() { + DocumentImpl document = (DocumentImpl) getContainerDocument(); + if (document == null) + return; + + syncDataEditableState(); + + XMLModelImpl model = (XMLModelImpl) document.getModel(); + if (model == null) + return; + model.valueChanged(this); + } + + /** + * removeChild method + * + * @return org.w3c.dom.Node + * @param oldChild + * org.w3c.dom.Node + */ + public Node removeChild(Node oldChild) throws DOMException { + throw new DOMException(DOMException.NOT_FOUND_ERR, new String()); + } + + /** + * removeChildNodes method + */ + public void removeChildNodes() { + } + + /** + * removeChildNodes method + * + * @return org.w3c.dom.DocumentFragment + * @param firstChild + * org.w3c.dom.Node + * @param lastChild + * org.w3c.dom.Node + */ + public DocumentFragment removeChildNodes(Node firstChild, Node lastChild) { + return null; + } + + /** + * replaceChild method + * + * @return org.w3c.dom.Node + * @param newChild + * org.w3c.dom.Node + * @param oldChild + * org.w3c.dom.Node + */ + public Node replaceChild(Node newChild, Node oldChild) throws DOMException { + throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, new String()); + } + + /** + * Resets children values from IStructuredDocumentRegion. + */ + void resetStructuredDocumentRegions() { + for (NodeImpl child = (NodeImpl) getFirstChild(); child != null; child = (NodeImpl) child.getNextSibling()) { + child.resetStructuredDocumentRegions(); + } + this.flatNode = null; + } + + public void setChildEditable(boolean editable) { + // nop + } + + public void setDataEditable(boolean editable) { + if (fDataEditable == editable) { + return; + } + + ReadOnlyController roc = ReadOnlyController.getInstance(); + if (editable) { + roc.unlockData(this); + } else { + roc.lockData(this); + } + + fDataEditable = editable; + + notifyEditableChanged(); + } + + public void setEditable(boolean editable, boolean deep) { + if (deep) { + XMLNode node = (XMLNode) getFirstChild(); + while (node != null) { + node.setEditable(editable, deep); + node = (XMLNode) node.getNextSibling(); + } + } + setChildEditable(editable); + setDataEditable(editable); + } + + /** + * setNextSibling method + * + * @param nextSibling + * org.w3c.dom.Node + */ + protected void setNextSibling(Node nextSibling) { + this.nextSibling = (NodeImpl) nextSibling; + } + + /** + * setNodeValue method + * + * @param nodeValue + * java.lang.String + */ + public void setNodeValue(String nodeValue) throws DOMException { + } + + /** + * setOwnerDocument method + * + * @param ownerDocument + * org.w3c.dom.Document + */ + protected void setOwnerDocument(Document ownerDocument) { + this.ownerDocument = (DocumentImpl) ownerDocument; + } + + /** + */ + protected void setOwnerDocument(Document ownerDocument, boolean deep) { + this.ownerDocument = (DocumentImpl) ownerDocument; + + if (deep) { + for (NodeImpl child = (NodeImpl) getFirstChild(); child != null; child = (NodeImpl) child.getNextSibling()) { + child.setOwnerDocument(ownerDocument, deep); + } + } + } + + /** + * setParentNode method + * + * @param parentNode + * org.w3c.dom.Node + */ + protected void setParentNode(Node parentNode) { + this.parentNode = (NodeImpl) parentNode; + } + + /** + */ + public void setPrefix(String prefix) throws DOMException { + } + + /** + * setPreviousSibling method + * + * @param previousSibling + * org.w3c.dom.Node + */ + protected void setPreviousSibling(Node previousSibling) { + this.previousSibling = (NodeImpl) previousSibling; + } + + /** + */ + public void setSource(String source) throws InvalidCharacterException { + // not supported + } + + /** + */ + void setStructuredDocumentRegion(IStructuredDocumentRegion flatNode) { + this.flatNode = flatNode; + } + + /** + */ + public void setValueSource(String source) { + setNodeValue(source); + } + + protected void syncDataEditableState() { + ReadOnlyController roc = ReadOnlyController.getInstance(); + if (fDataEditable) { + roc.unlockData(this); + } else { + roc.lockData(this); + } + } + + /** + * toString method + * + * @return java.lang.String + */ + public String toString() { + return getNodeName(); + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/NodeIteratorImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/NodeIteratorImpl.java new file mode 100644 index 0000000000..c4a278b694 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/NodeIteratorImpl.java @@ -0,0 +1,257 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.document; + + + +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; +import org.w3c.dom.traversal.NodeFilter; +import org.w3c.dom.traversal.NodeIterator; + +/** + * NodeIteratorImpl class + */ +public class NodeIteratorImpl implements NodeIterator { + private NodeFilter filter = null; + private Node nextNode = null; + + private Node rootNode = null; + private int whatToShow = NodeFilter.SHOW_ALL; + + /** + * NodeIteratorImpl constructor + * + * @param rootNode + * org.w3c.dom.Node + */ + NodeIteratorImpl(Node rootNode, int whatToShow, NodeFilter filter) { + this.rootNode = rootNode; + this.nextNode = rootNode; + this.whatToShow = whatToShow; + this.filter = filter; + } + + /** + */ + private final boolean acceptNode(Node node) { + if (this.whatToShow != NodeFilter.SHOW_ALL) { + if (node == null) + return false; + short nodeType = node.getNodeType(); + switch (this.whatToShow) { + case NodeFilter.SHOW_ELEMENT : + if (nodeType != Node.ELEMENT_NODE) + return false; + break; + case NodeFilter.SHOW_ATTRIBUTE : + if (nodeType != Node.ATTRIBUTE_NODE) + return false; + break; + case NodeFilter.SHOW_TEXT : + if (nodeType != Node.TEXT_NODE) + return false; + break; + case NodeFilter.SHOW_CDATA_SECTION : + if (nodeType != Node.CDATA_SECTION_NODE) + return false; + break; + case NodeFilter.SHOW_ENTITY_REFERENCE : + if (nodeType != Node.ENTITY_REFERENCE_NODE) + return false; + break; + case NodeFilter.SHOW_ENTITY : + if (nodeType != Node.ENTITY_NODE) + return false; + break; + case NodeFilter.SHOW_PROCESSING_INSTRUCTION : + if (nodeType != Node.PROCESSING_INSTRUCTION_NODE) + return false; + break; + case NodeFilter.SHOW_COMMENT : + if (nodeType != Node.COMMENT_NODE) + return false; + break; + case NodeFilter.SHOW_DOCUMENT : + if (nodeType != Node.DOCUMENT_NODE) + return false; + break; + case NodeFilter.SHOW_DOCUMENT_TYPE : + if (nodeType != Node.DOCUMENT_TYPE_NODE) + return false; + break; + case NodeFilter.SHOW_DOCUMENT_FRAGMENT : + if (nodeType != Node.DOCUMENT_FRAGMENT_NODE) + return false; + break; + case NodeFilter.SHOW_NOTATION : + if (nodeType != Node.NOTATION_NODE) + return false; + break; + default : + return false; + } + } + if (this.filter != null) { + return (this.filter.acceptNode(node) == NodeFilter.FILTER_ACCEPT); + } + return true; + } + + /** + * Detaches the <code>NodeIterator</code> from the set which it iterated + * over, releasing any computational resources and placing the iterator in + * the INVALID state. After <code>detach</code> has been invoked, calls + * to <code>nextNode</code> or <code>previousNode</code> will raise + * the exception INVALID_STATE_ERR. + */ + public void detach() { + this.rootNode = null; + this.nextNode = null; + this.filter = null; + } + + /** + * The value of this flag determines whether the children of entity + * reference nodes are visible to the iterator. If false, they and their + * descendants will be rejected. Note that this rejection takes precedence + * over <code>whatToShow</code> and the filter. Also note that this is + * currently the only situation where <code>NodeIterators</code> may + * reject a complete subtree rather than skipping individual nodes. <br> + * <br> + * To produce a view of the document that has entity references expanded + * and does not expose the entity reference node itself, use the + * <code>whatToShow</code> flags to hide the entity reference node and + * set <code>expandEntityReferences</code> to true when creating the + * iterator. To produce a view of the document that has entity reference + * nodes but no entity expansion, use the <code>whatToShow</code> flags + * to show the entity reference node and set + * <code>expandEntityReferences</code> to false. + */ + public boolean getExpandEntityReferences() { + // not supported + return false; + } + + /** + * The <code>NodeFilter</code> used to screen nodes. + */ + public NodeFilter getFilter() { + return this.filter; + } + + /** + */ + private final Node getNextNode() { + if (this.nextNode == null) + return null; + Node oldNext = this.nextNode; + Node child = this.nextNode.getFirstChild(); + if (child != null) { + this.nextNode = child; + return oldNext; + } + for (Node node = this.nextNode; node != null && node != this.rootNode; node = node.getParentNode()) { + Node next = node.getNextSibling(); + if (next != null) { + this.nextNode = next; + return oldNext; + } + } + this.nextNode = null; + return oldNext; + } + + /** + */ + private final Node getPreviousNode() { + if (this.nextNode == this.rootNode) + return null; + Node prev = null; + if (this.nextNode == null) { + prev = this.rootNode; // never null + } else { + prev = this.nextNode.getPreviousSibling(); + if (prev == null) { + this.nextNode = this.nextNode.getParentNode(); + return this.nextNode; + } + } + Node last = prev.getLastChild(); + while (last != null) { + prev = last; + last = prev.getLastChild(); + } + this.nextNode = prev; + return this.nextNode; + } + + /** + * The root node of the <code>NodeIterator</code>, as specified when it + * was created. + */ + public Node getRoot() { + return this.rootNode; + } + + /** + * This attribute determines which node types are presented via the + * iterator. The available set of constants is defined in the + * <code>NodeFilter</code> interface. Nodes not accepted by + * <code>whatToShow</code> will be skipped, but their children may still + * be considered. Note that this skip takes precedence over the filter, if + * any. + */ + public int getWhatToShow() { + return this.whatToShow; + } + + /** + * Returns the next node in the set and advances the position of the + * iterator in the set. After a <code>NodeIterator</code> is created, + * the first call to <code>nextNode()</code> returns the first node in + * the set. + * + * @return The next <code>Node</code> in the set being iterated over, or + * <code>null</code> if there are no more members in that set. + * @exception DOMException + * INVALID_STATE_ERR: Raised if this method is called after + * the <code>detach</code> method was invoked. + */ + public Node nextNode() throws DOMException { + for (Node node = getNextNode(); node != null; node = getNextNode()) { + if (acceptNode(node)) + return node; + } + return null; + } + + /** + * Returns the previous node in the set and moves the position of the + * <code>NodeIterator</code> backwards in the set. + * + * @return The previous <code>Node</code> in the set being iterated + * over, or <code>null</code> if there are no more members in + * that set. + * @exception DOMException + * INVALID_STATE_ERR: Raised if this method is called after + * the <code>detach</code> method was invoked. + */ + public Node previousNode() throws DOMException { + for (Node node = getPreviousNode(); node != null; node = getPreviousNode()) { + if (acceptNode(node)) + return node; + } + return null; + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/NodeListImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/NodeListImpl.java new file mode 100644 index 0000000000..4bfed52901 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/NodeListImpl.java @@ -0,0 +1,111 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.document; + + + +import java.util.Vector; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * NodeListImpl class + */ +public class NodeListImpl implements NodeList { + + Object lockObject = new byte[0]; + + private Vector nodes = null; + + /** + * NodeListImpl constructor + */ + public NodeListImpl() { + super(); + } + + /** + * appendNode method + * + * @return org.w3c.dom.Node + * @param node + * org.w3c.dom.Node + */ + protected Node appendNode(Node node) { + if (node == null) + return null; + if (this.nodes == null) + this.nodes = new Vector(); + this.nodes.addElement(node); + return node; + } + + /** + * getLength method + * + * @return int + */ + public int getLength() { + synchronized (lockObject) { + if (this.nodes == null) + return 0; + return this.nodes.size(); + } + } + + /** + */ + protected Node insertNode(Node node, int index) { + if (node == null) + return null; + if (this.nodes == null || index >= this.nodes.size()) { + return appendNode(node); + } + this.nodes.insertElementAt(node, index); + return node; + } + + /** + * item method + * + * @return org.w3c.dom.Node + */ + public Node item(int index) { + synchronized (lockObject) { + if (this.nodes == null) + return null; + if (index < 0 || index >= this.nodes.size()) + return null; + return (Node) this.nodes.elementAt(index); + } + } + + /** + * removeNode method + * + * @return org.w3c.dom.Node + * @param index + * int + */ + protected Node removeNode(int index) { + if (this.nodes == null) + return null; // no node + if (index < 0 || index >= this.nodes.size()) + return null; // invalid parameter + + Node removed = (Node) this.nodes.elementAt(index); + this.nodes.removeElementAt(index); + return removed; + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/NotationImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/NotationImpl.java new file mode 100644 index 0000000000..e0489499ed --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/NotationImpl.java @@ -0,0 +1,138 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.document; + + + +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; +import org.w3c.dom.Notation; + +/** + * NotationImpl class + */ +public class NotationImpl extends NodeImpl implements Notation { + + private String name = null; + private String publicId = null; + private String systemId = null; + + /** + * NotationImpl constructor + */ + protected NotationImpl() { + super(); + } + + /** + * NotationImpl constructor + * + * @param that + * NotationImpl + */ + protected NotationImpl(NotationImpl that) { + super(that); + + if (that != null) { + this.name = that.name; + this.publicId = that.publicId; + this.systemId = that.systemId; + } + } + + /** + * cloneNode method + * + * @return org.w3c.dom.Node + * @param deep + * boolean + */ + public Node cloneNode(boolean deep) { + NotationImpl cloned = new NotationImpl(this); + return cloned; + } + + /** + * getNodeName method + * + * @return java.lang.String + */ + public String getNodeName() { + if (this.name == null) + return new String(); + return this.name; + } + + /** + * getNodeType method + * + * @return short + */ + public short getNodeType() { + return NOTATION_NODE; + } + + /** + * getPublicId method + * + * @return java.lang.String + */ + public String getPublicId() { + return this.publicId; + } + + /** + * getSystemId method + * + * @return java.lang.String + */ + public String getSystemId() { + return this.systemId; + } + + /** + * setName method + * + * @param name + * java.lang.String + */ + protected void setName(String name) { + this.name = name; + } + + /** + * setPublicId method + * + * @param publicId + * java.lang.String + */ + public void setPublicId(String publicId) { + if (!isDataEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + this.publicId = publicId; + } + + /** + * setSystemId method + * + * @param systemId + * java.lang.String + */ + public void setSystemId(String systemId) { + if (!isDataEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + this.systemId = systemId; + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/ProcessingInstructionImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/ProcessingInstructionImpl.java new file mode 100644 index 0000000000..de9a4fe014 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/ProcessingInstructionImpl.java @@ -0,0 +1,227 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.document; + + + +import java.util.Iterator; + +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.core.text.ITextRegionList; +import org.eclipse.wst.xml.core.jsp.model.parser.temp.XMLJSPRegionContexts; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; +import org.w3c.dom.ProcessingInstruction; + + +/** + * ProcessingInstructionImpl class + */ +public class ProcessingInstructionImpl extends NodeImpl implements XMLJSPRegionContexts, ProcessingInstruction { + private String data = null; + + private String target = null; + + /** + * ProcessingInstructionImpl constructor + */ + protected ProcessingInstructionImpl() { + super(); + } + + /** + * ProcessingInstructionImpl constructor + * + * @param that + * ProcessingInstructionImpl + */ + protected ProcessingInstructionImpl(ProcessingInstructionImpl that) { + super(that); + + if (that != null) { + this.target = that.target; + this.data = that.getData(); + } + } + + /** + * cloneNode method + * + * @return org.w3c.dom.Node + * @param deep + * boolean + */ + public Node cloneNode(boolean deep) { + ProcessingInstructionImpl cloned = new ProcessingInstructionImpl(this); + return cloned; + } + + /** + * getData method + * + * @return java.lang.String + */ + public String getData() { + if (this.data != null) + return this.data; + + IStructuredDocumentRegion flatNode = getFirstStructuredDocumentRegion(); + if (flatNode == null) + return new String(); + ITextRegionList regions = flatNode.getRegions(); + if (regions == null) + return new String(); + + ITextRegion targetRegion = null; + ITextRegion dataRegion = null; + ITextRegion closeRegion = null; + Iterator e = regions.iterator(); + while (e.hasNext()) { + ITextRegion region = (ITextRegion) e.next(); + String regionType = region.getType(); + if (regionType == XMLRegionContext.XML_PI_OPEN) + continue; + if (regionType == XMLRegionContext.XML_PI_CLOSE) { + closeRegion = region; + } else { + if (targetRegion == null) + targetRegion = region; + else if (dataRegion == null) + dataRegion = region; + } + } + if (dataRegion == null) + return new String(); + int offset = dataRegion.getStart(); + int end = flatNode.getLength(); + if (closeRegion != null) + end = closeRegion.getStart(); + String source = flatNode.getText(); + return source.substring(offset, end); + } + + /** + * getNodeName method + * + * @return java.lang.String + */ + public String getNodeName() { + return getTarget(); + } + + /** + * getNodeType method + * + * @return short + */ + public short getNodeType() { + return PROCESSING_INSTRUCTION_NODE; + } + + /** + * getNodeValue method + * + * @return java.lang.String + */ + public String getNodeValue() { + return getData(); + } + + /** + * getTarget method + * + * @return java.lang.String + */ + public String getTarget() { + if (this.target == null) + return new String(); + return this.target; + } + + /** + */ + public boolean isClosed() { + IStructuredDocumentRegion flatNode = getStructuredDocumentRegion(); + if (flatNode == null) + return true; // will be generated + String regionType = StructuredDocumentRegionUtil.getLastRegionType(flatNode); + return (regionType == XMLRegionContext.XML_PI_CLOSE); + } + + /** + */ + void resetStructuredDocumentRegions() { + this.data = getData(); + setStructuredDocumentRegion(null); + } + + /** + * setData method + * + * @param data + * java.lang.String + */ + public void setData(String data) throws DOMException { + if (!isDataEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + + this.data = data; + + notifyValueChanged(); + } + + /** + * setNodeValue method + * + * @param nodeValue + * java.lang.String + */ + public void setNodeValue(String nodeValue) throws DOMException { + setData(nodeValue); + } + + /** + */ + void setStructuredDocumentRegion(IStructuredDocumentRegion flatNode) { + super.setStructuredDocumentRegion(flatNode); + if (flatNode != null) + this.data = null; + } + + /** + * setTarget method + * + * @param target + * java.lang.String + */ + protected void setTarget(String target) { + this.target = target; + } + + /** + * toString method + * + * @return java.lang.String + */ + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append(getTarget()); + buffer.append('('); + buffer.append(getData()); + buffer.append(')'); + return buffer.toString(); + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/RangeImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/RangeImpl.java new file mode 100644 index 0000000000..1c54ba53d0 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/RangeImpl.java @@ -0,0 +1,630 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.document; + + + +import org.eclipse.wst.xml.core.document.XMLNode; +import org.w3c.dom.DOMException; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; +import org.w3c.dom.ranges.Range; +import org.w3c.dom.ranges.RangeException; + + +/** + */ +public class RangeImpl implements Range { + private Node endContainer = null; + private int endOffset = 0; + + private Node startContainer = null; + private int startOffset = 0; + + /** + */ + protected RangeImpl() { + super(); + } + + /** + */ + protected RangeImpl(RangeImpl that) { + super(); + + if (that != null) { + this.startContainer = that.startContainer; + this.startOffset = that.startOffset; + this.endContainer = that.endContainer; + this.endOffset = that.endOffset; + } + } + + /** + * Duplicates the contents of a Range + * + * @return A DocumentFragment that contains content equivalent to this + * Range. + * @exception DOMException + * HIERARCHY_REQUEST_ERR: Raised if a DocumentType node + * would be extracted into the new DocumentFragment. <br> + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public DocumentFragment cloneContents() throws DOMException { + // not supported + return null; + } + + /** + * Produces a new Range whose boundary-points are equal to the + * boundary-points of the Range. + * + * @return The duplicated Range. + * @exception DOMException + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public Range cloneRange() throws DOMException { + return new RangeImpl(this); + } + + /** + * Collapse a Range onto one of its boundary-points + * + * @param toStartIf + * TRUE, collapses the Range onto its start; if FALSE, + * collapses it onto its end. + * @exception DOMException + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public void collapse(boolean toStart) throws DOMException { + if (toStart) { + this.endContainer = this.startContainer; + this.endOffset = this.startOffset; + } else { + this.startContainer = this.endContainer; + this.startOffset = this.endOffset; + } + } + + /** + * Compare the boundary-points of two Ranges in a document. + * + * @param howA + * code representing the type of comparison, as defined above. + * @param sourceRangeThe + * <code>Range</code> on which this current + * <code>Range</code> is compared to. + * @return -1, 0 or 1 depending on whether the corresponding + * boundary-point of the Range is respectively before, equal to, + * or after the corresponding boundary-point of + * <code>sourceRange</code>. + * @exception DOMException + * WRONG_DOCUMENT_ERR: Raised if the two Ranges are not in + * the same Document or DocumentFragment. <br> + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public short compareBoundaryPoints(short how, Range sourceRange) throws DOMException { + if (sourceRange == null) + return (short) 0; // error + + Node container1 = null; + int offset1 = 0; + Node container2 = null; + int offset2 = 0; + + switch (how) { + case START_TO_START : + container1 = this.startContainer; + offset1 = this.startOffset; + container2 = sourceRange.getStartContainer(); + offset2 = sourceRange.getStartOffset(); + break; + case START_TO_END : + container1 = this.startContainer; + offset1 = this.startOffset; + container2 = sourceRange.getEndContainer(); + offset2 = sourceRange.getEndOffset(); + break; + case END_TO_END : + container1 = this.endContainer; + offset1 = this.endOffset; + container2 = sourceRange.getEndContainer(); + offset2 = sourceRange.getEndOffset(); + break; + case END_TO_START : + container1 = this.endContainer; + offset1 = this.endOffset; + container2 = sourceRange.getStartContainer(); + offset2 = sourceRange.getStartOffset(); + break; + default : + return (short) 0; // error + } + + return comparePoints(container1, offset1, container2, offset2); + } + + /* + */ + protected short comparePoints(Node container1, int offset1, Node container2, int offset2) { + if (container1 == null || container2 == null) + return (short) 0; // error + + if (container1 == container2) { + if (offset1 > offset2) + return (short) 1; + if (offset1 < offset2) + return (short) -1; + return 0; + } + + // get node offsets + XMLNode node1 = null; + if (container1.hasChildNodes()) { + Node child = container1.getFirstChild(); + for (int i = 0; i < offset1; i++) { + Node next = child.getNextSibling(); + if (next == null) + break; + child = next; + } + node1 = (XMLNode) child; + offset1 = 0; + } else { + node1 = (XMLNode) container1; + } + int nodeOffset1 = node1.getStartOffset(); + XMLNode node2 = null; + if (container2.hasChildNodes()) { + Node child = container2.getFirstChild(); + for (int i = 0; i < offset2; i++) { + Node next = child.getNextSibling(); + if (next == null) + break; + child = next; + } + node2 = (XMLNode) child; + offset2 = 0; + } else { + node2 = (XMLNode) container1; + } + int nodeOffset2 = node2.getStartOffset(); + + if (nodeOffset1 > nodeOffset2) + return (short) 1; + if (nodeOffset1 < nodeOffset2) + return (short) -1; + if (offset1 > offset2) + return (short) 1; + if (offset1 < offset2) + return (short) -1; + return (short) 0; + } + + /** + * Removes the contents of a Range from the containing document or + * document fragment without returning a reference to the removed content. + * + * @exception DOMException + * NO_MODIFICATION_ALLOWED_ERR: Raised if any portion of + * the content of the Range is read-only or any of the + * nodes that contain any of the content of the Range are + * read-only. <br> + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public void deleteContents() throws DOMException { + // not supported + } + + /** + * Called to indicate that the Range is no longer in use and that the + * implementation may relinquish any resources associated with this Range. + * Subsequent calls to any methods or attribute getters on this Range will + * result in a <code>DOMException</code> being thrown with an error code + * of <code>INVALID_STATE_ERR</code>. + * + * @exception DOMException + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public void detach() throws DOMException { + this.startContainer = null; + this.startOffset = 0; + this.endContainer = null; + this.endOffset = 0; + } + + /** + * Moves the contents of a Range from the containing document or document + * fragment to a new DocumentFragment. + * + * @return A DocumentFragment containing the extracted contents. + * @exception DOMException + * NO_MODIFICATION_ALLOWED_ERR: Raised if any portion of + * the content of the Range is read-only or any of the + * nodes which contain any of the content of the Range are + * read-only. <br> + * HIERARCHY_REQUEST_ERR: Raised if a DocumentType node + * would be extracted into the new DocumentFragment. <br> + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public DocumentFragment extractContents() throws DOMException { + // not supported + return null; + } + + /** + * TRUE if the Range is collapsed + * + * @exception DOMException + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public boolean getCollapsed() throws DOMException { + if (this.startContainer == this.endContainer && this.startOffset == this.endOffset) + return true; + return false; + } + + /** + * The deepest common ancestor container of the Range's two + * boundary-points. + * + * @exception DOMException + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public Node getCommonAncestorContainer() throws DOMException { + if (this.startContainer == null) + return null; + return ((NodeImpl) this.startContainer).getCommonAncestor(this.endContainer); + } + + /** + * Node within which the Range ends + * + * @exception DOMException + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public Node getEndContainer() throws DOMException { + return this.endContainer; + } + + /** + * Offset within the ending node of the Range. + * + * @exception DOMException + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public int getEndOffset() throws DOMException { + return this.endOffset; + } + + /** + * Node within which the Range begins + * + * @exception DOMException + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public Node getStartContainer() throws DOMException { + return this.startContainer; + } + + /** + * Offset within the starting node of the Range. + * + * @exception DOMException + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public int getStartOffset() throws DOMException { + return this.startOffset; + } + + /** + * Inserts a node into the Document or DocumentFragment at the start of + * the Range. If the container is a Text node, this will be split at the + * start of the Range (as if the Text node's splitText method was + * performed at the insertion point) and the insertion will occur between + * the two resulting Text nodes. Adjacent Text nodes will not be + * automatically merged. If the node to be inserted is a DocumentFragment + * node, the children will be inserted rather than the DocumentFragment + * node itself. + * + * @param newNodeThe + * node to insert at the start of the Range + * @exception DOMException + * NO_MODIFICATION_ALLOWED_ERR: Raised if an ancestor + * container of the start of the Range is read-only. <br> + * WRONG_DOCUMENT_ERR: Raised if <code>newNode</code> and + * the container of the start of the Range were not created + * from the same document. <br> + * HIERARCHY_REQUEST_ERR: Raised if the container of the + * start of the Range is of a type that does not allow + * children of the type of <code>newNode</code> or if + * <code>newNode</code> is an ancestor of the container. + * <br> + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + * @exception RangeException + * INVALID_NODE_TYPE_ERR: Raised if <code>newNode</code> + * is an Attr, Entity, Notation, or Document node. + */ + public void insertNode(Node newNode) throws RangeException, DOMException { + // not supported + } + + /** + * Select a node and its contents + * + * @param refNodeThe + * node to select. + * @exception RangeException + * INVALID_NODE_TYPE_ERR: Raised if an ancestor of + * <code>refNode</code> is an Entity, Notation or + * DocumentType node or if <code>refNode</code> is a + * Document, DocumentFragment, Attr, Entity, or Notation + * node. + * @exception DOMException + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public void selectNode(Node refNode) throws RangeException, DOMException { + if (refNode == null) + return; + Node parent = refNode.getParentNode(); + if (parent == null) + return; + int index = ((NodeImpl) refNode).getIndex(); + if (index < 0) + return; + setStart(parent, index); + setEnd(parent, index + 1); + } + + /** + * Select the contents within a node + * + * @param refNodeNode + * to select from + * @exception RangeException + * INVALID_NODE_TYPE_ERR: Raised if <code>refNode</code> + * or an ancestor of <code>refNode</code> is an Entity, + * Notation or DocumentType node. + * @exception DOMException + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public void selectNodeContents(Node refNode) throws RangeException, DOMException { + if (refNode == null) + return; + if (refNode.getNodeType() == Node.TEXT_NODE) { + Text text = (Text) refNode; + setStart(refNode, 0); + setEnd(refNode, text.getLength()); + } else { + NodeList childNodes = refNode.getChildNodes(); + int length = (childNodes != null ? childNodes.getLength() : 0); + setStart(refNode, 0); + setEnd(refNode, length); + } + } + + /** + * Sets the attributes describing the end of a Range. + * + * @param refNodeThe + * <code>refNode</code> value. This parameter must be + * different from <code>null</code>. + * @param offsetThe + * <code>endOffset</code> value. + * @exception RangeException + * INVALID_NODE_TYPE_ERR: Raised if <code>refNode</code> + * or an ancestor of <code>refNode</code> is an Entity, + * Notation, or DocumentType node. + * @exception DOMException + * INDEX_SIZE_ERR: Raised if <code>offset</code> is + * negative or greater than the number of child units in + * <code>refNode</code>. Child units are 16-bit units if + * <code>refNode</code> is a type of CharacterData node + * (e.g., a Text or Comment node) or a + * ProcessingInstruction node. Child units are Nodes in all + * other cases. <br> + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public void setEnd(Node refNode, int offset) throws RangeException, DOMException { + this.endContainer = refNode; + this.endOffset = offset; + } + + /** + * Sets the end of a Range to be after a node + * + * @param refNodeRange + * ends after <code>refNode</code>. + * @exception RangeException + * INVALID_NODE_TYPE_ERR: Raised if the root container of + * <code>refNode</code> is not an Attr, Document or + * DocumentFragment node or if <code>refNode</code> is a + * Document, DocumentFragment, Attr, Entity, or Notation + * node. + * @exception DOMException + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public void setEndAfter(Node refNode) throws RangeException, DOMException { + if (refNode == null) + return; + Node parent = refNode.getParentNode(); + if (parent == null) + return; + int index = ((NodeImpl) refNode).getIndex(); + if (index < 0) + return; + setEnd(parent, index + 1); + } + + /** + * Sets the end position to be before a node. + * + * @param refNodeRange + * ends before <code>refNode</code> + * @exception RangeException + * INVALID_NODE_TYPE_ERR: Raised if the root container of + * <code>refNode</code> is not an Attr, Document, or + * DocumentFragment node or if <code>refNode</code> is a + * Document, DocumentFragment, Attr, Entity, or Notation + * node. + * @exception DOMException + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public void setEndBefore(Node refNode) throws RangeException, DOMException { + if (refNode == null) + return; + Node parent = refNode.getParentNode(); + if (parent == null) + return; + int index = ((NodeImpl) refNode).getIndex(); + if (index < 0) + return; + setEnd(parent, index); + } + + /** + * Sets the attributes describing the start of the Range. + * + * @param refNodeThe + * <code>refNode</code> value. This parameter must be + * different from <code>null</code>. + * @param offsetThe + * <code>startOffset</code> value. + * @exception RangeException + * INVALID_NODE_TYPE_ERR: Raised if <code>refNode</code> + * or an ancestor of <code>refNode</code> is an Entity, + * Notation, or DocumentType node. + * @exception DOMException + * INDEX_SIZE_ERR: Raised if <code>offset</code> is + * negative or greater than the number of child units in + * <code>refNode</code>. Child units are 16-bit units if + * <code>refNode</code> is a type of CharacterData node + * (e.g., a Text or Comment node) or a + * ProcessingInstruction node. Child units are Nodes in all + * other cases. <br> + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public void setStart(Node refNode, int offset) throws RangeException, DOMException { + this.startContainer = refNode; + this.startOffset = offset; + } + + /** + * Sets the start position to be after a node + * + * @param refNodeRange + * starts after <code>refNode</code> + * @exception RangeException + * INVALID_NODE_TYPE_ERR: Raised if the root container of + * <code>refNode</code> is not an Attr, Document, or + * DocumentFragment node or if <code>refNode</code> is a + * Document, DocumentFragment, Attr, Entity, or Notation + * node. + * @exception DOMException + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public void setStartAfter(Node refNode) throws RangeException, DOMException { + if (refNode == null) + return; + Node parent = refNode.getParentNode(); + if (parent == null) + return; + int index = ((NodeImpl) refNode).getIndex(); + if (index < 0) + return; + setStart(parent, index + 1); + } + + /** + * Sets the start position to be before a node + * + * @param refNodeRange + * starts before <code>refNode</code> + * @exception RangeException + * INVALID_NODE_TYPE_ERR: Raised if the root container of + * <code>refNode</code> is not an Attr, Document, or + * DocumentFragment node or if <code>refNode</code> is a + * Document, DocumentFragment, Attr, Entity, or Notation + * node. + * @exception DOMException + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public void setStartBefore(Node refNode) throws RangeException, DOMException { + if (refNode == null) + return; + Node parent = refNode.getParentNode(); + if (parent == null) + return; + int index = ((NodeImpl) refNode).getIndex(); + if (index < 0) + return; + setStart(parent, index); + } + + /** + * Reparents the contents of the Range to the given node and inserts the + * node at the position of the start of the Range. + * + * @param newParentThe + * node to surround the contents with. + * @exception DOMException + * NO_MODIFICATION_ALLOWED_ERR: Raised if an ancestor + * container of either boundary-point of the Range is + * read-only. <br> + * WRONG_DOCUMENT_ERR: Raised if <code> newParent</code> + * and the container of the start of the Range were not + * created from the same document. <br> + * HIERARCHY_REQUEST_ERR: Raised if the container of the + * start of the Range is of a type that does not allow + * children of the type of <code>newParent</code> or if + * <code>newParent</code> is an ancestor of the container + * or if <code>node</code> would end up with a child node + * of a type not allowed by the type of <code>node</code>. + * <br> + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + * @exception RangeException + * BAD_BOUNDARYPOINTS_ERR: Raised if the Range partially + * selects a non-text node. <br> + * INVALID_NODE_TYPE_ERR: Raised if <code> node</code> is + * an Attr, Entity, DocumentType, Notation, Document, or + * DocumentFragment node. + */ + public void surroundContents(Node newParent) throws RangeException, DOMException { + // not supported + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/ReadOnlyController.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/ReadOnlyController.java new file mode 100644 index 0000000000..67aa59c493 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/ReadOnlyController.java @@ -0,0 +1,334 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.document; + + + +import org.eclipse.wst.sse.core.text.IStructuredDocument; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.core.text.ITextRegionList; +import org.eclipse.wst.xml.core.document.XMLElement; +import org.eclipse.wst.xml.core.document.XMLNode; +import org.eclipse.wst.xml.core.document.XMLText; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; +import org.w3c.dom.Node; + + +class ReadOnlyController { + + class Span { + int length; + int offset; + + Span(int offset, int length) { + this.offset = offset; + this.length = length; + } + } + + private static ReadOnlyController fInstance; + + static synchronized ReadOnlyController getInstance() { + if (fInstance == null) { + fInstance = new ReadOnlyController(); + } + return fInstance; + } + + static private void lock(IStructuredDocument doc, int offset, int length, boolean canInsertBefore, boolean canInsertAfter) { + if (doc == null) { + return; + } + doc.makeReadOnly(offset, length); + } + + static private void lock(IStructuredDocumentRegion node, boolean canInsertBefore, boolean canInsertAfter) { + if (node == null) { + return; + } + IStructuredDocument doc = node.getParentDocument(); + if (doc == null) { + return; + } + doc.makeReadOnly(node.getStart(), node.getLength()); + } + + static private void unlock(IStructuredDocumentRegion node) { + if (node == null) { + return; + } + IStructuredDocument doc = node.getParentDocument(); + if (doc == null) { + return; + } + doc.clearReadOnly(node.getStart(), node.getLength()); + } + + private ReadOnlyController() { + super(); + } + + private Span getDataSpan(XMLNode node) { + switch (node.getNodeType()) { + case Node.ELEMENT_NODE : + return getDataSpanForElement((XMLElement) node); + case Node.TEXT_NODE : + return getDataSpanForText((XMLText) node); + default : + return new Span(0, -1); + } + } + + private Span getDataSpanForElement(XMLElement node) { + IStructuredDocumentRegion docRegion = node.getStartStructuredDocumentRegion(); + if (docRegion == null) { + return new Span(0, -1); + } + + ITextRegionList regions = docRegion.getRegions(); + if (regions == null) { + return new Span(0, -1); + } + + String startType; + String endType; + if (node.isCommentTag()) { + startType = XMLRegionContext.XML_COMMENT_OPEN; + endType = XMLRegionContext.XML_COMMENT_CLOSE; + } else { + startType = XMLRegionContext.XML_TAG_NAME; + endType = XMLRegionContext.XML_TAG_CLOSE; + } + + int startOffset = -1; + int endOffset = -1; + ITextRegion prevRegion = null; + ITextRegion region; + for (int i = 0; i < regions.size(); i++) { + region = regions.get(i); + String type = region.getType(); + if (type == startType) { + startOffset = region.getEnd(); + } else if (type == endType && prevRegion != null) { + endOffset = prevRegion.getTextEnd(); + } + prevRegion = region; + } + + if (0 <= startOffset && 0 <= endOffset) { + return new Span(startOffset, endOffset - startOffset); + } else { + return new Span(0, -1); + } + } + + private Span getDataSpanForText(XMLText node) { + IStructuredDocumentRegion docRegion = ((NodeImpl) node).getStructuredDocumentRegion(); + if (docRegion == null) { + return new Span(0, -1); + } + return new Span(0, docRegion.getLength()); + } + + /** + * This method is used from parent's setChildEditable() + * + * case 1:<parent><node attr="value"/> <node2></parent> + * x####################x case 2:<parent><node attr="value"> <child> + * </child> </node> </parent> x###################? ?#######x (? : + * editable if node.isEditable() == true) + */ + void lockBoth(XMLNode node) { + if (node == null) { + return; + } + + IStructuredDocumentRegion flatNode; + boolean canInsert = false; + + // end node (element) + if (node.getNodeType() == Node.ELEMENT_NODE) { + flatNode = node.getEndStructuredDocumentRegion(); + if (flatNode != null) { + canInsert = node.isChildEditable(); + lock(flatNode, canInsert, false); + } + } + // start node + flatNode = node.getStartStructuredDocumentRegion(); + if (flatNode != null) { + lock(flatNode, false, canInsert); + } + } + + void lockData(XMLNode node) { + if (node == null) { + return; + } + + Span span = getDataSpan(node); + if (0 <= span.length) { + lock(node.getModel().getStructuredDocument(), node.getStartOffset() + span.offset, span.length, false, false); + } + } + + /** + * lock itself and all descendants + */ + void lockDeep(XMLNode node) { + if (node == null) { + return; + } + + int offset = node.getStartOffset(); + int length = node.getEndOffset() - offset; + + boolean canInsert = true; + XMLNode parent = (XMLNode) node.getParentNode(); + if (parent != null && !parent.isChildEditable()) { + canInsert = false; + } + lock(node.getStructuredDocument(), offset, length, canInsert, canInsert); + } + + /** + * This method is used from parent's setChildEditable() + * + * case 1:<parent><node attr="value"/> <node2></parent> x######x x##x + * case 2:<parent><node attr="value"> <child></child> </node> </parent> + * x######x x#? ?#######x (? : editable if node.isEditable() == true) + */ + void lockNode(XMLNode node) { + if (node == null) { + return; + } + if (!node.isDataEditable()) { + lockBoth(node); + return; + } + + IStructuredDocumentRegion flatNode; + boolean canInsert = false; + + // end node (element) + if (node.getNodeType() == Node.ELEMENT_NODE) { + flatNode = node.getEndStructuredDocumentRegion(); + if (flatNode != null) { + canInsert = node.isChildEditable(); + lock(flatNode, canInsert, false); + } + } + // start node + flatNode = node.getStartStructuredDocumentRegion(); + if (flatNode != null) { + Span span = getDataSpan(node); + if (0 <= span.length) { + IStructuredDocument structuredDocument = flatNode.getParentDocument(); + int offset, length; + offset = flatNode.getStart(); + length = span.offset; + lock(structuredDocument, offset, length, false, false); + offset = offset + span.offset + span.length; + length = flatNode.getEnd() - offset; + lock(structuredDocument, offset, length, canInsert, false); + } else { + lock(flatNode, false, canInsert); + } + } + } + + private void unlock(IStructuredDocument doc, int offset, int length) { + if (doc == null) { + return; + } + doc.clearReadOnly(offset, length); + } + + void unlockBoth(XMLNode node) { + if (node == null) { + return; + } + + IStructuredDocumentRegion flatNode; + // start node + flatNode = node.getStartStructuredDocumentRegion(); + if (flatNode != null) { + unlock(flatNode); + } + // end node + flatNode = node.getEndStructuredDocumentRegion(); + if (flatNode != null) { + unlock(flatNode); + } + } + + void unlockData(XMLNode node) { + if (node == null) { + return; + } + + Span span = getDataSpan(node); + if (0 <= span.length) { + unlock(node.getModel().getStructuredDocument(), span.offset, span.length); + } + } + + void unlockDeep(XMLNode node) { + if (node == null) { + return; + } + + int offset = node.getStartOffset(); + int length = node.getEndOffset() - offset; + + unlock(node.getStructuredDocument(), offset, length); + } + + void unlockNode(XMLNode node) { + if (node == null) { + return; + } + + IStructuredDocumentRegion flatNode; + // end node + if (node.getNodeType() == Node.ELEMENT_NODE) { + flatNode = node.getEndStructuredDocumentRegion(); + if (flatNode != null) { + unlock(flatNode); + } + } + + // start node + flatNode = node.getStartStructuredDocumentRegion(); + if (flatNode != null) { + if (node.isDataEditable()) { + unlock(flatNode); + } else { + Span span = getDataSpan(node); + if (span.length <= 0) { + unlock(flatNode); + } else { + IStructuredDocument structuredDocument = flatNode.getParentDocument(); + int offset, length; + offset = flatNode.getStart(); + length = span.offset - offset; + unlock(structuredDocument, offset, length); + offset = span.offset + span.length; + length = flatNode.getEnd() - span.offset; + unlock(structuredDocument, offset, length); + } + } + } + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/SourceValidator.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/SourceValidator.java new file mode 100644 index 0000000000..3b3d941c6c --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/SourceValidator.java @@ -0,0 +1,351 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.document; + + + +import org.eclipse.wst.sse.core.internal.nls.ResourceHandler1; +import org.eclipse.wst.xml.core.document.InvalidCharacterException; +import org.eclipse.wst.xml.core.document.JSPTag; +import org.eclipse.wst.xml.core.document.XMLCharEntity; +import org.eclipse.wst.xml.core.document.XMLDocument; +import org.w3c.dom.Attr; +import org.w3c.dom.Node; + + +/** + */ +public class SourceValidator { + + private NodeImpl node = null; + + /** + */ + public SourceValidator(Node node) { + super(); + + if (node != null) { + this.node = (NodeImpl) node; + } + } + + /** + */ + public String convertSource(String source) { + if (source == null) + return null; + if (this.node == null) + return null; // error + + // setup conversion conditions + boolean acceptTag = false; + boolean acceptClose = false; + boolean acceptQuote = false; + boolean acceptAmpersand = false; + boolean acceptEntityRef = true; + boolean acceptJSPEnd = true; + String endTagName = null; + if (this.node.getNodeType() == Node.ATTRIBUTE_NODE) { + XMLDocument document = (XMLDocument) this.node.getOwnerDocument(); + if (document != null && document.isJSPType()) + acceptTag = true; + if (acceptTag) { + Attr attr = (Attr) this.node; + ElementImpl element = (ElementImpl) attr.getOwnerElement(); + if (element != null && element.isJSPTag()) + acceptTag = false; + } + // if the source does not include single quote, + // double quote is valid + acceptQuote = (source.indexOf('\'') < 0); + } else if (this.node.getNodeType() == Node.TEXT_NODE) { + TextImpl text = (TextImpl) this.node; + if (text.isJSPContent()) { + int index = source.indexOf(JSPTag.TAG_CLOSE); + if (index < 0) + return source; + acceptTag = true; + acceptClose = true; + acceptQuote = true; + acceptAmpersand = true; + acceptJSPEnd = false; + } else if (text.isCDATAContent()) { + endTagName = text.getParentNode().getNodeName(); + if (endTagName == null) + return null; // error + acceptTag = true; + acceptClose = true; + acceptQuote = true; + acceptAmpersand = true; + } + } else { + XMLDocument document = null; + if (this.node.getNodeType() == Node.DOCUMENT_NODE) { + document = (XMLDocument) this.node; + } else { + document = (XMLDocument) this.node.getOwnerDocument(); + } + if (document != null && document.isJSPType()) + acceptTag = true; + } + + StringBuffer buffer = null; + int copiedLength = 0; + int length = source.length(); + for (int i = 0; i < length; i++) { + String ref = null; + char c = source.charAt(i); + switch (c) { + case '<' : + if (acceptTag) { + if (endTagName != null) { + if (!matchEndTag(source, i + 1, endTagName)) + continue; + } else { + int skip = skipTag(source, i + 1); + if (skip >= 0) { + i += skip; + continue; + } + } + // invalid JSP tag + } + ref = XMLCharEntity.LT_REF; + break; + case '>' : + if (acceptClose) + continue; + ref = XMLCharEntity.GT_REF; + break; + case '&' : + if (acceptAmpersand) + continue; + if (acceptEntityRef) { + int skip = skipEntityRef(source, i + 1); + if (skip >= 0) { + i += skip; + continue; + } + } + ref = XMLCharEntity.AMP_REF; + break; + case '"' : + if (acceptQuote) + continue; + ref = XMLCharEntity.QUOT_REF; + break; + case '%' : + if (acceptJSPEnd) + continue; + if (source.charAt(i + 1) != '>') + continue; + i++; + ref = XMLCharEntity.GT_REF; + break; + default : + continue; + } + + if (ref != null) { + if (buffer == null) { + buffer = new StringBuffer(length + 8); + } + if (i > copiedLength) { + buffer.append(source.substring(copiedLength, i)); + } + buffer.append(ref); + copiedLength = i + 1; // skip this character + } + } + + if (buffer != null) { + if (copiedLength < length) { + buffer.append(source.substring(copiedLength, length)); + } + return buffer.toString(); + } + return source; + } + + /** + */ + private final boolean matchEndTag(String source, int offset, String endTagName) { + if (source == null || endTagName == null) + return false; + int length = source.length(); + if (offset < 0 || offset >= length) + return false; + if (source.charAt(offset) != '/') + return false; + offset++; + int end = offset + endTagName.length(); + if (end > length) + return false; + return endTagName.equalsIgnoreCase(source.substring(offset, end)); + } + + /** + */ + private final int skipEntityRef(String source, int offset) { + if (source == null) + return -1; + if (offset < 0 || offset >= source.length()) + return -1; + DocumentImpl document = (DocumentImpl) this.node.getOwnerDocument(); + if (document == null) + return -1; // error + + int end = source.indexOf(';', offset); + if (end < 0 || end == offset) + return -1; + String name = source.substring(offset, end); + if (name == null || document.getCharValue(name) == null) + return -1; + return (end + 1 - offset); + } + + /** + */ + private final int skipTag(String source, int offset) { + if (source == null) + return -1; + if (offset < 0 || offset >= source.length()) + return -1; + + int end = offset; + if (source.charAt(offset) == '%') { + // JSP tag + int found = source.indexOf(JSPTag.TAG_CLOSE, offset + 1); + if (found < 0) + return -1; // invalid JSP tag + end = found + 2; + } else { + // normal tag + int found = source.indexOf('>', offset); + if (found < 0) + return -1; // invalid tag + end = found + 1; + } + return (end - offset); + } + + /** + */ + public boolean validateSource(String source) throws InvalidCharacterException { + if (source == null) + return true; + if (this.node == null) + return false; // error + String message = null; + + // setup validation conditions + boolean acceptTag = false; + boolean acceptClose = false; + boolean acceptQuote = true; + boolean acceptEntityRef = true; + String endTagName = null; + if (this.node.getNodeType() == Node.ATTRIBUTE_NODE) { + XMLDocument document = (XMLDocument) this.node.getOwnerDocument(); + if (document != null && document.isJSPType()) + acceptTag = true; + if (acceptTag) { + Attr attr = (Attr) this.node; + ElementImpl element = (ElementImpl) attr.getOwnerElement(); + if (element != null && element.isJSPTag()) + acceptTag = false; + } + // if the source does not include single quote, + // double quote is valid + acceptQuote = (source.indexOf('\'') < 0); + } else if (this.node.getNodeType() == Node.TEXT_NODE) { + TextImpl text = (TextImpl) this.node; + if (text.isJSPContent()) { + int index = source.indexOf(JSPTag.TAG_CLOSE); + if (index < 0) + return true; + message = ResourceHandler1.getString("Invalid_character_('>')_fo_ERROR_"); //$NON-NLS-1$ = "Invalid character ('>') found" + throw new InvalidCharacterException(message, '>', index + 1); + } else if (text.isCDATAContent()) { + endTagName = text.getParentNode().getNodeName(); + if (endTagName == null) + return false; // error + acceptTag = true; + acceptClose = true; + } + } else { + XMLDocument document = null; + if (this.node.getNodeType() == Node.DOCUMENT_NODE) { + document = (XMLDocument) this.node; + } else { + document = (XMLDocument) this.node.getOwnerDocument(); + } + if (document != null && document.isJSPType()) + acceptTag = true; + } + + char c = 0; + int length = source.length(); + for (int i = 0; i < length; i++) { + c = source.charAt(i); + switch (c) { + case '<' : + if (acceptTag) { + if (endTagName != null) { + if (!matchEndTag(source, i + 1, endTagName)) + continue; + } else { + int skip = skipTag(source, i + 1); + if (skip >= 0) { + i += skip; + continue; + } + } + // invalid tag + } + message = ResourceHandler1.getString("Invalid_character_('<')_fo_ERROR_"); //$NON-NLS-1$ = "Invalid character ('<') found" + break; + case '>' : + if (acceptClose) + continue; + message = ResourceHandler1.getString("Invalid_character_('>')_fo_ERROR_"); //$NON-NLS-1$ = "Invalid character ('>') found" + break; + case '&' : + if (acceptEntityRef) { + if (endTagName != null) + continue; + int skip = skipEntityRef(source, i + 1); + if (skip >= 0) { + i += skip; + continue; + } + // invalid entity reference + } + message = ResourceHandler1.getString("Invalid_character_('&')_fo_ERROR_"); //$NON-NLS-1$ = "Invalid character ('&') found" + break; + case '"' : + if (acceptQuote) + continue; + message = ResourceHandler1.getString("Invalid_character_('__')_f_EXC_"); //$NON-NLS-1$ = "Invalid character ('\"') found" + break; + default : + continue; + } + + if (message != null) { + throw new InvalidCharacterException(message, c, i); + } + } + + return true; + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/StructuredDocumentRegionChecker.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/StructuredDocumentRegionChecker.java new file mode 100644 index 0000000000..47a50fd2c8 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/StructuredDocumentRegionChecker.java @@ -0,0 +1,143 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.document; + + + +import java.io.IOException; +import java.io.Writer; + +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.xml.core.document.XMLModel; +import org.w3c.dom.Node; + + +/** + * This class is only for debug purpose. + */ +public class StructuredDocumentRegionChecker { + String EOL = System.getProperty("line.separator"); //$NON-NLS-1$ + + private int offset = 0; + Writer testWriter = null; + + /** + */ + public StructuredDocumentRegionChecker() { + super(); + } + + public StructuredDocumentRegionChecker(Writer writer) { + super(); + testWriter = writer; + } + + /** + */ + private void checkChildNodes(Node node) { + for (Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) { + checkNode(child); + } + } + + /** + */ + public void checkModel(XMLModel model) { + checkChildNodes(model.getDocument()); + } + + /** + */ + private void checkNode(Node node) { + checkStructuredDocumentRegion(((NodeImpl) node).getStructuredDocumentRegion()); + if (node.getNodeType() == Node.ELEMENT_NODE) { + checkChildNodes(node); + checkStructuredDocumentRegion(((ElementImpl) node).getEndStructuredDocumentRegion()); + } + } + + /** + */ + private void checkStructuredDocumentRegion(IStructuredDocumentRegion flatNode) { + if (flatNode == null) + return; + + if (flatNode instanceof StructuredDocumentRegionContainer) { + StructuredDocumentRegionContainer container = (StructuredDocumentRegionContainer) flatNode; + int n = container.getStructuredDocumentRegionCount(); + for (int i = 0; i < n; i++) { + IStructuredDocumentRegion c = container.getStructuredDocumentRegion(i); + if (c == null) { + reportError("null"); //$NON-NLS-1$ + continue; + } + checkStructuredDocumentRegion(c); + } + return; + } + + int start = flatNode.getStart(); + if (start < this.offset) + reportError("overwrap"); //$NON-NLS-1$ + if (start > this.offset) + reportError("gap"); //$NON-NLS-1$ + int end = flatNode.getEnd(); + this.offset = end; + + if (flatNode instanceof StructuredDocumentRegionProxy) { + StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) flatNode; + IStructuredDocumentRegion p = proxy.getStructuredDocumentRegion(); + if (p == null) { + reportError("null"); //$NON-NLS-1$ + return; + } + int s = p.getStart(); + int e = p.getEnd(); + if (s > start || e < end) + reportError("out"); //$NON-NLS-1$ + if (s == start && e == end) + reportWarning("vain"); //$NON-NLS-1$ + } + } + + /** + */ + private void reportError(String message) { + String msg = "StructuredDocumentRegionChecker : error : " + message; //$NON-NLS-1$ + if (testWriter != null) { + try { + testWriter.write(msg + EOL); + } catch (IOException e) { + e.printStackTrace(); + } + } else { + System.out.println(msg); + } + throw new StructuredDocumentRegionManagementException(); + } + + /** + */ + private void reportWarning(String message) { + String msg = "StructuredDocumentRegionChecker : warning : " + message; //$NON-NLS-1$ + if (testWriter != null) { + try { + testWriter.write(msg + EOL); + } catch (IOException e) { + e.printStackTrace(); + } + } else { + System.out.println(msg); + } + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/StructuredDocumentRegionContainer.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/StructuredDocumentRegionContainer.java new file mode 100644 index 0000000000..166d8c67b1 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/StructuredDocumentRegionContainer.java @@ -0,0 +1,605 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.document; + + + +import java.util.Vector; + +import org.eclipse.wst.sse.core.events.StructuredDocumentEvent; +import org.eclipse.wst.sse.core.text.IStructuredDocument; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.core.text.ITextRegionContainer; +import org.eclipse.wst.sse.core.text.ITextRegionList; + + +class StructuredDocumentRegionContainer implements IStructuredDocumentRegion { + + private Vector flatNodes = new Vector(2); + + /** + */ + StructuredDocumentRegionContainer() { + super(); + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#addRegion(com.ibm.sed.structured.text.ITextRegion) + */ + public void addRegion(ITextRegion aRegion) { + // XXX Auto-generated method stub + + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegion#adjust(int) + */ + public void adjust(int i) { + // XXX Auto-generated method stub + + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegion#adjustLengthWith(int) + */ + public void adjustLengthWith(int i) { + // XXX Auto-generated method stub + + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegion#adjustStart(int) + */ + public void adjustStart(int i) { + // XXX Auto-generated method stub + + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegion#adjustTextLength(int) + */ + public void adjustTextLength(int i) { + // XXX Auto-generated method stub + + } + + /** + */ + void appendStructuredDocumentRegion(IStructuredDocumentRegion flatNode) { + if (flatNode == null) + return; + if (flatNode instanceof StructuredDocumentRegionContainer) { + StructuredDocumentRegionContainer container = (StructuredDocumentRegionContainer) flatNode; + if (container.getStructuredDocumentRegionCount() > 0) { + this.flatNodes.addAll(container.flatNodes); + } + } else { + this.flatNodes.addElement(flatNode); + } + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegionCollection#containsOffset(int) + */ + public boolean containsOffset(int i) { + // XXX Auto-generated method stub + return false; + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegionCollection#containsOffset(com.ibm.sed.structured.text.ITextRegion, + * int) + */ + public boolean containsOffset(ITextRegion region, int i) { + // XXX Auto-generated method stub + return false; + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegion#equatePositions(com.ibm.sed.structured.text.ITextRegion) + */ + public void equatePositions(ITextRegion region) { + // XXX Auto-generated method stub + + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegionCollection#getDeepestRegionAtCharacterOffset(int) + */ + public ITextRegion getDeepestRegionAtCharacterOffset(int offset) { + // XXX Auto-generated method stub + return null; + } + + /** + */ + public int getEnd() { + IStructuredDocumentRegion last = getLastStructuredDocumentRegion(); + if (last == null) + return 0; + return last.getEnd(); + } + + /** + */ + public int getEndOffset() { + return getEnd(); + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegionCollection#getEndOffset(com.ibm.sed.structured.text.ITextRegion) + */ + public int getEndOffset(ITextRegion containedRegion) { + // XXX Auto-generated method stub + return 0; + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegionCollection#getFirstRegion() + */ + public ITextRegion getFirstRegion() { + // XXX Auto-generated method stub + return null; + } + + /** + */ + IStructuredDocumentRegion getFirstStructuredDocumentRegion() { + if (this.flatNodes.isEmpty()) + return null; + return (IStructuredDocumentRegion) this.flatNodes.elementAt(0); + } + + /** + */ + public String getFullText() { + return getText(); + } + + /** + */ + public String getFullText(ITextRegion aRegion) { + // not supported + return null; + } + + /** + */ + public String getFullText(String context) { + // not supported + return null; + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegionCollection#getLastRegion() + */ + public ITextRegion getLastRegion() { + // XXX Auto-generated method stub + return null; + } + + /** + */ + IStructuredDocumentRegion getLastStructuredDocumentRegion() { + int size = this.flatNodes.size(); + if (size == 0) + return null; + return (IStructuredDocumentRegion) this.flatNodes.elementAt(size - 1); + } + + /** + */ + public int getLength() { + return (getEnd() - getStart()); + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#getNext() + */ + public IStructuredDocumentRegion getNext() { + // XXX Auto-generated method stub + return null; + } + + /** + */ + public int getNumberOfRegions() { + // not supported + return 0; + } + + /** + */ + public ITextRegionContainer getParent() { + return null; + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#getParentDocument() + */ + public IStructuredDocument getParentDocument() { + // XXX Auto-generated method stub + return null; + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#getPrevious() + */ + public IStructuredDocumentRegion getPrevious() { + // XXX Auto-generated method stub + return null; + } + + /** + */ + public ITextRegion getRegionAtCharacterOffset(int offset) { + // not supported + return null; + } + + /** + */ + public ITextRegionList getRegions() { + // not supported + return null; + } + + /** + */ + public int getStart() { + IStructuredDocumentRegion first = getFirstStructuredDocumentRegion(); + if (first == null) + return 0; + return first.getStart(); + } + + /** + */ + public int getStartOffset() { + return getStart(); + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegionCollection#getStartOffset(com.ibm.sed.structured.text.ITextRegion) + */ + public int getStartOffset(ITextRegion containedRegion) { + // XXX Auto-generated method stub + return 0; + } + + /** + */ + public IStructuredDocument getStructuredDocument() { + IStructuredDocumentRegion first = getFirstStructuredDocumentRegion(); + if (first == null) + return null; + return first.getParentDocument(); + } + + /** + */ + IStructuredDocumentRegion getStructuredDocumentRegion(int index) { + if (index < 0 || index >= this.flatNodes.size()) + return null; + return (IStructuredDocumentRegion) this.flatNodes.elementAt(index); + } + + /** + */ + int getStructuredDocumentRegionCount() { + return this.flatNodes.size(); + } + + /** + */ + public String getText() { + int size = this.flatNodes.size(); + if (size == 0) + return new String(); + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < size; i++) { + IStructuredDocumentRegion flatNode = (IStructuredDocumentRegion) this.flatNodes.elementAt(i); + if (flatNode == null) + continue; + buffer.append(flatNode.getText()); + } + return buffer.toString(); + } + + /** + */ + public String getText(ITextRegion aRegion) { + // not supported + return null; + } + + /** + */ + public String getText(String context) { + // not supported + return null; + } + + /** + */ + public int getTextEnd() { + return getEnd(); + } + + /** + */ + public int getTextEndOffset() { + return getTextEnd(); + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegionCollection#getTextEndOffset(com.ibm.sed.structured.text.ITextRegion) + */ + public int getTextEndOffset(ITextRegion containedRegion) { + // XXX Auto-generated method stub + return 0; + } + + /** + * The text length is equal to length if there is no white space at the + * end of a region. Otherwise it is smaller than length. + */ + public int getTextLength() { + return (getTextEnd() - getStart()); + } + + /** + */ + public String getType() { + return "StructuredDocumentRegionContainer";//$NON-NLS-1$ + } + + /** + */ + void insertStructuredDocumentRegion(IStructuredDocumentRegion flatNode, int index) { + if (flatNode == null) + return; + if (index < 0) + return; + int size = this.flatNodes.size(); + if (index > size) + return; + if (index == size) { + appendStructuredDocumentRegion(flatNode); + return; + } + this.flatNodes.insertElementAt(flatNode, index); + } + + public boolean isDeleted() { + // I'll assume never really needed here + return false; + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#isEnded() + */ + public boolean isEnded() { + // XXX Auto-generated method stub + return false; + } + + /** + */ + IStructuredDocumentRegion removeStructuredDocumentRegion(int index) { + if (index < 0 || index >= this.flatNodes.size()) + return null; + IStructuredDocumentRegion flatNode = (IStructuredDocumentRegion) this.flatNodes.elementAt(index); + this.flatNodes.removeElementAt(index); + return flatNode; + } + + /** + */ + IStructuredDocumentRegion removeStructuredDocumentRegion(IStructuredDocumentRegion oldStructuredDocumentRegion) { + if (oldStructuredDocumentRegion == null) + return null; + int size = this.flatNodes.size(); + for (int i = 0; i < size; i++) { + IStructuredDocumentRegion flatNode = (IStructuredDocumentRegion) this.flatNodes.elementAt(i); + if (flatNode == oldStructuredDocumentRegion) { + this.flatNodes.removeElementAt(i); + return flatNode; + } + } + return null; // not found + } + + /** + */ + IStructuredDocumentRegion replaceStructuredDocumentRegion(IStructuredDocumentRegion flatNode, int index) { + if (flatNode == null) + return removeStructuredDocumentRegion(index); + if (index < 0 || index >= this.flatNodes.size()) + return null; + IStructuredDocumentRegion oldStructuredDocumentRegion = (IStructuredDocumentRegion) this.flatNodes.elementAt(index); + this.flatNodes.setElementAt(flatNode, index); + return oldStructuredDocumentRegion; + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#sameAs(com.ibm.sed.structured.text.IStructuredDocumentRegion, + * int) + */ + public boolean sameAs(IStructuredDocumentRegion region, int shift) { + // XXX Auto-generated method stub + return false; + } + + /** + */ + public boolean sameAs(ITextRegion region, int shift) { + // not support + return false; + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#sameAs(com.ibm.sed.structured.text.ITextRegion, + * com.ibm.sed.structured.text.IStructuredDocumentRegion, + * com.ibm.sed.structured.text.ITextRegion, int) + */ + public boolean sameAs(ITextRegion oldRegion, IStructuredDocumentRegion documentRegion, ITextRegion newRegion, int shift) { + // XXX Auto-generated method stub + return false; + } + + public void setDeleted(boolean deleted) { + // I'll assume never really needed here + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#setEnded(boolean) + */ + public void setEnded(boolean hasEnd) { + // XXX Auto-generated method stub + + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#setLength(int) + */ + public void setLength(int newLength) { + // XXX Auto-generated method stub + + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#setNext(com.ibm.sed.structured.text.IStructuredDocumentRegion) + */ + public void setNext(IStructuredDocumentRegion newNext) { + // XXX Auto-generated method stub + + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#setParentDocument(com.ibm.sed.structured.text.IStructuredDocument) + */ + public void setParentDocument(IStructuredDocument document) { + // XXX Auto-generated method stub + + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#setPrevious(com.ibm.sed.structured.text.IStructuredDocumentRegion) + */ + public void setPrevious(IStructuredDocumentRegion newPrevious) { + // XXX Auto-generated method stub + + } + + /** + */ + public void setRegions(ITextRegionList embeddedRegions) { + // not supported + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#setStart(int) + */ + public void setStart(int newStart) { + // XXX Auto-generated method stub + + } + + /** + * toString method + * + * @return java.lang.String + */ + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append('{'); + int count = getStructuredDocumentRegionCount(); + for (int i = 0; i < count; i++) { + if (i != 0) + buffer.append(','); + IStructuredDocumentRegion flatNode = getStructuredDocumentRegion(i); + if (flatNode == null) + buffer.append("null");//$NON-NLS-1$ + else + buffer.append(flatNode.toString()); + } + buffer.append('}'); + return buffer.toString(); + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegion#updateModel(java.lang.Object, + * com.ibm.sed.structured.text.IStructuredDocumentRegion, + * java.lang.String, int, int) + */ + public StructuredDocumentEvent updateModel(Object requester, IStructuredDocumentRegion flatnode, String changes, int start, int end) { + // XXX Auto-generated method stub + return null; + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/StructuredDocumentRegionManagementException.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/StructuredDocumentRegionManagementException.java new file mode 100644 index 0000000000..0057dd537f --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/StructuredDocumentRegionManagementException.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.document; + +import org.eclipse.wst.sse.core.exceptions.SourceEditingRuntimeException; + + + +/** + */ +public class StructuredDocumentRegionManagementException extends SourceEditingRuntimeException { + + /** + * StructuredDocumentRegionManagementException constructor + */ + public StructuredDocumentRegionManagementException() { + super("IStructuredDocumentRegion management failed.");//$NON-NLS-1$ + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/StructuredDocumentRegionProxy.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/StructuredDocumentRegionProxy.java new file mode 100644 index 0000000000..1503845032 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/StructuredDocumentRegionProxy.java @@ -0,0 +1,548 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.document; + + + +import org.eclipse.wst.sse.core.events.StructuredDocumentEvent; +import org.eclipse.wst.sse.core.text.IStructuredDocument; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.core.text.ITextRegionContainer; +import org.eclipse.wst.sse.core.text.ITextRegionList; + + +class StructuredDocumentRegionProxy implements IStructuredDocumentRegion { + private IStructuredDocumentRegion flatNode = null; + private int length = 0; + + private int offset = 0; + + /** + */ + StructuredDocumentRegionProxy() { + super(); + } + + /** + */ + StructuredDocumentRegionProxy(int offset, int length) { + super(); + + this.offset = offset; + this.length = length; + } + + /** + */ + StructuredDocumentRegionProxy(int offset, int length, IStructuredDocumentRegion flatNode) { + super(); + + this.offset = offset; + this.length = length; + this.flatNode = flatNode; + if (this.flatNode != null) + this.offset -= this.flatNode.getStart(); + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#addRegion(com.ibm.sed.structured.text.ITextRegion) + */ + public void addRegion(ITextRegion aRegion) { + // XXX Auto-generated method stub + + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegion#adjust(int) + */ + public void adjust(int i) { + // XXX Auto-generated method stub + + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegion#adjustLengthWith(int) + */ + public void adjustLengthWith(int i) { + // XXX Auto-generated method stub + + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegion#adjustStart(int) + */ + public void adjustStart(int i) { + // XXX Auto-generated method stub + + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegion#adjustTextLength(int) + */ + public void adjustTextLength(int i) { + // XXX Auto-generated method stub + + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegionCollection#containsOffset(int) + */ + public boolean containsOffset(int i) { + // XXX Auto-generated method stub + return false; + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegionCollection#containsOffset(com.ibm.sed.structured.text.ITextRegion, + * int) + */ + public boolean containsOffset(ITextRegion region, int i) { + // XXX Auto-generated method stub + return false; + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegion#equatePositions(com.ibm.sed.structured.text.ITextRegion) + */ + public void equatePositions(ITextRegion region) { + // XXX Auto-generated method stub + + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegionCollection#getDeepestRegionAtCharacterOffset(int) + */ + public ITextRegion getDeepestRegionAtCharacterOffset(int offset) { + // XXX Auto-generated method stub + return null; + } + + /** + */ + public int getEnd() { + int flatNodeOffset = 0; + if (this.flatNode != null) + flatNodeOffset = this.flatNode.getStart(); + return flatNodeOffset + this.offset + this.length; + } + + /** + */ + public int getEndOffset() { + return getEnd(); + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegionCollection#getEndOffset(com.ibm.sed.structured.text.ITextRegion) + */ + public int getEndOffset(ITextRegion containedRegion) { + // XXX Auto-generated method stub + return 0; + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegionCollection#getFirstRegion() + */ + public ITextRegion getFirstRegion() { + // XXX Auto-generated method stub + return null; + } + + /** + */ + public String getFullText() { + return getText(); + } + + /** + */ + public String getFullText(ITextRegion aRegion) { + // not supported + return null; + } + + /** + */ + public String getFullText(String context) { + // not supported + return null; + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegionCollection#getLastRegion() + */ + public ITextRegion getLastRegion() { + // XXX Auto-generated method stub + return null; + } + + /** + */ + public int getLength() { + return this.length; + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#getNext() + */ + public IStructuredDocumentRegion getNext() { + // XXX Auto-generated method stub + return null; + } + + /** + */ + public int getNumberOfRegions() { + // not supported + return 0; + } + + /** + */ + int getOffset() { + int flatNodeOffset = 0; + if (this.flatNode != null) + flatNodeOffset = this.flatNode.getStart(); + return flatNodeOffset + this.offset; + } + + /** + */ + public ITextRegionContainer getParent() { + return null; + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#getParentDocument() + */ + public IStructuredDocument getParentDocument() { + // XXX Auto-generated method stub + return null; + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#getPrevious() + */ + public IStructuredDocumentRegion getPrevious() { + // XXX Auto-generated method stub + return null; + } + + /** + */ + public ITextRegion getRegionAtCharacterOffset(int offset) { + // not supported + return null; + } + + /** + */ + public ITextRegionList getRegions() { + // not supported + return null; + } + + /** + */ + public int getStart() { + int flatNodeOffset = 0; + if (this.flatNode != null) + flatNodeOffset = this.flatNode.getStart(); + return flatNodeOffset + this.offset; + } + + /** + */ + public int getStartOffset() { + return getStart(); + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegionCollection#getStartOffset(com.ibm.sed.structured.text.ITextRegion) + */ + public int getStartOffset(ITextRegion containedRegion) { + // XXX Auto-generated method stub + return 0; + } + + /** + */ + public IStructuredDocument getStructuredDocument() { + // not supported + return null; + } + + /** + */ + IStructuredDocumentRegion getStructuredDocumentRegion() { + return this.flatNode; + } + + /** + */ + public String getText() { + if (this.flatNode == null) + return new String(); + String text = this.flatNode.getText(); + if (text == null) + return new String(); + int end = this.offset + this.length; + return text.substring(this.offset, end); + } + + /** + */ + public String getText(ITextRegion aRegion) { + // not supported + return null; + } + + /** + */ + public String getText(String context) { + // not supported + return null; + } + + /** + */ + public int getTextEnd() { + return getEnd(); + } + + /** + */ + public int getTextEndOffset() { + return getTextEnd(); + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegionCollection#getTextEndOffset(com.ibm.sed.structured.text.ITextRegion) + */ + public int getTextEndOffset(ITextRegion containedRegion) { + // XXX Auto-generated method stub + return 0; + } + + /** + * The text length is equal to length if there is no white space at the + * end of a region. Otherwise it is smaller than length. + */ + public int getTextLength() { + return getLength(); + } + + /** + */ + public String getType() { + return "StructuredDocumentRegionProxy";//$NON-NLS-1$ + } + + public boolean isDeleted() { + // I'll assume never really needed here + return false; + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#isEnded() + */ + public boolean isEnded() { + // XXX Auto-generated method stub + return false; + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#sameAs(com.ibm.sed.structured.text.IStructuredDocumentRegion, + * int) + */ + public boolean sameAs(IStructuredDocumentRegion region, int shift) { + // XXX Auto-generated method stub + return false; + } + + /** + */ + public boolean sameAs(ITextRegion region, int shift) { + // not supported + return false; + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#sameAs(com.ibm.sed.structured.text.ITextRegion, + * com.ibm.sed.structured.text.IStructuredDocumentRegion, + * com.ibm.sed.structured.text.ITextRegion, int) + */ + public boolean sameAs(ITextRegion oldRegion, IStructuredDocumentRegion documentRegion, ITextRegion newRegion, int shift) { + // XXX Auto-generated method stub + return false; + } + + public void setDeleted(boolean deleted) { + // I'll assume never really needed here + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#setEnded(boolean) + */ + public void setEnded(boolean hasEnd) { + // XXX Auto-generated method stub + + } + + /** + * had to make public, due to API transition. + */ + public void setLength(int length) { + this.length = length; + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#setNext(com.ibm.sed.structured.text.IStructuredDocumentRegion) + */ + public void setNext(IStructuredDocumentRegion newNext) { + // XXX Auto-generated method stub + + } + + /** + */ + void setOffset(int offset) { + this.offset = offset; + if (this.flatNode != null) + this.offset -= this.flatNode.getStart(); + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#setParentDocument(com.ibm.sed.structured.text.IStructuredDocument) + */ + public void setParentDocument(IStructuredDocument document) { + // XXX Auto-generated method stub + + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#setPrevious(com.ibm.sed.structured.text.IStructuredDocumentRegion) + */ + public void setPrevious(IStructuredDocumentRegion newPrevious) { + // XXX Auto-generated method stub + + } + + /** + */ + public void setRegions(ITextRegionList embeddedRegions) { + // not supported + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.IStructuredDocumentRegion#setStart(int) + */ + public void setStart(int newStart) { + // XXX Auto-generated method stub + + } + + /** + */ + void setStructuredDocumentRegion(IStructuredDocumentRegion flatNode) { + if (this.flatNode != null) + this.offset += this.flatNode.getStart(); + this.flatNode = flatNode; + if (this.flatNode != null) + this.offset -= flatNode.getStart(); + } + + /** + * toString method + * + * @return java.lang.String + */ + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append('['); + buffer.append(getStart()); + buffer.append(','); + buffer.append(getEnd()); + buffer.append(']'); + buffer.append('('); + if (this.flatNode != null) + buffer.append(this.flatNode.toString()); + else + buffer.append("null");//$NON-NLS-1$ + buffer.append(')'); + return buffer.toString(); + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegion#updateModel(java.lang.Object, + * com.ibm.sed.structured.text.IStructuredDocumentRegion, + * java.lang.String, int, int) + */ + public StructuredDocumentEvent updateModel(Object requester, IStructuredDocumentRegion flatnode, String changes, int start, int end) { + // XXX Auto-generated method stub + return null; + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/StructuredDocumentRegionUtil.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/StructuredDocumentRegionUtil.java new file mode 100644 index 0000000000..82c848d940 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/StructuredDocumentRegionUtil.java @@ -0,0 +1,167 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.document; + + + +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.core.text.ITextRegionList; +import org.eclipse.wst.xml.core.jsp.model.parser.temp.XMLJSPRegionContexts; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; + + +/** + * Provides convenient functions to handle IStructuredDocumentRegion and + * ITextRegion. + */ +class StructuredDocumentRegionUtil implements XMLJSPRegionContexts { + + /** + * Extracts contents enclosed with quotes. Quotes may be double or single. + */ + static String getAttrValue(IStructuredDocumentRegion flatNode, ITextRegion region) { + if (region == null) + return null; + if (flatNode == null) + return null; + String value = flatNode.getText(region); + if (value == null) + return null; + int length = value.length(); + if (length == 0) + return value; + char firstChar = value.charAt(0); + if (firstChar == '"' || firstChar == '\'') { + if (length == 1) + return null; + if (value.charAt(length - 1) == firstChar) + length--; + return value.substring(1, length); + } + return value; + } + + /** + * Extracts the name without heading '&' and tailing ';'. + */ + static String getEntityRefName(IStructuredDocumentRegion flatNode, ITextRegion region) { + if (region == null) + return null; + String ref = flatNode.getText(region); + int length = ref.length(); + if (length == 0) + return ref; + int offset = 0; + if (ref.charAt(0) == '&') + offset = 1; + if (ref.charAt(length - 1) == ';') + length--; + if (offset >= length) + return null; + return ref.substring(offset, length); + } + + /** + * Returns the first region. + */ + static ITextRegion getFirstRegion(IStructuredDocumentRegion flatNode) { + if (flatNode == null) + return null; + ITextRegionList regions = flatNode.getRegions(); + if (regions == null || regions.size() == 0) + return null; + return regions.get(0); + } + + /** + * Returns the type of the first region. + */ + static String getFirstRegionType(IStructuredDocumentRegion flatNode) { + if (flatNode == null) + return XMLRegionContext.UNDEFINED; + ITextRegionList regions = flatNode.getRegions(); + if (regions == null || regions.size() == 0) + return XMLRegionContext.UNDEFINED; + ITextRegion region = regions.get(0); + return region.getType(); + } + + /** + */ + static IStructuredDocumentRegion getFirstStructuredDocumentRegion(IStructuredDocumentRegion flatNode) { + if (flatNode == null) + return null; + if (flatNode instanceof StructuredDocumentRegionContainer) { + flatNode = ((StructuredDocumentRegionContainer) flatNode).getFirstStructuredDocumentRegion(); + } + if (flatNode instanceof StructuredDocumentRegionProxy) { + flatNode = ((StructuredDocumentRegionProxy) flatNode).getStructuredDocumentRegion(); + } + return flatNode; + } + + /** + * Returns the last region. + */ + static ITextRegion getLastRegion(IStructuredDocumentRegion flatNode) { + if (flatNode == null) + return null; + ITextRegionList regions = flatNode.getRegions(); + if (regions == null || regions.size() == 0) + return null; + return regions.get(regions.size() - 1); + } + + /** + * Returns the type of the first region. + */ + static String getLastRegionType(IStructuredDocumentRegion flatNode) { + if (flatNode == null) + return XMLRegionContext.UNDEFINED; + ITextRegionList regions = flatNode.getRegions(); + if (regions == null || regions.size() == 0) + return XMLRegionContext.UNDEFINED; + ITextRegion region = regions.get(regions.size() - 1); + return region.getType(); + } + + /** + */ + static IStructuredDocumentRegion getLastStructuredDocumentRegion(IStructuredDocumentRegion flatNode) { + if (flatNode == null) + return null; + if (flatNode instanceof StructuredDocumentRegionContainer) { + flatNode = ((StructuredDocumentRegionContainer) flatNode).getLastStructuredDocumentRegion(); + } + if (flatNode instanceof StructuredDocumentRegionProxy) { + flatNode = ((StructuredDocumentRegionProxy) flatNode).getStructuredDocumentRegion(); + } + return flatNode; + } + + /** + */ + static IStructuredDocumentRegion getStructuredDocumentRegion(IStructuredDocumentRegion flatNode) { + if (flatNode == null) + return null; + if (flatNode instanceof StructuredDocumentRegionProxy) { + flatNode = ((StructuredDocumentRegionProxy) flatNode).getStructuredDocumentRegion(); + } + return flatNode; + } + + StructuredDocumentRegionUtil() { + super(); + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/TextImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/TextImpl.java new file mode 100644 index 0000000000..826fe54b3b --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/TextImpl.java @@ -0,0 +1,1107 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.document; + + + +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.xml.core.document.InvalidCharacterException; +import org.eclipse.wst.xml.core.document.XMLGenerator; +import org.eclipse.wst.xml.core.document.XMLModel; +import org.eclipse.wst.xml.core.document.XMLText; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; +import org.w3c.dom.DOMException; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.Text; + + +/** + * TextImpl class + */ +public class TextImpl extends CharacterDataImpl implements XMLText { + + /** + */ + private class StringPair { + private String fFirst = null; + private String fSecond = null; + + StringPair(String first, String second) { + this.fFirst = first; + this.fSecond = second; + } + + String getFirst() { + return this.fFirst; + } + + String getSecond() { + return this.fSecond; + } + } + + private String fSource = null; + + /** + * TextImpl constructor + */ + protected TextImpl() { + super(); + } + + /** + * TextImpl constructor + * + * @param that + * TextImpl + */ + protected TextImpl(TextImpl that) { + super(that); + + if (that != null) { + this.fSource = that.getSource(); + } + } + + /** + * appendData method + * + * @param arg + * java.lang.String + */ + public void appendData(String arg) throws DOMException { + if (arg == null || arg.length() == 0) + return; + + if (!isDataEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + + String newSource = getSource(arg); + if (newSource == null) + return; + String source = getSource(); + if (source != null) + setTextSource(source + newSource); + else + setTextSource(newSource); + } + + /** + */ + IStructuredDocumentRegion appendStructuredDocumentRegion(IStructuredDocumentRegion newStructuredDocumentRegion) { + if (newStructuredDocumentRegion == null) + return null; + + IStructuredDocumentRegion flatNode = getStructuredDocumentRegion(); + if (flatNode == null) { + setStructuredDocumentRegion(newStructuredDocumentRegion); + return newStructuredDocumentRegion; + } + + if (flatNode instanceof StructuredDocumentRegionContainer) { + StructuredDocumentRegionContainer container = (StructuredDocumentRegionContainer) flatNode; + container.appendStructuredDocumentRegion(newStructuredDocumentRegion); + } else { + StructuredDocumentRegionContainer container = new StructuredDocumentRegionContainer(); + container.appendStructuredDocumentRegion(flatNode); + container.appendStructuredDocumentRegion(newStructuredDocumentRegion); + setStructuredDocumentRegion(container); + } + + return newStructuredDocumentRegion; + } + + /** + * appendText method + * + * @param text + * org.w3c.dom.Text + */ + public void appendText(Text newText) { + if (newText == null) + return; + + if (!isDataEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + + TextImpl text = (TextImpl) newText; + String newSource = text.getSource(); + if (newSource == null && newSource.length() == 0) + return; + String source = getSource(); + if (source != null) + setTextSource(source + newSource); + else + setTextSource(newSource); + } + + /** + * cloneNode method + * + * @return org.w3c.dom.Node + * @param deep + * boolean + */ + public Node cloneNode(boolean deep) { + TextImpl cloned = new TextImpl(this); + return cloned; + } + + /** + * deleteData method + * + * @param offset + * int + * @param count + * int + */ + public void deleteData(int offset, int count) throws DOMException { + if (count == 0) + return; + if (!isDataEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + if (count < 0 || offset < 0) { + throw new DOMException(DOMException.INDEX_SIZE_ERR, new String()); + } + + String source = getSource(); + if (source == null || source.length() == 0) { + throw new DOMException(DOMException.INDEX_SIZE_ERR, new String()); + } + StringPair pair = substringSourceExcluded(source, offset, count); + if (pair == null) + return; + source = null; + String first = pair.getFirst(); + if (first != null) + source = first; + String second = pair.getSecond(); + if (second != null) { + if (source != null) + source += second; + else + source = second; + } + if (source == null) + source = new String(); // delete all + setTextSource(source); + } + + /** + * getData method + * + * @return java.lang.String + */ + public String getData() throws DOMException { + if (this.fSource != null) + return getData(this.fSource); + String data = super.getData(); + if (data != null) + return data; + return getData(getStructuredDocumentRegion()); + } + + /** + */ + private String getData(IStructuredDocumentRegion flatNode) { + if (flatNode == null) + return new String(); + + if (flatNode instanceof StructuredDocumentRegionContainer) { + StructuredDocumentRegionContainer container = (StructuredDocumentRegionContainer) flatNode; + int length = container.getLength(); + if (length < 16) + length = 16; // default + StringBuffer buffer = new StringBuffer(length); + int count = container.getStructuredDocumentRegionCount(); + for (int i = 0; i < count; i++) { + IStructuredDocumentRegion content = container.getStructuredDocumentRegion(i); + String data = getData(content); + if (data == null) + continue; + buffer.append(data); + } + return buffer.toString(); + } + + if (flatNode instanceof StructuredDocumentRegionProxy) { + return flatNode.getText(); + } + + ITextRegion region = StructuredDocumentRegionUtil.getFirstRegion(flatNode); + if (region != null) { + String regionType = region.getType(); + if (regionType == XMLRegionContext.XML_ENTITY_REFERENCE || regionType == XMLRegionContext.XML_CHAR_REFERENCE) { + String name = StructuredDocumentRegionUtil.getEntityRefName(flatNode, region); + if (name != null) { + DocumentImpl document = (DocumentImpl) getOwnerDocument(); + if (document != null) { + String value = document.getCharValue(name); + if (value != null) + return value; + } + } + } + } + + return flatNode.getText(); + } + + /** + * Returns data for the source + */ + private String getData(String source) { + if (source == null) + return null; + StringBuffer buffer = null; + int offset = 0; + int length = source.length(); + int ref = source.indexOf('&'); + while (ref >= 0) { + int end = source.indexOf(';', ref + 1); + if (end > ref + 1) { + String name = source.substring(ref + 1, end); + String value = getCharValue(name); + if (value != null) { + if (buffer == null) + buffer = new StringBuffer(length); + if (ref > offset) + buffer.append(source.substring(offset, ref)); + buffer.append(value); + offset = end + 1; + ref = end; + } + } + ref = source.indexOf('&', ref + 1); + } + if (buffer == null) + return source; + if (length > offset) + buffer.append(source.substring(offset)); + return buffer.toString(); + } + + /** + * getFirstStructuredDocumentRegion method + * + * @return com.ibm.sed.structuredDocument.IStructuredDocumentRegion + */ + public IStructuredDocumentRegion getFirstStructuredDocumentRegion() { + return StructuredDocumentRegionUtil.getFirstStructuredDocumentRegion(getStructuredDocumentRegion()); + } + + /** + * getLastStructuredDocumentRegion method + * + * @return com.ibm.sed.structuredDocument.IStructuredDocumentRegion + */ + public IStructuredDocumentRegion getLastStructuredDocumentRegion() { + return StructuredDocumentRegionUtil.getLastStructuredDocumentRegion(getStructuredDocumentRegion()); + } + + /** + * getNodeName method + * + * @return java.lang.String + */ + public String getNodeName() { + return "#text";//$NON-NLS-1$ + } + + /** + * getNodeType method + * + * @return short + */ + public short getNodeType() { + return TEXT_NODE; + } + + /** + */ + public String getSource() { + if (this.fSource != null) + return this.fSource; + String data = super.getData(); + if (data != null && data.length() > 0) { + String source = getSource(data); + if (source != null) + return source; + } + return super.getSource(); + } + + /** + * Returns source for the data + */ + private String getSource(String data) { + if (data == null) + return null; + XMLModel model = getModel(); + if (model == null) + return null; // error + XMLGenerator generator = model.getGenerator(); + if (generator == null) + return null; // error + return generator.generateTextData(this, data); + } + + /** + */ + String getTextSource() { + return this.fSource; + } + + /** + */ + public String getValueSource() { + return getSource(); + } + + /** + */ + boolean hasStructuredDocumentRegion(IStructuredDocumentRegion askedStructuredDocumentRegion) { + if (askedStructuredDocumentRegion == null) + return false; + + IStructuredDocumentRegion flatNode = getStructuredDocumentRegion(); + if (flatNode == null) + return false; + + if (flatNode == askedStructuredDocumentRegion) + return true; + + if (flatNode instanceof StructuredDocumentRegionProxy) { + StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) flatNode; + if (proxy.getStructuredDocumentRegion() == askedStructuredDocumentRegion) + return true; + return false; + } + + if (flatNode instanceof StructuredDocumentRegionContainer) { + StructuredDocumentRegionContainer container = (StructuredDocumentRegionContainer) flatNode; + int count = container.getStructuredDocumentRegionCount(); + for (int i = 0; i < count; i++) { + IStructuredDocumentRegion content = container.getStructuredDocumentRegion(i); + if (content == null) + continue; + if (content == askedStructuredDocumentRegion) + return true; + if (content instanceof StructuredDocumentRegionProxy) { + StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) content; + if (proxy.getStructuredDocumentRegion() == askedStructuredDocumentRegion) + return true; + } + } + return false; + } + + return false; + } + + /** + * insertData method + * + * @param offset + * int + * @param arg + * java.lang.String + */ + public void insertData(int offset, String arg) throws DOMException { + if (arg == null || arg.length() == 0) + return; + if (!isDataEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + if (offset < 0) { + throw new DOMException(DOMException.INDEX_SIZE_ERR, new String()); + } + + String source = getSource(); + if (source == null || source.length() == 0) { + if (offset > 0) { + throw new DOMException(DOMException.INDEX_SIZE_ERR, new String()); + } + source = getSource(arg); + if (source != null) + setTextSource(source); + return; + } + + StringPair pair = substringSourceExcluded(source, offset, 0); + if (pair == null) + return; // error + StringBuffer buffer = new StringBuffer(source.length() + arg.length()); + String first = pair.getFirst(); + if (first != null) + buffer.append(first); + source = getSource(arg); + if (source != null) + buffer.append(source); + String second = pair.getSecond(); + if (second != null) + buffer.append(second); + setTextSource(buffer.toString()); + } + + /** + */ + IStructuredDocumentRegion insertStructuredDocumentRegion(IStructuredDocumentRegion newStructuredDocumentRegion, IStructuredDocumentRegion nextStructuredDocumentRegion) { + if (newStructuredDocumentRegion == null) + return null; + if (nextStructuredDocumentRegion == null) + return appendStructuredDocumentRegion(newStructuredDocumentRegion); + + IStructuredDocumentRegion flatNode = getStructuredDocumentRegion(); + if (flatNode == null) + return null; // error + + if (flatNode == nextStructuredDocumentRegion) { + StructuredDocumentRegionContainer container = new StructuredDocumentRegionContainer(); + container.appendStructuredDocumentRegion(newStructuredDocumentRegion); + container.appendStructuredDocumentRegion(flatNode); + setStructuredDocumentRegion(container); + return newStructuredDocumentRegion; + } + + if (flatNode instanceof StructuredDocumentRegionContainer) { + StructuredDocumentRegionContainer container = (StructuredDocumentRegionContainer) flatNode; + int count = container.getStructuredDocumentRegionCount(); + for (int i = 0; i < count; i++) { + IStructuredDocumentRegion content = container.getStructuredDocumentRegion(i); + if (content == nextStructuredDocumentRegion) { + container.insertStructuredDocumentRegion(newStructuredDocumentRegion, i); + return newStructuredDocumentRegion; + } + } + return null; // error + } + + return null; // error + } + + /** + * insertText method + * + * @param text + * org.w3c.dom.Text + * @param offset + * int + */ + public void insertText(Text newText, int offset) throws DOMException { + if (newText == null) + return; + if (!isDataEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + TextImpl text = (TextImpl) newText; + String newSource = text.getSource(); + if (newSource == null && newSource.length() == 0) + return; + if (offset < 0) { + throw new DOMException(DOMException.INDEX_SIZE_ERR, new String()); + } + + String source = getSource(); + if (source == null || source.length() == 0) { + if (offset > 0) { + throw new DOMException(DOMException.INDEX_SIZE_ERR, new String()); + } + setTextSource(newSource); + return; + } + + StringPair pair = substringSourceExcluded(source, offset, 0); + if (pair == null) + return; // error + StringBuffer buffer = new StringBuffer(source.length() + newSource.length()); + String first = pair.getFirst(); + if (first != null) + buffer.append(first); + buffer.append(newSource); + String second = pair.getSecond(); + if (second != null) + buffer.append(second); + setTextSource(buffer.toString()); + } + + /** + * isCDATAContent method + * + * @return boolean + */ + public boolean isCDATAContent() { + Node parent = getParentNode(); + if (parent == null || parent.getNodeType() != Node.ELEMENT_NODE) + return false; + ElementImpl element = (ElementImpl) parent; + return element.isCDATAContainer(); + } + + /** + */ + public boolean isInvalid() { + return isInvalid(getStructuredDocumentRegion()); + } + + /** + */ + private boolean isInvalid(IStructuredDocumentRegion flatNode) { + if (flatNode == null) + return false; + + if (flatNode instanceof StructuredDocumentRegionContainer) { + StructuredDocumentRegionContainer container = (StructuredDocumentRegionContainer) flatNode; + int count = container.getStructuredDocumentRegionCount(); + for (int i = 0; i < count; i++) { + IStructuredDocumentRegion content = container.getStructuredDocumentRegion(i); + if (isInvalid(content)) + return true; + } + return false; + } + + if (flatNode instanceof StructuredDocumentRegionProxy) { + StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) flatNode; + return isInvalid(proxy.getStructuredDocumentRegion()); + } + + String regionType = StructuredDocumentRegionUtil.getFirstRegionType(flatNode); + if (regionType != XMLRegionContext.XML_CONTENT && regionType != JSP_CONTENT && regionType != XMLRegionContext.XML_ENTITY_REFERENCE && regionType != XMLRegionContext.XML_CHAR_REFERENCE && regionType != XMLRegionContext.BLOCK_TEXT && regionType != XMLRegionContext.WHITE_SPACE) { + return true; + } + + return false; + } + + /** + */ + boolean isSharingStructuredDocumentRegion(IStructuredDocumentRegion sharedStructuredDocumentRegion) { + if (sharedStructuredDocumentRegion == null) + return false; + + IStructuredDocumentRegion flatNode = getStructuredDocumentRegion(); + if (flatNode == null) + return false; + + if (flatNode == sharedStructuredDocumentRegion) + return false; + + if (flatNode instanceof StructuredDocumentRegionProxy) { + StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) flatNode; + if (proxy.getStructuredDocumentRegion() == sharedStructuredDocumentRegion) + return true; + return false; + } + + if (flatNode instanceof StructuredDocumentRegionContainer) { + StructuredDocumentRegionContainer container = (StructuredDocumentRegionContainer) flatNode; + int count = container.getStructuredDocumentRegionCount(); + for (int i = 0; i < count; i++) { + IStructuredDocumentRegion content = container.getStructuredDocumentRegion(i); + if (content == null) + continue; + if (content == sharedStructuredDocumentRegion) + return false; + if (content instanceof StructuredDocumentRegionProxy) { + StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) content; + if (proxy.getStructuredDocumentRegion() == sharedStructuredDocumentRegion) + return true; + } + } + return false; + } + + return false; + } + + /** + */ + public boolean isWhitespace() { + String data = getData(); + if (data == null) + return true; + int length = data.length(); + for (int i = 0; i < length; i++) { + if (!Character.isWhitespace(data.charAt(i))) + return false; + } + return true; + } + + /** + */ + IStructuredDocumentRegion removeStructuredDocumentRegion(IStructuredDocumentRegion oldStructuredDocumentRegion) { + if (oldStructuredDocumentRegion == null) + return null; + + IStructuredDocumentRegion flatNode = getStructuredDocumentRegion(); + if (flatNode == null) + return null; // error + + if (flatNode == oldStructuredDocumentRegion) { + setStructuredDocumentRegion(null); + return oldStructuredDocumentRegion; + } + + if (flatNode instanceof StructuredDocumentRegionProxy) { + StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) flatNode; + if (proxy.getStructuredDocumentRegion() == oldStructuredDocumentRegion) { + // removed with proxy + setStructuredDocumentRegion(null); + return oldStructuredDocumentRegion; + } + return null; // error + } + + if (flatNode instanceof StructuredDocumentRegionContainer) { + StructuredDocumentRegionContainer container = (StructuredDocumentRegionContainer) flatNode; + int count = container.getStructuredDocumentRegionCount(); + for (int i = 0; i < count; i++) { + IStructuredDocumentRegion content = container.getStructuredDocumentRegion(i); + if (content == oldStructuredDocumentRegion) { + container.removeStructuredDocumentRegion(i); + if (container.getStructuredDocumentRegionCount() == 1) { + // get back to single IStructuredDocumentRegion + setStructuredDocumentRegion(container.getStructuredDocumentRegion(0)); + } + return oldStructuredDocumentRegion; + } + + if (content instanceof StructuredDocumentRegionProxy) { + StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) content; + if (proxy.getStructuredDocumentRegion() == oldStructuredDocumentRegion) { + // removed with proxy + container.removeStructuredDocumentRegion(i); + if (container.getStructuredDocumentRegionCount() == 1) { + // get back to single IStructuredDocumentRegion + setStructuredDocumentRegion(container.getStructuredDocumentRegion(0)); + } + return oldStructuredDocumentRegion; + } + } + } + return null; // error + } + + return null; // error + } + + /** + * replaceData method + * + * @param offset + * int + * @param count + * int + * @param arg + * java.lang.String + */ + public void replaceData(int offset, int count, String arg) throws DOMException { + if (!isDataEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + if (arg == null || arg.length() == 0) { + deleteData(offset, count); + return; + } + if (count == 0) { + insertData(offset, arg); + return; + } + if (offset < 0 || count < 0) { + throw new DOMException(DOMException.INDEX_SIZE_ERR, new String()); + } + + String source = getSource(); + if (source == null || source.length() == 0) { + throw new DOMException(DOMException.INDEX_SIZE_ERR, new String()); + } + + StringPair pair = substringSourceExcluded(source, offset, count); + if (pair == null) + return; // error + StringBuffer buffer = new StringBuffer(source.length() + arg.length()); + String first = pair.getFirst(); + if (first != null) + buffer.append(first); + source = getSource(arg); + if (source != null) + buffer.append(source); + String second = pair.getSecond(); + if (second != null) + buffer.append(second); + setTextSource(buffer.toString()); + } + + /** + */ + IStructuredDocumentRegion replaceStructuredDocumentRegion(IStructuredDocumentRegion newStructuredDocumentRegion, IStructuredDocumentRegion oldStructuredDocumentRegion) { + if (oldStructuredDocumentRegion == null) + return null; + if (newStructuredDocumentRegion == null) + return removeStructuredDocumentRegion(oldStructuredDocumentRegion); + + IStructuredDocumentRegion flatNode = getStructuredDocumentRegion(); + if (flatNode == null) + return null; // error + + if (flatNode == oldStructuredDocumentRegion) { + setStructuredDocumentRegion(newStructuredDocumentRegion); + return oldStructuredDocumentRegion; + } + + if (flatNode instanceof StructuredDocumentRegionProxy) { + StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) flatNode; + if (proxy.getStructuredDocumentRegion() == oldStructuredDocumentRegion) { + if (newStructuredDocumentRegion instanceof StructuredDocumentRegionProxy) { + // proxy must not be nested + setStructuredDocumentRegion(newStructuredDocumentRegion); + } else { + proxy.setStructuredDocumentRegion(newStructuredDocumentRegion); + } + return oldStructuredDocumentRegion; + } + return null; // error + } + + if (flatNode instanceof StructuredDocumentRegionContainer) { + StructuredDocumentRegionContainer container = (StructuredDocumentRegionContainer) flatNode; + int count = container.getStructuredDocumentRegionCount(); + for (int i = 0; i < count; i++) { + IStructuredDocumentRegion content = container.getStructuredDocumentRegion(i); + if (content == null) + continue; // error + if (content == oldStructuredDocumentRegion) { + container.replaceStructuredDocumentRegion(newStructuredDocumentRegion, i); + return oldStructuredDocumentRegion; + } + + if (content instanceof StructuredDocumentRegionProxy) { + StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) content; + if (proxy.getStructuredDocumentRegion() == oldStructuredDocumentRegion) { + if (newStructuredDocumentRegion instanceof StructuredDocumentRegionProxy) { + // proxy must not be nested + container.replaceStructuredDocumentRegion(newStructuredDocumentRegion, i); + } else { + proxy.setStructuredDocumentRegion(newStructuredDocumentRegion); + } + return oldStructuredDocumentRegion; + } + } + } + return null; // error + } + + return null; // error + } + + /** + */ + void resetStructuredDocumentRegions() { + String source = getSource(); + if (source != null && source.length() > 0) + this.fSource = source; + super.resetStructuredDocumentRegions(); + } + + /** + * getData method + * + * @return java.lang.String + */ + public void setData(String data) throws DOMException { + if (!isDataEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + + this.fSource = null; + super.setData(data); + } + + /** + */ + public void setSource(String source) throws InvalidCharacterException { + if (!isDataEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + + SourceValidator validator = new SourceValidator(this); + if (validator.validateSource(source)) + setTextSource(source); + } + + /** + */ + void setStructuredDocumentRegion(IStructuredDocumentRegion flatNode) { + super.setStructuredDocumentRegion(flatNode); + if (flatNode != null) + this.fSource = null; + } + + /** + */ + public void setTextSource(String source) { + if (!isDataEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + + this.fSource = source; + + notifyValueChanged(); + } + + /** + */ + public void setValueSource(String source) { + if (!isDataEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + + SourceValidator validator = new SourceValidator(this); + setTextSource(validator.convertSource(source)); + } + + /** + * splitText method + * + * @return org.w3c.dom.Text + * @param offset + * int + */ + public Text splitText(int offset) throws DOMException { + if (!isDataEditable()) { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, new String()); + } + if (offset < 0) { + throw new DOMException(DOMException.INDEX_SIZE_ERR, new String()); + } + int length = getLength(); + if (offset > length) { + throw new DOMException(DOMException.INDEX_SIZE_ERR, new String()); + } + Document document = getOwnerDocument(); + if (document == null) + return null; + + String source = null; + if (offset < length) { + int count = length - offset; + source = substringSource(offset, count); + deleteData(offset, count); + } + TextImpl text = (TextImpl) document.createTextNode(null); + if (source != null) + text.setTextSource(source); + + Node parent = getParentNode(); + if (parent != null) + parent.insertBefore(text, getNextSibling()); + + return text; + } + + /** + */ + Text splitText(IStructuredDocumentRegion nextStructuredDocumentRegion) { + if (nextStructuredDocumentRegion == null) + return null; + + IStructuredDocumentRegion flatNode = getStructuredDocumentRegion(); + if (flatNode == null || !(flatNode instanceof StructuredDocumentRegionContainer)) + return null; // error + + StructuredDocumentRegionContainer container = (StructuredDocumentRegionContainer) flatNode; + int count = container.getStructuredDocumentRegionCount(); + int index = 0; + for (; index < count; index++) { + if (container.getStructuredDocumentRegion(index) == nextStructuredDocumentRegion) + break; + } + if (index >= count) { + // this is the case nextStructuredDocumentRegion is a new + // IStructuredDocumentRegion + // search gap by offset + int offset = nextStructuredDocumentRegion.getStart(); + for (index = 0; index < count; index++) { + IStructuredDocumentRegion content = container.getStructuredDocumentRegion(index); + if (content == null) + continue; // error + if (content.getStart() >= offset) + break; + } + if (index >= count) + return null; // error + } + if (index == 0) + return this; // nothing to do + + Document document = getOwnerDocument(); + if (document == null) + return null; // error + Node parent = getParentNode(); + if (parent == null) + return null; // error + TextImpl nextText = (TextImpl) document.createTextNode(null); + if (nextText == null) + return null; // error + + for (; index < count; count--) { + nextText.appendStructuredDocumentRegion(container.removeStructuredDocumentRegion(index)); + } + + // normalize IStructuredDocumentRegion + if (index == 1) { + setStructuredDocumentRegion(container.getStructuredDocumentRegion(0)); + } + + parent.insertBefore(nextText, getNextSibling()); + return nextText; + } + + /** + * Retruns data for the range + */ + private String substringData(String data, int offset, int count) throws DOMException { + // sure offset and count are non-negative + if (count == 0) + return new String(); + if (data == null) { + throw new DOMException(DOMException.INDEX_SIZE_ERR, new String()); + } + int length = data.length(); + if (offset > length) { + throw new DOMException(DOMException.INDEX_SIZE_ERR, new String()); + } + int end = offset + count; + if (end > length) { + throw new DOMException(DOMException.INDEX_SIZE_ERR, new String()); + } + return data.substring(offset, end); + } + + /** + * Returns source for the range specified by: offset: data offset count: + * data count + */ + private String substringSource(int offset, int count) throws DOMException { + // sure offset and count are non-negative + if (this.fSource != null) + return substringSource(this.fSource, offset, count); + + String data = super.getData(); + if (data != null && data.length() > 0) { + data = substringData(data, offset, count); + if (data == null) + return new String(); + String source = getSource(data); + if (source != null) + return source; + } + + return substringSource(getSource(), offset, count); + } + + /** + * Returns source for the range specified by: offset: data offset count: + * data count + */ + private String substringSource(String source, int offset, int count) throws DOMException { + // sure offset and count are non-negative + if (count == 0) + return new String(); + if (source == null) { + throw new DOMException(DOMException.INDEX_SIZE_ERR, new String()); + } + + int length = source.length(); + int end = offset + count; + + // find character reference + int ref = source.indexOf('&'); + while (ref >= 0) { + if (ref >= end) + break; + int refEnd = source.indexOf(';', ref + 1); + if (refEnd > ref + 1) { + String name = source.substring(ref + 1, refEnd); + if (getCharValue(name) != null) { + // found, shift for source offsets + int refCount = refEnd - ref; + if (ref < offset) + offset += refCount; + if (ref < end) + end += refCount; + ref = refEnd; + } + } + ref = source.indexOf('&', ref + 1); + } + + if (offset > length || end > length) { + throw new DOMException(DOMException.INDEX_SIZE_ERR, new String()); + } + + return source.substring(offset, end); + } + + /** + * Returns sources before and after the range specified by: offset: data + * offset count: data count + */ + private StringPair substringSourceExcluded(String source, int offset, int count) throws DOMException { + // sure offset and count are non-negative + if (source == null) { + if (offset == 0 && count == 0) + return new StringPair(null, null); + throw new DOMException(DOMException.INDEX_SIZE_ERR, new String()); + } + + int length = source.length(); + int end = offset + count; + + // find character reference + int ref = source.indexOf('&'); + while (ref >= 0) { + if (ref >= end) + break; + int refEnd = source.indexOf(';', ref + 1); + if (refEnd > ref + 1) { + String name = source.substring(ref + 1, refEnd); + if (getCharValue(name) != null) { + // found, shift for source offsets + int refCount = refEnd - ref; + if (ref < offset) + offset += refCount; + if (ref < end) + end += refCount; + ref = refEnd; + } + } + ref = source.indexOf('&', ref + 1); + } + + if (offset > length || end > length) { + throw new DOMException(DOMException.INDEX_SIZE_ERR, new String()); + } + + String first = (offset > 0 ? source.substring(0, offset) : null); + String second = (end < length ? source.substring(end, length) : null); + return new StringPair(first, second); + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLGeneratorImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLGeneratorImpl.java new file mode 100644 index 0000000000..5000a4d009 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLGeneratorImpl.java @@ -0,0 +1,738 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.document; + + + +import org.eclipse.wst.common.contentmodel.CMAttributeDeclaration; +import org.eclipse.wst.common.contentmodel.CMDataType; +import org.eclipse.wst.xml.core.commentelement.impl.CommentElementRegistry; +import org.eclipse.wst.xml.core.document.DocumentTypeAdapter; +import org.eclipse.wst.xml.core.document.JSPTag; +import org.eclipse.wst.xml.core.document.TagAdapter; +import org.eclipse.wst.xml.core.document.XMLAttr; +import org.eclipse.wst.xml.core.document.XMLCharEntity; +import org.eclipse.wst.xml.core.document.XMLDocument; +import org.eclipse.wst.xml.core.document.XMLElement; +import org.eclipse.wst.xml.core.document.XMLGenerator; +import org.eclipse.wst.xml.core.document.XMLNode; +import org.w3c.dom.Attr; +import org.w3c.dom.CDATASection; +import org.w3c.dom.Comment; +import org.w3c.dom.DocumentType; +import org.w3c.dom.Element; +import org.w3c.dom.EntityReference; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.ProcessingInstruction; +import org.w3c.dom.Text; + + +/** + */ +public class XMLGeneratorImpl implements XMLGenerator { + private static final String CDATA_CLOSE = "]]>";//$NON-NLS-1$ + private static final String CDATA_OPEN = "<![CDATA[";//$NON-NLS-1$ + private static final String COMMENT_CLOSE = "-->";//$NON-NLS-1$ + private static final String COMMENT_OPEN = "<!--";//$NON-NLS-1$ + private static final String DOCTYPE_OPEN = "<!DOCTYPE";//$NON-NLS-1$ + private static final String EMPTY_CLOSE = " />";//$NON-NLS-1$ + private static final String END_OPEN = "</";//$NON-NLS-1$ + + private static XMLGeneratorImpl instance = null; + private static final String PI_CLOSE = "?>";//$NON-NLS-1$ + private static final String PI_OPEN = "<?";//$NON-NLS-1$ + private static final String PUBLIC_ID = "PUBLIC";//$NON-NLS-1$ + private static final String SSI_PREFIX = "ssi";//$NON-NLS-1$ + //private static final String SSI_FEATURE = "SSI";//$NON-NLS-1$ + private static final String SSI_TOKEN = "#";//$NON-NLS-1$ + private static final String SYSTEM_ID = "SYSTEM";//$NON-NLS-1$ + private static final String TAG_CLOSE = ">";//$NON-NLS-1$ + + /** + */ + public synchronized static XMLGenerator getInstance() { + if (instance == null) + instance = new XMLGeneratorImpl(); + return instance; + } + + /** + */ + //private boolean isCommentTag(XMLElement element) { + // if (element == null) return false; + // DocumentImpl document = (DocumentImpl)element.getOwnerDocument(); + // if (document == null) return false; + // DocumentTypeAdapter adapter = document.getDocumentTypeAdapter(); + // if (adapter == null) return false; + // if (!adapter.hasFeature(SSI_FEATURE)) return false; + // String prefix = element.getPrefix(); + // return (prefix != null && prefix.equals(SSI_PREFIX)); + //} + /** + * Helper to modify the tag name in sub-classes + */ + private static void setTagName(Element element, String tagName) { + if (element == null || tagName == null) + return; + ((ElementImpl) element).setTagName(tagName); + } + + /** + * XMLModelGenerator constructor + */ + private XMLGeneratorImpl() { + super(); + } + + /** + */ + public String generateAttrName(Attr attr) { + if (attr == null) + return null; + String attrName = attr.getName(); + if (attrName == null) + return null; + if (attrName.startsWith(JSPTag.TAG_OPEN)) { + if (!attrName.endsWith(JSPTag.TAG_CLOSE)) { + // close JSP + return (attrName + JSPTag.TAG_CLOSE); + } + } + if (((XMLAttr) attr).isGlobalAttr() && CMNodeUtil.getAttributeDeclaration(attr) != null) { + switch (getAttrNameCase(attr)) { + case DocumentTypeAdapter.UPPER_CASE : + attrName = attrName.toUpperCase(); + break; + case DocumentTypeAdapter.LOWER_CASE : + attrName = attrName.toLowerCase(); + break; + default : + // ASIS_CASE + break; + } + } + return attrName; + } + + /** + */ + public String generateAttrValue(Attr attr) { + return generateAttrValue(attr, (char) 0); // no quote preference + } + + /** + */ + public String generateAttrValue(Attr attr, char quote) { + if (attr == null) + return null; + String name = attr.getName(); + SourceValidator validator = new SourceValidator(attr); + String value = validator.convertSource(((XMLNode) attr).getValueSource()); + if (value == null || value.length() == 0) { + if (name != null && name.startsWith(JSPTag.TAG_OPEN)) + return null; + if (isBooleanAttr(attr)) { + if (((AttrImpl) attr).isXMLAttr()) { + // generate the name as value + value = attr.getName(); + } else { + // not to generate '=' and value for HTML boolean + return null; + } + } + } + return generateAttrValue(value, quote); + } + + /** + */ + public String generateAttrValue(String value, char quote) { + // assume the valid is already validated not to include both quotes + if (quote == '"') { + if ((value != null) && (value.indexOf('"') >= 0)) + quote = '\''; // force + } else if (quote == '\'') { + if ((value != null) && (value.indexOf('\'') >= 0)) + quote = '"'; // force + } else { // no preference + if ((value != null) && (value.indexOf('"') < 0)) + quote = '"'; + else + quote = '\''; + } + + int length = (value == null ? 0 : value.length()); + StringBuffer buffer = new StringBuffer(length + 2); + buffer.append(quote); + if (value != null) + buffer.append(value); + buffer.append(quote); + return buffer.toString(); + } + + /** + * generateCDATASection method + * + * @return java.lang.String + * @param comment + * org.w3c.dom.CDATASection + */ + public String generateCDATASection(CDATASection cdata) { + if (cdata == null) + return null; + + String data = cdata.getData(); + int length = (data != null ? data.length() : 0); + StringBuffer buffer = new StringBuffer(length + 16); + buffer.append(CDATA_OPEN); + if (data != null) + buffer.append(data); + buffer.append(CDATA_CLOSE); + return buffer.toString(); + } + + /** + * generateChild method + * + * @return java.lang.String + * @param org.w3c.dom.Node + */ + public String generateChild(Node parentNode) { + if (parentNode == null) + return null; + if (!parentNode.hasChildNodes()) + return null; + + StringBuffer buffer = new StringBuffer(); + for (Node child = parentNode.getFirstChild(); child != null; child = child.getNextSibling()) { + String childSource = generateSource(child); + if (childSource != null) + buffer.append(childSource); + } + return buffer.toString(); + } + + /** + */ + public String generateCloseTag(Node node) { + if (node == null) + return null; + + switch (node.getNodeType()) { + case Node.ELEMENT_NODE : { + ElementImpl element = (ElementImpl) node; + if (element.isCommentTag()) { + if (element.isJSPTag()) + return JSPTag.COMMENT_CLOSE; + return COMMENT_CLOSE; + } + if (element.isJSPTag()) + return JSPTag.TAG_CLOSE; + if (element.isEmptyTag()) + return EMPTY_CLOSE; + return TAG_CLOSE; + } + case Node.COMMENT_NODE : { + CommentImpl comment = (CommentImpl) node; + if (comment.isJSPTag()) + return JSPTag.COMMENT_CLOSE; + return COMMENT_CLOSE; + } + case Node.DOCUMENT_TYPE_NODE : + return TAG_CLOSE; + case Node.PROCESSING_INSTRUCTION_NODE : + return PI_CLOSE; + case Node.CDATA_SECTION_NODE : + return CDATA_CLOSE; + default : + break; + } + + return null; + } + + /** + * generateComment method + * + * @return java.lang.String + * @param comment + * org.w3c.dom.Comment + */ + public String generateComment(Comment comment) { + if (comment == null) + return null; + + String data = comment.getData(); + int length = (data != null ? data.length() : 0); + StringBuffer buffer = new StringBuffer(length + 8); + CommentImpl impl = (CommentImpl) comment; + if (!impl.isJSPTag()) + buffer.append(COMMENT_OPEN); + else + buffer.append(JSPTag.COMMENT_OPEN); + if (data != null) + buffer.append(data); + if (!impl.isJSPTag()) + buffer.append(COMMENT_CLOSE); + else + buffer.append(JSPTag.COMMENT_CLOSE); + return buffer.toString(); + } + + /** + * generateDoctype method + * + * @return java.lang.String + * @param docType + * org.w3c.dom.DocumentType + */ + public String generateDoctype(DocumentType docType) { + if (docType == null) + return null; + + String name = docType.getName(); + int length = (name != null ? name.length() : 0); + StringBuffer buffer = new StringBuffer(length + 16); + buffer.append(DOCTYPE_OPEN); + buffer.append(' '); + if (name != null) + buffer.append(name); + DocumentTypeImpl dt = (DocumentTypeImpl) docType; + String publicID = dt.getPublicId(); + String systemID = dt.getSystemId(); + if (publicID != null) { + buffer.append(' '); + buffer.append(PUBLIC_ID); + buffer.append(' '); + buffer.append('"'); + buffer.append(publicID); + buffer.append('"'); + if (systemID != null) { + buffer.append(' '); + buffer.append('"'); + buffer.append(systemID); + buffer.append('"'); + } + } else { + if (systemID != null) { + buffer.append(' '); + buffer.append(SYSTEM_ID); + buffer.append(' '); + buffer.append('"'); + buffer.append(systemID); + buffer.append('"'); + } + } + buffer.append('>'); + return buffer.toString(); + } + + /** + * generateElement method + * + * @return java.lang.String + * @param element + * Element + */ + public String generateElement(Element element) { + if (element == null) + return null; + + // if empty tag is preferrable, generate as empty tag + ElementImpl impl = (ElementImpl) element; + if (impl.preferEmptyTag()) + impl.setEmptyTag(true); + + StringBuffer buffer = new StringBuffer(); + String startTag = generateStartTag(element); + if (startTag != null) + buffer.append(startTag); + String child = generateChild(element); + if (child != null) + buffer.append(child); + String endTag = generateEndTag(element); + if (endTag != null) + buffer.append(endTag); + return buffer.toString(); + } + + /** + * generateEndTag method + * + * @return java.lang.String + * @param element + * org.w3c.dom.Element + */ + public String generateEndTag(Element element) { + if (element == null) + return null; + + ElementImpl impl = (ElementImpl) element; + + // first check if tag adapter exists + TagAdapter adapter = (TagAdapter) impl.getExistingAdapter(TagAdapter.class); + if (adapter != null) { + String endTag = adapter.getEndTag(impl); + if (endTag != null) + return endTag; + } + + if (impl.isEmptyTag()) + return null; + if (!impl.isContainer()) + return null; + if (impl.isJSPTag()) + return JSPTag.TAG_CLOSE; + + String tagName = generateTagName(element); + int length = (tagName != null ? tagName.length() : 0); + StringBuffer buffer = new StringBuffer(length + 4); + buffer.append(END_OPEN); + if (tagName != null) + buffer.append(tagName); + buffer.append('>'); + return buffer.toString(); + } + + /** + * generateEntityRef method + * + * @return java.lang.String + * @param entityRef + * org.w3c.dom.EntityReference + */ + public String generateEntityRef(EntityReference entityRef) { + if (entityRef == null) + return null; + + String name = entityRef.getNodeName(); + int length = (name != null ? name.length() : 0); + StringBuffer buffer = new StringBuffer(length + 4); + buffer.append('&'); + if (name != null) + buffer.append(name); + buffer.append(';'); + return buffer.toString(); + } + + /** + * generatePI method + * + * @return java.lang.String + * @param pi + * org.w3c.dom.ProcessingInstruction + */ + public String generatePI(ProcessingInstruction pi) { + if (pi == null) + return null; + + String target = pi.getTarget(); + String data = pi.getData(); + int length = (target != null ? target.length() : 0); + if (data != null) + length += data.length(); + StringBuffer buffer = new StringBuffer(length + 8); + buffer.append(PI_OPEN); + if (target != null) + buffer.append(target); + buffer.append(' '); + if (data != null) + buffer.append(data); + buffer.append(PI_CLOSE); + return buffer.toString(); + } + + /** + * generateSource method + * + * @return java.lang.String + * @param node + * org.w3c.dom.Node + */ + public String generateSource(Node node) { + switch (node.getNodeType()) { + case Node.ELEMENT_NODE : + return generateElement((Element) node); + case Node.TEXT_NODE : + return generateText((Text) node); + case Node.COMMENT_NODE : + return generateComment((Comment) node); + case Node.DOCUMENT_TYPE_NODE : + return generateDoctype((DocumentType) node); + case Node.PROCESSING_INSTRUCTION_NODE : + return generatePI((ProcessingInstruction) node); + case Node.CDATA_SECTION_NODE : + return generateCDATASection((CDATASection) node); + case Node.ENTITY_REFERENCE_NODE : + return generateEntityRef((EntityReference) node); + default : + // DOCUMENT + break; + } + return generateChild(node); + } + + /** + * generateStartTag method + * + * @return java.lang.String + * @param element + * Element + */ + public String generateStartTag(Element element) { + if (element == null) + return null; + + ElementImpl impl = (ElementImpl) element; + + if (impl.isJSPTag()) { + // check if JSP content type and JSP Document + XMLDocument document = (XMLDocument) element.getOwnerDocument(); + if (document != null && document.isJSPType()) { + if (document.isJSPDocument() && !impl.hasChildNodes()) { + impl.setJSPTag(false); + } + } else { + impl.setJSPTag(false); + } + } + if (impl.isCommentTag() && impl.getExistingAdapter(TagAdapter.class) == null) { + CommentElementRegistry registry = CommentElementRegistry.getInstance(); + registry.setupCommentElement(impl); + } + + // first check if tag adapter exists + TagAdapter adapter = (TagAdapter) impl.getExistingAdapter(TagAdapter.class); + if (adapter != null) { + String startTag = adapter.getStartTag(impl); + if (startTag != null) + return startTag; + } + + StringBuffer buffer = new StringBuffer(); + + if (impl.isCommentTag()) { + if (impl.isJSPTag()) + buffer.append(JSPTag.COMMENT_OPEN); + else + buffer.append(COMMENT_OPEN); + String tagName = generateTagName(element); + if (tagName != null) + buffer.append(tagName); + } else if (impl.isJSPTag()) { + buffer.append(JSPTag.TAG_OPEN); + String tagName = generateTagName(element); + if (tagName != null) + buffer.append(tagName); + if (impl.isContainer()) + return buffer.toString(); // JSP container + } else { + buffer.append('<'); + String tagName = generateTagName(element); + if (tagName != null) + buffer.append(tagName); + } + + NamedNodeMap attributes = element.getAttributes(); + int length = attributes.getLength(); + for (int i = 0; i < length; i++) { + AttrImpl attr = (AttrImpl) attributes.item(i); + if (attr == null) + continue; + buffer.append(' '); + String attrName = generateAttrName(attr); + if (attrName != null) + buffer.append(attrName); + String attrValue = generateAttrValue(attr); + if (attrValue != null) { + // attr name only for HTML boolean and JSP + buffer.append('='); + buffer.append(attrValue); + } + } + + String closeTag = generateCloseTag(element); + if (closeTag != null) + buffer.append(closeTag); + + return buffer.toString(); + } + + /** + */ + public String generateTagName(Element element) { + if (element == null) + return null; + XMLElement xe = (XMLElement) element; + String tagName = element.getTagName(); + if (tagName == null) + return null; + if (xe.isJSPTag()) { + if (tagName.equals(JSPTag.JSP_EXPRESSION)) + return JSPTag.EXPRESSION_TOKEN; + if (tagName.equals(JSPTag.JSP_DECLARATION)) + return JSPTag.DECLARATION_TOKEN; + if (tagName.equals(JSPTag.JSP_DIRECTIVE)) + return JSPTag.DIRECTIVE_TOKEN; + if (tagName.startsWith(JSPTag.JSP_DIRECTIVE)) { + int offset = JSPTag.JSP_DIRECTIVE.length() + 1; // after '.' + return (JSPTag.DIRECTIVE_TOKEN + tagName.substring(offset)); + } + return (xe.isCommentTag()) ? tagName : null; + } else if (tagName.startsWith(JSPTag.TAG_OPEN)) { + if (!tagName.endsWith(JSPTag.TAG_CLOSE)) { + // close JSP + return (tagName + JSPTag.TAG_CLOSE); + } + } else if (xe.isCommentTag()) { + String prefix = element.getPrefix(); + if (prefix.equals(SSI_PREFIX)) { + return (SSI_TOKEN + element.getLocalName()); + } + } else { + if (!xe.isJSPTag() && xe.isGlobalTag() && // global tag + CMNodeUtil.getElementDeclaration(xe) != null) { + String newName = tagName; + switch (getTagNameCase(xe)) { + case DocumentTypeAdapter.UPPER_CASE : + newName = tagName.toUpperCase(); + break; + case DocumentTypeAdapter.LOWER_CASE : + newName = tagName.toLowerCase(); + break; + } + if (newName != tagName) { + tagName = newName; + setTagName(element, tagName); + } + } + } + return tagName; + } + + /** + * generateText method + * + * @return java.lang.String + * @param text + * org.w3c.dom.Text + */ + public String generateText(Text text) { + if (text == null) + return null; + TextImpl impl = (TextImpl) text; + String source = impl.getTextSource(); + if (source != null) + return source; + return generateTextData(text, impl.getData()); + } + + /** + */ + public String generateTextData(Text text, String data) { + if (data == null) + return null; + if (text == null) + return null; + TextImpl impl = (TextImpl) text; + if (impl.isJSPContent() || impl.isCDATAContent()) { + return new SourceValidator(impl).convertSource(data); + } + String source = data; + + // convert special characters to character entities + StringBuffer buffer = null; + int offset = 0; + int length = data.length(); + for (int i = 0; i < length; i++) { + String name = getCharName(data.charAt(i)); + if (name == null) + continue; + if (buffer == null) + buffer = new StringBuffer(length + 8); + if (i > offset) + buffer.append(data.substring(offset, i)); + buffer.append('&'); + buffer.append(name); + buffer.append(';'); + offset = i + 1; + } + if (buffer != null) { + if (length > offset) + buffer.append(data.substring(offset)); + source = buffer.toString(); + } + + if (source == null || source.length() == 0) + return null; + return source; + } + + /** + */ + private int getAttrNameCase(Attr attr) { + DocumentImpl document = (DocumentImpl) attr.getOwnerDocument(); + if (document == null) + return DocumentTypeAdapter.STRICT_CASE; + DocumentTypeAdapter adapter = document.getDocumentTypeAdapter(); + if (adapter == null) + return DocumentTypeAdapter.STRICT_CASE; + return adapter.getAttrNameCase(); + } + + /** + */ + private String getCharName(char c) { + switch (c) { + case '<' : + return XMLCharEntity.LT_NAME; + case '>' : + return XMLCharEntity.GT_NAME; + case '&' : + return XMLCharEntity.AMP_NAME; + case '"' : + return XMLCharEntity.QUOT_NAME; + } + return null; + } + + /** + */ + private int getTagNameCase(Element element) { + DocumentImpl document = (DocumentImpl) element.getOwnerDocument(); + if (document == null) + return DocumentTypeAdapter.STRICT_CASE; + DocumentTypeAdapter adapter = document.getDocumentTypeAdapter(); + if (adapter == null) + return DocumentTypeAdapter.STRICT_CASE; + return adapter.getTagNameCase(); + } + + /** + */ + private boolean isBooleanAttr(Attr attr) { + if (attr == null) + return false; + CMAttributeDeclaration decl = CMNodeUtil.getAttributeDeclaration(attr); + if (decl == null) + return false; + CMDataType type = decl.getAttrType(); + if (type == null) + return false; + String values[] = type.getEnumeratedValues(); + if (values == null) + return false; + return (values.length == 1 && values[0].equals(decl.getAttrName())); + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLModelContext.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLModelContext.java new file mode 100644 index 0000000000..6a799f75f4 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLModelContext.java @@ -0,0 +1,237 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.document; + + + +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.Text; + +/** + * XMLModelContext class + */ +class XMLModelContext { + private Node nextNode = null; + private Node parentNode = null; + + // private XMLModelImpl model = null; + private Node rootNode = null; + + /** + * XMLModelContext constructor + * + * @param rootNode + * org.w3c.dom.Node + */ + XMLModelContext(Node rootNode) { + super(); + + this.rootNode = rootNode; + } + + /** + * findEndTag method + * + * @return org.w3c.dom.Element + * @param tagName + * java.lang.String + */ + Element findEndTag(String tagName) { + if (tagName == null) + return null; + if (this.parentNode == null) + return null; + + for (Node parent = this.parentNode.getParentNode(); parent != null; parent = parent.getParentNode()) { + if (parent.getNodeType() != Node.ELEMENT_NODE) + break; + ElementImpl element = (ElementImpl) parent; + if (element.hasEndTag()) { + if (element.matchTagName(tagName)) + return element; + // if ancestor element has end tag stop search + break; + } + if (element.getNextSibling() != null) + break; + } + + return null; + } + + /** + */ + Text findNextText() { + Node node = this.nextNode; + while (node != null) { + if (node != this.nextNode && node.getNodeType() == Node.TEXT_NODE) { + TextImpl text = (TextImpl) node; + // skip empty text + if (text.getStructuredDocumentRegion() != null) + return text; + } + Node child = node.getFirstChild(); + if (child != null) { + node = child; + continue; + } + while (node != null) { + Node next = node.getNextSibling(); + if (next != null) { + node = next; + break; + } + node = node.getParentNode(); + } + } + return null; + } + + /** + * findPreviousText method + * + * @return org.w3c.dom.Text + */ + Text findPreviousText() { + if (this.parentNode == null) + return null; + Node node = null; + if (this.nextNode != null) + node = this.nextNode.getPreviousSibling(); + else + node = this.parentNode.getLastChild(); + if (node == null || node.getNodeType() != Node.TEXT_NODE) + return null; + return (Text) node; + } + + /** + * findStartTag method + * + * @return org.w3c.dom.Element + * @param tagName + * java.lang.String + */ + Element findStartTag(String tagName, String rootName) { + if (tagName == null) + return null; + + // check previous for empty content element + Node prev = null; + if (this.nextNode != null) + prev = this.nextNode.getPreviousSibling(); + else if (this.parentNode != null) + prev = this.parentNode.getLastChild(); + if (prev != null && prev.getNodeType() == Node.ELEMENT_NODE) { + ElementImpl element = (ElementImpl) prev; + if (!element.hasEndTag() && !element.isEmptyTag() && element.matchTagName(tagName)) + return element; + } + + for (Node parent = this.parentNode; parent != null; parent = parent.getParentNode()) { + if (parent.getNodeType() != Node.ELEMENT_NODE) + break; + ElementImpl element = (ElementImpl) parent; + if (element.matchTagName(tagName)) + return element; + if (rootName != null && element.matchTagName(rootName)) + break; + } + + return null; + } + + /** + * getNextNode method + * + * @return org.w3c.dom.Node + */ + Node getNextNode() { + return this.nextNode; + } + + /** + * getParentNode method + * + * @return org.w3c.dom.Node + */ + Node getParentNode() { + return this.parentNode; + } + + /** + * getRootNode method + * + * @return org.w3c.dom.Node + */ + Node getRootNode() { + return this.rootNode; + } + + /** + * setLast method + */ + void setLast() { + if (this.parentNode == null) + return; + if (this.nextNode != null) { + Node prev = this.nextNode.getPreviousSibling(); + if (prev == null || prev.getNodeType() != Node.ELEMENT_NODE) + return; + ElementImpl element = (ElementImpl) prev; + if (element.hasEndTag() || !element.isContainer() || element.isEmptyTag()) + return; + setParentNode(prev); + } + + // find last open parent + Node parent = this.parentNode; + Node last = parent.getLastChild(); + while (last != null) { + if (last.getNodeType() != Node.ELEMENT_NODE) + break; + ElementImpl element = (ElementImpl) last; + if (element.hasEndTag() || !element.isContainer() || element.isEmptyTag()) + break; + parent = element; + last = parent.getLastChild(); + } + if (parent != this.parentNode) + setParentNode(parent); + } + + /** + * setNextNode method + * + * @param nextNode + * org.w3c.dom.Node + */ + void setNextNode(Node nextNode) { + this.nextNode = nextNode; + if (nextNode == null) + return; + this.parentNode = nextNode.getParentNode(); + } + + /** + * setParentNode method + * + * @param parentNode + * org.w3c.dom.Node + */ + void setParentNode(Node parentNode) { + this.parentNode = parentNode; + this.nextNode = null; + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLModelImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLModelImpl.java new file mode 100644 index 0000000000..640a164113 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLModelImpl.java @@ -0,0 +1,875 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.document; + +import org.eclipse.wst.sse.core.AbstractStructuredModel; +import org.eclipse.wst.sse.core.IndexedRegion; +import org.eclipse.wst.sse.core.events.IStructuredDocumentListener; +import org.eclipse.wst.sse.core.events.NewDocumentEvent; +import org.eclipse.wst.sse.core.events.NoChangeEvent; +import org.eclipse.wst.sse.core.events.RegionChangedEvent; +import org.eclipse.wst.sse.core.events.RegionsReplacedEvent; +import org.eclipse.wst.sse.core.events.StructuredDocumentRegionsReplacedEvent; +import org.eclipse.wst.sse.core.text.IStructuredDocument; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegionList; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.core.text.ITextRegionList; +import org.eclipse.wst.xml.core.Logger; +import org.eclipse.wst.xml.core.document.XMLDocument; +import org.eclipse.wst.xml.core.document.XMLGenerator; +import org.eclipse.wst.xml.core.document.XMLModel; +import org.eclipse.wst.xml.core.document.XMLModelNotifier; +import org.eclipse.wst.xml.core.document.XMLNode; +import org.w3c.dom.Attr; +import org.w3c.dom.DOMException; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + + +/** + * XMLModelImpl class + */ +public class XMLModelImpl extends AbstractStructuredModel implements IStructuredDocumentListener, XMLModel, DOMImplementation { + private static String TRACE_PARSER_MANAGEMENT_EXCEPTION = "parserManagement"; //$NON-NLS-1$ + private Object active = null; + protected DocumentImpl document = null; + private XMLGenerator generator = null; + private XMLModelNotifier notifier = null; + private XMLModelParser parser = null; + private boolean refresh = false; + private XMLModelUpdater updater = null; + + /** + * XMLModelImpl constructor + */ + public XMLModelImpl() { + super(); + this.document = (DocumentImpl) internalCreateDocument(); + } + + /** + * This API allows clients to declare that they are about to make a + * "large" change to the model. This change might be in terms of content + * or it might be in terms of the model id or base location. + * + * Note that in the case of embedded calls, notification to listners is + * sent only once. + * + * Note that the client who is making these changes has the responsibility + * to restore the models state once finished with the changes. See + * getMemento and restoreState. + * + * The method isModelStateChanging can be used by a client to determine if + * the model is already in a change sequence. + */ + public void aboutToChangeModel() { + super.aboutToChangeModel(); + // technically, no need to call beginChanging so often, + // since aboutToChangeModel can be nested. + // but will leave as is for this release. + // see modelChanged, and be sure stays coordinated there. + getModelNotifier().beginChanging(); + } + + public void aboutToReinitializeModel() { + XMLModelNotifier notifier = getModelNotifier(); + notifier.cancelPending(); + super.aboutToReinitializeModel(); + } + + /** + * attrReplaced method + * + * @param element + * org.w3c.dom.Element + * @param newAttr + * org.w3c.dom.Attr + * @param oldAttr + * org.w3c.dom.Attr + */ + protected void attrReplaced(Element element, Attr newAttr, Attr oldAttr) { + if (element == null) + return; + if (getActiveParser() == null) { + XMLModelUpdater updater = getModelUpdater(); + setActive(updater); + updater.initialize(); + updater.replaceAttr(element, newAttr, oldAttr); + setActive(null); + } + getModelNotifier().attrReplaced(element, newAttr, oldAttr); + } + + /** + * This API allows a client controlled way of notifying all ModelEvent + * listners that the model has been changed. This method is a matched pair + * to aboutToChangeModel, and must be called after aboutToChangeModel ... + * or some listeners could be left waiting indefinitely for the changed + * event. So, its suggested that changedModel always be in a finally + * clause. Likewise, a client should never call changedModel without + * calling aboutToChangeModel first. + * + * In the case of embedded calls, the notification is just sent once. + * + */ + public void changedModel() { + // NOTE: the order of 'changedModel' and 'endChanging' is significant. + // By calling changedModel first, this basically decrements the + // "isChanging" counter + // in super class and when zero all listeners to model state events + // will be notified + // that the model has been changed. 'endChanging' will notify all + // deferred adapters. + // So, the significance of order is that adapters (and methods they + // call) + // can count on the state of model "isChanging" to be accurate. + // But, remember, that this means the "modelChanged" event can be + // received before all + // adapters have finished their processing. + // NOTE NOTE: The above note is obsolete in fact (though still states + // issue correctly). + // Due to popular demand, the order of these calls were reversed and + // behavior + // changed on 07/22/2004. + // + // see also + // https://w3.opensource.ibm.com/bugzilla/show_bug.cgi?id=4302 + // for motivation for this 'on verge of' call. + // this could be improved in future if notifier also used counting + // flag to avoid nested calls. If/when changed be sure to check if + // aboutToChangeModel needs any changes too. + if (isModelChangeStateOnVergeOfEnding()) { + // end lock before noticiation loop, since directly or indirectly + // we may be "called from foriegn code" during notification. + endLock(); + + // the notifier is what controls adaper notification, which + // should be sent out before the 'modelChanged' event. + getModelNotifier().endChanging(); + } + // changedModel handles 'nesting', so only one event sent out + // when mulitple calls to 'aboutToChange/Changed'. + super.changedModel(); + handleRefresh(); + } + + /** + * childReplaced method + * + * @param parentNode + * org.w3c.dom.Node + * @param newChild + * org.w3c.dom.Node + * @param oldChild + * org.w3c.dom.Node + */ + protected void childReplaced(Node parentNode, Node newChild, Node oldChild) { + if (parentNode == null) + return; + if (getActiveParser() == null) { + XMLModelUpdater updater = getModelUpdater(); + setActive(updater); + updater.initialize(); + updater.replaceChild(parentNode, newChild, oldChild); + setActive(null); + } + getModelNotifier().childReplaced(parentNode, newChild, oldChild); + } + + /** + * Creates an XML <code>Document</code> object of the specified type + * with its document element. HTML-only DOM implementations do not need to + * implement this method. + * + * @param namespaceURIThe + * namespace URI of the document element to create. + * @param qualifiedNameThe + * qualified name of the document element to be created. + * @param doctypeThe + * type of document to be created or <code>null</code>. When + * <code>doctype</code> is not <code>null</code>, its + * <code>Node.ownerDocument</code> attribute is set to the + * document being created. + * @return A new <code>Document</code> object. + * @exception DOMException + * INVALID_CHARACTER_ERR: Raised if the specified qualified + * name contains an illegal character. <br> + * NAMESPACE_ERR: Raised if the <code>qualifiedName</code> + * is malformed, if the <code>qualifiedName</code> has a + * prefix and the <code>namespaceURI</code> is + * <code>null</code>, or if the + * <code>qualifiedName</code> has a prefix that is "xml" + * and the <code>namespaceURI</code> is different from " + * http://www.w3.org/XML/1998/namespace" .<br> + * WRONG_DOCUMENT_ERR: Raised if <code>doctype</code> has + * already been used with a different document or was + * created from a different implementation. + * @since DOM Level 2 + */ + public Document createDocument(String namespaceURI, String qualifiedName, DocumentType doctype) throws DOMException { + return null; + } + + /** + * Creates an empty <code>DocumentType</code> node. Entity declarations + * and notations are not made available. Entity reference expansions and + * default attribute additions do not occur. It is expected that a future + * version of the DOM will provide a way for populating a + * <code>DocumentType</code>.<br> + * HTML-only DOM implementations do not need to implement this method. + * + * @param qualifiedNameThe + * qualified name of the document type to be created. + * @param publicIdThe + * external subset public identifier. + * @param systemIdThe + * external subset system identifier. + * @return A new <code>DocumentType</code> node with + * <code>Node.ownerDocument</code> set to <code>null</code>. + * @exception DOMException + * INVALID_CHARACTER_ERR: Raised if the specified qualified + * name contains an illegal character. <br> + * NAMESPACE_ERR: Raised if the <code>qualifiedName</code> + * is malformed. + * @since DOM Level 2 + */ + public DocumentType createDocumentType(String qualifiedName, String publicId, String systemId) throws DOMException { + DocumentTypeImpl documentType = new DocumentTypeImpl(); + documentType.setName(qualifiedName); + documentType.setPublicId(publicId); + documentType.setSystemId(systemId); + return documentType; + } + + /** + */ + protected void documentTypeChanged() { + if (this.refresh) + return; + // unlike 'resfresh', 'reinitialize' finishes loop + // and flushes remaining notification que before + // actually reinitializing. + // FUTURE: perhaps all "handleRefresh" should be changed + // to "reinit needede"? + this.setReinitializeNeeded(true); + } + + protected void editableChanged(Node node) { + if (node != null) { + getModelNotifier().editableChanged(node); + } + } + + /** + */ + protected void endTagChanged(Element element) { + if (element == null) + return; + if (getActiveParser() == null) { + XMLModelUpdater updater = getModelUpdater(); + setActive(updater); + updater.initialize(); + updater.changeEndTag(element); + setActive(null); + } + getModelNotifier().endTagChanged(element); + } + + /** + */ + private XMLModelParser getActiveParser() { + if (this.parser == null) + return null; + if (this.parser != this.active) + return null; + return this.parser; + } + + /** + */ + private XMLModelUpdater getActiveUpdater() { + if (this.updater == null) + return null; + if (this.updater != this.active) + return null; + return this.updater; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class) + */ + public Object getAdapter(Class adapter) { + if (Document.class.equals(adapter)) + return getDocument(); + return super.getAdapter(adapter); + } + + /** + * getDocument method + * + * @return XMLDocument + */ + public XMLDocument getDocument() { + return this.document; + } + + public XMLGenerator getGenerator() { + if (this.generator == null) { + this.generator = XMLGeneratorImpl.getInstance(); + } + return this.generator; + } + + /** + * getNode method + * + * @param offset + * int + */ + public IndexedRegion getIndexedRegion(int offset) { + if (this.document == null) + return null; + // search in document children + XMLNode parent = null; + int length = this.document.getEndOffset(); + if (offset * 2 < length) { + // search from the first + XMLNode child = (XMLNode) this.document.getFirstChild(); + while (child != null) { + if (child.getEndOffset() <= offset) { + child = (XMLNode) child.getNextSibling(); + continue; + } + if (child.getStartOffset() > offset) { + break; + } + IStructuredDocumentRegion startStructuredDocumentRegion = child.getStartStructuredDocumentRegion(); + if (startStructuredDocumentRegion != null) { + if (startStructuredDocumentRegion.getEnd() > offset) + return child; + } + IStructuredDocumentRegion endStructuredDocumentRegion = child.getEndStructuredDocumentRegion(); + if (endStructuredDocumentRegion != null) { + if (endStructuredDocumentRegion.getStart() <= offset) + return child; + } + // dig more + parent = child; + child = (XMLNode) parent.getFirstChild(); + } + } else { + // search from the last + XMLNode child = (XMLNode) this.document.getLastChild(); + while (child != null) { + if (child.getStartOffset() > offset) { + child = (XMLNode) child.getPreviousSibling(); + continue; + } + if (child.getEndOffset() <= offset) { + break; + } + IStructuredDocumentRegion startStructuredDocumentRegion = child.getStartStructuredDocumentRegion(); + if (startStructuredDocumentRegion != null) { + if (startStructuredDocumentRegion.getEnd() > offset) + return child; + } + IStructuredDocumentRegion endStructuredDocumentRegion = child.getEndStructuredDocumentRegion(); + if (endStructuredDocumentRegion != null) { + if (endStructuredDocumentRegion.getStart() <= offset) + return child; + } + // dig more + parent = child; + child = (XMLNode) parent.getLastChild(); + } + } + return parent; + } + + /** + */ + public XMLModelNotifier getModelNotifier() { + if (this.notifier == null) { + this.notifier = new XMLModelNotifierImpl(); + } + return this.notifier; + } + + /** + */ + private XMLModelParser getModelParser() { + if (this.parser == null) { + this.parser = new XMLModelParser(this); + } + return this.parser; + } + + /** + */ + private XMLModelUpdater getModelUpdater() { + if (this.updater == null) { + this.updater = new XMLModelUpdater(this); + } + return this.updater; + } + + /** + */ + private void handleRefresh() { + if (!this.refresh) + return; + XMLModelNotifier notifier = getModelNotifier(); + boolean isChanging = notifier.isChanging(); + if (!isChanging) + notifier.beginChanging(true); + XMLModelParser parser = getModelParser(); + setActive(parser); + this.document.removeChildNodes(); + try { + parser.replaceStructuredDocumentRegions(getStructuredDocument().getRegionList(), null); + } catch (Exception ex) { + Logger.logException(ex); + } finally { + setActive(null); + if (!isChanging) + notifier.endChanging(); + this.refresh = false; + } + } + + /** + * Test if the DOM implementation implements a specific feature. + * + * @param featureThe + * name of the feature to test (case-insensitive). The values + * used by DOM features are defined throughout the DOM Level 2 + * specifications and listed in the section. The name must be + * an XML name. To avoid possible conflicts, as a convention, + * names referring to features defined outside the DOM + * specification should be made unique by reversing the name of + * the Internet domain name of the person (or the organization + * that the person belongs to) who defines the feature, + * component by component, and using this as a prefix. For + * instance, the W3C SVG Working Group defines the feature + * "org.w3c.dom.svg". + * @param versionThis + * is the version number of the feature to test. In Level 2, + * the string can be either "2.0" or "1.0". If the version is + * not specified, supporting any version of the feature causes + * the method to return <code>true</code>. + * @return <code>true</code> if the feature is implemented in the + * specified version, <code>false</code> otherwise. + */ + public boolean hasFeature(String feature, String version) { + if (feature == null) + return false; + if (version != null) { + if (!version.equals("1.0") && !version.equals("2.0")) { //$NON-NLS-2$//$NON-NLS-1$ + return false; + } + } + if (feature.equalsIgnoreCase("Core")) //$NON-NLS-1$ + return true; //$NON-NLS-1$ + if (feature.equalsIgnoreCase("XML")) //$NON-NLS-1$ + return true; //$NON-NLS-1$ + return false; + } + + /** + * createDocument method + * + * @return org.w3c.dom.Document + */ + protected Document internalCreateDocument() { + DocumentImpl document = new DocumentImpl(); + document.setModel(this); + return document; + } + + boolean isReparsing() { + return (active != null); + } + + /** + * nameChanged method + * + * @param node + * org.w3c.dom.Node + */ + protected void nameChanged(Node node) { + if (node == null) + return; + if (getActiveParser() == null) { + XMLModelUpdater updater = getModelUpdater(); + setActive(updater); + updater.initialize(); + updater.changeName(node); + setActive(null); + } + // notification is already sent + } + + /** + * newModel method + * + * @param structuredDocumentEvent + * com.ibm.sed.structuredDocument.impl.events.NewModelEvent + */ + public void newModel(NewDocumentEvent structuredDocumentEvent) { + if (structuredDocumentEvent == null) + return; + IStructuredDocument structuredDocument = structuredDocumentEvent.getStructuredDocument(); + if (structuredDocument == null) + return; + // this should not happen, but for the case + if (structuredDocument != getStructuredDocument()) + setStructuredDocument(structuredDocument); + IStructuredDocumentRegionList flatNodes = structuredDocument.getRegionList(); + if (flatNodes == null) + return; + if (this.document == null) + return; // being constructed + XMLModelUpdater updater = getActiveUpdater(); + if (updater != null) { // being updated + try { + updater.replaceStructuredDocumentRegions(flatNodes, null); + } catch (Exception ex) { + Logger.logException(ex); + this.refresh = true; + handleRefresh(); + } finally { + setActive(null); + } + // // for new model, we might need to + // // re-init, e.g. if someone calls setText + // // on an existing model + // checkForReinit(); + return; + } + XMLModelNotifier notifier = getModelNotifier(); + boolean isChanging = notifier.isChanging(); + // call even if changing to notify doing new model + getModelNotifier().beginChanging(true); + XMLModelParser parser = getModelParser(); + setActive(parser); + this.document.removeChildNodes(); + try { + parser.replaceStructuredDocumentRegions(flatNodes, null); + } catch (Exception ex) { + Logger.logException(ex); + // meaningless to refresh, because the result might be the same + } finally { + setActive(null); + if (!isChanging) { + getModelNotifier().endChanging(); + } + // ignore refresh + this.refresh = false; + } + // checkForReinit(); + } + + /** + */ + public void noChange(NoChangeEvent event) { + XMLModelUpdater updater = getActiveUpdater(); + if (updater != null) { // being updated + // cleanup updater staffs + try { + updater.replaceStructuredDocumentRegions(null, null); + } catch (Exception ex) { + Logger.logException(ex); + this.refresh = true; + handleRefresh(); + } finally { + setActive(null); + } + // I guess no chanage means the model could not need re-init + //checkForReinit(); + return; + } + } + + /** + * nodesReplaced method + * + * @param event + * com.ibm.sed.structuredDocument.impl.events.NodesReplacedElement + */ + public void nodesReplaced(StructuredDocumentRegionsReplacedEvent event) { + if (event == null) + return; + IStructuredDocumentRegionList oldStructuredDocumentRegions = event.getOldStructuredDocumentRegions(); + IStructuredDocumentRegionList newStructuredDocumentRegions = event.getNewStructuredDocumentRegions(); + XMLModelUpdater updater = getActiveUpdater(); + if (updater != null) { // being updated + try { + updater.replaceStructuredDocumentRegions(newStructuredDocumentRegions, oldStructuredDocumentRegions); + } catch (Exception ex) { + if (ex.getClass().equals(StructuredDocumentRegionManagementException.class)) { + Logger.traceException(TRACE_PARSER_MANAGEMENT_EXCEPTION, ex); + } else { + Logger.logException(ex); + } + this.refresh = true; + handleRefresh(); + } finally { + setActive(null); + } + //checkForReinit(); + return; + } + XMLModelNotifier notifier = getModelNotifier(); + boolean isChanging = notifier.isChanging(); + if (!isChanging) + notifier.beginChanging(); + XMLModelParser parser = getModelParser(); + setActive(parser); + try { + parser.replaceStructuredDocumentRegions(newStructuredDocumentRegions, oldStructuredDocumentRegions); + } catch (Exception ex) { + Logger.logException(ex); + this.refresh = true; + handleRefresh(); + } finally { + setActive(null); + if (!isChanging) { + notifier.endChanging(); + handleRefresh(); + } + } + + } + + /** + * regionChanged method + * + * @param structuredDocumentEvent + * com.ibm.sed.structuredDocument.impl.events.RegionChangedEvent + */ + public void regionChanged(RegionChangedEvent event) { + if (event == null) + return; + IStructuredDocumentRegion flatNode = event.getStructuredDocumentRegion(); + if (flatNode == null) + return; + ITextRegion region = event.getRegion(); + if (region == null) + return; + XMLModelUpdater updater = getActiveUpdater(); + if (updater != null) { // being updated + try { + updater.changeRegion(flatNode, region); + } catch (Exception ex) { + Logger.logException(ex); + this.refresh = true; + handleRefresh(); + } finally { + setActive(null); + } + // checkForReinit(); + return; + } + XMLModelNotifier notifier = getModelNotifier(); + boolean isChanging = notifier.isChanging(); + if (!isChanging) + notifier.beginChanging(); + XMLModelParser parser = getModelParser(); + setActive(parser); + try { + parser.changeRegion(flatNode, region); + } catch (Exception ex) { + Logger.logException(ex); + this.refresh = true; + handleRefresh(); + } finally { + setActive(null); + if (!isChanging) { + notifier.endChanging(); + handleRefresh(); + } + } + // checkForReinit(); + } + + /** + * regionsReplaced method + * + * @param event + * com.ibm.sed.structuredDocument.impl.events.RegionReplacedEvent + */ + public void regionsReplaced(RegionsReplacedEvent event) { + if (event == null) + return; + IStructuredDocumentRegion flatNode = event.getStructuredDocumentRegion(); + if (flatNode == null) + return; + ITextRegionList oldRegions = event.getOldRegions(); + ITextRegionList newRegions = event.getNewRegions(); + if (oldRegions == null && newRegions == null) + return; + XMLModelUpdater updater = getActiveUpdater(); + if (updater != null) { // being updated + try { + updater.replaceRegions(flatNode, newRegions, oldRegions); + } catch (Exception ex) { + Logger.logException(ex); + this.refresh = true; + handleRefresh(); + } finally { + setActive(null); + } + // checkForReinit(); + return; + } + XMLModelNotifier notifier = getModelNotifier(); + boolean isChanging = notifier.isChanging(); + if (!isChanging) + notifier.beginChanging(); + XMLModelParser parser = getModelParser(); + setActive(parser); + try { + parser.replaceRegions(flatNode, newRegions, oldRegions); + } catch (Exception ex) { + Logger.logException(ex); + this.refresh = true; + handleRefresh(); + } finally { + setActive(null); + if (!isChanging) { + notifier.endChanging(); + handleRefresh(); + } + } + // checkForReinit(); + } + + /** + */ + public void releaseFromEdit() { + if (!isShared()) { + //this.document.releaseStyleSheets(); + this.document.releaseDocumentType(); + } + super.releaseFromEdit(); + } + + /** + */ + public void releaseFromRead() { + if (!isShared()) { + //this.document.releaseStyleSheets(); + this.document.releaseDocumentType(); + } + super.releaseFromRead(); + } + + /** + */ + private void setActive(Object active) { + this.active = active; + // side effect + // when ever becomes active, besure tagNameCache is cleared + // (and not used) + if (active == null) { + document.activateTagNameCache(true); + } else { + document.activateTagNameCache(false); + } + + } + + /** + */ + public void setGenerator(XMLGenerator generator) { + this.generator = generator; + } + + /** + */ + public void setModelNotifier(XMLModelNotifier notifier) { + this.notifier = notifier; + } + + /** + */ + public void setModelParser(XMLModelParser parser) { + this.parser = parser; + } + + /** + */ + public void setModelUpdater(XMLModelUpdater updater) { + this.updater = updater; + } + + /** + * setStructuredDocument method + * + * @param structuredDocument + * com.ibm.sed.structuredDocument.IStructuredDocument + */ + public void setStructuredDocument(IStructuredDocument structuredDocument) { + IStructuredDocument oldStructuredDocument = super.getStructuredDocument(); + if (structuredDocument == oldStructuredDocument) + return; // nothing to do + if (oldStructuredDocument != null) + oldStructuredDocument.removeDocumentChangingListener(this); + super.setStructuredDocument(structuredDocument); + if (structuredDocument.getLength() > 0) { + newModel(new NewDocumentEvent(structuredDocument, this)); + } + if (structuredDocument != null) + structuredDocument.addDocumentChangingListener(this); + } + + /** + */ + protected void startTagChanged(Element element) { + if (element == null) + return; + if (getActiveParser() == null) { + XMLModelUpdater updater = getModelUpdater(); + setActive(updater); + updater.initialize(); + updater.changeStartTag(element); + setActive(null); + } + getModelNotifier().startTagChanged(element); + } + + /** + * valueChanged method + * + * @param node + * org.w3c.dom.Node + */ + protected void valueChanged(Node node) { + if (node == null) + return; + if (getActiveParser() == null) { + XMLModelUpdater updater = getModelUpdater(); + setActive(updater); + updater.initialize(); + updater.changeValue(node); + setActive(null); + } + getModelNotifier().valueChanged(node); + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLModelNotifierImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLModelNotifierImpl.java new file mode 100644 index 0000000000..4146e0c5af --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLModelNotifierImpl.java @@ -0,0 +1,469 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.document; + +import java.util.Iterator; +import java.util.Vector; + +import org.eclipse.wst.sse.core.INodeNotifier; +import org.eclipse.wst.sse.core.util.Debug; +import org.eclipse.wst.xml.core.Logger; +import org.eclipse.wst.xml.core.document.XMLModelNotifier; +import org.eclipse.wst.xml.core.document.XMLNode; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + + +public class XMLModelNotifierImpl implements XMLModelNotifier { + + /* end: for debugging only */ + private class NotifyEvent { + Object changedFeature; + boolean discarded; + Object newValue; + // note: don't initialize instance variables, since + // that causes double assignments, and lots of these are created. + INodeNotifier notifier; + Object oldValue; + int pos; + String reason; + int type; + + NotifyEvent(INodeNotifier notifier, int type, Object changedFeature, Object oldValue, Object newValue, int pos) { + this.notifier = notifier; + this.type = type; + this.changedFeature = changedFeature; + this.oldValue = oldValue; + this.newValue = newValue; + this.pos = pos; + this.reason = ""; //$NON-NLS-1$ + } + } + + private final static String ADDED_THEN_REMOVED = "Discard: Added then removed rule"; //$NON-NLS-1$ + private final static boolean fOptimizeDeferred = true; + private final static boolean fOptimizeDeferredAccordingToParentAdded = true; + private final static boolean fOptimizeDeferredAccordingToParentRemoved = true; + private final static String PARENT_IS_ADDED = "Disarded: Parent has just been added"; //$NON-NLS-1$ + /* start: for debugging only */ + private final static String PARENT_IS_REMOVED_TOO = "Discard: Parent was removed too"; //$NON-NLS-1$ + private final static String PARENT_IS_REPARENTED = "Not Discard: Parent was removed so this implies reparenting"; //$NON-NLS-1$ + private Node changedRoot = null; + + private boolean changing = false; + private boolean doingNewModel = false; + private Vector events = null; + private boolean flushing = false; + + /** + */ + public XMLModelNotifierImpl() { + super(); + } + + /** + * attrReplaced method + * + * @param element + * org.w3c.dom.Element + * @param newAttr + * org.w3c.dom.Attr + * @param oldAttr + * org.w3c.dom.Attr + */ + public void attrReplaced(Element element, Attr newAttr, Attr oldAttr) { + if (element == null) + return; + Attr attr = null; + String oldValue = null; + String newValue = null; + if (oldAttr != null) { + attr = oldAttr; + oldValue = oldAttr.getValue(); + } + if (newAttr != null) { + attr = newAttr; + newValue = newAttr.getValue(); + } + XMLNode notifier = (XMLNode) element; + int offset = notifier.getStartOffset(); + notify(notifier, INodeNotifier.CHANGE, attr, oldValue, newValue, offset); + propertyChanged(notifier); + } + + /** + */ + public void beginChanging() { + this.changing = true; + } + + /** + */ + public void beginChanging(boolean newModel) { + beginChanging(); + this.doingNewModel = newModel; + } + + /** + * @see com.ibm.sed.model.xml.XMLModelNotifier#cancelPending() + */ + public void cancelPending() { + // we don't want to change the size of this array, since + // the array may be being processed, in the defferred notification + // loop, but we can signal that all + // should be discarded, so any remaining ones will be ignored. + if (this.events != null) { + Iterator iterator = this.events.iterator(); + while (iterator.hasNext()) { + NotifyEvent event = (NotifyEvent) iterator.next(); + event.discarded = true; + } + } + // this cancel is presumably being called as a function of + // "reinitiailization" so we can ignore changes to the + // old root, and changes to the new one will be triggered during + // reinitialization. + changedRoot = null; + } + + /** + * childReplaced method + * + * @param parentNode + * org.w3c.dom.Node + * @param newChild + * org.w3c.dom.Node + * @param oldChild + * org.w3c.dom.Node + */ + public void childReplaced(Node parentNode, Node newChild, Node oldChild) { + if (parentNode == null) + return; + XMLNode notifier = (XMLNode) parentNode; + int type = INodeNotifier.CHANGE; + if (newChild == null) + type = INodeNotifier.REMOVE; + else if (oldChild == null) + type = INodeNotifier.ADD; + int offset = notifier.getStartOffset(); + notify(notifier, type, oldChild, oldChild, newChild, offset); + structureChanged(notifier); + } + + public void editableChanged(Node node) { + if (node == null) + return; + XMLNode notifier = (XMLNode) node; + int offset = notifier.getStartOffset(); + notify(notifier, INodeNotifier.CHANGE, null, null, null, offset); + propertyChanged(notifier); + } + + /** + */ + public void endChanging() { + this.doingNewModel = false; + if (!this.changing) + return; // avoid nesting calls + notifyDeferred(); + if (this.changedRoot != null) { + notifyStructureChanged(this.changedRoot); + if (Debug.debugNotifyDeferred) { + String p = this.changedRoot.getNodeName(); + System.out.println("Deferred STRUCUTRE_CHANGED: " + p); //$NON-NLS-1$ + } + this.changedRoot = null; + } + this.changing = false; + } + + /** + */ + public void endTagChanged(Element element) { + if (element == null) + return; + XMLNode notifier = (XMLNode) element; + int offset = notifier.getStartOffset(); + notify(notifier, INodeNotifier.CHANGE, null, null, null, offset); + propertyChanged(element); + } + + /** + */ + public boolean hasChanged() { + return (this.events != null); + } + + /** + */ + public boolean isChanging() { + return this.changing; + } + + /** + */ + private void notify(INodeNotifier notifier, int eventType, Object changedFeature, Object oldValue, Object newValue, int pos) { + if (notifier == null) + return; + if (this.changing && !this.flushing) { + // defer notification + if (this.events == null) + this.events = new Vector(); + // we do not defer anything if we are doing a new Model, + // except for the document event, since all others are + // trivial and not needed at that initial point. + // But even for that one document event, in the new model case, + // it is still important to defer it. + if ((!doingNewModel) || (((Node) notifier).getNodeType() == Node.DOCUMENT_NODE)) { + this.events.addElement(new NotifyEvent(notifier, eventType, changedFeature, oldValue, newValue, pos)); + } + return; + } + try { + // Its important to "keep going" if exception occurs, since this + // notification + // comes in between "about to change" and "changed" events. We do + // log, however, + // since would indicate a program error. + notifier.notify(eventType, changedFeature, oldValue, newValue, pos); + } catch (Exception e) { + Logger.logException("A structured model client threw following exception during adapter notification (" + INodeNotifier.EVENT_TYPE_STRINGS[eventType] + " )", e); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + + /** + */ + private void notifyDeferred() { + if (this.events == null) + return; + if (this.flushing) + return; + this.flushing = true; // force notification + int count = this.events.size(); + for (int i = 0; i < count; i++) { + NotifyEvent event = (NotifyEvent) this.events.elementAt(i); + if (event == null) + continue; // error + if (event.discarded) + continue; + if (!doingNewModel && fOptimizeDeferred) { + // check redundant events (no need to check if doing NewModel, + // since + // shouldn't be redunancies) + if (event.type == INodeNotifier.ADD) { + for (int n = i + 1; n < count; n++) { + NotifyEvent next = (NotifyEvent) this.events.elementAt(n); + if (next == null) + continue; // error + if (next.type == INodeNotifier.REMOVE && next.oldValue == event.newValue) { + // Added then removed later, discard both + event.discarded = true; + next.discarded = true; + if (Debug.debugNotifyDeferred) { + event.reason = event.reason + ADDED_THEN_REMOVED + "(see " + n + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + next.reason = next.reason + ADDED_THEN_REMOVED + "(see " + i + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + } + break; + } + } + if (event.discarded) + continue; + if (fOptimizeDeferredAccordingToParentAdded) { + for (int p = 0; p < i; p++) { + NotifyEvent prev = (NotifyEvent) this.events.elementAt(p); + if (prev == null) + continue; // error + if (prev.type == INodeNotifier.REMOVE && prev.oldValue == event.notifier) { + // parent is reparented, do not discard + if (Debug.debugNotifyDeferred) { + event.reason = event.reason + PARENT_IS_REPARENTED + "(see " + p + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + } + break; + } else if (prev.type == INodeNotifier.ADD && prev.newValue == event.notifier) { + // parent has been added, discard this + event.discarded = true; + if (Debug.debugNotifyDeferred) { + event.reason = event.reason + PARENT_IS_ADDED + "(see " + p + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + } + break; + } + } + if (event.discarded) + continue; + } + } else if (event.type == INodeNotifier.REMOVE) { + if (fOptimizeDeferredAccordingToParentRemoved) { + for (int n = i + 1; n < count; n++) { + NotifyEvent next = (NotifyEvent) this.events.elementAt(n); + if (next == null) + continue; // error + if (next.type == INodeNotifier.REMOVE) { + if (next.oldValue == event.notifier) { + // parent will be removed, discard this + event.discarded = true; + if (Debug.debugNotifyDeferred) { + event.reason = event.reason + PARENT_IS_REMOVED_TOO + "(see " + n + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + } + break; + } + } + } + if (event.discarded) + continue; + } + } + } + notify(event.notifier, event.type, event.changedFeature, event.oldValue, event.newValue, event.pos); + } + if (Debug.debugNotifyDeferred) { + for (int l = 0; l < count; l++) { + NotifyEvent event = (NotifyEvent) this.events.elementAt(l); + Object o = null; + String t = null; + if (event.type == INodeNotifier.ADD) { + o = event.newValue; + t = " + "; //$NON-NLS-1$ + } else if (event.type == INodeNotifier.REMOVE) { + o = event.oldValue; + t = " - "; //$NON-NLS-1$ + } + if (o instanceof Element) { + String p = ((Node) event.notifier).getNodeName(); + String c = ((Node) o).getNodeName(); + String d = (event.discarded ? "! " : " "); //$NON-NLS-1$ //$NON-NLS-2$ + System.out.println(d + p + t + c); + } + } + } + this.flushing = false; + this.events = null; + } + + /** + */ + private void notifyStructureChanged(Node root) { + if (root == null) + return; + INodeNotifier notifier = (INodeNotifier) root; + try { + // Its important to "keep going" if exception occurs, since this + // notification + // comes in between "about to change" and "changed" events. We do + // log, however, + // since would indicate a program error. + notifier.notify(INodeNotifier.STRUCTURE_CHANGED, null, null, null, -1); + } catch (Exception e) { + Logger.logException("A structured model client threw following exception during adapter notification (" + INodeNotifier.EVENT_TYPE_STRINGS[INodeNotifier.STRUCTURE_CHANGED] + " )", e); //$NON-NLS-1$ //$NON-NLS-2$ + } + + } + + /** + */ + public void propertyChanged(Node node) { + } + + /** + * @param node + */ + private void setCommonRootIfNeeded(Node node) { + // defer notification + if (this.changedRoot == null) { + this.changedRoot = node; + } else { + // tiny optimization: if previous commonAncestor (changedRoot) is + // already 'document', + // or if already equal to this 'node', + // then no need to re-calculate + if (changedRoot.getNodeType() != Node.DOCUMENT_NODE && changedRoot != node) { + Node common = ((NodeImpl) this.changedRoot).getCommonAncestor(node); + if (common != null) + this.changedRoot = common; + else + this.changedRoot = node; + } + } + } + + /** + */ + public void startTagChanged(Element element) { + if (element == null) + return; + XMLNode notifier = (XMLNode) element; + int offset = notifier.getStartOffset(); + notify(notifier, INodeNotifier.CHANGE, null, null, null, offset); + propertyChanged(element); + } + + /** + */ + public void structureChanged(Node node) { + if (node == null) + return; + if (isChanging()) { + setCommonRootIfNeeded(node); + if (Debug.debugNotifyDeferred) { + String p = this.changedRoot.getNodeName(); + System.out.println("requested STRUCUTRE_CHANGED: " + p); //$NON-NLS-1$ + } + return; + } + if (Debug.debugNotifyDeferred) { + String p = node.getNodeName(); + System.out.println("STRUCUTRE_CHANGED: " + p); //$NON-NLS-1$ + } + notifyStructureChanged(node); + } + + /** + * valueChanged method + * + * @param node + * org.w3c.dom.Node + */ + public void valueChanged(Node node) { + if (node == null) + return; + XMLNode notifier = null; + if (node.getNodeType() == Node.ATTRIBUTE_NODE) { + Attr attr = (Attr) node; + notifier = (XMLNode) attr.getOwnerElement(); + // TODO_dmw: experimental: changed 06/29/2004 to send "strucuture + // changed" even for attribute value changes + // there are pros and cons to considering attribute value + // "structure changed". Will (re)consider + // setCommonRootIfNeeded(notifier); + if (notifier == null) + return; + String value = attr.getValue(); + int offset = notifier.getStartOffset(); + notify(notifier, INodeNotifier.CHANGE, attr, null, value, offset); + } else { + // note: we do not send structured changed event for content + // changed + notifier = (XMLNode) node; + String value = node.getNodeValue(); + int offset = notifier.getStartOffset(); + notify(notifier, INodeNotifier.CHANGE, null, null, value, offset); + if (node.getNodeType() != Node.ELEMENT_NODE) { + XMLNode parent = (XMLNode) node.getParentNode(); + if (parent != null) { + notify(parent, INodeNotifier.CONTENT_CHANGED, node, null, value, offset); + } + } + } + propertyChanged(notifier); + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLModelParser.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLModelParser.java new file mode 100644 index 0000000000..7d64743d9a --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLModelParser.java @@ -0,0 +1,2365 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.document; + + + +import java.util.Enumeration; +import java.util.Iterator; +import java.util.Vector; + +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegionList; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.core.text.ITextRegionList; +import org.eclipse.wst.xml.core.commentelement.impl.CommentElementConfiguration; +import org.eclipse.wst.xml.core.commentelement.impl.CommentElementRegistry; +import org.eclipse.wst.xml.core.document.JSPTag; +import org.eclipse.wst.xml.core.document.XMLDocument; +import org.eclipse.wst.xml.core.document.XMLElement; +import org.eclipse.wst.xml.core.document.XMLModel; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; +import org.w3c.dom.Attr; +import org.w3c.dom.DOMException; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.Text; + + +/** + * XMLModelParser + */ +public class XMLModelParser implements org.eclipse.wst.xml.core.jsp.model.parser.temp.XMLJSPRegionContexts { + private ModelParserAdapter adapter = null; + private XMLModelContext context = null; + private DocumentImpl document = null; + + private XMLModelImpl model = null; + + /** + */ + protected XMLModelParser(XMLModelImpl model) { + super(); + + if (model != null) { + this.model = model; + this.document = (DocumentImpl) model.getDocument(); + if (this.document != null) { + this.adapter = (ModelParserAdapter) this.document.getAdapterFor(ModelParserAdapter.class); + } + } + } + + /** + */ + protected boolean canBeImplicitTag(Element element) { + if (this.adapter != null) { + return this.adapter.canBeImplicitTag(element); + } + return false; + } + + /** + */ + protected boolean canBeImplicitTag(Element element, Node child) { + if (this.adapter != null) { + return this.adapter.canBeImplicitTag(element, child); + } + return false; + } + + /** + */ + protected boolean canContain(Element element, Node child) { + if (element == null || child == null) + return false; + ElementImpl impl = (ElementImpl) element; + if (impl.isEndTag()) + return false; // invalid (floating) end tag + if (!impl.isContainer()) + return false; + if (child.getNodeType() != Node.TEXT_NODE) { + if (impl.isJSPContainer() || impl.isCDATAContainer()) { + // accepts only Text child + return false; + } + } + if (this.adapter != null) { + return this.adapter.canContain(element, child); + } + return true; + } + + /** + */ + private void changeAttrEqual(IStructuredDocumentRegion flatNode, ITextRegion region) { + int offset = flatNode.getStart(); + if (offset < 0) + return; + NodeImpl root = (NodeImpl) this.context.getRootNode(); + if (root == null) + return; + Node node = root.getNodeAt(offset); + if (node == null) + return; + if (node.getNodeType() != Node.ELEMENT_NODE) { + if (node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) { + // just notify the change instead of setting data + ProcessingInstructionImpl pi = (ProcessingInstructionImpl) node; + pi.notifyValueChanged(); + } + return; + } + // actually, do nothing + } + + /** + * changeAttrName method + * + * @param flatNode + * com.ibm.sed.structuredDocument.IStructuredDocumentRegion + * @param region + * com.ibm.sed.structuredDocument.ITextRegion + */ + private void changeAttrName(IStructuredDocumentRegion flatNode, ITextRegion region) { + int offset = flatNode.getStart(); + if (offset < 0) + return; + NodeImpl root = (NodeImpl) this.context.getRootNode(); + if (root == null) + return; + Node node = root.getNodeAt(offset); + if (node == null) + return; + if (node.getNodeType() != Node.ELEMENT_NODE) { + if (node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) { + // just notify the change instead of setting data + ProcessingInstructionImpl pi = (ProcessingInstructionImpl) node; + pi.notifyValueChanged(); + } + return; + } + + ElementImpl element = (ElementImpl) node; + NamedNodeMap attributes = element.getAttributes(); + if (attributes == null) + return; + int length = attributes.getLength(); + for (int i = 0; i < length; i++) { + AttrImpl attr = (AttrImpl) attributes.item(i); + if (attr == null) + continue; + if (attr.getNameRegion() != region) + continue; + + String name = flatNode.getText(region); + attr.setName(name); + break; + } + } + + /** + * changeAttrValue method + * + * @param flatNode + * com.ibm.sed.structuredDocument.IStructuredDocumentRegion + * @param region + * com.ibm.sed.structuredDocument.ITextRegion + */ + private void changeAttrValue(IStructuredDocumentRegion flatNode, ITextRegion region) { + int offset = flatNode.getStart(); + if (offset < 0) + return; + NodeImpl root = (NodeImpl) this.context.getRootNode(); + if (root == null) + return; + Node node = root.getNodeAt(offset); + if (node == null) + return; + if (node.getNodeType() != Node.ELEMENT_NODE) { + if (node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) { + // just notify the change instead of setting data + ProcessingInstructionImpl pi = (ProcessingInstructionImpl) node; + pi.notifyValueChanged(); + } + return; + } + + ElementImpl element = (ElementImpl) node; + NamedNodeMap attributes = element.getAttributes(); + if (attributes == null) + return; + int length = attributes.getLength(); + for (int i = 0; i < length; i++) { + AttrImpl attr = (AttrImpl) attributes.item(i); + if (attr == null) + continue; + if (attr.getValueRegion() != region) + continue; + // just notify the change instead of setting value + attr.notifyValueChanged(); + break; + } + } + + /** + * changeData method + * + * @param flatNode + * com.ibm.sed.structuredDocument.IStructuredDocumentRegion + * @param region + * com.ibm.sed.structuredDocument.ITextRegion + */ + private void changeData(IStructuredDocumentRegion flatNode, ITextRegion region) { + int offset = flatNode.getStart(); + if (offset < 0) + return; + NodeImpl root = (NodeImpl) this.context.getRootNode(); + if (root == null) + return; + Node node = root.getNodeAt(offset); + if (node == null) + return; + switch (node.getNodeType()) { + case Node.TEXT_NODE : { + TextImpl text = (TextImpl) node; + if (text.isSharingStructuredDocumentRegion(flatNode)) { + // has consecutive text sharing IStructuredDocumentRegion + changeStructuredDocumentRegion(flatNode); + return; + } + this.context.setNextNode(node); + cleanupText(); + break; + } + case Node.CDATA_SECTION_NODE : + case Node.PROCESSING_INSTRUCTION_NODE : + break; + case Node.COMMENT_NODE : + case Node.ELEMENT_NODE : + // comment tag + changeStructuredDocumentRegion(flatNode); + return; + default : + return; + } + + // just notify the change instead of setting data + NodeImpl impl = (NodeImpl) node; + impl.notifyValueChanged(); + } + + /** + */ + private void changeEndTag(IStructuredDocumentRegion flatNode, ITextRegionList newRegions, ITextRegionList oldRegions) { + int offset = flatNode.getStart(); + if (offset < 0) + return; // error + NodeImpl root = (NodeImpl) this.context.getRootNode(); + if (root == null) + return; // error + Node node = root.getNodeAt(offset); + if (node == null) + return; // error + + if (node.getNodeType() != Node.ELEMENT_NODE) { + changeStructuredDocumentRegion(flatNode); + return; + } + + // check if change is only for close tag + if (newRegions != null) { + Iterator e = newRegions.iterator(); + while (e.hasNext()) { + ITextRegion region = (ITextRegion) e.next(); + String regionType = region.getType(); + if (regionType == XMLRegionContext.XML_TAG_CLOSE) + continue; + + // other region has changed + changeStructuredDocumentRegion(flatNode); + return; + } + } + if (oldRegions != null) { + Iterator e = oldRegions.iterator(); + while (e.hasNext()) { + ITextRegion region = (ITextRegion) e.next(); + String regionType = region.getType(); + if (regionType == XMLRegionContext.XML_TAG_CLOSE) + continue; + + // other region has changed + changeStructuredDocumentRegion(flatNode); + return; + } + } + + // change for close tag has no impact + // do nothing + } + + /** + * changeRegion method + * + * @param flatNode + * com.ibm.sed.structuredDocument.IStructuredDocumentRegion + * @param region + * com.ibm.sed.structuredDocument.ITextRegion + */ + void changeRegion(IStructuredDocumentRegion flatNode, ITextRegion region) { + if (flatNode == null || region == null) + return; + if (this.document == null) + return; + this.context = new XMLModelContext(this.document); + + // optimize typical cases + String regionType = region.getType(); + if (regionType == XMLRegionContext.XML_CONTENT || regionType == XMLRegionContext.XML_COMMENT_TEXT || regionType == XMLRegionContext.XML_CDATA_TEXT || regionType == XMLRegionContext.BLOCK_TEXT || regionType == JSP_CONTENT) { + changeData(flatNode, region); + } else if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_NAME) { + changeAttrName(flatNode, region); + } else if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE) { + changeAttrValue(flatNode, region); + } else if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_EQUALS) { + changeAttrEqual(flatNode, region); + } else if (regionType == XMLRegionContext.XML_TAG_NAME || regionType == JSP_ROOT_TAG_NAME || regionType == JSP_DIRECTIVE_NAME) { + changeTagName(flatNode, region); + } else { + changeStructuredDocumentRegion(flatNode); + } + } + + /** + */ + private void changeStartTag(IStructuredDocumentRegion flatNode, ITextRegionList newRegions, ITextRegionList oldRegions) { + int offset = flatNode.getStart(); + if (offset < 0) + return; // error + NodeImpl root = (NodeImpl) this.context.getRootNode(); + if (root == null) + return; // error + Node node = root.getNodeAt(offset); + if (node == null) + return; // error + + if (node.getNodeType() != Node.ELEMENT_NODE) { + changeStructuredDocumentRegion(flatNode); + return; + } + ElementImpl element = (ElementImpl) node; + + // check if changes are only for attributes and close tag + boolean tagNameUnchanged = false; + if (newRegions != null) { + Iterator e = newRegions.iterator(); + while (e.hasNext()) { + ITextRegion region = (ITextRegion) e.next(); + String regionType = region.getType(); + if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_NAME || regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_EQUALS || regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE) + continue; + if (regionType == XMLRegionContext.XML_TAG_CLOSE) { + // change from empty tag may have impact on structure + if (!element.isEmptyTag()) + continue; + } else if (regionType == XMLRegionContext.XML_TAG_NAME || regionType == JSP_ROOT_TAG_NAME || regionType == JSP_DIRECTIVE_NAME) { + String oldTagName = element.getTagName(); + String newTagName = flatNode.getText(region); + if (oldTagName != null && newTagName != null && oldTagName.equals(newTagName)) { + // the tag name is unchanged + tagNameUnchanged = true; + continue; + } + } + + // other region has changed + changeStructuredDocumentRegion(flatNode); + return; + } + } + if (oldRegions != null) { + Iterator e = oldRegions.iterator(); + while (e.hasNext()) { + ITextRegion region = (ITextRegion) e.next(); + String regionType = region.getType(); + if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_NAME || regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_EQUALS || regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE) + continue; + if (regionType == XMLRegionContext.XML_TAG_CLOSE) { + // change from empty tag may have impact on structure + if (!element.isEmptyTag()) + continue; + } else if (regionType == XMLRegionContext.XML_TAG_NAME || regionType == JSP_ROOT_TAG_NAME) { + // if new tag name is unchanged, it's OK + if (tagNameUnchanged) + continue; + } + + // other region has changed + changeStructuredDocumentRegion(flatNode); + return; + } + } + + // update attributes + ITextRegionList regions = flatNode.getRegions(); + if (regions == null) + return; // error + NamedNodeMap attributes = element.getAttributes(); + if (attributes == null) + return; // error + + // first remove attributes + int regionIndex = 0; + int attrIndex = 0; + AttrImpl attr = null; + while (attrIndex < attributes.getLength()) { + attr = (AttrImpl) attributes.item(attrIndex); + if (attr == null) { // error + attrIndex++; + continue; + } + ITextRegion nameRegion = attr.getNameRegion(); + if (nameRegion == null) { // error + element.removeAttributeNode(attr); + continue; + } + boolean found = false; + for (int i = regionIndex; i < regions.size(); i++) { + ITextRegion region = regions.get(i); + if (region == nameRegion) { + regionIndex = i + 1; // next region + found = true; + break; + } + } + if (found) { + attrIndex++; + } else { + element.removeAttributeNode(attr); + } + } + + // insert or update attributes + attrIndex = 0; // reset to first + AttrImpl newAttr = null; + ITextRegion oldValueRegion = null; + Iterator e = regions.iterator(); + while (e.hasNext()) { + ITextRegion region = (ITextRegion) e.next(); + String regionType = region.getType(); + if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_NAME) { + if (newAttr != null) { + // insert deferred new attribute + element.insertAttributeNode(newAttr, attrIndex++); + newAttr = null; + } else if (attr != null && oldValueRegion != null) { + // notify existing attribute value removal + attr.notifyValueChanged(); + } + + oldValueRegion = null; + attr = (AttrImpl) attributes.item(attrIndex); + if (attr != null && attr.getNameRegion() == region) { + // existing attribute + attrIndex++; + // clear other regions + oldValueRegion = attr.getValueRegion(); + attr.setEqualRegion(null); + attr.setValueRegion(null); + } else { + String name = flatNode.getText(region); + attr = (AttrImpl) this.document.createAttribute(name); + if (attr != null) + attr.setNameRegion(region); + // defer insertion of new attribute + newAttr = attr; + } + } else if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_EQUALS) { + if (attr != null) { + attr.setEqualRegion(region); + } + } else if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE) { + if (attr != null) { + attr.setValueRegion(region); + if (attr != newAttr && oldValueRegion != region) { + // notify existing attribute value changed + attr.notifyValueChanged(); + } + oldValueRegion = null; + attr = null; + } + } + } + + if (newAttr != null) { + // insert deferred new attribute + element.appendAttributeNode(newAttr); + } else if (attr != null && oldValueRegion != null) { + // notify existing attribute value removal + attr.notifyValueChanged(); + } + } + + /** + * changeStructuredDocumentRegion method + * + * @param flatNode + * com.ibm.sed.structuredDocument.IStructuredDocumentRegion + */ + private void changeStructuredDocumentRegion(IStructuredDocumentRegion flatNode) { + if (flatNode == null) + return; + if (this.document == null) + return; + + setupContext(flatNode); + + removeStructuredDocumentRegion(flatNode); + // make sure the parent is set to deepest level + // when end tag has been removed + this.context.setLast(); + insertStructuredDocumentRegion(flatNode); + + cleanupText(); + cleanupEndTag(); + } + + /** + */ + private void changeTagName(IStructuredDocumentRegion flatNode, ITextRegion region) { + int offset = flatNode.getStart(); + if (offset < 0) + return; // error + NodeImpl root = (NodeImpl) this.context.getRootNode(); + if (root == null) + return; // error + Node node = root.getNodeAt(offset); + if (node == null) + return; // error + + if (node.getNodeType() != Node.ELEMENT_NODE) { + changeStructuredDocumentRegion(flatNode); + return; + } + + ElementImpl element = (ElementImpl) node; + String newTagName = flatNode.getText(region); + if (newTagName == null || !element.matchTagName(newTagName)) { + // the tag name is changed + changeStructuredDocumentRegion(flatNode); + return; + } + + // the tag name is unchanged + // this happens when typing spaces after the tag name + // do nothing, but... + // if it's not a change in the end tag of an element with the start + // tag, + // and case has been changed, set to element and notify + if (!element.hasStartTag() || StructuredDocumentRegionUtil.getFirstRegionType(flatNode) != XMLRegionContext.XML_END_TAG_OPEN) { + String tagName = element.getTagName(); + if (tagName == null || !tagName.equals(newTagName)) { + element.setTagName(newTagName); + element.notifyValueChanged(); + } + } + } + + /** + * cleanupContext method + */ + private void cleanupEndTag() { + Node parent = this.context.getParentNode(); + Node next = this.context.getNextNode(); + while (parent != null) { + while (next != null) { + if (next.getNodeType() == Node.ELEMENT_NODE) { + ElementImpl element = (ElementImpl) next; + if (element.isEndTag()) { + // floating end tag + String tagName = element.getTagName(); + String rootName = getFindRootName(tagName); + ElementImpl start = (ElementImpl) this.context.findStartTag(tagName, rootName); + if (start != null) { + insertEndTag(start); + // move the end tag from 'element' to 'start' + start.addEndTag(element); + removeNode(element); + parent = this.context.getParentNode(); + next = this.context.getNextNode(); + continue; + } + } + } + + Node first = next.getFirstChild(); + if (first != null) { + parent = next; + next = first; + this.context.setNextNode(next); + } else { + next = next.getNextSibling(); + this.context.setNextNode(next); + } + } + + if (parent.getNodeType() == Node.ELEMENT_NODE) { + ElementImpl element = (ElementImpl) parent; + if (!element.hasEndTag() && element.hasStartTag() && element.getNextSibling() == null) { + String tagName = element.getTagName(); + ElementImpl end = (ElementImpl) this.context.findEndTag(tagName); + if (end != null) { + // move the end tag from 'end' to 'element' + element.addEndTag(end); + removeEndTag(end); + this.context.setParentNode(parent); // reset context + continue; + } + } + } + + next = parent.getNextSibling(); + parent = parent.getParentNode(); + if (next != null) { + this.context.setNextNode(next); + } else { + this.context.setParentNode(parent); + } + } + } + + /** + */ + private void cleanupText() { + Node parent = this.context.getParentNode(); + if (parent == null) + return; // error + Node next = this.context.getNextNode(); + Node prev = (next == null ? parent.getLastChild() : next.getPreviousSibling()); + + TextImpl nextText = null; + TextImpl prevText = null; + if (next != null && next.getNodeType() == Node.TEXT_NODE) { + nextText = (TextImpl) next; + } + if (prev != null && prev.getNodeType() == Node.TEXT_NODE) { + prevText = (TextImpl) prev; + } + if (nextText == null && prevText == null) + return; + if (nextText != null && prevText != null) { + // consecutive Text nodes created by setupContext(), + // concat them + IStructuredDocumentRegion flatNode = nextText.getStructuredDocumentRegion(); + if (flatNode != null) + prevText.appendStructuredDocumentRegion(flatNode); + Node newNext = next.getNextSibling(); + parent.removeChild(next); + next = null; + this.context.setNextNode(newNext); + } + + TextImpl childText = (prevText != null ? prevText : nextText); + if (childText.getNextSibling() == null && childText.getPreviousSibling() == null) { + if (parent.getNodeType() == Node.ELEMENT_NODE) { + ElementImpl parentElement = (ElementImpl) parent; + if (!parentElement.hasStartTag() && !parentElement.hasEndTag()) { + if (childText.isWhitespace() || childText.isInvalid()) { + // implicit parent is not required + Node newParent = parent.getParentNode(); + if (newParent != null) { + Node newNext = parent.getNextSibling(); + newParent.removeChild(parent); + parent.removeChild(childText); + newParent.insertBefore(childText, newNext); + if (childText == next) { + this.context.setNextNode(childText); + } else if (newNext != null) { + this.context.setNextNode(newNext); + } else { + this.context.setParentNode(newParent); + } + // try again + cleanupText(); + } + } + } + } + } + } + + /** + * This routine create an Element from comment data for comment style + * elements, such as SSI and METADATA + */ + protected Element createCommentElement(String data, boolean isJSPTag) { + String trimmedData = data.trim(); + CommentElementConfiguration[] configs = CommentElementRegistry.getInstance().getConfigurations(); + for (int iConfig = 0; iConfig < configs.length; iConfig++) { + CommentElementConfiguration config = configs[iConfig]; + if ((isJSPTag && !config.acceptJSPComment()) || (!isJSPTag && !config.acceptXMLComment())) { + continue; + } + String[] prefixes = config.getPrefix(); + for (int iPrefix = 0; iPrefix < prefixes.length; iPrefix++) { + if (trimmedData.startsWith(prefixes[iPrefix])) { + return config.createElement(this.document, data, isJSPTag); + } + } + } + if (this.adapter != null) { + return this.adapter.createCommentElement(this.document, data, isJSPTag); + } + return null; + } + + /** + * This routine create an implicit Element for given parent and child, + * such as HTML, BODY, HEAD, and TBODY for HTML document. + */ + protected Element createImplicitElement(Node parent, Node child) { + if (this.adapter != null) { + return this.adapter.createImplicitElement(this.document, parent, child); + } + return null; + } + + /** + */ + private void demoteNodes(Node root, Node newParent, Node oldParent, Node next) { + if (newParent.getNodeType() != Node.ELEMENT_NODE) + return; + ElementImpl newElement = (ElementImpl) newParent; + + // find next + while (next == null) { + if (oldParent.getNodeType() != Node.ELEMENT_NODE) + return; + ElementImpl oldElement = (ElementImpl) oldParent; + if (oldElement.hasEndTag()) + return; + oldParent = oldElement.getParentNode(); + if (oldParent == null) + return; // error + next = oldElement.getNextSibling(); + } + + while (next != null) { + boolean done = false; + if (next.getNodeType() == Node.ELEMENT_NODE) { + ElementImpl nextElement = (ElementImpl) next; + if (!nextElement.hasStartTag()) { + Node nextChild = nextElement.getFirstChild(); + if (nextChild != null) { + // demote children + next = nextChild; + oldParent = nextElement; + continue; + } + + if (nextElement.hasEndTag()) { + if (nextElement.matchEndTag(newElement)) { + // stop at the matched invalid end tag + next = nextElement.getNextSibling(); + oldParent.removeChild(nextElement); + newElement.addEndTag(nextElement); + + if (newElement == root) + return; + Node p = newElement.getParentNode(); + // check if reached to top + if (p == null || p == oldParent || p.getNodeType() != Node.ELEMENT_NODE) + return; + newElement = (ElementImpl) p; + done = true; + } + } else { + // remove implicit element + next = nextElement.getNextSibling(); + oldParent.removeChild(nextElement); + done = true; + } + } + } + + if (!done) { + if (!canContain(newElement, next)) { + if (newElement == root) + return; + Node p = newElement.getParentNode(); + // check if reached to top + if (p == null || p == oldParent || p.getNodeType() != Node.ELEMENT_NODE) + return; + newElement = (ElementImpl) p; + continue; + } + + Node child = next; + next = next.getNextSibling(); + oldParent.removeChild(child); + insertNode(newElement, child, null); + Node childParent = child.getParentNode(); + if (childParent != newElement) { + newElement = (ElementImpl) childParent; + } + } + + // find next parent and sibling + while (next == null) { + if (oldParent.getNodeType() != Node.ELEMENT_NODE) + return; + ElementImpl oldElement = (ElementImpl) oldParent; + + // dug parent must not have children at this point + if (!oldElement.hasChildNodes() && !oldElement.hasStartTag()) { + oldParent = oldElement.getParentNode(); + if (oldParent == null) + return; // error + next = oldElement; + break; + } + + if (oldElement.hasEndTag()) + return; + oldParent = oldElement.getParentNode(); + if (oldParent == null) + return; // error + next = oldElement.getNextSibling(); + } + } + } + + /** + */ + protected final XMLDocument getDocument() { + return this.document; + } + + /** + */ + protected String getFindRootName(String tagName) { + if (this.adapter != null) { + return this.adapter.getFindRootName(tagName); + } + return null; + } + + /** + */ + protected final XMLModel getModel() { + return this.model; + } + + /** + * insertCDATASection method + * + * @param flatNode + * com.ibm.sed.structuredDocument.IStructuredDocumentRegion + */ + private void insertCDATASection(IStructuredDocumentRegion flatNode) { + ITextRegionList regions = flatNode.getRegions(); + if (regions == null) + return; + + CDATASectionImpl cdata = null; + try { + cdata = (CDATASectionImpl) this.document.createCDATASection(null); + } catch (DOMException ex) { + } + if (cdata == null) { // CDATA section might not be supported + insertInvalidDecl(flatNode); // regard as invalid decl + return; + } + + cdata.setStructuredDocumentRegion(flatNode); + insertNode(cdata); + } + + /** + * insertComment method + * + * @param flatNode + * com.ibm.sed.structuredDocument.IStructuredDocumentRegion + */ + private void insertComment(IStructuredDocumentRegion flatNode) { + ITextRegionList regions = flatNode.getRegions(); + if (regions == null) + return; + + String data = null; + boolean isJSPTag = false; + Iterator e = regions.iterator(); + while (e.hasNext()) { + ITextRegion region = (ITextRegion) e.next(); + String regionType = region.getType(); + if (regionType == JSP_COMMENT_OPEN) { + isJSPTag = true; + } else if (regionType == XMLRegionContext.XML_COMMENT_TEXT || regionType == JSP_COMMENT_TEXT) { + if (data == null) { + data = flatNode.getText(region); + } + } + } + + if (data != null) { + ElementImpl element = (ElementImpl) createCommentElement(data, isJSPTag); + if (element != null) { + if (!isEndTag(element)) { + element.setStartStructuredDocumentRegion(flatNode); + insertStartTag(element); + return; + } + + // end tag + element.setEndStructuredDocumentRegion(flatNode); + + String tagName = element.getTagName(); + String rootName = getFindRootName(tagName); + ElementImpl start = (ElementImpl) this.context.findStartTag(tagName, rootName); + if (start != null) { // start tag found + insertEndTag(start); + start.addEndTag(element); + return; + } + + // invalid end tag + insertNode(element); + return; + } + } + + CommentImpl comment = (CommentImpl) this.document.createComment(null); + if (comment == null) + return; + if (isJSPTag) + comment.setJSPTag(true); + comment.setStructuredDocumentRegion(flatNode); + insertNode(comment); + } + + /** + * insertDecl method + * + * @param flatNode + * com.ibm.sed.structuredDocument.IStructuredDocumentRegion + */ + private void insertDecl(IStructuredDocumentRegion flatNode) { + ITextRegionList regions = flatNode.getRegions(); + if (regions == null) + return; + + boolean isDocType = false; + String name = null; + String publicId = null; + String systemId = null; + Iterator e = regions.iterator(); + while (e.hasNext()) { + ITextRegion region = (ITextRegion) e.next(); + String regionType = region.getType(); + if (regionType == XMLRegionContext.XML_DOCTYPE_DECLARATION) { + isDocType = true; + } else if (regionType == XMLRegionContext.XML_DOCTYPE_NAME) { + if (name == null) + name = flatNode.getText(region); + } else if (regionType == XMLRegionContext.XML_DOCTYPE_EXTERNAL_ID_PUBREF) { + if (publicId == null) + publicId = StructuredDocumentRegionUtil.getAttrValue(flatNode, region); + } else if (regionType == XMLRegionContext.XML_DOCTYPE_EXTERNAL_ID_SYSREF) { + if (systemId == null) + systemId = StructuredDocumentRegionUtil.getAttrValue(flatNode, region); + } + } + + // invalid declaration + if (!isDocType) { + insertInvalidDecl(flatNode); + return; + } + + DocumentTypeImpl docType = (DocumentTypeImpl) this.document.createDoctype(name); + if (docType == null) + return; + if (publicId != null) + docType.setPublicId(publicId); + if (systemId != null) + docType.setSystemId(systemId); + docType.setStructuredDocumentRegion(flatNode); + insertNode(docType); + } + + /** + * insertEndTag method + * + * @param element + * org.w3c.dom.Element + */ + private void insertEndTag(Element element) { + if (element == null) + return; + + Node newParent = element.getParentNode(); + if (newParent == null) + return; // error + + if (!((ElementImpl) element).isContainer()) { + // just update context + Node elementNext = element.getNextSibling(); + if (elementNext != null) + this.context.setNextNode(elementNext); + else + this.context.setParentNode(newParent); + return; + } + + // promote children + Node newNext = element.getNextSibling(); + Node oldParent = this.context.getParentNode(); + if (oldParent == null) + return; // error + Node oldNext = this.context.getNextNode(); + promoteNodes(element, newParent, newNext, oldParent, oldNext); + + // update context + // re-check the next sibling + newNext = element.getNextSibling(); + if (newNext != null) + this.context.setNextNode(newNext); + else + this.context.setParentNode(newParent); + } + + /** + * insertEndTag method + * + * @param flatNode + * com.ibm.sed.structuredDocument.IStructuredDocumentRegion + */ + private void insertEndTag(IStructuredDocumentRegion flatNode) { + ITextRegionList regions = flatNode.getRegions(); + if (regions == null) + return; + + String tagName = null; + Iterator e = regions.iterator(); + while (e.hasNext()) { + ITextRegion region = (ITextRegion) e.next(); + if (region.getType() == XMLRegionContext.XML_TAG_NAME || region.getType() == JSP_ROOT_TAG_NAME || region.getType() == JSP_DIRECTIVE_NAME) { + if (tagName == null) + tagName = flatNode.getText(region); + } + } + + if (tagName == null) { // invalid end tag + insertText(flatNode); // regard as invalid text + return; + } + + String rootName = getFindRootName(tagName); + ElementImpl start = (ElementImpl) this.context.findStartTag(tagName, rootName); + if (start != null) { // start tag found + insertEndTag(start); + start.setEndStructuredDocumentRegion(flatNode); + return; + } + + // invalid end tag + ElementImpl end = null; + try { + end = (ElementImpl) this.document.createElement(tagName); + } catch (DOMException ex) { + } + if (end == null) { // invalid end tag + insertText(flatNode); // regard as invalid text + return; + } + end.setEndStructuredDocumentRegion(flatNode); + insertNode(end); + } + + /** + * insertEntityRef method + * + * @param flatNode + * com.ibm.sed.structuredDocument.IStructuredDocumentRegion + */ + private void insertEntityRef(IStructuredDocumentRegion flatNode) { + ITextRegionList regions = flatNode.getRegions(); + if (regions == null) + return; + + String name = null; + Iterator e = regions.iterator(); + while (e.hasNext()) { + ITextRegion region = (ITextRegion) e.next(); + String regionType = region.getType(); + if (regionType == XMLRegionContext.XML_ENTITY_REFERENCE || regionType == XMLRegionContext.XML_CHAR_REFERENCE) { + if (name == null) + name = StructuredDocumentRegionUtil.getEntityRefName(flatNode, region); + } + } + + if (name == null) { // invalid entity + insertText(flatNode); + return; + } + + String value = this.document.getCharValue(name); + if (value != null) { // character entity + TextImpl text = (TextImpl) this.context.findPreviousText(); + if (text != null) { // existing text found + // do not append data + text.appendStructuredDocumentRegion(flatNode); + // notify the change + text.notifyValueChanged(); + return; + } + + // new text + text = (TextImpl) this.document.createTextNode(null); + if (text == null) + return; + text.setStructuredDocumentRegion(flatNode); + insertNode(text); + return; + } + + // general entity reference + EntityReferenceImpl ref = null; + try { + ref = (EntityReferenceImpl) this.document.createEntityReference(name); + } catch (DOMException ex) { + } + if (ref == null) { // entity reference might not be supported + insertText(flatNode); // regard as invalid text + return; + } + + ref.setStructuredDocumentRegion(flatNode); + insertNode(ref); + } + + /** + * insertInvalidDecl method + * + * @param flatNode + * com.ibm.sed.structuredDocument.IStructuredDocumentRegion + */ + private void insertInvalidDecl(IStructuredDocumentRegion flatNode) { + ITextRegionList regions = flatNode.getRegions(); + if (regions == null) + return; + + ElementImpl element = null; + try { + element = (ElementImpl) this.document.createElement("!");//$NON-NLS-1$ + } catch (DOMException ex) { + } + if (element == null) { // invalid tag + insertText(flatNode); // regard as invalid text + return; + } + element.setEmptyTag(true); + element.setStartStructuredDocumentRegion(flatNode); + insertNode(element); + } + + /** + * insertJSPTag method + * + * @param flatNode + * com.ibm.sed.structuredDocument.IStructuredDocumentRegion + */ + private void insertJSPTag(IStructuredDocumentRegion flatNode) { + ITextRegionList regions = flatNode.getRegions(); + if (regions == null) + return; + + String tagName = null; + AttrImpl attr = null; + Vector attrNodes = null; + boolean isCloseTag = false; + Iterator e = regions.iterator(); + while (e.hasNext()) { + ITextRegion region = (ITextRegion) e.next(); + String regionType = region.getType(); + if (regionType == JSP_SCRIPTLET_OPEN) { + tagName = JSPTag.JSP_SCRIPTLET; + } else if (regionType == JSP_EXPRESSION_OPEN) { + tagName = JSPTag.JSP_EXPRESSION; + } else if (regionType == JSP_DECLARATION_OPEN) { + tagName = JSPTag.JSP_DECLARATION; + } else if (regionType == JSP_DIRECTIVE_OPEN) { + tagName = JSPTag.JSP_DIRECTIVE; + } else if (regionType == JSP_DIRECTIVE_NAME) { + tagName += '.'; + tagName += flatNode.getText(region); + } else if (regionType == JSP_CLOSE) { + isCloseTag = true; + } else if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_NAME) { + String name = flatNode.getText(region); + attr = (AttrImpl) this.document.createAttribute(name); + if (attr != null) { + attr.setNameRegion(region); + if (attrNodes == null) + attrNodes = new Vector(); + attrNodes.addElement(attr); + } + } else if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_EQUALS) { + if (attr != null) { + attr.setEqualRegion(region); + } + } else if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE) { + if (attr != null) { + attr.setValueRegion(region); + attr = null; + } + } + } + + if (tagName == null) { + if (isCloseTag) { + // close JSP tag + Node parent = this.context.getParentNode(); + if (parent != null && parent.getNodeType() == Node.ELEMENT_NODE) { + ElementImpl start = (ElementImpl) parent; + if (start.isJSPContainer()) { + insertEndTag(start); + start.setEndStructuredDocumentRegion(flatNode); + return; + } + } + } + // invalid JSP tag + insertText(flatNode); // regard as invalid text + return; + } + + ElementImpl element = null; + try { + element = (ElementImpl) this.document.createElement(tagName); + } catch (DOMException ex) { + } + if (element == null) { // invalid tag + insertText(flatNode); // regard as invalid text + return; + } + if (attrNodes != null) { + Enumeration ae = attrNodes.elements(); + while (ae.hasMoreElements()) { + Attr a = (Attr) ae.nextElement(); + if (a == null) + continue; + element.appendAttributeNode(a); + } + } + element.setJSPTag(true); + element.setStartStructuredDocumentRegion(flatNode); + insertStartTag(element); + } + + /** + * insertNode method + * + * @param child + * org.w3c.dom.Node + */ + private void insertNode(Node node) { + if (node == null) + return; + if (this.context == null) + return; + + Node parent = this.context.getParentNode(); + if (parent == null) + return; + Node next = this.context.getNextNode(); + while (parent.getNodeType() == Node.ELEMENT_NODE) { + ElementImpl element = (ElementImpl) parent; + if (canContain(element, node)) { + if (!element.hasStartTag() && next == element.getFirstChild()) { + // first child of implicit tag + // deletege to the parent + parent = element.getParentNode(); + if (parent == null) + return; + next = element; + this.context.setNextNode(next); + continue; + } + break; + } + parent = element.getParentNode(); + if (parent == null) + return; + + // promote siblings + Node newNext = element.getNextSibling(); + Node child = next; + while (child != null) { + Node nextChild = child.getNextSibling(); + element.removeChild(child); + parent.insertBefore(child, newNext); + child = nextChild; + } + + // leave the old end tag where it is + if (element.hasEndTag()) { + Element end = element.removeEndTag(); + if (end != null) { + parent.insertBefore(end, newNext); + if (next == null) + next = end; + } + } + if (!element.hasStartTag()) { + // implicit element + if (!element.hasChildNodes()) { + parent.removeChild(element); + } + } + + // update context + if (next == null) + next = newNext; + if (next != null) + this.context.setNextNode(next); + else + this.context.setParentNode(parent); + } + + insertNode(parent, node, next); + next = node.getNextSibling(); + if (next != null) + this.context.setNextNode(next); + else + this.context.setParentNode(node.getParentNode()); + } + + /** + */ + private void insertNode(Node parent, Node node, Node next) { + while (next != null && next.getNodeType() == Node.ELEMENT_NODE) { + ElementImpl nextElement = (ElementImpl) next; + if (nextElement.hasStartTag()) + break; + if (!canBeImplicitTag(nextElement, node)) + break; + parent = nextElement; + next = nextElement.getFirstChild(); + } + Element implicitElement = createImplicitElement(parent, node); + if (implicitElement != null) + node = implicitElement; + parent.insertBefore(node, next); + } + + /** + * insertPI method + * + * @param flatNode + * com.ibm.sed.structuredDocument.IStructuredDocumentRegion + */ + private void insertPI(IStructuredDocumentRegion flatNode) { + ITextRegionList regions = flatNode.getRegions(); + if (regions == null) + return; + + String target = null; + Iterator e = regions.iterator(); + while (e.hasNext()) { + ITextRegion region = (ITextRegion) e.next(); + String regionType = region.getType(); + if (regionType == XMLRegionContext.XML_PI_OPEN || regionType == XMLRegionContext.XML_PI_CLOSE) + continue; + if (target == null) + target = flatNode.getText(region); + } + + ProcessingInstructionImpl pi = (ProcessingInstructionImpl) this.document.createProcessingInstruction(target, null); + if (pi == null) + return; + pi.setStructuredDocumentRegion(flatNode); + insertNode(pi); + } + + /** + * insertStartTag method + * + * @param element + * org.w3c.dom.Element + */ + private void insertStartTag(Element element) { + if (element == null) + return; + if (this.context == null) + return; + + insertNode(element); + + ElementImpl newElement = (ElementImpl) element; + if (newElement.isEmptyTag() || !newElement.isContainer()) + return; + + // demote siblings + Node parent = this.context.getParentNode(); + if (parent == null) + return; // error + Node next = this.context.getNextNode(); + demoteNodes(element, element, parent, next); + + // update context + Node firstChild = element.getFirstChild(); + if (firstChild != null) + this.context.setNextNode(firstChild); + else + this.context.setParentNode(element); + } + + /** + * insertStartTag method + * + * @param flatNode + * com.ibm.sed.structuredDocument.IStructuredDocumentRegion + */ + private void insertStartTag(IStructuredDocumentRegion flatNode) { + ITextRegionList regions = flatNode.getRegions(); + if (regions == null) + return; + + String tagName = null; + boolean isEmptyTag = false; + AttrImpl attr = null; + Vector attrNodes = null; + Iterator e = regions.iterator(); + while (e.hasNext()) { + ITextRegion region = (ITextRegion) e.next(); + String regionType = region.getType(); + if (regionType == XMLRegionContext.XML_TAG_NAME || regionType == JSP_ROOT_TAG_NAME || regionType == JSP_DIRECTIVE_NAME) { + if (tagName == null) + tagName = flatNode.getText(region); + } else if (regionType == XMLRegionContext.XML_EMPTY_TAG_CLOSE) { + isEmptyTag = true; + } else if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_NAME) { + String name = flatNode.getText(region); + attr = (AttrImpl) this.document.createAttribute(name); + if (attr != null) { + attr.setNameRegion(region); + if (attrNodes == null) + attrNodes = new Vector(); + attrNodes.addElement(attr); + } + } else if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_EQUALS) { + if (attr != null) { + attr.setEqualRegion(region); + } + } else if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE) { + if (attr != null) { + attr.setValueRegion(region); + attr = null; + } + } + } + + if (tagName == null) { // invalid start tag + insertText(flatNode); // regard as invalid text + return; + } + + ElementImpl element = null; + try { + element = (ElementImpl) this.document.createElement(tagName); + } catch (DOMException ex) { + } + if (element == null) { // invalid tag + insertText(flatNode); // regard as invalid text + return; + } + if (attrNodes != null) { + Enumeration ae = attrNodes.elements(); + while (ae.hasMoreElements()) { + Attr a = (Attr) ae.nextElement(); + if (a == null) + continue; + element.appendAttributeNode(a); + } + } + if (isEmptyTag) + element.setEmptyTag(true); + element.setStartStructuredDocumentRegion(flatNode); + insertStartTag(element); + } + + /** + * insertStructuredDocumentRegion method + * + * @param flatNode + * com.ibm.sed.structuredDocument.IStructuredDocumentRegion + */ + private void insertStructuredDocumentRegion(IStructuredDocumentRegion flatNode) { + String regionType = StructuredDocumentRegionUtil.getFirstRegionType(flatNode); + if (regionType == XMLRegionContext.XML_TAG_OPEN) { + insertStartTag(flatNode); + } else if (regionType == XMLRegionContext.XML_END_TAG_OPEN) { + insertEndTag(flatNode); + } else if (regionType == XMLRegionContext.XML_COMMENT_OPEN || regionType == JSP_COMMENT_OPEN) { + insertComment(flatNode); + } else if (regionType == XMLRegionContext.XML_ENTITY_REFERENCE || regionType == XMLRegionContext.XML_CHAR_REFERENCE) { + insertEntityRef(flatNode); + } else if (regionType == XMLRegionContext.XML_DECLARATION_OPEN) { + insertDecl(flatNode); + } else if (regionType == XMLRegionContext.XML_PI_OPEN) { + insertPI(flatNode); + } else if (regionType == XMLRegionContext.XML_CDATA_OPEN) { + insertCDATASection(flatNode); + } else if (regionType == JSP_SCRIPTLET_OPEN || regionType == JSP_EXPRESSION_OPEN || regionType == JSP_DECLARATION_OPEN || regionType == JSP_DIRECTIVE_OPEN || regionType == JSP_CLOSE) { + insertJSPTag(flatNode); + } else { + insertText(flatNode); + } + } + + /** + * insertText method + * + * @param flatNode + * com.ibm.sed.structuredDocument.IStructuredDocumentRegion + */ + private void insertText(IStructuredDocumentRegion flatNode) { + TextImpl text = (TextImpl) this.context.findPreviousText(); + if (text != null) { // existing text found + text.appendStructuredDocumentRegion(flatNode); + // notify the change + text.notifyValueChanged(); + return; + } + + // new text + text = (TextImpl) this.document.createTextNode(null); + if (text == null) + return; + text.setStructuredDocumentRegion(flatNode); + insertNode(text); + } + + /** + */ + protected boolean isEndTag(XMLElement element) { + if (this.adapter != null) { + return this.adapter.isEndTag(element); + } + return element.isEndTag(); + } + + /** + */ + private void promoteNodes(Node root, Node newParent, Node newNext, Node oldParent, Node next) { + ElementImpl newElement = null; + if (newParent.getNodeType() == Node.ELEMENT_NODE) { + newElement = (ElementImpl) newParent; + } + + Node rootParent = root.getParentNode(); + while (oldParent != rootParent) { + while (next != null) { + boolean done = false; + boolean endTag = false; + if (next.getNodeType() == Node.ELEMENT_NODE) { + ElementImpl nextElement = (ElementImpl) next; + if (!nextElement.hasStartTag()) { + Node nextChild = nextElement.getFirstChild(); + if (nextChild != null) { + // promote children + next = nextChild; + oldParent = nextElement; + continue; + } + + if (nextElement.hasEndTag()) { + if (nextElement.matchEndTag(newElement)) { + endTag = true; + } + } else { + // remove implicit element + next = nextElement.getNextSibling(); + oldParent.removeChild(nextElement); + done = true; + } + } + } + + if (!done) { + if (!endTag && newElement != null && !canContain(newElement, next)) { + newParent = newElement.getParentNode(); + if (newParent == null) + return; // error + Node elementNext = newElement.getNextSibling(); + // promote siblings + promoteNodes(newElement, newParent, elementNext, newElement, newNext); + newNext = newElement.getNextSibling(); + if (newParent.getNodeType() == Node.ELEMENT_NODE) { + newElement = (ElementImpl) newParent; + } else { + newElement = null; + } + continue; + } + + Node child = next; + next = next.getNextSibling(); + oldParent.removeChild(child); + insertNode(newParent, child, newNext); + Node childParent = child.getParentNode(); + if (childParent != newParent) { + newParent = childParent; + newElement = (ElementImpl) newParent; + newNext = child.getNextSibling(); + } + } + } + + if (oldParent.getNodeType() != Node.ELEMENT_NODE) + return; + ElementImpl oldElement = (ElementImpl) oldParent; + oldParent = oldElement.getParentNode(); + if (oldParent == null) + return; // error + next = oldElement.getNextSibling(); + + if (oldElement.hasEndTag()) { + Element end = null; + if (!oldElement.hasChildNodes() && !oldElement.hasStartTag()) { + oldParent.removeChild(oldElement); + end = oldElement; + } else { + end = oldElement.removeEndTag(); + } + if (end != null) { + insertNode(newParent, end, newNext); + Node endParent = end.getParentNode(); + if (endParent != newParent) { + newParent = endParent; + newElement = (ElementImpl) newParent; + newNext = end.getNextSibling(); + } + } + } + } + } + + /** + * removeEndTag method + * + * @param element + * org.w3c.dom.Element + */ + private void removeEndTag(Element element) { + if (element == null) + return; + if (this.context == null) + return; + + Node parent = element.getParentNode(); + if (parent == null) + return; // error + + if (!((ElementImpl) element).isContainer()) { + // just update context + Node elementNext = element.getNextSibling(); + if (elementNext != null) + this.context.setNextNode(elementNext); + else + this.context.setParentNode(parent); + return; + } + + // demote siblings + Node next = element.getNextSibling(); + ElementImpl newElement = (ElementImpl) element; + // find new parent + for (Node last = newElement.getLastChild(); last != null; last = last.getLastChild()) { + if (last.getNodeType() != Node.ELEMENT_NODE) + break; + ElementImpl lastElement = (ElementImpl) last; + if (lastElement.hasEndTag() || lastElement.isEmptyTag() || !lastElement.isContainer()) + break; + newElement = lastElement; + } + Node lastChild = newElement.getLastChild(); + demoteNodes(element, newElement, parent, next); + + // update context + Node newNext = null; + if (lastChild != null) + newNext = lastChild.getNextSibling(); + else + newNext = newElement.getFirstChild(); + if (newNext != null) + this.context.setNextNode(newNext); + else + this.context.setParentNode(newElement); + } + + /** + * Remove the specified node if it is no longer required implicit tag with + * remaining child nodes promoted. + */ + private Element removeImplicitElement(Node parent) { + if (parent == null) + return null; + if (parent.getNodeType() != Node.ELEMENT_NODE) + return null; + ElementImpl element = (ElementImpl) parent; + if (!element.isImplicitTag()) + return null; + if (canBeImplicitTag(element)) + return null; + + Node elementParent = element.getParentNode(); + if (elementParent == null) + return null; // error + Node firstChild = element.getFirstChild(); + Node child = firstChild; + Node elementNext = element.getNextSibling(); + while (child != null) { + Node nextChild = child.getNextSibling(); + element.removeChild(child); + elementParent.insertBefore(child, elementNext); + child = nextChild; + } + + // reset context + if (this.context.getParentNode() == element) { + Node oldNext = this.context.getNextNode(); + if (oldNext != null) { + this.context.setNextNode(oldNext); + } else { + if (elementNext != null) { + this.context.setNextNode(elementNext); + } else { + this.context.setParentNode(elementParent); + } + } + } else if (this.context.getNextNode() == element) { + if (firstChild != null) { + this.context.setNextNode(firstChild); + } else { + if (elementNext != null) { + this.context.setNextNode(elementNext); + } else { + this.context.setParentNode(elementParent); + } + } + } + + removeNode(element); + return element; + } + + /** + * removeNode method + * + * @param node + * org.w3c.dom.Node + */ + private void removeNode(Node node) { + if (node == null) + return; + if (this.context == null) + return; + + Node parent = node.getParentNode(); + if (parent == null) + return; + Node next = node.getNextSibling(); + Node prev = node.getPreviousSibling(); + + // update context + Node oldParent = this.context.getParentNode(); + if (node == oldParent) { + if (next != null) + this.context.setNextNode(next); + else + this.context.setParentNode(parent); + } else { + Node oldNext = this.context.getNextNode(); + if (node == oldNext) { + this.context.setNextNode(next); + } + } + + parent.removeChild(node); + + if (removeImplicitElement(parent) != null) + return; + + // demote sibling + if (prev != null && prev.getNodeType() == Node.ELEMENT_NODE) { + ElementImpl newElement = (ElementImpl) prev; + if (!newElement.hasEndTag() && !newElement.isEmptyTag() && newElement.isContainer()) { + // find new parent + for (Node last = newElement.getLastChild(); last != null; last = last.getLastChild()) { + if (last.getNodeType() != Node.ELEMENT_NODE) + break; + ElementImpl lastElement = (ElementImpl) last; + if (lastElement.hasEndTag() || lastElement.isEmptyTag() || !lastElement.isContainer()) + break; + newElement = lastElement; + } + Node lastChild = newElement.getLastChild(); + demoteNodes(prev, newElement, parent, next); + + // update context + Node newNext = null; + if (lastChild != null) + newNext = lastChild.getNextSibling(); + else + newNext = newElement.getFirstChild(); + if (newNext != null) + this.context.setNextNode(newNext); + else + this.context.setParentNode(newElement); + } + } + } + + /** + * removeStartTag method + * + * @param element + * org.w3c.dom.Element + */ + private void removeStartTag(Element element) { + if (element == null) + return; + if (this.context == null) + return; + + // for implicit tag + ElementImpl oldElement = (ElementImpl) element; + if (canBeImplicitTag(oldElement)) { + Node newParent = null; + Node prev = oldElement.getPreviousSibling(); + if (prev != null && prev.getNodeType() == Node.ELEMENT_NODE) { + ElementImpl prevElement = (ElementImpl) prev; + if (!prevElement.hasEndTag()) { + if (prevElement.hasStartTag() || prevElement.matchTagName(oldElement.getTagName())) { + newParent = prevElement; + } + } + } + if (newParent == null) { + // this element should stay as implicit tag + // just remove all attributes + oldElement.removeStartTag(); + + // update context + Node child = oldElement.getFirstChild(); + if (child != null) { + this.context.setNextNode(child); + } else if (oldElement.hasEndTag()) { + this.context.setParentNode(oldElement); + } + return; + } + } + // for comment tag + if (oldElement.isCommentTag()) + oldElement.removeStartTag(); + + // promote children + Node elementParent = element.getParentNode(); + Node parent = elementParent; + if (parent == null) + return; + Node first = element.getFirstChild(); + Node firstElement = null; // for the case first is removed as end tag + if (first != null) { + // find new parent for children + ElementImpl newElement = null; + for (Node last = element.getPreviousSibling(); last != null; last = last.getLastChild()) { + if (last.getNodeType() != Node.ELEMENT_NODE) + break; + ElementImpl lastElement = (ElementImpl) last; + if (lastElement.hasEndTag() || lastElement.isEmptyTag() || !lastElement.isContainer()) + break; + newElement = lastElement; + } + Node next = first; + if (newElement != null) { + while (next != null) { + if (!newElement.hasEndTag() && newElement.hasStartTag() && next.getNodeType() == Node.ELEMENT_NODE) { + ElementImpl nextElement = (ElementImpl) next; + if (!nextElement.hasStartTag() && nextElement.hasEndTag() && nextElement.matchEndTag(newElement)) { + // stop at the matched invalid end tag + Node elementChild = nextElement.getFirstChild(); + while (elementChild != null) { + Node nextChild = elementChild.getNextSibling(); + nextElement.removeChild(elementChild); + newElement.appendChild(elementChild); + elementChild = nextChild; + } + + next = nextElement.getNextSibling(); + element.removeChild(nextElement); + newElement.addEndTag(nextElement); + if (nextElement == first) + firstElement = newElement; + + Node newParent = newElement.getParentNode(); + if (newParent == parent) + break; + if (newParent == null || newParent.getNodeType() != Node.ELEMENT_NODE) + break; // error + newElement = (ElementImpl) newParent; + continue; + } + } + if (!canContain(newElement, next)) { + Node newParent = newElement.getParentNode(); + if (newParent == parent) + break; + if (newParent == null || newParent.getNodeType() != Node.ELEMENT_NODE) + break; // error + newElement = (ElementImpl) newParent; + continue; + } + Node child = next; + next = next.getNextSibling(); + element.removeChild(child); + newElement.appendChild(child); + } + newElement = null; + } + if (parent.getNodeType() == Node.ELEMENT_NODE) { + newElement = (ElementImpl) parent; + } + while (next != null) { + if (newElement == null || canContain(newElement, next)) { + Node child = next; + next = next.getNextSibling(); + element.removeChild(child); + parent.insertBefore(child, element); + continue; + } + + parent = newElement.getParentNode(); + if (parent == null) + return; + + // promote siblings + Node newNext = newElement.getNextSibling(); + Node child = element; + while (child != null) { + Node nextChild = child.getNextSibling(); + newElement.removeChild(child); + parent.insertBefore(child, newNext); + child = nextChild; + } + + // leave the old end tag where it is + if (newElement.hasEndTag()) { + Element end = newElement.removeEndTag(); + if (end != null) { + parent.insertBefore(end, newNext); + } + } + if (!newElement.hasStartTag()) { + // implicit element + if (!newElement.hasChildNodes()) { + parent.removeChild(newElement); + } + } + + if (parent.getNodeType() == Node.ELEMENT_NODE) { + newElement = (ElementImpl) parent; + } else { + newElement = null; + } + } + } + + Node newNext = element; + Node startElement = null; // for the case element is removed as end + // tag + if (oldElement.hasEndTag()) { + // find new parent for invalid end tag and siblings + ElementImpl newElement = null; + for (Node last = element.getPreviousSibling(); last != null; last = last.getLastChild()) { + if (last.getNodeType() != Node.ELEMENT_NODE) + break; + ElementImpl lastElement = (ElementImpl) last; + if (lastElement.hasEndTag() || lastElement.isEmptyTag() || !lastElement.isContainer()) + break; + newElement = lastElement; + } + if (newElement != null) { + // demote invalid end tag and sibling + Node next = element; + while (next != null) { + if (!newElement.hasEndTag() && newElement.hasStartTag() && next.getNodeType() == Node.ELEMENT_NODE) { + ElementImpl nextElement = (ElementImpl) next; + if (!nextElement.hasStartTag() && nextElement.hasEndTag() && nextElement.matchEndTag(newElement)) { + // stop at the matched invalid end tag + Node elementChild = nextElement.getFirstChild(); + while (elementChild != null) { + Node nextChild = elementChild.getNextSibling(); + nextElement.removeChild(elementChild); + newElement.appendChild(elementChild); + elementChild = nextChild; + } + + next = nextElement.getNextSibling(); + parent.removeChild(nextElement); + newElement.addEndTag(nextElement); + if (nextElement == newNext) + startElement = newElement; + + Node newParent = newElement.getParentNode(); + if (newParent == parent) + break; + if (newParent == null || newParent.getNodeType() != Node.ELEMENT_NODE) + break; // error + newElement = (ElementImpl) newParent; + continue; + } + } + if (!canContain(newElement, next)) { + Node newParent = newElement.getParentNode(); + if (newParent == parent) + break; + if (newParent == null || newParent.getNodeType() != Node.ELEMENT_NODE) + break; // error + newElement = (ElementImpl) newParent; + continue; + } + Node child = next; + next = next.getNextSibling(); + parent.removeChild(child); + if (child == oldElement) { + if (!oldElement.isCommentTag()) { + // clone (re-create) end tag + Element end = oldElement.removeEndTag(); + if (end != null) { + child = end; + newNext = end; + } + } + } + newElement.appendChild(child); + } + } else { + if (!oldElement.isCommentTag()) { + // clone (re-create) end tag + Element end = oldElement.removeEndTag(); + if (end != null) { + parent.insertBefore(end, oldElement); + parent.removeChild(oldElement); + newNext = end; + } + } + } + } else { + newNext = oldElement.getNextSibling(); + parent.removeChild(oldElement); + } + + // update context + Node oldParent = this.context.getParentNode(); + Node oldNext = this.context.getNextNode(); + if (element == oldParent) { + if (oldNext != null) { + this.context.setNextNode(oldNext); // reset for new parent + } else if (newNext != null) { + this.context.setNextNode(newNext); + } else { + this.context.setParentNode(parent); + } + } else if (element == oldNext) { + if (firstElement != null) { + this.context.setParentNode(firstElement); + } else if (first != null) { + this.context.setNextNode(first); + } else if (startElement != null) { + this.context.setParentNode(startElement); + } else { + this.context.setNextNode(newNext); + } + } + + removeImplicitElement(elementParent); + } + + /** + * removeStructuredDocumentRegion method + * + * @param oldStructuredDocumentRegion + * com.ibm.sed.structuredDocument.IStructuredDocumentRegion + */ + private void removeStructuredDocumentRegion(IStructuredDocumentRegion oldStructuredDocumentRegion) { + NodeImpl next = (NodeImpl) this.context.getNextNode(); + if (next != null) { + short nodeType = next.getNodeType(); + if (nodeType != Node.ELEMENT_NODE) { + IStructuredDocumentRegion flatNode = next.getStructuredDocumentRegion(); + if (flatNode == oldStructuredDocumentRegion) { + removeNode(next); + return; + } + if (nodeType != Node.TEXT_NODE) { + throw new StructuredDocumentRegionManagementException(); + } + if (flatNode == null) { + // this is the case for empty Text + // remove and continue + removeNode(next); + removeStructuredDocumentRegion(oldStructuredDocumentRegion); + return; + } + TextImpl text = (TextImpl) next; + boolean isShared = text.isSharingStructuredDocumentRegion(oldStructuredDocumentRegion); + if (isShared) { + // make sure there is next Text node sharing this + TextImpl nextText = (TextImpl) this.context.findNextText(); + if (nextText == null || !nextText.hasStructuredDocumentRegion(oldStructuredDocumentRegion)) { + isShared = false; + } + } + oldStructuredDocumentRegion = text.removeStructuredDocumentRegion(oldStructuredDocumentRegion); + if (oldStructuredDocumentRegion == null) { + throw new StructuredDocumentRegionManagementException(); + } + if (text.getStructuredDocumentRegion() == null) { + // this is the case partial IStructuredDocumentRegion is + // removed + removeNode(text); + } else { + // notify the change + text.notifyValueChanged(); + } + // if shared, continue to remove IStructuredDocumentRegion + // from them + if (isShared) + removeStructuredDocumentRegion(oldStructuredDocumentRegion); + return; + } + + ElementImpl element = (ElementImpl) next; + if (element.hasStartTag()) { + IStructuredDocumentRegion flatNode = element.getStartStructuredDocumentRegion(); + if (flatNode != oldStructuredDocumentRegion) { + throw new StructuredDocumentRegionManagementException(); + } + if (element.hasEndTag() || element.hasChildNodes()) { + element.setStartStructuredDocumentRegion(null); + removeStartTag(element); + } else { + removeNode(element); + } + } else { + Node child = element.getFirstChild(); + if (child != null) { + this.context.setNextNode(child); + removeStructuredDocumentRegion(oldStructuredDocumentRegion); + return; + } + + if (!element.hasEndTag()) { + // implicit element + removeNode(element); + removeStructuredDocumentRegion(oldStructuredDocumentRegion); + return; + } + + IStructuredDocumentRegion flatNode = element.getEndStructuredDocumentRegion(); + if (flatNode != oldStructuredDocumentRegion) { + throw new StructuredDocumentRegionManagementException(); + } + removeNode(element); + } + return; + } + + Node parent = this.context.getParentNode(); + if (parent == null || parent.getNodeType() != Node.ELEMENT_NODE) { + throw new StructuredDocumentRegionManagementException(); + } + + ElementImpl end = (ElementImpl) parent; + if (end.hasEndTag()) { + IStructuredDocumentRegion flatNode = end.getEndStructuredDocumentRegion(); + if (flatNode != oldStructuredDocumentRegion) { + throw new StructuredDocumentRegionManagementException(); + } + if (!end.hasStartTag() && !end.hasChildNodes()) { + this.context.setNextNode(end); + removeNode(end); + } else { + end.setEndStructuredDocumentRegion(null); + removeEndTag(end); + } + return; + } + + next = (NodeImpl) end.getNextSibling(); + if (next != null) { + this.context.setNextNode(next); + removeStructuredDocumentRegion(oldStructuredDocumentRegion); + return; + } + + parent = (NodeImpl) end.getParentNode(); + if (parent != null) { + this.context.setParentNode(parent); + removeStructuredDocumentRegion(oldStructuredDocumentRegion); + return; + } + } + + /** + * replaceRegions method + * + * @param flatNode + * com.ibm.sed.structuredDocument.IStructuredDocumentRegion + * @param newRegions + * java.util.Vector + * @param oldRegions + * java.util.Vector + */ + void replaceRegions(IStructuredDocumentRegion flatNode, ITextRegionList newRegions, ITextRegionList oldRegions) { + if (flatNode == null) + return; + if (this.document == null) + return; + this.context = new XMLModelContext(this.document); + + // optimize typical cases + String regionType = StructuredDocumentRegionUtil.getFirstRegionType(flatNode); + if (regionType == XMLRegionContext.XML_TAG_OPEN) { + changeStartTag(flatNode, newRegions, oldRegions); + } else if (regionType == XMLRegionContext.XML_END_TAG_OPEN) { + changeEndTag(flatNode, newRegions, oldRegions); + } else { + changeStructuredDocumentRegion(flatNode); + } + } + + /** + * replaceStructuredDocumentRegions method + * + * @param newStructuredDocumentRegions + * com.ibm.sed.structuredDocument.IStructuredDocumentRegionList + * @param oldStructuredDocumentRegions + * com.ibm.sed.structuredDocument.IStructuredDocumentRegionList + */ + void replaceStructuredDocumentRegions(IStructuredDocumentRegionList newStructuredDocumentRegions, IStructuredDocumentRegionList oldStructuredDocumentRegions) { + if (this.document == null) + return; + this.context = new XMLModelContext(this.document); + + int newCount = (newStructuredDocumentRegions != null ? newStructuredDocumentRegions.getLength() : 0); + int oldCount = (oldStructuredDocumentRegions != null ? oldStructuredDocumentRegions.getLength() : 0); + + if (oldCount > 0) { + setupContext(oldStructuredDocumentRegions.item(0)); + // Node startParent = this.context.getParentNode(); + + Enumeration e = oldStructuredDocumentRegions.elements(); + while (e.hasMoreElements()) { + IStructuredDocumentRegion flatNode = (IStructuredDocumentRegion) e.nextElement(); + if (flatNode == null) + continue; + removeStructuredDocumentRegion(flatNode); + } + } else { + if (newCount == 0) + return; + setupContext(newStructuredDocumentRegions.item(0)); + } + // make sure the parent is set to deepest level + // when end tag has been removed + this.context.setLast(); + + if (newCount > 0) { + Enumeration e = newStructuredDocumentRegions.elements(); + while (e.hasMoreElements()) { + IStructuredDocumentRegion flatNode = (IStructuredDocumentRegion) e.nextElement(); + if (flatNode == null) + continue; + insertStructuredDocumentRegion(flatNode); + } + } + + cleanupText(); + cleanupEndTag(); + } + + /** + * setupContext method + * + * @param flatNode + * com.ibm.sed.structuredDocument.IStructuredDocumentRegion + */ + private void setupContext(IStructuredDocumentRegion startStructuredDocumentRegion) { + int offset = startStructuredDocumentRegion.getStart(); + if (offset < 0) + return; + NodeImpl root = (NodeImpl) this.context.getRootNode(); + if (root == null) + return; + + if (offset == 0) { + // at the beggining of document + Node child = root.getFirstChild(); + if (child != null) + this.context.setNextNode(child); + else + this.context.setParentNode(root); + return; + } + + NodeImpl node = (NodeImpl) root.getNodeAt(offset); + if (node == null) { + // might be at the end of document + this.context.setParentNode(root); + this.context.setLast(); + return; + } + + if (offset == node.getStartOffset()) { + this.context.setNextNode(node); + return; + } + + if (node.getNodeType() == Node.TEXT_NODE) { + TextImpl text = (TextImpl) node; + Text nextText = text.splitText(startStructuredDocumentRegion); + // notify the change + text.notifyValueChanged(); + if (nextText == null) + return; // error + this.context.setNextNode(nextText); + return; + } + + for (Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) { + if (offset >= ((NodeImpl) child).getEndOffset()) + continue; + this.context.setNextNode(child); + return; + } + this.context.setParentNode(node); + this.context.setLast(); + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLModelUpdater.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLModelUpdater.java new file mode 100644 index 0000000000..c9cab984c8 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/document/XMLModelUpdater.java @@ -0,0 +1,1647 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.document; + + + +import java.util.Enumeration; +import java.util.Iterator; + +import org.eclipse.wst.sse.core.text.IStructuredDocument; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegionList; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.core.text.ITextRegionList; +import org.eclipse.wst.xml.core.document.JSPTag; +import org.eclipse.wst.xml.core.document.XMLElement; +import org.eclipse.wst.xml.core.document.XMLGenerator; +import org.eclipse.wst.xml.core.document.XMLNode; +import org.eclipse.wst.xml.core.jsp.model.parser.temp.XMLJSPRegionContexts; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.Text; + + +/** + * XMLModelUpdater class + */ +public class XMLModelUpdater implements XMLJSPRegionContexts { + private int diff = 0; + private int gapLength = 0; + private int gapOffset = 0; + private IStructuredDocumentRegion gapStructuredDocumentRegion = null; + private XMLGenerator generator = null; + private XMLModelImpl model = null; + private NodeImpl nextNode = null; + private NodeImpl parentNode = null; + + protected XMLModelUpdater(XMLModelImpl model) { + super(); + + if (model != null) { + this.model = model; + this.generator = model.getGenerator(); + } + } + + /** + * changeAttrValue method + * + * @param attrNode + * org.w3c.dom.Attr + */ + private void changeAttrName(Attr attrNode) { + if (attrNode == null) + return; + + AttrImpl attr = (AttrImpl) attrNode; + ElementImpl element = (ElementImpl) attr.getOwnerElement(); + if (element == null) + return; + + if (element.isCommentTag()) { + changeStartTag(element); + return; + } + + int offset = element.getStartOffset(); + int start = offset; + int end = offset; + + String name = attr.getName(); + if (name == null) + name = new String(); + ITextRegion nameRegion = attr.getNameRegion(); + if (nameRegion == null) + return; // error + start += nameRegion.getStart(); + // use getTextEnd() because getEnd() may include the tailing spaces + end += nameRegion.getTextEnd(); + + replaceSource(name, start, end); + } + + /** + * changeAttrValue method + * + * @param attrNode + * org.w3c.dom.Attr + */ + private void changeAttrValue(Attr attrNode) { + if (attrNode == null) + return; + + AttrImpl attr = (AttrImpl) attrNode; + ElementImpl element = (ElementImpl) attr.getOwnerElement(); + if (element == null) + return; + + if (element.isCommentTag()) { + changeStartTag(element); + return; + } + + int offset = element.getStartOffset(); + int start = offset; + int end = offset; + + String value = null; + ITextRegion valueRegion = attr.getValueRegion(); + if (valueRegion != null) { + char quote = 0; // no quote preference + // DW: 4/16/2003 due to change in structuredDocument ... we need a + // flatnode to + // get at region values. For now I'll assume this is always the + // first + // flatnode .. may need to make smarter later (e.g. to search for + // the flatnode that this.valueRegion belongs to. + IStructuredDocumentRegion documentRegion = element.getFirstStructuredDocumentRegion(); + String oldValue = documentRegion.getText(valueRegion); + if (oldValue != null && oldValue.length() > 0) { + char firstChar = oldValue.charAt(0); + if (firstChar == '"' || firstChar == '\'') { + quote = firstChar; + } + } + + ITextRegion startRegion = valueRegion; + + value = this.generator.generateAttrValue(attr, quote); + if (value == null) { + value = new String(); + // remove equal too + ITextRegion equalRegion = attr.getEqualRegion(); + if (equalRegion != null) + startRegion = equalRegion; + } + attr.setValueRegion(valueRegion); // reset value + + start += startRegion.getStart(); + // use getTextEnd() because getEnd() may include the tailing + // spaces + end += valueRegion.getTextEnd(); + } else { + ITextRegion equalRegion = attr.getEqualRegion(); + + value = this.generator.generateAttrValue(attr); + if (value == null) { + if (equalRegion == null) + return; // nothng to do + value = new String(); + // remove equal + start += equalRegion.getStart(); + end += equalRegion.getTextEnd(); + } else { + if (equalRegion != null) { + // use getTextEnd() because getEnd() may include the + // tailing spaces + start += equalRegion.getTextEnd(); + } else { + ITextRegion nameRegion = attr.getNameRegion(); + if (nameRegion == null) + return; // must never happen + // use getTextEnd() because getEnd() may include the + // tailing spaces + start += nameRegion.getTextEnd(); + value = '=' + value; + } + end = start; + } + } + + replaceSource(value, start, end); + } + + /** + */ + void changeEndTag(Element element) { + String source = this.generator.generateEndTag(element); + if (source == null) + return; + int length = source.length(); + if (length == 0) + return; + + ElementImpl impl = (ElementImpl) element; + int offset = impl.getEndStartOffset(); + int start = offset; + int end = offset; + if (impl.hasEndTag()) { + end = impl.getEndOffset(); + this.gapStructuredDocumentRegion = impl.getEndStructuredDocumentRegion(); + impl.setEndStructuredDocumentRegion(new StructuredDocumentRegionProxy(offset, length)); + } + + replaceSource(source, start, end); + } + + /** + * changeName method + * + * @param node + * org.w3c.dom.Node + */ + void changeName(Node node) { + if (node == null) + return; + if (getStructuredDocument() == null) + return; + + // support changing name of attribute for setPrefix() + short nodeType = node.getNodeType(); + if (nodeType == Node.ATTRIBUTE_NODE) { + changeAttrName((Attr) node); + return; + } + + // not supported + return; + } + + void changeRegion(IStructuredDocumentRegion flatNode, ITextRegion region) { + // future_TODO: optimize + + NodeImpl root = (NodeImpl) this.model.getDocument(); + this.parentNode = root; + this.nextNode = (NodeImpl) root.getFirstChild(); + + removeGapStructuredDocumentRegion(flatNode); + insertGapStructuredDocumentRegionBefore(flatNode.getStart()); + changeStructuredDocumentRegion(flatNode); + insertGapStructuredDocumentRegionAfter(flatNode.getEnd()); + } + + /** + * This is a fallback method to regenerate the start tag. + */ + void changeStartTag(Element element) { + if (element == null) + return; + ElementImpl impl = (ElementImpl) element; + + if (!impl.hasStartTag() && !impl.hasEndTag()) { + // need to generate the start and the end tags + Node parent = element.getParentNode(); + if (parent != null) { + replaceChild(parent, element, element); + return; + } + // else error + } + + String source = this.generator.generateStartTag(element); + if (source == null) + return; + int length = source.length(); + if (length == 0) + return; + + int offset = impl.getStartOffset(); + int start = offset; + int end = offset; + if (impl.hasStartTag()) { + end = impl.getStartEndOffset(); + this.gapStructuredDocumentRegion = impl.getStartStructuredDocumentRegion(); + } + impl.setStartStructuredDocumentRegion(new StructuredDocumentRegionProxy(offset, length)); + + replaceSource(source, start, end); + } + + private void changeStructuredDocumentRegion(IStructuredDocumentRegion oldStructuredDocumentRegion) { + if (oldStructuredDocumentRegion == null) + return; // error + if (this.parentNode == null) + return; // error + + int oldOffset = oldStructuredDocumentRegion.getStart(); + int oldEnd = oldStructuredDocumentRegion.getEnd(); + boolean isEndTag = false; + + // find owner node + NodeImpl ownerNode = null; + while (this.parentNode != null) { + if (this.nextNode != null) { + IStructuredDocumentRegion nextStructuredDocumentRegion = this.nextNode.getStructuredDocumentRegion(); + if (nextStructuredDocumentRegion != null) { + if (nextStructuredDocumentRegion == oldStructuredDocumentRegion) { + ownerNode = this.nextNode; + break; + } + int nextOffset = nextStructuredDocumentRegion.getStart(); + if (nextOffset == oldOffset) { // found + ownerNode = this.nextNode; + break; + } + if (this.nextNode.getNodeType() == Node.TEXT_NODE) { + TextImpl text = (TextImpl) this.nextNode; + if (text.hasStructuredDocumentRegion(oldStructuredDocumentRegion)) { + ownerNode = this.nextNode; + break; + } + int nextEnd = nextStructuredDocumentRegion.getEnd(); + if (nextOffset < oldEnd && nextEnd > oldOffset) { + ownerNode = this.nextNode; + break; + } + } + } + + Node child = this.nextNode.getFirstChild(); + if (child != null) { + this.parentNode = this.nextNode; + this.nextNode = (NodeImpl) child; + continue; + } + + if (this.nextNode.getNodeType() == Node.ELEMENT_NODE) { + this.parentNode = this.nextNode; + this.nextNode = null; + continue; + } + + this.nextNode = (NodeImpl) this.nextNode.getNextSibling(); + if (this.nextNode != null) + continue; + } + + if (this.parentNode.getNodeType() == Node.ELEMENT_NODE) { + ElementImpl element = (ElementImpl) this.parentNode; + IStructuredDocumentRegion endStructuredDocumentRegion = element.getEndStructuredDocumentRegion(); + if (endStructuredDocumentRegion != null) { + if (endStructuredDocumentRegion == oldStructuredDocumentRegion) { + ownerNode = this.parentNode; + isEndTag = true; + break; + } + int endOffset = endStructuredDocumentRegion.getStart(); + if (endOffset == oldOffset) { // found + ownerNode = this.parentNode; + isEndTag = true; + break; + } + } + } + + this.nextNode = (NodeImpl) this.parentNode.getNextSibling(); + this.parentNode = (NodeImpl) this.parentNode.getParentNode(); + } + if (ownerNode == null) + throw new StructuredDocumentRegionManagementException(); + + short nodeType = ownerNode.getNodeType(); + if (nodeType == Node.ELEMENT_NODE) { + ElementImpl element = (ElementImpl) ownerNode; + if (isEndTag) { + element.setEndStructuredDocumentRegion(oldStructuredDocumentRegion); + } else { + element.setStartStructuredDocumentRegion(oldStructuredDocumentRegion); + updateAttrRegions(element, oldStructuredDocumentRegion); + } + } else if (nodeType == Node.TEXT_NODE) { + TextImpl text = (TextImpl) ownerNode; + + IStructuredDocumentRegion flatNode = text.getStructuredDocumentRegion(); + if (flatNode == oldStructuredDocumentRegion) { + int newOffset = oldOffset; + int newEnd = oldEnd; + if (oldOffset == this.gapOffset) { + newOffset += this.diff; + } else { + newEnd = this.gapOffset; + } + int newLength = newEnd - newOffset; + IStructuredDocumentRegion newStructuredDocumentRegion = new StructuredDocumentRegionProxy(newOffset, newLength, oldStructuredDocumentRegion); + text.setStructuredDocumentRegion(newStructuredDocumentRegion); + + if (oldEnd > newEnd) { + this.nextNode = (NodeImpl) text.getNextSibling(); + changeStructuredDocumentRegion(oldStructuredDocumentRegion); + } + return; + } + + if (flatNode instanceof StructuredDocumentRegionProxy) { + StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) flatNode; + int offset = proxy.getOffset(); + int end = offset + proxy.getLength(); + if (proxy.getStructuredDocumentRegion() == null) { + if (offset == oldOffset && end == oldEnd) { + text.setStructuredDocumentRegion(oldStructuredDocumentRegion); + } else { + if (end > oldEnd) { + StructuredDocumentRegionContainer container = new StructuredDocumentRegionContainer(); + container.appendStructuredDocumentRegion(oldStructuredDocumentRegion); + proxy.setOffset(oldEnd); + proxy.setLength(end - oldEnd); + container.appendStructuredDocumentRegion(proxy); + text.setStructuredDocumentRegion(container); + } else { + proxy.setStructuredDocumentRegion(oldStructuredDocumentRegion); + + if (end < oldEnd) { // to be shared + this.nextNode = (NodeImpl) text.getNextSibling(); + changeStructuredDocumentRegion(oldStructuredDocumentRegion); + } + } + } + return; + } + + if (offset >= this.gapOffset) { + proxy.setOffset(offset + this.diff); + end += this.diff; + } + if (end < oldEnd) { // to be shared + this.nextNode = (NodeImpl) text.getNextSibling(); + changeStructuredDocumentRegion(oldStructuredDocumentRegion); + return; + } + } else if (flatNode instanceof StructuredDocumentRegionContainer) { + StructuredDocumentRegionContainer container = (StructuredDocumentRegionContainer) flatNode; + int count = container.getStructuredDocumentRegionCount(); + for (int i = 0; i < count; i++) { + IStructuredDocumentRegion content = container.getStructuredDocumentRegion(i); + if (content == null) + continue; // error + if (content == oldStructuredDocumentRegion) { + int newOffset = oldOffset; + int newEnd = oldEnd; + if (oldOffset == this.gapOffset) { + newOffset += this.diff; + } else { + newEnd = this.gapOffset; + } + int newLength = newEnd - newOffset; + IStructuredDocumentRegion newStructuredDocumentRegion = new StructuredDocumentRegionProxy(newOffset, newLength, oldStructuredDocumentRegion); + container.replaceStructuredDocumentRegion(newStructuredDocumentRegion, i); + + if (oldEnd > newEnd) { // to be shared + this.nextNode = (NodeImpl) text.getNextSibling(); + changeStructuredDocumentRegion(oldStructuredDocumentRegion); + } + return; + } + + if (content instanceof StructuredDocumentRegionProxy) { + StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) content; + int offset = proxy.getOffset(); + int end = offset + proxy.getLength(); + if (end <= oldOffset) + continue; + if (proxy.getStructuredDocumentRegion() == null) { + if (offset == oldOffset && end == oldEnd) { + container.replaceStructuredDocumentRegion(oldStructuredDocumentRegion, i); + } else { + if (end > oldEnd) { + container.insertStructuredDocumentRegion(oldStructuredDocumentRegion, i); + proxy.setOffset(oldEnd); + proxy.setLength(end - oldEnd); + } else { + proxy.setStructuredDocumentRegion(oldStructuredDocumentRegion); + + if (end < oldEnd) { // to be shared + this.nextNode = (NodeImpl) text.getNextSibling(); + changeStructuredDocumentRegion(oldStructuredDocumentRegion); + } + } + } + return; + } + + if (offset >= this.gapOffset) { + proxy.setOffset(offset + this.diff); + end += this.diff; + } + if (end < oldEnd) { // to be shared + this.nextNode = (NodeImpl) text.getNextSibling(); + changeStructuredDocumentRegion(oldStructuredDocumentRegion); + return; + } + } + } + } else { + throw new StructuredDocumentRegionManagementException(); + } + } else { + ownerNode.setStructuredDocumentRegion(oldStructuredDocumentRegion); + } + } + + /** + */ + private void changeTextData(Text text) { + if (text == null) + return; + + String source = this.generator.generateSource(text); + if (source == null) + source = new String(); + int length = source.length(); + + TextImpl impl = (TextImpl) text; + int start = impl.getStartOffset(); + int end = impl.getEndOffset(); + int offset = start; + + // make sure previous tag is closed + Node prev = text.getPreviousSibling(); + if (prev != null) { + String preTag = getCloseTag((XMLNode) prev); + if (preTag != null && preTag.length() > 0) { + offset += preTag.length(); + source = preTag + source; + } + } else { + Node parent = text.getParentNode(); + if (parent != null && parent.getNodeType() == Node.ELEMENT_NODE) { + ElementImpl element = (ElementImpl) parent; + String preTag = getStartCloseTag(element); + if (preTag != null && preTag.length() > 0) { + offset += preTag.length(); + StringBuffer buffer = new StringBuffer(); + buffer.append(preTag); + buffer.append(source); + if (text.getNextSibling() == null && !element.hasEndTag() && (element.isJSPContainer() || element.isCDATAContainer())) { + // need to generate the end tag + String postTag = this.generator.generateEndTag(element); + if (postTag != null) { + int postLength = postTag.length(); + if (postLength > 0) { + buffer.append(postTag); + int postOffset = offset + length; + IStructuredDocumentRegion flatNode = new StructuredDocumentRegionProxy(postOffset, postLength); + element.setEndStructuredDocumentRegion(flatNode); + } + } + } + source = buffer.toString(); + } + } + } + + this.gapStructuredDocumentRegion = impl.getStructuredDocumentRegion(); + IStructuredDocumentRegion newStructuredDocumentRegion = null; + if (length > 0) + newStructuredDocumentRegion = new StructuredDocumentRegionProxy(offset, length); + impl.setStructuredDocumentRegion(newStructuredDocumentRegion); + + replaceSource(source, start, end); + } + + /** + * changeValue method + * + * @param node + * org.w3c.dom.Node + */ + void changeValue(Node node) { + if (node == null) + return; + if (getStructuredDocument() == null) + return; + + short nodeType = node.getNodeType(); + if (nodeType == Node.TEXT_NODE) { + changeTextData((Text) node); + return; + } + if (nodeType == Node.ATTRIBUTE_NODE) { + changeAttrValue((Attr) node); + return; + } + if (nodeType == Node.ELEMENT_NODE) { + changeStartTag((Element) node); + return; + } + + String source = this.generator.generateSource(node); + if (source == null) + source = new String(); + int length = source.length(); + + NodeImpl impl = (NodeImpl) node; + int start = impl.getStartOffset(); + int end = impl.getEndOffset(); + + this.gapStructuredDocumentRegion = impl.getStructuredDocumentRegion(); + IStructuredDocumentRegion flatNode = null; + if (length > 0) + flatNode = new StructuredDocumentRegionProxy(start, length); + impl.setStructuredDocumentRegion(flatNode); + + replaceSource(source, start, end); + } + + /** + */ + private String getAttrValueClose(XMLElement element) { + if (element == null) + return null; + + IStructuredDocumentRegion flatNode = element.getStartStructuredDocumentRegion(); + if (flatNode == null) + return null; + ITextRegion region = StructuredDocumentRegionUtil.getLastRegion(flatNode); + if (region == null || region.getType() != XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE) + return null; + String value = flatNode.getText(region); + if (value == null) + return null; + int length = value.length(); + if (length == 0) + return null; + + // check open JSP tag + boolean closeJSPTag = false; + int offset = value.indexOf(JSPTag.TAG_OPEN); + while (offset >= 0) { + offset = value.indexOf(JSPTag.TAG_CLOSE, offset + 2); + if (offset < 0) { + closeJSPTag = true; + break; + } + offset = value.indexOf(JSPTag.TAG_OPEN, offset + 2); + } + + // check quote + boolean closeQuote = false; + char firstChar = value.charAt(0); + if (firstChar == '"' || firstChar == '\'') { + if (closeJSPTag || length == 1 || value.charAt(length - 1) != firstChar) { + closeQuote = true; + } + } + + if (!closeJSPTag && !closeQuote) + return null; + + StringBuffer buffer = new StringBuffer(); + if (closeJSPTag) + buffer.append(JSPTag.TAG_CLOSE); + if (closeQuote) + buffer.append(firstChar); + return buffer.toString(); + } + + /** + * Gather close tags recursively. + */ + private String getCloseTag(XMLNode node) { + if (node == null || node.isClosed()) + return null; + + if (node.getNodeType() != Node.ELEMENT_NODE) { + return this.generator.generateCloseTag(node); + } + + ElementImpl element = (ElementImpl) node; + if (element.hasEndTag()) { + // end tag is not closed + return this.generator.generateCloseTag(element); + } + + // no end tag + int offset = element.getEndOffset(); + StringBuffer buffer = new StringBuffer(); + + XMLNode lastChild = (XMLNode) element.getLastChild(); + if (lastChild == null) { + if (!element.isStartTagClosed()) { + if (element.preferEmptyTag()) + element.setEmptyTag(true); + String closeTag = getStartCloseTag(element); + if (closeTag != null) { + int length = closeTag.length(); + if (length > 0) { + buffer.append(closeTag); + offset += length; + } + } + } + } else { + String closeTag = getCloseTag(lastChild); + if (closeTag != null) { + int length = closeTag.length(); + if (length > 0) { + buffer.append(closeTag); + offset += length; + } + } + } + + String endTag = this.generator.generateEndTag(element); + if (endTag != null) { + int length = endTag.length(); + if (length > 0) { + buffer.append(endTag); + IStructuredDocumentRegion flatNode = new StructuredDocumentRegionProxy(offset, length); + element.setEndStructuredDocumentRegion(flatNode); + } + } + + return buffer.toString(); + } + + /** + */ + private String getStartCloseTag(XMLElement element) { + if (element == null || element.isStartTagClosed()) + return null; + + StringBuffer buffer = new StringBuffer(); + String attrValueClose = getAttrValueClose(element); + if (attrValueClose != null) + buffer.append(attrValueClose); + String closeTag = this.generator.generateCloseTag(element); + if (closeTag != null) + buffer.append(closeTag); + return buffer.toString(); + } + + private IStructuredDocument getStructuredDocument() { + if (model == null) + return null; + return model.getStructuredDocument(); + } + + /** + */ + void initialize() { + this.gapStructuredDocumentRegion = null; + this.gapOffset = 0; + this.gapLength = 0; + this.diff = 0; + this.parentNode = null; + this.nextNode = null; + } + + private void insertGapStructuredDocumentRegionAfter(int endOffset) { + if (this.gapStructuredDocumentRegion == null) + return; + + if (this.gapStructuredDocumentRegion instanceof StructuredDocumentRegionProxy) { + StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) this.gapStructuredDocumentRegion; + IStructuredDocumentRegion flatNode = proxy.getStructuredDocumentRegion(); + if (flatNode != null) + insertStructuredDocumentRegion(flatNode); + } else if (this.gapStructuredDocumentRegion instanceof StructuredDocumentRegionContainer) { + StructuredDocumentRegionContainer container = (StructuredDocumentRegionContainer) this.gapStructuredDocumentRegion; + int count = container.getStructuredDocumentRegionCount(); + for (int i = 0; i < count; i++) { + IStructuredDocumentRegion content = container.getStructuredDocumentRegion(i); + if (content == null) + continue; + if (content.getStart() < endOffset) + continue; + if (content instanceof StructuredDocumentRegionProxy) { + StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) content; + IStructuredDocumentRegion flatNode = proxy.getStructuredDocumentRegion(); + if (flatNode != null) + insertStructuredDocumentRegion(flatNode); + } else { + insertStructuredDocumentRegion(content); + } + } + } else { + insertStructuredDocumentRegion(this.gapStructuredDocumentRegion); + } + } + + private void insertGapStructuredDocumentRegionBefore(int startOffset) { + if (this.gapStructuredDocumentRegion == null) + return; + + if (this.gapStructuredDocumentRegion instanceof StructuredDocumentRegionProxy) { + StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) this.gapStructuredDocumentRegion; + IStructuredDocumentRegion flatNode = proxy.getStructuredDocumentRegion(); + if (flatNode != null) + insertStructuredDocumentRegion(flatNode); + } else if (this.gapStructuredDocumentRegion instanceof StructuredDocumentRegionContainer) { + StructuredDocumentRegionContainer container = (StructuredDocumentRegionContainer) this.gapStructuredDocumentRegion; + int count = container.getStructuredDocumentRegionCount(); + for (int i = 0; i < count; i++) { + IStructuredDocumentRegion content = container.getStructuredDocumentRegion(i); + if (content == null) + continue; + if (content.getStart() >= startOffset) + return; + if (content instanceof StructuredDocumentRegionProxy) { + StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) content; + IStructuredDocumentRegion flatNode = proxy.getStructuredDocumentRegion(); + if (flatNode != null) + insertStructuredDocumentRegion(flatNode); + } else { + insertStructuredDocumentRegion(content); + } + } + } else { + insertStructuredDocumentRegion(this.gapStructuredDocumentRegion); + } + } + + /** + */ + private void insertStructuredDocumentRegion(IStructuredDocumentRegion newStructuredDocumentRegion) { + if (newStructuredDocumentRegion == null) + return; // error + if (this.parentNode == null) + return; // error + + int newOffset = newStructuredDocumentRegion.getStart(); + int newEnd = newStructuredDocumentRegion.getEnd(); + boolean isEndTag = false; + + // find owner node + NodeImpl ownerNode = null; + while (this.parentNode != null) { + if (this.nextNode != null) { + IStructuredDocumentRegion nextStructuredDocumentRegion = this.nextNode.getStructuredDocumentRegion(); + if (nextStructuredDocumentRegion != null) { + int nextOffset = nextStructuredDocumentRegion.getStart(); + if (nextOffset == newOffset) { // found + ownerNode = this.nextNode; + break; + } + if (this.nextNode.getNodeType() == Node.TEXT_NODE) { + int nextEnd = nextStructuredDocumentRegion.getEnd(); + if (nextOffset < newEnd && nextEnd > newOffset) { + ownerNode = this.nextNode; + break; + } + } + } + + Node child = this.nextNode.getFirstChild(); + if (child != null) { + this.parentNode = this.nextNode; + this.nextNode = (NodeImpl) child; + continue; + } + + if (this.nextNode.getNodeType() == Node.ELEMENT_NODE) { + this.parentNode = this.nextNode; + this.nextNode = null; + continue; + } + + this.nextNode = (NodeImpl) this.nextNode.getNextSibling(); + if (this.nextNode != null) + continue; + } + + if (this.parentNode.getNodeType() == Node.ELEMENT_NODE) { + ElementImpl element = (ElementImpl) this.parentNode; + IStructuredDocumentRegion endStructuredDocumentRegion = element.getEndStructuredDocumentRegion(); + if (endStructuredDocumentRegion != null) { + int endOffset = endStructuredDocumentRegion.getStart(); + if (endOffset == newOffset) { // found + ownerNode = this.parentNode; + isEndTag = true; + break; + } + } + } + + this.nextNode = (NodeImpl) this.parentNode.getNextSibling(); + this.parentNode = (NodeImpl) this.parentNode.getParentNode(); + } + if (ownerNode == null) + throw new StructuredDocumentRegionManagementException(); + + short nodeType = ownerNode.getNodeType(); + if (nodeType == Node.ELEMENT_NODE) { + ElementImpl element = (ElementImpl) ownerNode; + if (isEndTag) { + element.setEndStructuredDocumentRegion(newStructuredDocumentRegion); + } else { + element.setStartStructuredDocumentRegion(newStructuredDocumentRegion); + updateAttrRegions(element, newStructuredDocumentRegion); + } + } else if (nodeType == Node.TEXT_NODE) { + TextImpl text = (TextImpl) ownerNode; + IStructuredDocumentRegion oldStructuredDocumentRegion = text.getStructuredDocumentRegion(); + if (oldStructuredDocumentRegion == null) { + throw new StructuredDocumentRegionManagementException(); + } + int oldOffset = oldStructuredDocumentRegion.getStart(); + int oldEnd = oldStructuredDocumentRegion.getEnd(); + if (oldOffset == newOffset && oldEnd == newEnd) { + text.setStructuredDocumentRegion(newStructuredDocumentRegion); + return; + } + + if (oldStructuredDocumentRegion instanceof StructuredDocumentRegionProxy) { + StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) oldStructuredDocumentRegion; + if (oldEnd > newEnd) { + StructuredDocumentRegionContainer container = new StructuredDocumentRegionContainer(); + if (oldOffset == newOffset) { + container.appendStructuredDocumentRegion(newStructuredDocumentRegion); + } else { + StructuredDocumentRegionProxy newProxy = new StructuredDocumentRegionProxy(); + newProxy.setOffset(oldOffset); + newProxy.setLength(newEnd - oldOffset); + newProxy.setStructuredDocumentRegion(newStructuredDocumentRegion); + container.appendStructuredDocumentRegion(newProxy); + } + proxy.setOffset(newEnd); + proxy.setLength(oldEnd - newEnd); + container.appendStructuredDocumentRegion(proxy); + text.setStructuredDocumentRegion(container); + } else { + proxy.setStructuredDocumentRegion(newStructuredDocumentRegion); + + if (oldEnd < newEnd) { // to be shared + this.nextNode = (NodeImpl) text.getNextSibling(); + insertStructuredDocumentRegion(newStructuredDocumentRegion); + } + } + return; + } + + if (oldStructuredDocumentRegion instanceof StructuredDocumentRegionContainer) { + StructuredDocumentRegionContainer container = (StructuredDocumentRegionContainer) oldStructuredDocumentRegion; + int count = container.getStructuredDocumentRegionCount(); + for (int i = 0; i < count; i++) { + IStructuredDocumentRegion content = container.getStructuredDocumentRegion(i); + if (content == null) + continue; // error + int offset = content.getStart(); + int end = content.getEnd(); + if (end <= newOffset) + continue; + if (offset == newOffset && end == newEnd) { + container.replaceStructuredDocumentRegion(newStructuredDocumentRegion, i); + return; + } + + if (content instanceof StructuredDocumentRegionProxy) { + StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) content; + if (end > newEnd) { + if (offset == newOffset) { + container.insertStructuredDocumentRegion(newStructuredDocumentRegion, i); + } else { + StructuredDocumentRegionProxy newProxy = new StructuredDocumentRegionProxy(); + newProxy.setOffset(offset); + newProxy.setLength(newEnd - offset); + newProxy.setStructuredDocumentRegion(newStructuredDocumentRegion); + container.insertStructuredDocumentRegion(newProxy, i); + } + proxy.setOffset(newEnd); + proxy.setLength(end - newEnd); + return; + } else { + proxy.setStructuredDocumentRegion(newStructuredDocumentRegion); + if (end == newEnd) + return; + } + } + } + + if (oldEnd < newEnd) { // to be shared + this.nextNode = (NodeImpl) text.getNextSibling(); + insertStructuredDocumentRegion(newStructuredDocumentRegion); + } + return; + } else { + throw new StructuredDocumentRegionManagementException(); + } + } else { + ownerNode.setStructuredDocumentRegion(newStructuredDocumentRegion); + } + } + + private void removeGapStructuredDocumentRegion(IStructuredDocumentRegion oldStructuredDocumentRegion) { + if (this.gapStructuredDocumentRegion == null) + return; + + if (this.gapStructuredDocumentRegion == oldStructuredDocumentRegion) { + this.gapStructuredDocumentRegion = null; + return; + } + + if (this.gapStructuredDocumentRegion instanceof StructuredDocumentRegionProxy) { + StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) this.gapStructuredDocumentRegion; + IStructuredDocumentRegion flatNode = proxy.getStructuredDocumentRegion(); + if (flatNode == oldStructuredDocumentRegion) + this.gapStructuredDocumentRegion = null; + } else if (this.gapStructuredDocumentRegion instanceof StructuredDocumentRegionContainer) { + StructuredDocumentRegionContainer container = (StructuredDocumentRegionContainer) this.gapStructuredDocumentRegion; + int count = container.getStructuredDocumentRegionCount(); + for (int i = 0; i < count; i++) { + IStructuredDocumentRegion content = container.getStructuredDocumentRegion(i); + if (content == null) + continue; + if (content == oldStructuredDocumentRegion) { + if (count > 1) + container.removeStructuredDocumentRegion(i); + else + this.gapStructuredDocumentRegion = null; + return; + } + if (content instanceof StructuredDocumentRegionProxy) { + StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) content; + if (proxy.getStructuredDocumentRegion() == oldStructuredDocumentRegion) { + if (count > 1) + container.removeStructuredDocumentRegion(i); + else + this.gapStructuredDocumentRegion = null; + return; + } + } + } + } + } + + private void removeStructuredDocumentRegion(IStructuredDocumentRegion oldStructuredDocumentRegion) { + if (oldStructuredDocumentRegion == null) + return; // error + if (this.parentNode == null) + return; // error + + int gapEnd = this.gapOffset + this.gapLength; + int oldOffset = oldStructuredDocumentRegion.getStart(); + int oldEnd = oldStructuredDocumentRegion.getEnd(); + if (oldOffset >= this.gapOffset && oldEnd <= gapEnd) + return; // do nothing + int oldLength = oldEnd - oldOffset; + if (oldOffset >= gapEnd) + oldOffset += this.diff; + + // find owner node + NodeImpl ownerNode = null; + ElementImpl ownerEndTag = null; + TextImpl ownerText = null; + while (this.parentNode != null) { + if (this.nextNode != null) { + if (this.nextNode.getStructuredDocumentRegion() == oldStructuredDocumentRegion) { + ownerNode = this.nextNode; + break; + } + if (this.nextNode.getNodeType() == Node.TEXT_NODE) { + TextImpl text = (TextImpl) this.nextNode; + if (text.hasStructuredDocumentRegion(oldStructuredDocumentRegion)) { + ownerNode = this.nextNode; + ownerText = text; + break; + } + } + + Node child = this.nextNode.getFirstChild(); + if (child != null) { + this.parentNode = this.nextNode; + this.nextNode = (NodeImpl) child; + continue; + } + + if (this.nextNode.getNodeType() == Node.ELEMENT_NODE) { + this.parentNode = this.nextNode; + this.nextNode = null; + continue; + } + + this.nextNode = (NodeImpl) this.nextNode.getNextSibling(); + if (this.nextNode != null) + continue; + } + + if (this.parentNode.getNodeType() == Node.ELEMENT_NODE) { + ElementImpl element = (ElementImpl) this.parentNode; + if (element.getEndStructuredDocumentRegion() == oldStructuredDocumentRegion) { + ownerNode = this.parentNode; + ownerEndTag = element; + break; + } + } + + this.nextNode = (NodeImpl) this.parentNode.getNextSibling(); + this.parentNode = (NodeImpl) this.parentNode.getParentNode(); + } + if (ownerNode == null) + throw new StructuredDocumentRegionManagementException(); + + if (ownerText != null) { + IStructuredDocumentRegion flatNode = ownerText.getStructuredDocumentRegion(); + if (flatNode == oldStructuredDocumentRegion) { + IStructuredDocumentRegion newStructuredDocumentRegion = new StructuredDocumentRegionProxy(oldOffset, oldLength); + ownerText.setStructuredDocumentRegion(newStructuredDocumentRegion); + return; + } + + if (flatNode instanceof StructuredDocumentRegionProxy) { + StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) flatNode; + if (proxy.getStructuredDocumentRegion() != oldStructuredDocumentRegion) { + throw new StructuredDocumentRegionManagementException(); + } + int offset = proxy.getOffset(); + int end = offset + proxy.getLength(); + if (offset >= this.gapOffset) { + proxy.setOffset(offset + this.diff); + } + proxy.setStructuredDocumentRegion(null); + if (end < oldEnd && (end < this.gapOffset || oldEnd > gapEnd)) { // has + // shared + removeStructuredDocumentRegion(oldStructuredDocumentRegion); + return; + } + } else if (flatNode instanceof StructuredDocumentRegionContainer) { + StructuredDocumentRegionContainer container = (StructuredDocumentRegionContainer) flatNode; + int count = container.getStructuredDocumentRegionCount(); + for (int i = 0; i < count; i++) { + IStructuredDocumentRegion content = container.getStructuredDocumentRegion(i); + if (content == null) + continue; // error + if (content == oldStructuredDocumentRegion) { + IStructuredDocumentRegion newStructuredDocumentRegion = new StructuredDocumentRegionProxy(oldOffset, oldLength); + container.replaceStructuredDocumentRegion(newStructuredDocumentRegion, i); + return; + } + + if (content instanceof StructuredDocumentRegionProxy) { + StructuredDocumentRegionProxy proxy = (StructuredDocumentRegionProxy) content; + if (proxy.getStructuredDocumentRegion() == oldStructuredDocumentRegion) { + int offset = proxy.getOffset(); + int end = offset + proxy.getLength(); + if (offset >= this.gapOffset) { + proxy.setOffset(offset + this.diff); + } + proxy.setStructuredDocumentRegion(null); + if (end < oldEnd && (end < this.gapOffset || oldEnd > gapEnd)) { // has + // shared + removeStructuredDocumentRegion(oldStructuredDocumentRegion); + return; + } + } + } + } + } else { + throw new StructuredDocumentRegionManagementException(); + } + } else { + IStructuredDocumentRegion newStructuredDocumentRegion = new StructuredDocumentRegionProxy(oldOffset, oldLength); + if (ownerEndTag != null) { + ownerEndTag.setEndStructuredDocumentRegion(newStructuredDocumentRegion); + } else { + ownerNode.setStructuredDocumentRegion(newStructuredDocumentRegion); + } + } + } + + /** + * replaceAttr method + * + * @param ownerElement + * org.w3c.dom.Element + * @param newAttr + * org.w3c.dom.Attr + * @param oldAttr + * org.w3c.dom.Attr + */ + void replaceAttr(Element ownerElement, Attr newAttr, Attr oldAttr) { + if (ownerElement == null) + return; + if (getStructuredDocument() == null) + return; + + ElementImpl element = (ElementImpl) ownerElement; + if (!element.hasStartTag()) { + changeStartTag(element); + return; + } + if (element.isCommentTag()) { + changeStartTag(element); + return; + } + + int offset = element.getStartOffset(); + int start = offset; + int end = offset; + + boolean insertSpace = false; + String attrValueClose = null; + if (oldAttr != null) { + AttrImpl impl = (AttrImpl) oldAttr; + ITextRegion nameRegion = impl.getNameRegion(); + if (nameRegion == null) + return; // must never happen + ITextRegion lastRegion = impl.getValueRegion(); + if (lastRegion != null) { + end += lastRegion.getEnd(); + } else { + lastRegion = impl.getEqualRegion(); + if (lastRegion != null) { + end += lastRegion.getEnd(); + } else { + end += nameRegion.getEnd(); + lastRegion = nameRegion; + } + } + // check there are extra space before the last attribute + IStructuredDocumentRegion flatNode = element.getStartStructuredDocumentRegion(); + if (flatNode == null) + return; // must never happen + ITextRegionList regions = flatNode.getRegions(); + if (regions == null) + return; // must never happen + ITextRegion prevRegion = null; + ITextRegion nextRegion = null; + for (int i = 0; i < regions.size(); i++) { + ITextRegion region = regions.get(i); + if (region == nameRegion) { + if (i > 0) { + prevRegion = regions.get(i - 1); + } + } + if (region == lastRegion) { + if (i + 1 < regions.size()) { + nextRegion = regions.get(i + 1); + } + break; + } + } + boolean isLastAttr = false; + if (nextRegion != null) { + String regionType = nextRegion.getType(); + if (regionType == XMLRegionContext.XML_TAG_CLOSE || regionType == XMLRegionContext.XML_EMPTY_TAG_CLOSE || regionType == JSP_CLOSE || regionType == JSP_DIRECTIVE_CLOSE) { + isLastAttr = true; + } + } + if (isLastAttr && prevRegion != null) { + start += prevRegion.getTextEnd(); + } else { + start += nameRegion.getStart(); + } + + // impl.resetRegions(ownerElement); + impl.resetRegions(element); + } else { // append attribute + IStructuredDocumentRegion flatNode = element.getStartStructuredDocumentRegion(); + if (flatNode == null) + return; // must never happen + + attrValueClose = getAttrValueClose(element); + if (attrValueClose != null && attrValueClose.length() > 0) { + insertSpace = true; + start = flatNode.getEndOffset(); + end = start; + } else { + ITextRegionList regions = flatNode.getRegions(); + if (regions == null) + return; // must never happen + int attrStart = 0; + for (int i = regions.size() - 1; i >= 0; i--) { + ITextRegion region = regions.get(i); + String regionType = region.getType(); + if (regionType == XMLRegionContext.XML_TAG_CLOSE || regionType == XMLRegionContext.XML_EMPTY_TAG_CLOSE || regionType == JSP_CLOSE || regionType == JSP_DIRECTIVE_CLOSE) + continue; + int regionEnd = region.getEnd(); + if (regionEnd == region.getTextEnd()) + insertSpace = true; + attrStart = regionEnd; + break; + } + if (attrStart == 0) + return; // not found, must never happen + start += attrStart; + end = start; + } + } + + String source = null; + if (newAttr != null) { + int size = 2; + if (attrValueClose != null) + size += attrValueClose.length(); + String name = this.generator.generateAttrName(newAttr); + if (name != null) + size += name.length(); + String value = this.generator.generateAttrValue(newAttr); + if (value != null) + size += value.length(); + StringBuffer buffer = new StringBuffer(size); + if (attrValueClose != null) + buffer.append(attrValueClose); + if (insertSpace) + buffer.append(' '); + buffer.append(name); + if (value != null) { + buffer.append('='); + buffer.append(value); + } + source = buffer.toString(); + } + + replaceSource(source, start, end); + } + + /** + * replaceChild method + * + * @param parentNode + * org.w3c.dom.Node + * @param newChild + * org.w3c.dom.Node + * @param oldChild + * org.w3c.dom.Node + */ + void replaceChild(Node parentNode, Node newChild, Node oldChild) { + if (parentNode == null) + return; + if (newChild == null && oldChild == null) + return; + if (getStructuredDocument() == null) + return; + + int start = 0; + int end = 0; + String preTag = null; + String postTag = null; + ElementImpl postElement = null; + if (oldChild != null) { + NodeImpl node = (NodeImpl) oldChild; + start = node.getStartOffset(); + end = node.getEndOffset(); + if (oldChild.getNodeType() == Node.TEXT_NODE) { + this.gapStructuredDocumentRegion = node.getStructuredDocumentRegion(); + } + node.resetStructuredDocumentRegions(); // reset values from + // IStructuredDocumentRegion + } else { + NodeImpl prev = (NodeImpl) newChild.getPreviousSibling(); + if (prev != null) { + start = prev.getEndOffset(); + end = start; + preTag = getCloseTag(prev); + } else { + // first child + NodeImpl next = (NodeImpl) newChild.getNextSibling(); + if (next != null) { + start = next.getStartOffset(); + end = start; + if (parentNode.getNodeType() == Node.ELEMENT_NODE) { + preTag = getStartCloseTag((XMLElement) parentNode); + } + } else { + // newly having a child + if (parentNode.getNodeType() == Node.ELEMENT_NODE) { + ElementImpl element = (ElementImpl) parentNode; + if (element.isEmptyTag()) { // empty tag format + // need to generate the start and the end tags + end = element.getEndOffset(); + start = end - 2; // for "/>" + element.setEmptyTag(false); + preTag = this.generator.generateCloseTag(element); + postTag = this.generator.generateEndTag(element); + postElement = element; + } else if (!element.hasStartTag()) { + start = element.getStartOffset(); + end = start; + // invalid end tag or implicit tag + // need to generate the start tag + preTag = this.generator.generateStartTag(element); + if (preTag != null) { + int length = preTag.length(); + if (length > 0) { + IStructuredDocumentRegion flatNode = new StructuredDocumentRegionProxy(start, length); + element.setStartStructuredDocumentRegion(flatNode); + } + } + if (!element.hasEndTag()) { + // implicit tag + // need to generate the end tags + postTag = this.generator.generateEndTag(element); + postElement = element; + } + } else { + start = element.getStartEndOffset(); + end = start; + preTag = getStartCloseTag(element); + if (preTag != null && preTag.length() > 0) { + if (!element.hasEndTag() && (element.isJSPContainer() || element.isCDATAContainer())) { + // need to generate the end tag + postTag = this.generator.generateEndTag(element); + postElement = element; + } + } + } + } + // else might DOCUMENT_NODE, start and end are 0 + } + } + } + + String source = null; + if (newChild != null) { + StringBuffer buffer = new StringBuffer(); + int offset = start; + if (preTag != null) { + int length = preTag.length(); + if (length > 0) { + offset += length; + buffer.append(preTag); + } + } + + NodeImpl node = (NodeImpl) newChild; + while (node != null) { + if (node.getNodeType() == Node.ELEMENT_NODE) { + ElementImpl element = (ElementImpl) node; + if (element.preferEmptyTag()) + element.setEmptyTag(true); + IStructuredDocumentRegion flatNode = null; + String startTag = this.generator.generateStartTag(element); + if (startTag != null) { + int length = startTag.length(); + if (length > 0) { + buffer.append(startTag); + flatNode = new StructuredDocumentRegionProxy(offset, length); + offset += length; + } + } + element.setStartStructuredDocumentRegion(flatNode); + } else { + String content = this.generator.generateSource(node); + if (content == null) + content = new String(); + int length = content.length(); + IStructuredDocumentRegion flatNode = null; + if (length > 0) { + buffer.append(content); + flatNode = new StructuredDocumentRegionProxy(offset, length); + offset += length; + } + node.setStructuredDocumentRegion(flatNode); + } + + NodeImpl child = (NodeImpl) node.getFirstChild(); + if (child != null) { + node = child; + continue; + } + + if (node.getNodeType() == Node.ELEMENT_NODE) { + ElementImpl element = (ElementImpl) node; + IStructuredDocumentRegion flatNode = null; + String endTag = this.generator.generateEndTag(element); + if (endTag != null) { + int length = endTag.length(); + if (length > 0) { + buffer.append(endTag); + flatNode = new StructuredDocumentRegionProxy(offset, length); + offset += length; + } + } + element.setEndStructuredDocumentRegion(flatNode); + } + + while (node != null) { + if (node == newChild) { + node = null; + break; + } + NodeImpl next = (NodeImpl) node.getNextSibling(); + if (next != null) { + node = next; + break; + } + + node = (NodeImpl) node.getParentNode(); + if (node.getNodeType() != Node.ELEMENT_NODE) + continue; + ElementImpl element = (ElementImpl) node; + IStructuredDocumentRegion flatNode = null; + String endTag = this.generator.generateEndTag(element); + if (endTag != null) { + int length = endTag.length(); + if (length > 0) { + buffer.append(endTag); + flatNode = new StructuredDocumentRegionProxy(offset, length); + offset += length; + } + } + element.setEndStructuredDocumentRegion(flatNode); + } + } + + if (postTag != null) { + int length = postTag.length(); + if (length > 0) { + buffer.append(postTag); + if (postElement != null) { + IStructuredDocumentRegion flatNode = new StructuredDocumentRegionProxy(offset, length); + postElement.setEndStructuredDocumentRegion(flatNode); + } + } + } + source = buffer.toString(); + } + + if (start == end && (source == null || source.length() == 0)) { + // no thing changed + return; + } + + replaceSource(source, start, end); + } + + void replaceRegions(IStructuredDocumentRegion flatNode, ITextRegionList newRegions, ITextRegionList oldRegions) { + // future_TODO: optimize + + NodeImpl root = (NodeImpl) this.model.getDocument(); + this.parentNode = root; + this.nextNode = (NodeImpl) root.getFirstChild(); + + removeGapStructuredDocumentRegion(flatNode); + insertGapStructuredDocumentRegionBefore(flatNode.getStart()); + changeStructuredDocumentRegion(flatNode); + insertGapStructuredDocumentRegionAfter(flatNode.getEnd()); + } + + /** + * Wraps IStructuredDocumentRegion.replaceText() and sets contextual + * information. + */ + private void replaceSource(String source, int start, int end) { + int inserted = 0; + if (source == null) + source = new String(); + else + inserted = source.length(); + int removed = end - start; + if (inserted == 0 && removed == 0) + return; + + this.gapOffset = start; + this.gapLength = removed; + this.diff = inserted - removed; + // Note: due to bug + // https://w3.opensource.ibm.com/bugzilla/show_bug.cgi?id=3619 + // for now assume "ignore readonly" region is ok -- assume DOM itself + // checks if + // ok to insert or not. In reality, we may have to make or "contains" + // method more + // better. Or, we may have to "perculate up" the parameter for clients + // to tell us programatically + // that its ok to insert/format in a read-only region. + getStructuredDocument().replaceText(this.model, this.gapOffset, this.gapLength, source, true); + } + + void replaceStructuredDocumentRegions(IStructuredDocumentRegionList newStructuredDocumentRegions, IStructuredDocumentRegionList oldStructuredDocumentRegions) { + NodeImpl root = (NodeImpl) this.model.getDocument(); + + if (oldStructuredDocumentRegions != null) { + this.parentNode = root; + this.nextNode = (NodeImpl) root.getFirstChild(); + + Enumeration e = oldStructuredDocumentRegions.elements(); + while (e.hasMoreElements()) { + IStructuredDocumentRegion flatNode = (IStructuredDocumentRegion) e.nextElement(); + if (flatNode == null) + continue; + removeStructuredDocumentRegion(flatNode); + removeGapStructuredDocumentRegion(flatNode); + } + } + + if (newStructuredDocumentRegions != null) { + this.parentNode = root; + this.nextNode = (NodeImpl) root.getFirstChild(); + + IStructuredDocumentRegion lastStructuredDocumentRegion = null; + Enumeration e = newStructuredDocumentRegions.elements(); + while (e.hasMoreElements()) { + IStructuredDocumentRegion flatNode = (IStructuredDocumentRegion) e.nextElement(); + if (flatNode == null) + continue; + if (lastStructuredDocumentRegion == null) + insertGapStructuredDocumentRegionBefore(flatNode.getStart()); + insertStructuredDocumentRegion(flatNode); + lastStructuredDocumentRegion = flatNode; + } + if (lastStructuredDocumentRegion != null) { + insertGapStructuredDocumentRegionAfter(lastStructuredDocumentRegion.getEnd()); + } else { + insertGapStructuredDocumentRegionBefore(this.gapOffset); + // make sure to restore all backuped StructuredDocumentRegions + insertGapStructuredDocumentRegionAfter(this.gapOffset); + } + } else { + this.parentNode = root; + this.nextNode = (NodeImpl) root.getFirstChild(); + + insertGapStructuredDocumentRegionBefore(this.gapOffset); + // make sure to restore all backuped StructuredDocumentRegions + insertGapStructuredDocumentRegionAfter(this.gapOffset); + } + } + + /** + */ + private void updateAttrRegions(Element element, IStructuredDocumentRegion flatNode) { + + // update attributes + ITextRegionList regions = flatNode.getRegions(); + if (regions == null) + return; + NamedNodeMap attributes = element.getAttributes(); + if (attributes == null) + return; + int index = -1; + AttrImpl attr = null; + Iterator e = regions.iterator(); + while (e.hasNext()) { + ITextRegion region = (ITextRegion) e.next(); + String regionType = region.getType(); + if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_NAME) { + attr = (AttrImpl) attributes.item(++index); + if (attr != null) { + attr.setNameRegion(region); + // reset other regions + attr.setEqualRegion(null); + attr.setValueRegion(null); + } + } else if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_EQUALS) { + if (attr != null) + attr.setEqualRegion(region); + } else if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE) { + if (attr != null) { + attr.setValueRegion(region); + attr = null; + } + } + } + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/filebuffers/DocumentFactoryForXML.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/filebuffers/DocumentFactoryForXML.java new file mode 100644 index 0000000000..549752a77f --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/filebuffers/DocumentFactoryForXML.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.filebuffers; + +import org.eclipse.core.filebuffers.IDocumentFactory; +import org.eclipse.jface.text.IDocument; +import org.eclipse.wst.sse.core.document.StructuredDocumentFactory; +import org.eclipse.wst.sse.core.text.IStructuredDocument; +import org.eclipse.wst.xml.core.internal.parser.XMLSourceParser; + + + +public class DocumentFactoryForXML implements IDocumentFactory { + + public DocumentFactoryForXML() { + super(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.filebuffers.IDocumentFactory#createDocument() + */ + public IDocument createDocument() { + IStructuredDocument structuredDocument = StructuredDocumentFactory.getNewStructuredDocumentInstance(new XMLSourceParser()); + return structuredDocument; + } + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/filebuffers/SetupParticipantForXML.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/filebuffers/SetupParticipantForXML.java new file mode 100644 index 0000000000..1390a1f0fb --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/filebuffers/SetupParticipantForXML.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.filebuffers; + +import org.eclipse.core.filebuffers.IDocumentSetupParticipant; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IDocumentPartitioner; +import org.eclipse.wst.xml.core.text.rules.StructuredTextPartitionerForXML; + + + +public class SetupParticipantForXML implements IDocumentSetupParticipant { + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.filebuffers.IDocumentSetupParticipant#setup(org.eclipse.jface.text.IDocument) + */ + public void setup(IDocument document) { + if (document != null) { + IDocumentPartitioner partitioner = new StructuredTextPartitionerForXML(); + document.setDocumentPartitioner(partitioner); + partitioner.connect(document); + + // setup empty model here? coordinated via model manager? + + } + } + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/BlockStructuredDocumentRegion.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/BlockStructuredDocumentRegion.java new file mode 100644 index 0000000000..5442a10f0e --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/BlockStructuredDocumentRegion.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.parser; + + + +import org.eclipse.wst.sse.core.internal.text.BasicStructuredDocumentRegion; +import org.eclipse.wst.sse.core.parser.IBlockedStructuredDocumentRegion; + + +public class BlockStructuredDocumentRegion extends BasicStructuredDocumentRegion implements IBlockedStructuredDocumentRegion { + + private String partitionType; + + /** + * A BlockStructuredDocumentRegion is like a IStructuredDocumentRegion, + * but is the result of a "block scan". + */ + public BlockStructuredDocumentRegion() { + super(); + } + + public String getPartitionType() { + if (partitionType == null) { + // eventually can look up surroundingTag name + // but this field is primarily entended for future + // extensibility. This may change. + //partitionType = "org.eclipse.wst.sse.core." + tagname; + } + return partitionType; + } + + public void setPartitionType(String partitionType) { + this.partitionType = partitionType; + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/ContextRegionContainer.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/ContextRegionContainer.java new file mode 100644 index 0000000000..e238281ff4 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/ContextRegionContainer.java @@ -0,0 +1,386 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.parser; + + + +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.wst.sse.core.events.StructuredDocumentEvent; +import org.eclipse.wst.sse.core.internal.Logger; +import org.eclipse.wst.sse.core.internal.text.TextRegionListImpl; +import org.eclipse.wst.sse.core.text.IStructuredDocument; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.core.text.ITextRegionCollection; +import org.eclipse.wst.sse.core.text.ITextRegionContainer; +import org.eclipse.wst.sse.core.text.ITextRegionList; + + +public class ContextRegionContainer implements ITextRegionContainer { + protected int length; + protected ITextRegionCollection parent; + protected ITextRegionList regions; + protected int start; + protected int textLength; + protected String type; + + public ContextRegionContainer() { + super(); + regions = new TextRegionListImpl(); + + } + + /** + * these "deep" parenting is not normal, but just in case. + */ + private IStructuredDocument _getParentDocument() { + // go up enough parents to get to document + ITextRegionCollection parent = getParent(); + while (!(parent instanceof IStructuredDocumentRegion)) { + // would be an error not to be container, but + // won't check for it now + parent = ((ITextRegionContainer) parent).getParent(); + } + return ((IStructuredDocumentRegion) parent).getParentDocument(); + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegion#adjust(int) + */ + public void adjust(int i) { + + start += i; + // I erroneously added length and textLength + // may want to rename this method to adjustStart + //length += i; + //textLength += i; + + } + + public void adjustLengthWith(int i) { + length += i; + } + + public void adjustStart(int i) { + start += i; + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegion#adjustTextLength(int) + */ + public void adjustTextLength(int i) { + textLength += i; + + } + + public boolean containsOffset(int i) { + + return getStartOffset() <= i && i < getEndOffset(); + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegionCollection#containsOffset(com.ibm.sed.structured.text.ITextRegion, + * int) + */ + public boolean containsOffset(ITextRegion containedRegion, int offset) { + return getStartOffset(containedRegion) <= offset && offset < getEndOffset(containedRegion); + } + + /** + * This method is just to equate positions. clients may (will probably) + * still need to make calls to equate regions, parent, etc. + */ + public void equatePositions(ITextRegion region) { + start = region.getStart(); + length = region.getLength(); + textLength = region.getTextLength(); + } + + public int getEnd() { + return start + length; + } + + public int getEndOffset() { + // our startOffset take into account our parent, and our start + return getStartOffset() + getLength(); + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegionCollection#getEndOffset(com.ibm.sed.structured.text.ITextRegion) + */ + public int getEndOffset(ITextRegion containedRegion) { + return getStartOffset(containedRegion) + containedRegion.getLength(); + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegionCollection#getFirstRegion() + */ + public ITextRegion getFirstRegion() { + return getRegions().get(0); + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegionCollection#getFullText() + */ + public String getFullText() { + // CMVC > 252430, 245586 + // unit test > com.ibm.sed.tests.other.UnitTests.testDeepEmbeddedJSP3 + // this code modified on 6/25/03 (pa) + + // String result = null; + // try { + // result = _getParentDocument().get(start, length); + // } catch (BadLocationException e) { + // Logger.logException("program error: unreachable exception", e); + // //$NON-NLS-1$ + // } + // return result; + return getParent().getFullText(this); + } + + public String getFullText(org.eclipse.wst.sse.core.text.ITextRegion aRegion) { + // Must be proxied here since aRegion should always be a child of + // *this* container and indexed from + // this container's offset + // try { + return parent.getFullText().substring(start + aRegion.getStart(), start + aRegion.getEnd()); + //} catch (Exception e) { + //if (com.ibm.sed.util.Debug.debugStructuredDocument) + //e.printStackTrace(); + //} + //return "";//$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegionCollection#getLastRegion() + */ + public ITextRegion getLastRegion() { + return getRegions().get(getRegions().size() - 1); + } + + public int getLength() { + return length; + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegionCollection#getNumberOfRegions() + */ + public int getNumberOfRegions() { + return getRegions().size(); + } + + public ITextRegionCollection getParent() { + return parent; + } + + /** + * The parameter offset refers to the overall offset in the document. + */ + public ITextRegion getRegionAtCharacterOffset(int offset) { + ITextRegion result = null; + if (regions != null) { + // transform the requested offset to the "scale" that + // regions are stored in, which are all relative to the + // start point. + //int transformedOffset = offset - getStartOffset(); + // + int length = getRegions().size(); + for (int i = 0; i < length; i++) { + ITextRegion region = getRegions().get(i); + if (org.eclipse.wst.sse.core.util.Debug.debugStructuredDocument) { + System.out.println("region(s) in IStructuredDocumentRegion::getRegionAtCharacterOffset: " + region); //$NON-NLS-1$ + System.out.println(" requested offset: " + offset); //$NON-NLS-1$ + //System.out.println(" transformedOffset: " + + // transformedOffset); //$NON-NLS-1$ + System.out.println(" region start: " + region.getStart()); //$NON-NLS-1$ + System.out.println(" region end: " + region.getEnd()); //$NON-NLS-1$ + System.out.println(" region type: " + region.getType()); //$NON-NLS-1$ + System.out.println(" region class: " + region.getClass()); //$NON-NLS-1$ + + } + if ((getStartOffset(region) <= offset) && (offset < getEndOffset(region))) { + result = region; + break; + } + } + } + return result; + } + + public ITextRegionList getRegions() { + return regions; + } + + public int getStart() { + return start; + } + + public int getStartOffset() { + return getParent().getStartOffset() + getStart(); + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegionCollection#getStartOffset(com.ibm.sed.structured.text.ITextRegion) + */ + public int getStartOffset(ITextRegion containedRegion) { + return getStartOffset() + containedRegion.getStart(); + } + + /** + * same as getFullText for this region type ... do we need to take white + * space off? + */ + + public String getText() { + String result = null; + try { + IStructuredDocument parentDocument = _getParentDocument(); + result = parentDocument.get(start, length); + } catch (BadLocationException e) { + Logger.logException("program error: unreachable exception", e); //$NON-NLS-1$ + } + return result; + } + + public String getText(org.eclipse.wst.sse.core.text.ITextRegion aRegion) { + // Must be proxied here since aRegion should always be a child of + // *this* container and indexed from + // this container's offset + // com.ibm.sed.util.Assert.isTrue(regions.contains(aRegion)); + //try { + return parent.getText().substring(start + aRegion.getStart(), start + aRegion.getTextEnd()); + //} catch (Exception e) { + //if (com.ibm.sed.util.Debug.debugStructuredDocument) + //com.ibm.sed.util.Logger.log(e); + //} + // return ""; //$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegion#getTextEnd() + */ + public int getTextEnd() { + // int result = 0; + // ITextRegion lastRegion = (ITextRegion) regions.get(regions.size() - + // 1); + // result = getStartOffset(lastRegion) + lastRegion.getTextLength(); + // return result; + return start + textLength; + } + + public int getTextEndOffset() { + ITextRegion region = regions.get(regions.size() - 1); + // our startOffset take into account our parent, and our start + // (pa) 10/4 changed to be based on text end + // it used to return incorrect value for embedded region containers + // + + // TODO CRITICAL -- need to re-work this work around, so doesn't + // depend on XMLRegionContext + // // this is a workaround for 226823/////////// + // for (int i = regions.size() - 1; i >= 0 && region.getType() == + // XMLRegionContext.WHITE_SPACE; i--) + // region = (ITextRegion) regions.get(i); + // ///////////////////////////////////////////// + + return getStartOffset() + region.getTextEnd(); + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegionCollection#getTextEndOffset(com.ibm.sed.structured.text.ITextRegion) + */ + public int getTextEndOffset(ITextRegion containedRegion) { + int result = 0; + if (regions != null) { + int length = getRegions().size(); + for (int i = 0; i < length; i++) { + ITextRegion region = getRegions().get(i); + if (region == containedRegion) { + result = getStartOffset(region) + region.getTextEnd(); + break; + } + } + } + return result; + } + + public int getTextLength() { + return textLength; + } + + public String getType() { + return type; + } + + public void setLength(int i) { + length = i; + } + + public void setParent(ITextRegionCollection parentRegion) { + parent = parentRegion; + } + + public void setRegions(ITextRegionList containedRegions) { + regions = containedRegions; + } + + public void setStart(int i) { + start = i; + } + + public void setTextLength(int i) { + textLength = i; + } + + public void setType(String string) { + type = string; + } + + public String toString() { + String className = getClass().getName(); + String shortClassName = className.substring(className.lastIndexOf(".") + 1); //$NON-NLS-1$ + String result = "Container!!! " + shortClassName + "--> " + getType() + ": " + getStart() + "-" + getTextEnd() + (getTextEnd() != getEnd() ? ("/" + getEnd()) : ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ + return result; + } + + public StructuredDocumentEvent updateModel(Object requester, IStructuredDocumentRegion parent, String changes, int requestStart, int lengthToReplace) { + org.eclipse.wst.sse.core.events.RegionChangedEvent result = null; + // FUTURE_TO_DO: need to implement region level parsing in + // ITextRegionContainer::updateModel + // never being called? + return result; + } + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/IntStack.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/IntStack.java new file mode 100644 index 0000000000..b871545643 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/IntStack.java @@ -0,0 +1,97 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.parser; + + + +/* + * + * A non-resizable class implementing the behavior of java.util.Stack, but + * directly for the <code> integer </code> primitive. + */ +import java.util.EmptyStackException; + +public class IntStack { + private int[] list = null; + + private int size = 0; + + public IntStack() { + this(100); + } + + public IntStack(int maxdepth) { + super(); + list = new int[maxdepth]; + initialize(); + } + + public boolean empty() { + return size == 0; + } + + public int get(int slot) { + return list[slot]; + } + + void initialize() { + for (int i = 0; i < list.length; i++) + list[i] = -1; + } + + /** + * Returns the int at the top of the stack without removing it + * + * @return int at the top of this stack. + * @exception EmptyStackException + * when empty. + */ + public int peek() { + if (size == 0) + throw new EmptyStackException(); + return list[size - 1]; + } + + /** + * Removes and returns the int at the top of the stack + * + * @return int at the top of this stack. + * @exception EmptyStackException + * when empty. + */ + public int pop() { + int value = peek(); + list[size - 1] = -1; + size--; + return value; + } + + /** + * Pushes an item onto the top of this stack. + * + * @param newValue - + * the int to be pushed onto this stack. + * @return the <code>newValue</code> argument. + */ + public int push(int newValue) { + if (size == list.length) { + throw new StackOverflowError(); + } + list[size++] = newValue; + return newValue; + } + + public int size() { + return list.length; + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/RegionFactory.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/RegionFactory.java new file mode 100644 index 0000000000..f9c4ab9e08 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/RegionFactory.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.parser; + + + +import org.eclipse.wst.sse.core.internal.parser.ContextRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.core.text.ITextRegionContainer; + + +public class RegionFactory { + + public RegionFactory() { + super(); + } + + public ITextRegion createToken(ITextRegionContainer parent, String context, int start, int textLength, int length) { + return this.createToken(parent, context, start, textLength, length, null, null); + } + + public ITextRegion createToken(ITextRegionContainer parent, String context, int start, int textLength, int length, String lang, String surroundingTag) { + ITextRegion newRegion = createToken(context, start, textLength, length); + // DW, 4/16/2003 token regions no longer have parents + //newRegion.setParent(parent); + return newRegion; + } + + public ITextRegion createToken(String context, int start, int textLength, int length) { + return this.createToken(context, start, textLength, length, null, null); + } + + public ITextRegion createToken(String context, int start, int textLength, int length, String lang, String surroundingTag) { + ITextRegion newRegion = new ContextRegion(context, start, textLength, length); + return newRegion; + + + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XML10Names.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XML10Names.java new file mode 100644 index 0000000000..1ff05a0a8b --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XML10Names.java @@ -0,0 +1,541 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +/* The following code was generated by JFlex 1.4 on 7/17/04 3:43 AM */ + +/*nlsXXX*/ +package org.eclipse.wst.xml.core.internal.parser; + + + +/** + * This class is a scanner generated by <a href="http://www.jflex.de/">JFlex + * </a> 1.4 on 7/17/04 3:43 AM from the specification file + * <tt>XML10Names.jflex</tt> + */ +public final class XML10Names { + + /** This character denotes the end of file */ + private static final int YYEOF = -1; + + /** initial size of the lookahead buffer */ + private static final int ZZ_BUFFERSIZE = 2048; + + /** lexical states */ + private static final int YYINITIAL = 0; + + /** + * Translates characters to character classes + */ + private static final String ZZ_CMAP_PACKED = "\11\0\1\1\1\2\2\0\1\1\22\0\1\1\14\0\1\0\2\0" + "\12\0\1\3\6\0\32\3\4\0\1\3\1\0\32\3\74\0\1\0" + "\10\0\27\3\1\0\37\3\1\0\72\3\2\0\13\3\2\0\10\3" + "\1\0\65\3\1\0\104\3\11\0\44\3\3\0\2\3\4\0\36\3" + "\70\0\131\3\22\0\7\3\16\0\2\0\56\0\106\0\32\0\2\0" + "\44\0\1\3\1\0\3\3\1\0\1\3\1\0\24\3\1\0\54\3" + "\1\0\7\3\3\0\1\3\1\0\1\3\1\0\1\3\1\0\1\3" + "\1\0\22\3\15\0\14\3\1\0\102\3\1\0\14\3\1\0\44\3" + "\1\0\4\0\11\0\65\3\2\0\2\3\2\0\2\3\3\0\34\3" + "\2\0\10\3\2\0\2\3\67\0\46\3\2\0\1\3\7\0\46\3" + "\12\0\21\0\1\0\27\0\1\0\3\0\1\0\1\0\1\0\2\0" + "\1\0\1\0\13\0\33\3\5\0\3\3\56\0\32\3\5\0\1\0" + "\12\3\10\0\15\0\12\0\6\0\1\0\107\3\2\0\5\3\1\0" + "\17\3\1\0\4\3\1\0\1\3\17\0\2\3\2\0\1\0\4\0" + "\2\0\12\0\u0207\0\3\0\1\0\65\3\2\0\1\0\1\3\20\0" + "\3\0\4\0\3\0\12\3\2\0\2\0\12\0\21\0\3\0\1\0" + "\10\3\2\0\2\3\2\0\26\3\1\0\7\3\1\0\1\3\3\0" + "\4\3\2\0\1\0\1\0\7\0\2\0\2\0\2\0\3\0\11\0" + "\1\0\4\0\2\3\1\0\3\3\2\0\2\0\12\0\2\3\20\0" + + "\1\0\2\0\6\3\4\0\2\3\2\0\26\3\1\0\7\3\1\0" + "\2\3\1\0\2\3\1\0\2\3\2\0\1\0\1\0\5\0\4\0" + "\2\0\2\0\3\0\13\0\4\3\1\0\1\3\7\0\12\0\2\0" + "\3\3\14\0\3\0\1\0\7\3\1\0\1\3\1\0\3\3\1\0" + "\26\3\1\0\7\3\1\0\2\3\1\0\5\3\2\0\1\0\1\3" + "\10\0\1\0\3\0\1\0\3\0\22\0\1\3\5\0\12\0\21\0" + "\3\0\1\0\10\3\2\0\2\3\2\0\26\3\1\0\7\3\1\0" + "\2\3\2\0\4\3\2\0\1\0\1\3\6\0\3\0\2\0\2\0" + "\3\0\10\0\2\0\4\0\2\3\1\0\3\3\4\0\12\0\22\0" + "\2\0\1\0\6\3\3\0\3\3\1\0\4\3\3\0\2\3\1\0" + "\1\3\1\0\2\3\3\0\2\3\3\0\3\3\3\0\10\3\1\0" + "\3\3\4\0\5\0\3\0\3\0\1\0\4\0\11\0\1\0\17\0" + "\11\0\21\0\3\0\1\0\10\3\1\0\3\3\1\0\27\3\1\0" + "\12\3\1\0\5\3\4\0\7\0\1\0\3\0\1\0\4\0\7\0" + "\2\0\11\0\2\3\4\0\12\0\22\0\2\0\1\0\10\3\1\0" + "\3\3\1\0\27\3\1\0\12\3\1\0\5\3\4\0\7\0\1\0" + "\3\0\1\0\4\0\7\0\2\0\7\0\1\3\1\0\2\3\4\0" + "\12\0\22\0\2\0\1\0\10\3\1\0\3\3\1\0\27\3\1\0" + "\20\3\4\0\6\0\2\0\3\0\1\0\4\0\11\0\1\0\10\0" + "\2\3\4\0\12\0\221\0\56\3\1\0\1\3\1\0\2\3\7\0" + + "\5\0\6\3\1\0\10\0\1\0\12\0\47\0\2\3\1\0\1\3" + "\2\0\2\3\1\0\1\3\2\0\1\3\6\0\4\3\1\0\7\3" + "\1\0\3\3\1\0\1\3\1\0\1\3\2\0\2\3\1\0\2\3" + "\1\0\1\3\1\0\2\3\6\0\1\0\2\0\1\3\2\0\5\3" + "\1\0\1\0\1\0\6\0\2\0\12\0\76\0\2\0\6\0\12\0" + "\13\0\1\0\1\0\1\0\1\0\1\0\4\0\2\0\10\3\1\0" + "\41\3\7\0\24\0\1\0\6\0\4\0\6\0\1\0\1\0\1\0" + "\25\0\3\0\7\0\1\0\1\0\346\0\46\3\12\0\47\3\11\0" + "\1\3\1\0\2\3\1\0\3\3\1\0\1\3\1\0\2\3\1\0" + "\5\3\51\0\1\3\1\0\1\3\1\0\1\3\13\0\1\3\1\0" + "\1\3\1\0\1\3\3\0\2\3\3\0\1\3\5\0\3\3\1\0" + "\1\3\1\0\1\3\1\0\1\3\1\0\1\3\3\0\2\3\3\0" + "\2\3\1\0\1\3\50\0\1\3\11\0\1\3\2\0\1\3\2\0" + "\2\3\7\0\2\3\1\0\1\3\1\0\7\3\50\0\1\3\4\0" + "\1\3\10\0\1\3\u0c06\0\234\3\4\0\132\3\6\0\26\3\2\0" + "\6\3\2\0\46\3\2\0\6\3\2\0\10\3\1\0\1\3\1\0" + "\1\3\1\0\1\3\1\0\37\3\2\0\65\3\1\0\7\3\1\0" + "\1\3\3\0\3\3\1\0\7\3\3\0\4\3\2\0\6\3\4\0" + "\15\3\5\0\3\3\1\0\7\3\323\0\15\0\4\0\1\0\104\0" + "\1\3\3\0\2\3\2\0\1\3\121\0\3\3\u0e82\0\1\0\1\0" + + "\1\3\31\0\11\3\6\0\1\0\5\0\13\0\124\3\4\0\2\0" + "\2\0\2\0\2\0\132\3\1\0\3\0\6\0\50\3\u1cd3\0\u51a6\3" + "\u0c5a\0\u2ba4\3\u285c\0"; + + /** + * Translates characters to character classes + */ + private static final char[] ZZ_CMAP = zzUnpackCMap(ZZ_CMAP_PACKED); + + /** + * Translates DFA states to action switch labels. + */ + private static final int[] ZZ_ACTION = zzUnpackAction(); + + private static final String ZZ_ACTION_PACKED_0 = "\1\0\1\1\1\2\4\1"; + + private static int[] zzUnpackAction() { + int[] result = new int[7]; + int offset = 0; + offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackAction(String packed, int offset, int[] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int count = packed.charAt(i++); + int value = packed.charAt(i++); + do + result[j++] = value; + while (--count > 0); + } + return j; + } + + + /** + * Translates a state to a row index in the transition table + */ + private static final int[] ZZ_ROWMAP = zzUnpackRowMap(); + + private static final String ZZ_ROWMAP_PACKED_0 = "\0\0\0\4\0\10\0\14\0\20\0\24\0\30"; + + private static int[] zzUnpackRowMap() { + int[] result = new int[7]; + int offset = 0; + offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackRowMap(String packed, int offset, int[] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int high = packed.charAt(i++) << 16; + result[j++] = high | packed.charAt(i++); + } + return j; + } + + /** + * The transition table of the DFA + */ + private static final int ZZ_TRANS[] = {1, 1, -1, 2, -1, -1, -1, -1, 2, 3, 4, 2, 2, 3, 4, 5, -1, 4, 4, 6, 5, 5, 4, 5, 6, 6, -1, 6,}; + + /* error codes */ + private static final int ZZ_UNKNOWN_ERROR = 0; + private static final int ZZ_NO_MATCH = 1; + private static final int ZZ_PUSHBACK_2BIG = 2; + + /* error messages for the codes above */ + private static final String ZZ_ERROR_MSG[] = {"Unkown internal scanner error", "Error: could not match input", "Error: pushback value was too large"}; + + /** + * ZZ_ATTRIBUTE[aState] contains the attributes of state + * <code>aState</code> + */ + private static final int[] ZZ_ATTRIBUTE = zzUnpackAttribute(); + + private static final String ZZ_ATTRIBUTE_PACKED_0 = "\1\0\1\11\5\1"; + + private static int[] zzUnpackAttribute() { + int[] result = new int[7]; + int offset = 0; + offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackAttribute(String packed, int offset, int[] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int count = packed.charAt(i++); + int value = packed.charAt(i++); + do + result[j++] = value; + while (--count > 0); + } + return j; + } + + /** the input device */ + private java.io.Reader zzReader; + + /** the current state of the DFA */ + private int zzState; + + /** the current lexical state */ + private int zzLexicalState = YYINITIAL; + + /** + * this buffer contains the current text to be matched and is the source + * of the yytext() string + */ + private char zzBuffer[] = new char[ZZ_BUFFERSIZE]; + + /** the textposition at the last accepting state */ + private int zzMarkedPos; + + /** the textposition at the last state to be included in yytext */ + private int zzPushbackPos; + + /** the current text position in the buffer */ + private int zzCurrentPos; + + /** startRead marks the beginning of the yytext() string in the buffer */ + private int zzStartRead; + + /** + * endRead marks the last character in the buffer, that has been read from + * input + */ + private int zzEndRead; + + /** number of newlines encountered up to the start of the matched text */ + int yyline; + + /** the number of characters up to the start of the matched text */ + int yychar; + + /** + * the number of characters from the last newline up to the start of the + * matched text + */ + int yycolumn; + + /** + * zzAtBOL == true <=>the scanner is currently at the beginning of a line + */ + boolean zzAtBOL = true; + + /** zzAtEOF == true <=>the scanner is at the EOF */ + private boolean zzAtEOF; + + /* user code: */ + + /** + * Creates a new scanner + */ + public XML10Names() { + this.zzReader = null; + } + + public boolean isValidXML10Name(String stringToCheck) { + boolean result = false; + yyreset(new java.io.StringReader(stringToCheck)); + try { + result = isValidXML10Name(); + } catch (java.io.IOException e) { + // should be impossible with strings, but if occurs, just means + // "not" + result = false; + } + return result; + } + + + + /** + * Creates a new scanner There is also a java.io.InputStream version of + * this constructor. + * + * @param in + * the java.io.Reader to read input from. + */ + public XML10Names(java.io.Reader in) { + this.zzReader = in; + } + + /** + * Creates a new scanner. There is also java.io.Reader version of this + * constructor. + * + * @param in + * the java.io.Inputstream to read input from. + */ + public XML10Names(java.io.InputStream in) { + this(new java.io.InputStreamReader(in)); + } + + /** + * Unpacks the compressed character translation table. + * + * @param packed + * the packed character translation table + * @return the unpacked character translation table + */ + private static char[] zzUnpackCMap(String packed) { + char[] map = new char[0x10000]; + int i = 0; /* index in packed string */ + int j = 0; /* index in unpacked array */ + while (i < 1226) { + int count = packed.charAt(i++); + char value = packed.charAt(i++); + do + map[j++] = value; + while (--count > 0); + } + return map; + } + + + /** + * Refills the input buffer. + * + * @return <code>false</code>, iff there was new input. + * + * @exception java.io.IOException + * if any I/O-Error occurs + */ + private boolean zzRefill() throws java.io.IOException { + + /* first: make room (if you can) */ + if (zzStartRead > 0) { + System.arraycopy(zzBuffer, zzStartRead, zzBuffer, 0, zzEndRead - zzStartRead); + + /* translate stored positions */ + zzEndRead -= zzStartRead; + zzCurrentPos -= zzStartRead; + zzMarkedPos -= zzStartRead; + zzPushbackPos -= zzStartRead; + zzStartRead = 0; + } + + /* is the buffer big enough? */ + if (zzCurrentPos >= zzBuffer.length) { + /* if not: blow it up */ + char newBuffer[] = new char[zzCurrentPos * 2]; + System.arraycopy(zzBuffer, 0, newBuffer, 0, zzBuffer.length); + zzBuffer = newBuffer; + } + + /* finally: fill the buffer with new input */ + int numRead = zzReader.read(zzBuffer, zzEndRead, zzBuffer.length - zzEndRead); + + if (numRead < 0) { + return true; + } else { + zzEndRead += numRead; + return false; + } + } + + + /** + * Closes the input stream. + */ + final void yyclose() throws java.io.IOException { + zzAtEOF = true; /* indicate end of file */ + zzEndRead = zzStartRead; /* invalidate buffer */ + + if (zzReader != null) + zzReader.close(); + } + + + /** + * Resets the scanner to read from a new input stream. Does not close the + * old reader. + * + * All internal variables are reset, the old input stream <b>cannot </b> + * be reused (internal buffer is discarded and lost). Lexical state is set + * to <tt>ZZ_INITIAL</tt>. + * + * @param reader + * the new input stream + */ + private final void yyreset(java.io.Reader reader) { + zzReader = reader; + //zzAtBOL = true; + zzAtEOF = false; + zzEndRead = zzStartRead = 0; + zzCurrentPos = zzMarkedPos = zzPushbackPos = 0; + yyline = yychar = yycolumn = 0; + zzLexicalState = YYINITIAL; + } + + + /** + * Returns the current lexical state. + */ + final int yystate() { + return zzLexicalState; + } + + + /** + * Enters a new lexical state + * + * @param newState + * the new lexical state + */ + final void yybegin(int newState) { + zzLexicalState = newState; + } + + + /** + * Returns the text matched by the current regular expression. + */ + final String yytext() { + return new String(zzBuffer, zzStartRead, zzMarkedPos - zzStartRead); + } + + + /** + * Returns the character at position <tt>pos</tt> from the matched text. + * + * It is equivalent to yytext().charAt(pos), but faster + * + * @param pos + * the position of the character to fetch. A value from 0 to + * yylength()-1. + * + * @return the character at position pos + */ + final char yycharat(int pos) { + return zzBuffer[zzStartRead + pos]; + } + + + /** + * Returns the length of the matched text region. + */ + private final int yylength() { + return zzMarkedPos - zzStartRead; + } + + + /** + * Reports an error that occured while scanning. + * + * In a wellformed scanner (no or only correct usage of yypushback(int) + * and a match-all fallback rule) this method will only be called with + * things that "Can't Possibly Happen". If this method is called, + * something is seriously wrong (e.g. a JFlex bug producing a faulty + * scanner etc.). + * + * Usual syntax/scanner level error handling should be done in error + * fallback rules. + * + * @param errorCode + * the code of the errormessage to display + */ + private void zzScanError(int errorCode) { + String message; + try { + message = ZZ_ERROR_MSG[errorCode]; + } catch (ArrayIndexOutOfBoundsException e) { + message = ZZ_ERROR_MSG[ZZ_UNKNOWN_ERROR]; + } + + throw new Error(message); + } + + + /** + * Pushes the specified amount of characters back into the input stream. + * + * They will be read again by then next call of the scanning method + * + * @param number + * the number of characters to be read again. This number must + * not be greater than yylength()! + */ + void yypushback(int number) { + if (number > yylength()) + zzScanError(ZZ_PUSHBACK_2BIG); + + zzMarkedPos -= number; + } + + + /** + * Resumes scanning until the next regular expression is matched, the end + * of input is encountered or an I/O-Error occurs. + * + * @return the next token + * @exception java.io.IOException + * if any I/O-Error occurs + */ + private boolean isValidXML10Name() throws java.io.IOException { + int zzInput; + int zzAction; + + // cached fields: + int zzCurrentPosL; + int zzMarkedPosL; + int zzEndReadL = zzEndRead; + char[] zzBufferL = zzBuffer; + char[] zzCMapL = ZZ_CMAP; + + int[] zzTransL = ZZ_TRANS; + int[] zzRowMapL = ZZ_ROWMAP; + int[] zzAttrL = ZZ_ATTRIBUTE; + + while (true) { + zzMarkedPosL = zzMarkedPos; + + zzAction = -1; + + zzCurrentPosL = zzCurrentPos = zzStartRead = zzMarkedPosL; + + zzState = zzLexicalState; + + + zzForAction : { + while (true) { + + if (zzCurrentPosL < zzEndReadL) + zzInput = zzBufferL[zzCurrentPosL++]; + else if (zzAtEOF) { + zzInput = YYEOF; + break zzForAction; + } else { + // store back cached positions + zzCurrentPos = zzCurrentPosL; + zzMarkedPos = zzMarkedPosL; + boolean eof = zzRefill(); + // get translated positions and possibly new buffer + zzCurrentPosL = zzCurrentPos; + zzMarkedPosL = zzMarkedPos; + zzBufferL = zzBuffer; + zzEndReadL = zzEndRead; + if (eof) { + zzInput = YYEOF; + break zzForAction; + } else { + zzInput = zzBufferL[zzCurrentPosL++]; + } + } + int zzNext = zzTransL[zzRowMapL[zzState] + zzCMapL[zzInput]]; + if (zzNext == -1) + break zzForAction; + zzState = zzNext; + + int zzAttributes = zzAttrL[zzState]; + if ((zzAttributes & 1) == 1) { + zzAction = zzState; + zzMarkedPosL = zzCurrentPosL; + if ((zzAttributes & 8) == 8) + break zzForAction; + } + + } + } + + // store back cached position + zzMarkedPos = zzMarkedPosL; + + switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) { + case 1 : { + return false; + } + case 3 : + break; + case 2 : { + return true; + } + case 4 : + break; + default : + if (zzInput == YYEOF && zzStartRead == zzCurrentPos) { + zzAtEOF = true; + { + { + return false; + } + } + } else { + zzScanError(ZZ_NO_MATCH); + } + } + } + } + + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XMLRegionContexts.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XMLRegionContexts.java new file mode 100644 index 0000000000..5c622ab3c0 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XMLRegionContexts.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.parser; + +import org.eclipse.wst.xml.core.parser.XMLRegionContext; + +/** + * @deprecated - use org.eclipse.wst.xml.core.parser.XMLRegionContext + */ +public interface XMLRegionContexts extends XMLRegionContext { +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XMLSourceParser.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XMLSourceParser.java new file mode 100644 index 0000000000..63711818d9 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XMLSourceParser.java @@ -0,0 +1,595 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.parser; + + + +import java.io.StringReader; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.wst.sse.core.document.DocumentReader; +import org.eclipse.wst.sse.core.internal.text.CharSequenceReader; +import org.eclipse.wst.sse.core.internal.text.IRegionComparible; +import org.eclipse.wst.sse.core.parser.BlockMarker; +import org.eclipse.wst.sse.core.parser.BlockTagParser; +import org.eclipse.wst.sse.core.parser.BlockTokenizer; +import org.eclipse.wst.sse.core.parser.RegionParser; +import org.eclipse.wst.sse.core.parser.StructuredDocumentRegionHandler; +import org.eclipse.wst.sse.core.parser.StructuredDocumentRegionParser; +import org.eclipse.wst.sse.core.parser.StructuredDocumentRegionParserExtension; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.core.text.ITextRegionContainer; +import org.eclipse.wst.sse.core.text.ITextRegionList; +import org.eclipse.wst.sse.core.util.Debug; +import org.eclipse.wst.xml.core.Logger; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; + + +/** + * Takes input from the HTMLTokenizer and creates a tag list + */ + +public class XMLSourceParser implements RegionParser, BlockTagParser, StructuredDocumentRegionParser, IRegionComparible, StructuredDocumentRegionParserExtension { + // made public to aid access from inner classes in hierarchy. + // TODO: in future, figure out how to solve without exposing data. + public CharSequence fCharSequenceSource = null; + private IDocument fDocumentInput; + protected int fOffset = 0; + // DMW: 2/12/03. Removed some state data, since not really needed, + // and since it added a lot to overhead (since so many regions are + // created. + // protected IStructuredDocumentRegion fCurrentNode = null; + // protected IStructuredDocumentRegion fNodes = null; + // protected List fRegions = null; + // protected Object fInput = null; + protected String fStringInput = null; + protected List fStructuredDocumentRegionHandlers; + + protected BlockTokenizer fTokenizer = null; + protected long startTime; + protected long stopTime; + + /** + * HTMLSourceParser constructor comment. + */ + public XMLSourceParser() { + super(); + fStructuredDocumentRegionHandlers = new ArrayList(); + } + + /** + * This is a simple utility to count nodes. Used only for debug + * statements. + */ + protected int _countNodes(IStructuredDocumentRegion nodes) { + int result = 0; + IStructuredDocumentRegion countNode = nodes; + while (countNode != null) { + result++; + countNode = countNode.getNext(); + } + return result; + } + + public void addBlockMarker(BlockMarker marker) { + getTokenizer().addBlockMarker(marker); + } + + public void addStructuredDocumentRegionHandler(StructuredDocumentRegionHandler handler) { + if (fStructuredDocumentRegionHandlers == null) + fStructuredDocumentRegionHandlers = new ArrayList(); + fStructuredDocumentRegionHandlers.add(handler); + } + + public void beginBlockScan(String newTagName) { + getTokenizer().beginBlockTagScan(newTagName); + } + + /** + * @return IStructuredDocumentRegion + */ + protected IStructuredDocumentRegion createStructuredDocumentRegion(String type) { + IStructuredDocumentRegion newNode = null; + if (type == XMLRegionContext.BLOCK_TEXT) + newNode = XMLStructuredRegionFactory.createRegion(XMLStructuredRegionFactory.XML_BLOCK); + else + newNode = XMLStructuredRegionFactory.createRegion(XMLStructuredRegionFactory.XML); + return newNode; + } + + protected void fireNodeParsed(IStructuredDocumentRegion fCurrentNode) { + if (fCurrentNode != null && fStructuredDocumentRegionHandlers != null) { + for (int i = 0; i < fStructuredDocumentRegionHandlers.size(); i++) + ((StructuredDocumentRegionHandler) fStructuredDocumentRegionHandlers.get(i)).nodeParsed(fCurrentNode); + } + } + + public BlockMarker getBlockMarker(String tagName) { + List markers = getTokenizer().getBlockMarkers(); + for (int i = 0; i < markers.size(); i++) { + BlockMarker marker = (BlockMarker) markers.get(i); + if (marker.isCaseSensitive()) { + if (marker.getTagName().equals(tagName)) + return marker; + } else { + if (marker.getTagName().equalsIgnoreCase(tagName)) + return marker; + } + } + return null; + } + + public List getBlockMarkers() { + return getTokenizer().getBlockMarkers(); + } + + /** + * @return IStructuredDocumentRegion + */ + public IStructuredDocumentRegion getDocumentRegions() { + IStructuredDocumentRegion headnode = null; + if (headnode == null) { + if (Debug.perfTest) { + startTime = System.currentTimeMillis(); + } + headnode = parseNodes(); + if (Debug.perfTest) { + stopTime = System.currentTimeMillis(); + System.out.println(" -- creating nodes of IStructuredDocument -- "); //$NON-NLS-1$ + System.out.println(" Time parse and init all regions: " + (stopTime - startTime) + " (msecs)"); //$NON-NLS-2$//$NON-NLS-1$ + //System.out.println(" for " + fRegions.size() + " + // Regions");//$NON-NLS-2$//$NON-NLS-1$ + System.out.println(" and " + _countNodes(headnode) + " Nodes"); //$NON-NLS-2$//$NON-NLS-1$ + } + } + return headnode; + } + + protected ITextRegion getNextRegion() { + ITextRegion region = null; + try { + region = getTokenizer().getNextToken(); + // DMW: 2/12/03 Removed state + // if (region != null) { + // fRegions.add(region); + // } + return region; + } catch (StackOverflowError e) { + Logger.logException(getClass().getName() + ": input could not be parsed correctly at position " + getTokenizer().getOffset(), e); //$NON-NLS-1$ + throw e; + } catch (Exception e) { + Logger.logException(getClass().getName() + ": input could not be parsed correctly at position " + getTokenizer().getOffset() + " (" + e.getLocalizedMessage() + ")", e); //$NON-NLS-3$//$NON-NLS-2$//$NON-NLS-1$ + } + return null; + } + + /** + * Return the full list of known regions. Typically getNodes should be + * used instead of this method. + */ + public List getRegions() { + IStructuredDocumentRegion headNode = null; + if (!getTokenizer().isEOF()) { + headNode = getDocumentRegions(); + // throw new IllegalStateException("parsing has not finished"); + } + // for memory recovery, we assume if someone + // requests all regions, we can reset our big + // memory consuming objects + // but the new "getRegions" method is then more expensive. + // I don't think its used much, though. + List localRegionsList = getRegions(headNode); + primReset(); + return localRegionsList; + } + + /** + * Method getRegions. + * + * @param headNode + * @return List + */ + protected List getRegions(IStructuredDocumentRegion headNode) { + List allRegions = new ArrayList(); + IStructuredDocumentRegion currentNode = headNode; + while (currentNode != null) { + ITextRegionList nodeRegions = currentNode.getRegions(); + for (int i = 0; i < nodeRegions.size(); i++) { + allRegions.add(nodeRegions.get(i)); + } + currentNode = currentNode.getNext(); + } + return allRegions; + } + + /** + * + * @return java.util.List + */ + public List getStructuredDocumentRegionHandlers() { + if (fStructuredDocumentRegionHandlers == null) { + fStructuredDocumentRegionHandlers = new ArrayList(0); + } + return fStructuredDocumentRegionHandlers; + } + + /** + * Returns text from the current input. Text is only valid before + * getNodes() has been called and only when a raw String or DocumentReader + * is given as the input. + */ + public String getText(int offset, int length) { + String text = null; + if (fCharSequenceSource != null) { + int start = fOffset + offset; + int end = start + length; + text = fCharSequenceSource.subSequence(start, end).toString(); + } else if (fDocumentInput != null) { + try { + text = fDocumentInput.get(offset, length); + } catch (BadLocationException e) { + text = ""; + } + } else { + if (fStringInput == null || fStringInput.length() == 0 || offset + length > fStringInput.length() || offset < 0) { + text = ""; //$NON-NLS-1$ + } else { + // offset is entirely valid during parsing as the parse + // numbers haven't been adjusted. + text = fStringInput.substring(offset, offset + length); + } + } + return text; + } + + protected BlockTokenizer getTokenizer() { + if (fTokenizer == null) { + fTokenizer = new XMLTokenizer(); + } + return fTokenizer; + } + + /** + * @see com.ibm.sed.parser.RegionParser#newInstance() + */ + public RegionParser newInstance() { + XMLSourceParser newInstance = new XMLSourceParser(); + newInstance.setTokenizer(getTokenizer().newInstance()); + return newInstance; + } + + protected IStructuredDocumentRegion parseNodes() { + // regions are initially reported as complete offsets within the + // scanned input + // they are adjusted here to be indexes from the currentNode's start + // offset + IStructuredDocumentRegion headNode = null; + IStructuredDocumentRegion lastNode = null; + ITextRegion region = null; + IStructuredDocumentRegion currentNode = null; + String type = null; + + while ((region = getNextRegion()) != null) { + type = region.getType(); + // these types (might) demand a IStructuredDocumentRegion for each + // of them + if (type == XMLRegionContext.BLOCK_TEXT) { + if (currentNode != null && currentNode.getLastRegion().getType() == XMLRegionContext.BLOCK_TEXT) { + // multiple block texts indicated embedded containers; no + // new IStructuredDocumentRegion + currentNode.addRegion(region); + currentNode.setLength(region.getStart() + region.getLength() - currentNode.getStart()); + region.adjustStart(-currentNode.getStart()); + // DW 4/16/2003 regions no longer have parents + //region.setParent(currentNode); + } else { + // not continuing a IStructuredDocumentRegion + if (currentNode != null) { + // ensure that any existing node is at least + // terminated + if (!currentNode.isEnded()) { + currentNode.setLength(region.getStart() - currentNode.getStart()); + // fCurrentNode.setTextLength(region.getStart() - + // fCurrentNode.getStart()); + } + lastNode = currentNode; + } + fireNodeParsed(currentNode); + currentNode = createStructuredDocumentRegion(type); + if (lastNode != null) { + lastNode.setNext(currentNode); + } + currentNode.setPrevious(lastNode); + currentNode.setStart(region.getStart()); + currentNode.setLength(region.getStart() + region.getLength() - currentNode.getStart()); + currentNode.setEnded(true); + region.adjustStart(-currentNode.getStart()); + currentNode.addRegion(region); + // DW 4/16/2003 regions no longer have parents + //region.setParent(currentNode); + } + } + // the following contexts OPEN new StructuredDocumentRegions + else if ((currentNode != null && currentNode.isEnded()) || (type == XMLRegionContext.XML_CONTENT) || (type == XMLRegionContext.XML_CHAR_REFERENCE) || (type == XMLRegionContext.XML_ENTITY_REFERENCE) || (type == XMLRegionContext.XML_PI_OPEN) || (type == XMLRegionContext.XML_TAG_OPEN) || (type == XMLRegionContext.XML_END_TAG_OPEN) || (type == XMLRegionContext.XML_COMMENT_OPEN) || (type == XMLRegionContext.XML_CDATA_OPEN) || (type == XMLRegionContext.XML_DECLARATION_OPEN)) { + if (currentNode != null) { + // ensure that any existing node is at least terminated + if (!currentNode.isEnded()) { + currentNode.setLength(region.getStart() - currentNode.getStart()); + // fCurrentNode.setTextLength(region.getStart() - + // fCurrentNode.getStart()); + } + lastNode = currentNode; + } + fireNodeParsed(currentNode); + currentNode = createStructuredDocumentRegion(type); + if (lastNode != null) { + lastNode.setNext(currentNode); + } + currentNode.setPrevious(lastNode); + currentNode.setStart(region.getStart()); + currentNode.addRegion(region); + currentNode.setLength(region.getStart() + region.getLength() - currentNode.getStart()); + region.adjustStart(-currentNode.getStart()); + // DW 4/16/2003 regions no longer have parents + //region.setParent(currentNode); + } + // the following contexts neither open nor close + // StructuredDocumentRegions; just add to them + else if ((type == XMLRegionContext.XML_TAG_NAME) || (type == XMLRegionContext.XML_TAG_ATTRIBUTE_NAME) || (type == XMLRegionContext.XML_TAG_ATTRIBUTE_EQUALS) || (type == XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE) || (type == XMLRegionContext.XML_COMMENT_TEXT) || (type == XMLRegionContext.XML_PI_CONTENT) || (type == XMLRegionContext.XML_DOCTYPE_INTERNAL_SUBSET)) { + currentNode.addRegion(region); + currentNode.setLength(region.getStart() + region.getLength() - currentNode.getStart()); + region.adjustStart(-currentNode.getStart()); + // DW 4/16/2003 regions no longer have parents + //region.setParent(currentNode); + } + // the following contexts close off StructuredDocumentRegions + // cleanly + else if ((type == XMLRegionContext.XML_PI_CLOSE) || (type == XMLRegionContext.XML_TAG_CLOSE) || (type == XMLRegionContext.XML_EMPTY_TAG_CLOSE) || (type == XMLRegionContext.XML_COMMENT_CLOSE) || (type == XMLRegionContext.XML_DECLARATION_CLOSE) || (type == XMLRegionContext.XML_CDATA_CLOSE)) { + currentNode.setEnded(true); + currentNode.setLength(region.getStart() + region.getLength() - currentNode.getStart()); + currentNode.addRegion(region); + region.adjustStart(-currentNode.getStart()); + // DW 4/16/2003 regions no longer have parents + //region.setParent(currentNode); + } + // this is extremely rare, but valid + else if (type == XMLRegionContext.WHITE_SPACE) { + ITextRegion lastRegion = currentNode.getLastRegion(); + // pack the embedded container with this region + if (lastRegion instanceof ITextRegionContainer) { + ITextRegionContainer container = (ITextRegionContainer) lastRegion; + container.getRegions().add(region); + // containers must have parent set ... + // setting for EACH subregion is redundent, but not sure + // where else to do, so will do here for now. + container.setParent(currentNode); + // DW 4/16/2003 regions no longer have parents + //region.setParent(container); + region.adjustStart(container.getLength() - region.getStart()); + } + currentNode.getLastRegion().adjustLengthWith(region.getLength()); + currentNode.adjustLengthWith(region.getLength()); + } else if (type == XMLRegionContext.UNDEFINED && currentNode != null) { + // skip on a very-first region situation as the default + // behavior is good enough + // combine with previous if also undefined + if (currentNode.getLastRegion() != null && currentNode.getLastRegion().getType() == XMLRegionContext.UNDEFINED) { + currentNode.getLastRegion().adjustLengthWith(region.getLength()); + currentNode.adjustLengthWith(region.getLength()); + } + // previous wasn't undefined + else { + currentNode.addRegion(region); + currentNode.setLength(region.getStart() + region.getLength() - currentNode.getStart()); + region.adjustStart(-currentNode.getStart()); + } + } else { + // if an unknown type is the first region in the document, + // ensure that a node exists + if (currentNode == null) { + currentNode = createStructuredDocumentRegion(type); + currentNode.setStart(region.getStart()); + } + currentNode.addRegion(region); + currentNode.setLength(region.getStart() + region.getLength() - currentNode.getStart()); + region.adjustStart(-currentNode.getStart()); + // DW 4/16/2003 regions no longer have parents + //region.setParent(currentNode); + if (Debug.debugTokenizer) + System.out.println(getClass().getName() + " found region of not specifically handled type " + region.getType() + " @ " + region.getStart() + "[" + region.getLength() + "]"); //$NON-NLS-4$//$NON-NLS-3$//$NON-NLS-2$//$NON-NLS-1$ + //$NON-NLS-3$//$NON-NLS-2$//$NON-NLS-1$ + } + + // these regions also get their own node, so close them cleanly + // NOTE: these regions have new StructuredDocumentRegions created + // for them above; it may + // be more readable if that is handled here as well, but the + // current layout + // ensures that they open StructuredDocumentRegions the same way + if ((type == XMLRegionContext.XML_CONTENT) || (type == XMLRegionContext.XML_CHAR_REFERENCE) || (type == XMLRegionContext.XML_ENTITY_REFERENCE)) { + currentNode.setEnded(true); + } + if (headNode == null && currentNode != null) { + headNode = currentNode; + } + } + if (currentNode != null) { + fireNodeParsed(currentNode); + currentNode.setPrevious(lastNode); + } + //fStringInput = null; + primReset(); + return headNode; + } + + protected void primReset() { + //fNodes = null; + //fRegions = null; + //fInput = null; + fStringInput = null; + fCharSequenceSource = null; + fDocumentInput = null; + fOffset = 0; + //fCurrentNode = null; + // DMW: also reset tokenizer so it doesn't hold on + // to large arrays + getTokenizer().reset(new char[0]); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.core.internal.text.IRegionComparible#regionMatches(int, + * int, java.lang.String) + */ + public boolean regionMatches(int offset, int length, String stringToCompare) { + // by definition + if (stringToCompare == null) + return false; + + boolean result = false; + if (fCharSequenceSource != null && fCharSequenceSource instanceof IRegionComparible) { + result = ((IRegionComparible) fCharSequenceSource).regionMatches(offset, length, stringToCompare); + } else { + // old fashioned ways + String test = null; + if (fCharSequenceSource != null) { + test = fCharSequenceSource.subSequence(offset, offset + length).toString(); + } else if (fStringInput != null) { + test = fStringInput.substring(offset, offset + length); + } + result = stringToCompare.equals(test); + } + return result; + } + + public boolean regionMatchesIgnoreCase(int offset, int length, String stringToCompare) { + // by definition + if (stringToCompare == null) + return false; + + boolean result = false; + if (fCharSequenceSource != null && fCharSequenceSource instanceof IRegionComparible) { + result = ((IRegionComparible) fCharSequenceSource).regionMatchesIgnoreCase(offset, length, stringToCompare); + } else { + // old fashioned ways + String test = null; + if (fCharSequenceSource != null) { + test = fCharSequenceSource.subSequence(offset, offset + length).toString(); + } else if (fStringInput != null) { + test = fStringInput.substring(offset, offset + length); + } + result = stringToCompare.equalsIgnoreCase(test); + } + return result; + } + + public void removeBlockMarker(BlockMarker marker) { + getTokenizer().removeBlockMarker(marker); + } + + public void removeBlockMarker(String tagName) { + getTokenizer().removeBlockMarker(tagName); + } + + public void removeStructuredDocumentRegionHandler(StructuredDocumentRegionHandler handler) { + if (fStructuredDocumentRegionHandlers == null) + return; + if (fStructuredDocumentRegionHandlers.contains(handler)) + fStructuredDocumentRegionHandlers.remove(handler); + } + + /** + * Resets the input. + */ + public void reset(java.io.FileInputStream instream) { + primReset(); + //fInput = instream; + getTokenizer().reset(instream); + } + + /** + * Resets the input. + */ + public void reset(java.io.Reader reader) { + reset(reader, 0); + } + + /** + * Resets the input. + */ + public void reset(java.io.Reader reader, int position) { + primReset(); + fOffset = position; + getTokenizer().reset(reader, position); + if (reader instanceof DocumentReader) { + IDocument doc = ((DocumentReader) reader).getDocument(); + if (doc instanceof CharSequence) { + fCharSequenceSource = (CharSequence) doc; + } else { + // old fashioned IDocument + fDocumentInput = ((DocumentReader) reader).getDocument(); + } + + } else if (reader instanceof CharSequenceReader) { + fCharSequenceSource = ((CharSequenceReader) reader).getOriginalSource(); + } + } + + /** + * Resets the input. Use this version to allow text to be retrieved + * <em>during</em> parsing, such as by the + * StructuredDocumentRegionHandler. + */ + public void reset(String sourceString) { + reset(new StringReader(sourceString)); + fStringInput = sourceString; + } + + /** + * Resets the input. Use this version to allow text to be retrieved + * <em>during</em> parsing, such as by the + * StructuredDocumentRegionHandler. + */ + public void reset(String sourceString, int position) { + StringReader reader = new StringReader(sourceString); + reset(reader, position); + fStringInput = sourceString; + } + + public void resetHandlers() { + if (fStructuredDocumentRegionHandlers != null) { + int size = fStructuredDocumentRegionHandlers.size(); + for (int i = 0; i < size; i++) + ((StructuredDocumentRegionHandler) fStructuredDocumentRegionHandlers.get(i)).resetNodes(); + } + } + + /** + * + * @param List + */ + public void setStructuredDocumentRegionHandlers(List newStructuredDocumentRegionHandlers) { + fStructuredDocumentRegionHandlers = newStructuredDocumentRegionHandlers; + } + + protected void setTokenizer(BlockTokenizer newTokenizer) { + // DMW: changed from private to protected, so subclass could use in + // creation of 'newInstance'. + fTokenizer = newTokenizer; + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XMLStructuredDocumentReParser.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XMLStructuredDocumentReParser.java new file mode 100644 index 0000000000..518d4f63c6 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XMLStructuredDocumentReParser.java @@ -0,0 +1,125 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.parser; + +import org.eclipse.wst.sse.core.internal.text.StructuredDocumentReParser; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.IStructuredTextReParser; +import org.eclipse.wst.xml.core.jsp.model.parser.temp.XMLJSPRegionContexts; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; + + +public class XMLStructuredDocumentReParser extends StructuredDocumentReParser { + + public XMLStructuredDocumentReParser() { + super(); + } + + protected IStructuredDocumentRegion findDirtyEnd(int end) { + // Caution: here's one place we have to cast + IStructuredDocumentRegion result = fStructuredDocument.getRegionAtCharacterOffset(end); + // if not well formed, get one past, if there is something there + if ((result != null) && (!result.isEnded())) { + if (result.getNext() != null) { + result = result.getNext(); + } + } + // also, get one past if exactly equal to the end (this was needed + // as a simple fix to when a whole exact region is deleted. + // there's probably a better way. + if ((result != null) && (end == result.getEnd())) { + if (result.getNext() != null) { + result = result.getNext(); + } + } + + // 12/6/2001 - Since we've changed the parser/scanner to allow a lone + // '<' without + // always interpretting it as start of a tag name, we need to be a + // little fancier, in order + // to "skip" over any plain 'ol content between the lone '<' and any + // potential meating + // regions past plain 'ol content. + if (isLoneOpenFollowedByContent(result) && (result.getNext() != null)) { + result = result.getNext(); + } + + if (result != null) + fStructuredDocument.setCachedDocumentRegion(result); + dirtyEnd = result; + + return dirtyEnd; + } + + protected void findDirtyStart(int start) { + IStructuredDocumentRegion result = fStructuredDocument.getRegionAtCharacterOffset(start); + // heuristic: if the postion is exactly equal to the start, then + // go back one more, if it exists. This prevents problems with + // insertions + // of text that should be merged with the previous node instead of + // simply hung + // off of it as a separate node (ex.: XML content inserted right + // before an open + // bracket should become part of the previous content node) + if (result != null) { + IStructuredDocumentRegion previous = result.getPrevious(); + if ((previous != null) && ((!(previous.isEnded())) || (start == result.getStart()))) { + result = previous; + } + // If we are now at the end of a "tag dependent" content area (or + // JSP area) + // then we need to back up all the way to the beginning of that. + IStructuredDocumentRegion potential = result; + while (isPartOfBlockRegion(potential)) { + potential = potential.getPrevious(); + } + if (potential != null) { + result = potential; + fStructuredDocument.setCachedDocumentRegion(result); + } + } + dirtyStart = result; + } + + /** + * The rule is, that is we are content, preceded by lone <, then we need + * to advance one more for dirty end. + */ + protected boolean isLoneOpenFollowedByContent(IStructuredDocumentRegion flatNode) { + boolean result = false; + String type = flatNode.getType(); + if (type == XMLRegionContext.XML_CONTENT) { + IStructuredDocumentRegion previous = flatNode.getPrevious(); + String previousType = null; + if (previous != null) { + previousType = previous.getType(); + } + if (previousType != null) { + result = (previousType == XMLRegionContext.XML_TAG_OPEN); + } + } + return result; + } + + protected boolean isPartOfBlockRegion(IStructuredDocumentRegion flatNode) { + boolean result = false; + String type = flatNode.getType(); + result = (type == XMLRegionContext.BLOCK_TEXT || type == XMLJSPRegionContexts.JSP_CONTENT); + return result; + } + + public IStructuredTextReParser newInstance() { + return new XMLStructuredDocumentReParser(); + } + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XMLStructuredRegionFactory.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XMLStructuredRegionFactory.java new file mode 100644 index 0000000000..0411d664e2 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XMLStructuredRegionFactory.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.parser; + +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.xml.core.internal.text.XMLStructuredDocumentRegion; + + +/** + * A simple class to generate instances of StructuredRegions. + */ +public class XMLStructuredRegionFactory { + public final static int JSP_DIRECTIVE = 1003; + public final static int XML = 1001; + public final static int XML_BLOCK = 1002; + + public static IStructuredDocumentRegion createRegion(int type) { + IStructuredDocumentRegion instance = null; + switch (type) { + case XML : + instance = new XMLStructuredDocumentRegion(); + break; + case XML_BLOCK : + instance = new BlockStructuredDocumentRegion(); + break; + default : + throw new IllegalArgumentException("AbstractRegion::createRegion. Invalid type."); //$NON-NLS-1$ + } + return instance; + } + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XMLTokenizer.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XMLTokenizer.java new file mode 100644 index 0000000000..5f1101f1f8 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/XMLTokenizer.java @@ -0,0 +1,1699 @@ +/******************************************************************************* + * Copyright (c) 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +/* The following code was generated by JFlex 1.2.2 on 9/23/04 1:31 AM */ + +/*nlsXXX*/ +package org.eclipse.wst.xml.core.internal.parser; + +import java.io.CharArrayReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.wst.sse.core.parser.BlockMarker; +import org.eclipse.wst.sse.core.parser.BlockTokenizer; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.core.util.Debug; +import org.eclipse.wst.sse.core.util.StringUtils; +import org.eclipse.wst.xml.core.Logger; +import org.eclipse.wst.xml.core.internal.parser.regions.XMLParserRegionFactory; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; + + + +/** + * This class is a scanner generated by <a + * href="http://www.informatik.tu-muenchen.de/~kleing/jflex/">JFlex </a> 1.2.2 + * on 9/23/04 1:31 AM from the specification file + * <tt>file:/D:/eclipse.rad/workspace.rad/org.eclipse.wst.sse.core/DevTimeSupport/SedModel/HTMLTokenizer/devel/XMLTokenizer.jflex</tt> + */ +public class XMLTokenizer implements BlockTokenizer, XMLRegionContext { + + /** this character denotes the end of file */ + final public static int YYEOF = -1; + + /** lexical states */ + final public static int ST_XML_DOCTYPE_EXTERNAL_ID = 23; + final public static int ST_XML_ELEMENT_DECLARATION_CONTENT = 27; + final public static int ST_DHTML_ATTRIBUTE_NAME = 12; + final public static int ST_XML_PI_TAG_CLOSE = 11; + final public static int ST_XML_DECLARATION_CLOSE = 21; + final public static int ST_XML_PI_ATTRIBUTE_VALUE = 10; + final public static int ST_DHTML_EQUALS = 13; + final public static int ST_XML_TAG_NAME = 16; + final public static int ST_XML_ATTRIBUTE_VALUE = 19; + final public static int ST_DHTML_ATTRIBUTE_VALUE = 14; + final public static int ST_XML_DOCTYPE_ID_SYSTEM = 25; + final public static int ST_XML_ATTRIBUTE_NAME = 17; + final public static int ST_XML_ELEMENT_DECLARATION = 26; + final public static int ST_XML_DOCTYPE_DECLARATION = 22; + final public static int ST_XML_ATTLIST_DECLARATION = 28; + final public static int ST_XML_COMMENT_END = 4; + final public static int ST_CDATA_TEXT = 1; + final public static int ST_DHTML_TAG_CLOSE = 15; + final public static int ST_XML_COMMENT = 3; + final public static int ST_PI_CONTENT = 7; + final public static int ST_PI_WS = 6; + final public static int ST_CDATA_END = 2; + final public static int ST_XML_ATTLIST_DECLARATION_CONTENT = 29; + final public static int ST_BLOCK_TAG_SCAN = 30; + final public static int ST_XML_PI_EQUALS = 9; + final public static int ST_XML_DECLARATION = 20; + final public static int YYINITIAL = 0; + final public static int ST_XML_DOCTYPE_ID_PUBLIC = 24; + final public static int ST_XML_EQUALS = 18; + final public static int ST_PI = 5; + final public static int ST_XML_PI_ATTRIBUTE_NAME = 8; + + /** + * Translates characters to character classes + */ + final private static String yycmap_packed = "\11\0\1\5\1\22\2\0\1\14\22\0\1\14\1\21\1\11\1\51" + "\1\16\1\17\1\12\1\13\1\16\1\16\1\16\1\16\1\16\1\7" + "\1\6\1\3\12\15\1\10\1\54\1\1\1\43\1\2\1\4\1\16" + "\1\32\1\55\1\30\1\31\1\35\1\52\1\34\1\34\1\40\1\34" + "\1\34\1\26\1\25\1\42\1\41\1\45\1\34\1\36\1\37\1\33" + "\1\53\2\34\1\23\1\44\1\34\1\27\1\0\1\20\1\0\1\10" + "\1\0\1\47\1\55\1\56\1\50\1\35\1\52\1\34\1\34\1\40" + "\2\34\1\26\1\25\1\42\1\41\1\45\1\34\1\36\1\37\1\46" + "\1\53\1\34\1\34\1\24\1\44\1\34\1\0\1\0\72\0\1\60" + "\10\0\27\57\1\0\37\57\1\0\72\57\2\0\13\57\2\0\10\57" + "\1\0\65\57\1\0\104\57\11\0\44\57\3\0\2\57\4\0\36\57" + "\70\0\131\57\22\0\7\57\16\0\2\60\56\0\106\60\32\0\2\60" + "\44\0\1\57\1\60\3\57\1\0\1\57\1\0\24\57\1\0\54\57" + "\1\0\7\57\3\0\1\57\1\0\1\57\1\0\1\57\1\0\1\57" + "\1\0\22\57\15\0\14\57\1\0\102\57\1\0\14\57\1\0\44\57" + "\1\0\4\60\11\0\65\57\2\0\2\57\2\0\2\57\3\0\34\57" + "\2\0\10\57\2\0\2\57\67\0\46\57\2\0\1\57\7\0\46\57" + + "\12\0\21\60\1\0\27\60\1\0\3\60\1\0\1\60\1\0\2\60" + "\1\0\1\60\13\0\33\57\5\0\3\57\56\0\32\57\5\0\1\60" + "\12\57\10\60\15\0\12\60\6\0\1\60\107\57\2\0\5\57\1\0" + "\17\57\1\0\4\57\1\0\1\57\17\60\2\57\2\60\1\0\4\60" + "\2\0\12\60\u0207\0\3\60\1\0\65\57\2\0\1\60\1\57\20\60" + "\3\0\4\60\3\0\12\57\2\60\2\0\12\60\21\0\3\60\1\0" + "\10\57\2\0\2\57\2\0\26\57\1\0\7\57\1\0\1\57\3\0" + "\4\57\2\0\1\60\1\0\7\60\2\0\2\60\2\0\3\60\11\0" + "\1\60\4\0\2\57\1\0\3\57\2\60\2\0\12\60\2\57\20\0" + "\1\60\2\0\6\57\4\0\2\57\2\0\26\57\1\0\7\57\1\0" + "\2\57\1\0\2\57\1\0\2\57\2\0\1\60\1\0\5\60\4\0" + "\2\60\2\0\3\60\13\0\4\57\1\0\1\57\7\0\12\60\2\60" + "\3\57\14\0\3\60\1\0\7\57\1\0\1\57\1\0\3\57\1\0" + "\26\57\1\0\7\57\1\0\2\57\1\0\5\57\2\0\1\60\1\57" + "\10\60\1\0\3\60\1\0\3\60\22\0\1\57\5\0\12\60\21\0" + "\3\60\1\0\10\57\2\0\2\57\2\0\26\57\1\0\7\57\1\0" + "\2\57\2\0\4\57\2\0\1\60\1\57\6\60\3\0\2\60\2\0" + "\3\60\10\0\2\60\4\0\2\57\1\0\3\57\4\0\12\60\22\0" + + "\2\60\1\0\6\57\3\0\3\57\1\0\4\57\3\0\2\57\1\0" + "\1\57\1\0\2\57\3\0\2\57\3\0\3\57\3\0\10\57\1\0" + "\3\57\4\0\5\60\3\0\3\60\1\0\4\60\11\0\1\60\17\0" + "\11\60\21\0\3\60\1\0\10\57\1\0\3\57\1\0\27\57\1\0" + "\12\57\1\0\5\57\4\0\7\60\1\0\3\60\1\0\4\60\7\0" + "\2\60\11\0\2\57\4\0\12\60\22\0\2\60\1\0\10\57\1\0" + "\3\57\1\0\27\57\1\0\12\57\1\0\5\57\4\0\7\60\1\0" + "\3\60\1\0\4\60\7\0\2\60\7\0\1\57\1\0\2\57\4\0" + "\12\60\22\0\2\60\1\0\10\57\1\0\3\57\1\0\27\57\1\0" + "\20\57\4\0\6\60\2\0\3\60\1\0\4\60\11\0\1\60\10\0" + "\2\57\4\0\12\60\221\0\56\57\1\0\1\57\1\60\2\57\7\60" + "\5\0\6\57\1\60\10\60\1\0\12\60\47\0\2\57\1\0\1\57" + "\2\0\2\57\1\0\1\57\2\0\1\57\6\0\4\57\1\0\7\57" + "\1\0\3\57\1\0\1\57\1\0\1\57\2\0\2\57\1\0\2\57" + "\1\0\1\57\1\60\2\57\6\60\1\0\2\60\1\57\2\0\5\57" + "\1\0\1\60\1\0\6\60\2\0\12\60\76\0\2\60\6\0\12\60" + "\13\0\1\60\1\0\1\60\1\0\1\60\4\0\2\60\10\57\1\0" + "\41\57\7\0\24\60\1\0\6\60\4\0\6\60\1\0\1\60\1\0" + + "\25\60\3\0\7\60\1\0\1\60\346\0\46\57\12\0\47\57\11\0" + "\1\57\1\0\2\57\1\0\3\57\1\0\1\57\1\0\2\57\1\0" + "\5\57\51\0\1\57\1\0\1\57\1\0\1\57\13\0\1\57\1\0" + "\1\57\1\0\1\57\3\0\2\57\3\0\1\57\5\0\3\57\1\0" + "\1\57\1\0\1\57\1\0\1\57\1\0\1\57\3\0\2\57\3\0" + "\2\57\1\0\1\57\50\0\1\57\11\0\1\57\2\0\1\57\2\0" + "\2\57\7\0\2\57\1\0\1\57\1\0\7\57\50\0\1\57\4\0" + "\1\57\10\0\1\57\u0c06\0\234\57\4\0\132\57\6\0\26\57\2\0" + "\6\57\2\0\46\57\2\0\6\57\2\0\10\57\1\0\1\57\1\0" + "\1\57\1\0\1\57\1\0\37\57\2\0\65\57\1\0\7\57\1\0" + "\1\57\3\0\3\57\1\0\7\57\3\0\4\57\2\0\6\57\4\0" + "\15\57\5\0\3\57\1\0\7\57\323\0\15\60\4\0\1\60\104\0" + "\1\57\3\0\2\57\2\0\1\57\121\0\3\57\u0e82\0\1\60\1\0" + "\1\57\31\0\11\57\6\60\1\0\5\60\13\0\124\57\4\0\2\60" + "\2\0\2\60\2\0\132\57\1\0\3\60\6\0\50\57\u1cd3\0\u51a6\57" + "\u0c5a\0\u2ba4\57\134\0\u0800\0\u1ffe\0\2\0"; + + /** + * Translates characters to character classes + */ + final private static char[] yycmap = yy_unpack_cmap(yycmap_packed); + + /** + * Translates a state to a row index in the transition table + */ + final private static int yy_rowMap[] = {0, 49, 98, 147, 196, 245, 294, 343, 392, 441, 490, 539, 588, 637, 686, 735, 784, 833, 882, 931, 980, 1029, 1078, 1127, 1176, 1225, 1274, 1323, 1372, 1421, 1470, 1519, 1568, 1617, 1666, 1715, 1764, 1715, 1764, 1813, 1715, 1715, 1764, 1862, 1911, 1960, 2009, 2058, 2107, 2156, 1715, 1764, 2205, 2254, 2303, 1715, 2352, 2352, 2401, 2450, 2499, 2205, 1715, 2548, 2597, 1715, 2646, 2695, 2744, 2793, 2842, 2891, 1715, 2940, 2989, 3038, 3087, 1715, 3136, 3185, 3234, 3283, 3332, 1715, 3381, 3430, 3479, 3528, 3577, 3626, 3675, 3724, 3724, 3773, 3822, 3871, 3920, 3920, 3969, 4018, 4067, 4116, 4116, 4165, 4214, 4263, 4312, 1715, 4361, 4361, 4410, 4459, 4508, 4557, 1715, 1715, 1764, 1715, 1715, 4606, 4655, 4704, 4753, 4802, 4851, 4900, 4949, 1715, 4998, 5047, 1715, 1715, 2352, 5096, 2450, 1715, 5145, 2499, 2548, 2646, 2695, 5194, 2744, 1715, 5243, 2793, 1715, 3136, 5292, 3234, 1715, 5341, 3283, 4606, 5390, 5439, 5488, 3528, 1715, 5537, 5586, 3724, 5635, + 3773, 1715, 5684, 5733, 5782, 5782, 5831, 5880, 3871, 3724, 3920, 5929, 3969, 1715, 5978, 4018, 4067, 3920, 4116, 6027, 4165, 1715, 6076, 6125, 6174, 6174, 6223, 6272, 6321, 4361, 6370, 4410, 1715, 6419, 6468, 6517, 6517, 6566, 6615, 6664, 6713, 6762, 6811, 6860, 1715, 6909, 6958, 1715, 1715, 1715, 2009, 7007, 7056, 7105, 7154, 7203, 7252, 5684, 7301, 7301, 6076, 7350, 7350, 7399, 6419, 7448, 7448, 7497, 1715, 7546, 7595, 1715, 7644, 7693, 7742, 7791, 7840, 7889, 7938, 5831, 6223, 7987, 6566, 8036, 8085, 8134, 8183, 8232, 8281, 8330, 8379, 8428, 8477, 8526, 2009, 8575, 8624, 8673, 1715, 1715, 8722, 8771, 8820, 1715, 1715, 1715, 8869, 8918, 8967, 9016, 9065, 1715, 4263, 4508}; + + /** + * The packed transition table of the DFA + */ + final private static String yy_packed = "\1\40\1\41\10\40\1\42\4\40\1\43\41\40\1\44" + "\1\45\57\44\1\46\1\47\16\46\1\50\1\46\1\51" + "\36\46\1\52\1\53\57\52\1\46\1\47\5\46\1\54" + "\12\46\1\51\37\46\1\47\2\46\1\55\1\56\2\46" + "\1\57\3\46\1\56\5\46\1\56\2\60\2\57\1\46" + "\10\57\1\61\2\57\1\46\5\57\1\46\2\57\1\46" + "\3\57\2\46\1\47\2\46\1\55\1\62\6\46\1\62" + "\5\46\1\62\36\46\1\63\1\64\2\63\1\65\15\63" + "\1\51\36\63\1\46\1\47\2\46\1\66\1\56\2\46" + "\1\67\3\46\1\56\5\46\1\56\4\67\1\46\13\67" + "\1\46\5\67\1\46\2\67\1\46\3\67\2\46\1\47" + "\2\46\1\66\1\56\2\46\1\67\3\46\1\56\5\46" + "\1\56\4\67\1\46\13\67\1\70\5\67\1\46\2\67" + "\1\46\3\67\1\46\1\71\1\47\1\46\1\72\1\73" + "\1\56\3\71\1\74\1\71\1\75\1\56\5\71\1\56" + "\36\71\1\46\1\47\2\46\1\76\15\46\1\51\37\46" + "\1\47\1\77\1\100\1\46\1\56\2\46\1\101\3\46" + "\1\56\5\46\1\56\4\101\1\46\13\101\1\46\5\101" + "\1\46\2\101\1\46\3\101\2\46\1\47\1\77\1\100" + "\1\46\1\56\2\46\1\101\3\46\1\56\5\46\1\56" + + "\4\101\1\46\13\101\1\102\5\101\1\46\2\101\1\46" + "\3\101\1\46\1\103\1\47\1\77\1\104\1\103\1\56" + "\3\103\1\105\1\103\1\106\1\56\5\103\1\56\36\103" + "\1\46\1\47\3\46\1\56\6\46\1\56\5\46\1\56" + "\36\46\1\107\1\110\1\111\1\112\4\107\1\113\12\107" + "\4\114\1\107\13\114\1\107\5\114\1\107\2\114\1\107" + "\3\114\1\107\1\46\1\110\1\111\1\112\1\46\1\56" + "\2\46\1\115\3\46\1\56\5\46\1\56\4\115\1\46" + "\13\115\1\46\5\115\1\46\2\115\1\46\3\115\2\46" + "\1\110\1\111\1\112\1\46\1\56\2\46\1\115\3\46" + "\1\56\5\46\1\56\4\115\1\46\13\115\1\116\5\115" + "\1\46\2\115\1\46\3\115\1\46\1\117\1\110\1\111" + "\1\120\1\117\1\56\3\117\1\121\1\117\1\122\1\56" + "\5\117\1\56\36\117\1\46\1\123\1\124\2\46\1\56" + "\6\46\1\56\5\46\1\56\6\46\1\125\1\126\2\46" + "\1\127\11\46\1\126\1\125\11\46\1\47\1\124\2\46" + "\1\56\6\46\1\56\5\46\1\56\4\46\1\130\32\46" + "\1\47\1\124\2\46\1\56\2\46\1\131\3\46\1\56" + "\5\46\1\56\4\131\1\130\13\131\1\46\5\131\1\46" + + "\2\131\1\46\3\131\2\46\1\47\1\124\2\46\1\56" + "\6\46\1\56\5\46\1\56\4\46\1\130\7\46\1\132" + "\5\46\1\133\13\46\1\134\1\47\1\124\1\135\1\134" + "\1\56\3\134\1\136\1\134\1\137\1\56\5\134\1\56" + "\4\134\1\140\31\134\1\141\1\47\1\124\1\142\1\141" + "\1\56\3\141\1\143\1\141\1\144\1\56\5\141\1\56" + "\4\141\1\145\31\141\1\146\1\47\1\124\1\147\1\146" + "\1\56\3\146\1\150\1\146\1\151\1\56\5\146\1\56" + "\36\146\1\152\1\153\1\154\56\152\1\155\1\47\1\124" + "\1\156\1\155\1\56\3\155\1\157\1\155\1\160\1\56" + "\5\155\1\56\36\155\1\161\1\162\1\163\56\161\1\164" + "\1\165\57\164\1\40\1\0\10\40\1\0\4\40\1\0" + "\41\40\3\0\1\166\1\167\14\0\1\170\44\0\1\171" + "\2\0\1\172\3\0\1\171\5\0\1\171\4\172\1\0" + "\13\172\1\0\5\172\1\173\2\172\1\0\3\172\6\0" + "\1\171\2\0\1\174\3\0\1\171\5\0\1\171\4\174" + "\1\0\13\174\1\0\5\174\1\0\2\174\1\0\3\174" + "\103\0\1\175\57\0\1\176\47\0\1\177\53\0\1\200" + "\63\0\1\56\6\0\1\56\5\0\1\56\44\0\3\57" + "\4\0\1\57\5\0\4\57\1\0\13\57\1\0\5\57" + + "\1\0\2\57\1\0\4\57\6\0\3\57\4\0\1\57" + "\5\0\2\57\1\201\1\57\1\0\13\57\1\0\5\57" + "\1\0\2\57\1\0\4\57\6\0\3\57\4\0\1\57" + "\5\0\2\57\1\202\1\57\1\0\13\57\1\0\5\57" + "\1\0\2\57\1\0\4\57\5\0\1\62\6\0\1\62" + "\5\0\1\62\40\0\1\203\60\0\1\204\64\0\3\67" + "\4\0\1\67\5\0\4\67\1\0\13\67\1\0\5\67" + "\1\0\2\67\1\0\4\67\1\71\2\0\1\205\1\71" + "\1\0\3\71\1\0\1\71\2\0\5\71\1\0\37\71" + "\1\0\1\204\1\205\1\71\1\0\3\71\1\0\1\71" + "\2\0\5\71\1\0\36\71\1\74\1\0\1\206\1\207" + "\1\74\1\206\3\74\1\210\1\74\2\206\5\74\1\206" + "\36\74\1\75\1\0\1\211\1\212\1\75\1\211\3\75" + "\1\211\1\75\1\210\1\211\5\75\1\211\36\75\2\0" + "\1\77\1\213\63\0\3\101\4\0\1\101\5\0\4\101" + "\1\0\13\101\1\0\5\101\1\0\2\101\1\0\4\101" + "\1\103\2\0\1\214\1\103\1\0\3\103\1\0\1\103" + "\2\0\5\103\1\0\37\103\1\0\1\77\1\215\1\103" + "\1\0\3\103\1\0\1\103\2\0\5\103\1\0\36\103" + "\1\105\1\0\1\216\1\217\1\105\1\216\3\105\1\220" + "\1\105\2\216\5\105\1\216\36\105\1\106\1\0\1\221" + + "\1\222\1\106\1\221\3\106\1\221\1\106\1\220\1\221" + "\5\106\1\221\36\106\1\107\3\0\17\107\4\0\1\107" + "\13\0\1\107\5\0\1\107\2\0\1\107\3\0\1\107" + "\3\0\1\166\15\0\1\170\41\0\1\223\56\0\1\107" + "\3\0\2\107\3\113\4\107\1\113\5\107\4\114\1\107" + "\13\114\1\107\5\114\1\107\2\114\1\107\3\114\1\113" + "\6\0\3\114\4\0\1\114\5\0\4\114\1\0\13\114" + "\1\0\5\114\1\0\2\114\1\0\4\114\6\0\3\115" + "\4\0\1\115\5\0\4\115\1\0\13\115\1\0\5\115" + "\1\0\2\115\1\0\4\115\1\117\2\0\1\224\1\117" + "\1\0\3\117\1\0\1\117\2\0\5\117\1\0\37\117" + "\1\0\1\223\1\224\1\117\1\0\3\117\1\0\1\117" + "\2\0\5\117\1\0\36\117\1\121\1\0\1\225\1\226" + "\1\121\1\225\3\121\1\227\1\121\2\225\5\121\1\225" + "\36\121\1\122\1\0\1\230\1\231\1\122\1\230\3\122" + "\1\230\1\122\1\227\1\230\5\122\1\230\36\122\3\0" + "\1\166\15\0\1\232\100\0\1\233\52\0\1\234\12\0" + "\1\234\40\0\1\235\32\0\20\236\1\237\40\236\6\0" + "\3\131\4\0\1\131\5\0\4\131\1\0\13\131\1\0" + "\5\131\1\0\2\131\1\0\4\131\44\0\1\240\67\0" + + "\1\241\5\0\1\134\2\0\1\242\1\134\1\0\3\134" + "\1\0\1\134\2\0\5\134\1\0\36\134\1\136\1\0" + "\1\243\1\244\1\136\1\243\3\136\1\245\1\136\2\243" + "\5\136\1\243\36\136\1\246\1\0\1\247\1\250\1\251" + "\1\247\3\251\1\247\1\246\1\252\1\253\3\251\1\246" + "\1\251\1\253\4\251\1\246\27\251\2\246\1\140\2\236" + "\1\254\1\140\1\236\3\140\1\236\1\140\2\236\3\140" + "\1\255\1\140\1\236\36\140\1\141\2\0\1\256\1\141" + "\1\0\3\141\1\0\1\141\2\0\5\141\1\0\36\141" + "\1\143\2\257\1\260\1\143\1\257\3\143\1\261\1\143" + "\2\257\5\143\1\257\36\143\1\144\2\262\1\263\1\144" + "\1\262\3\144\1\262\1\144\1\261\1\262\5\144\1\262" + "\36\144\1\145\2\236\1\264\1\145\1\236\3\145\1\236" + "\1\145\2\236\3\145\1\265\1\145\1\236\36\145\1\146" + "\2\0\1\266\1\146\1\0\3\146\1\0\1\146\2\0" + "\5\146\1\0\36\146\1\150\1\0\1\267\1\270\1\150" + "\1\267\3\150\1\271\1\150\2\267\5\150\1\267\36\150" + "\1\272\1\0\1\273\1\274\1\275\1\273\3\275\1\273" + "\1\272\1\276\1\277\3\275\1\272\1\275\1\277\4\275" + + "\1\272\27\275\2\272\2\152\1\0\60\152\1\0\16\152" + "\1\300\37\152\1\155\2\0\1\301\1\155\1\0\3\155" + "\1\0\1\155\2\0\5\155\1\0\36\155\1\157\1\0" + "\1\302\1\303\1\157\1\302\3\157\1\304\1\157\2\302" + "\5\157\1\302\36\157\1\305\1\0\1\306\1\307\1\310" + "\1\306\3\310\1\306\1\305\1\311\1\312\3\310\1\305" + "\1\310\1\312\4\310\1\305\27\310\2\305\2\161\1\0" + "\60\161\1\0\16\161\1\313\37\161\7\0\1\314\17\0" + "\1\315\36\0\1\171\2\0\1\40\3\0\1\171\5\0" + "\1\171\4\40\1\0\13\40\1\0\5\40\1\0\2\40" + "\1\0\3\40\1\0\1\316\1\0\3\316\1\317\3\172" + "\1\316\1\0\1\316\1\317\1\172\1\316\1\0\2\316" + "\1\317\4\172\1\316\13\172\1\316\5\172\1\316\2\172" + "\1\320\4\172\15\0\1\321\6\0\1\322\34\0\1\316" + "\1\0\3\316\1\317\3\174\1\316\1\0\1\316\1\317" + "\1\174\1\316\1\0\2\316\1\317\4\174\1\316\13\174" + "\1\316\5\174\1\316\2\174\1\323\4\174\27\0\1\315" + "\33\0\1\324\60\0\1\325\64\0\3\57\4\0\1\57" + "\5\0\3\57\1\326\1\0\13\57\1\0\5\57\1\0" + "\2\57\1\0\4\57\6\0\3\57\4\0\1\57\5\0" + + "\4\57\1\0\13\57\1\0\1\57\1\327\3\57\1\0" + "\2\57\1\0\4\57\1\206\1\0\7\206\1\210\47\206" + "\1\211\1\0\11\211\1\210\45\211\1\216\1\0\7\216" + "\1\220\47\216\1\221\1\0\11\221\1\220\45\221\1\225" + "\1\0\7\225\1\227\47\225\1\230\1\0\11\230\1\227" + "\45\230\30\0\1\330\25\0\1\330\35\0\1\331\12\0" + "\1\331\47\0\1\332\62\0\1\333\76\0\1\334\3\0" + "\1\243\1\0\7\243\1\245\47\243\1\246\1\0\1\247" + "\1\335\1\246\1\247\3\246\1\247\1\246\1\245\1\247" + "\5\246\1\247\36\246\1\247\1\0\11\247\1\245\45\247" + "\1\246\1\0\1\247\1\335\1\246\1\247\3\246\1\247" + "\1\246\1\336\1\247\5\246\1\247\36\246\13\0\1\337" + "\45\0\1\247\1\0\11\247\1\336\45\247\11\257\1\261" + "\47\257\13\262\1\261\45\262\1\267\1\0\7\267\1\271" + "\47\267\1\272\1\0\1\273\1\340\1\272\1\273\3\272" + "\1\273\1\272\1\271\1\273\5\272\1\273\36\272\1\273" + "\1\0\11\273\1\271\45\273\1\272\1\0\1\273\1\340" + "\1\272\1\273\3\272\1\273\1\272\1\341\1\273\5\272" + "\1\273\36\272\13\0\1\342\45\0\1\273\1\0\11\273" + + "\1\341\45\273\2\152\1\0\24\152\1\343\31\152\1\302" + "\1\0\7\302\1\304\47\302\1\305\1\0\1\306\1\344" + "\1\305\1\306\3\305\1\306\1\305\1\304\1\306\5\305" + "\1\306\36\305\1\306\1\0\11\306\1\304\45\306\1\305" + "\1\0\1\306\1\344\1\305\1\306\3\305\1\306\1\305" + "\1\345\1\306\5\305\1\306\36\305\13\0\1\346\45\0" + "\1\306\1\0\11\306\1\345\45\306\2\161\1\0\24\161" + "\1\347\31\161\7\0\1\350\101\0\1\351\30\0\1\316" + "\1\0\10\316\1\0\4\316\1\0\34\316\1\0\5\316" + "\1\0\3\316\1\317\4\316\1\0\1\316\1\317\2\316" + "\1\0\2\316\1\317\31\316\1\352\4\316\15\0\1\321" + "\36\0\1\353\21\0\1\354\12\0\3\354\2\0\1\354" + "\11\0\2\354\1\0\1\354\2\0\2\354\10\0\3\57" + "\4\0\1\57\5\0\4\57\1\0\11\57\1\355\1\57" + "\1\0\5\57\1\0\2\57\1\0\4\57\33\0\1\356" + "\12\0\1\356\40\0\1\357\57\0\1\360\66\0\1\361" + "\12\0\1\361\40\0\1\362\35\0\2\363\1\0\3\363" + "\2\0\1\252\4\363\1\0\6\363\1\0\27\363\5\0" + "\2\364\1\0\3\364\2\0\1\276\4\364\1\0\6\364" + + "\1\0\27\364\2\0\2\152\1\0\25\152\1\365\30\152" + "\3\0\2\366\1\0\3\366\2\0\1\311\4\366\1\0" + "\6\366\1\0\27\366\2\0\2\161\1\0\25\161\1\367" + "\30\161\31\0\1\370\103\0\1\352\21\0\1\354\12\0" + "\3\354\2\0\1\354\11\0\2\354\1\0\1\354\1\0" + "\1\353\2\354\10\0\3\57\4\0\1\57\5\0\4\57" + "\1\0\6\57\1\371\4\57\1\0\5\57\1\0\2\57" + "\1\0\4\57\44\0\1\372\54\0\1\373\55\0\1\374" + "\60\0\1\375\63\0\1\376\20\0\2\152\1\0\26\152" + "\1\377\27\152\2\161\1\0\26\161\1\u0100\27\161\32\0" + "\1\u0101\34\0\3\57\4\0\1\57\5\0\4\57\1\0" + "\3\57\1\u0102\7\57\1\0\2\57\1\u0102\2\57\1\0" + "\2\57\1\0\4\57\45\0\1\u0103\52\0\1\u0104\63\0" + "\1\u0105\43\0\1\u0106\63\0\1\u0107\25\0\1\u0107\2\0" + "\2\152\1\0\27\152\1\u0108\26\152\2\161\1\0\27\161" + "\1\u0109\26\161\33\0\1\u010a\62\0\1\u010b\56\0\1\u010c" + "\12\0\1\u010c\45\0\1\u010d\12\0\1\u010d\12\0\2\152" + "\1\0\30\152\1\u010e\25\152\2\161\1\0\30\161\1\u010f" + "\25\161\32\0\1\u0110\26\0\2\152\1\0\27\152\1\u0111" + + "\26\152\2\161\1\0\27\161\1\u0112\26\161\27\0\1\u0113" + "\31\0\2\152\1\0\24\152\1\u0114\31\152\2\161\1\0" + "\24\161\1\u0115\31\161"; + + /** + * The transition table of the DFA + */ + final private static int yytrans[] = yy_unpack(yy_packed); + + + /* error codes */ + final private static int YY_UNKNOWN_ERROR = 0; + // final private static int YY_ILLEGAL_STATE = 1; + final private static int YY_NO_MATCH = 2; + final private static int YY_PUSHBACK_2BIG = 3; + + /* error messages for the codes above */ + final private static String YY_ERROR_MSG[] = {"Unkown internal scanner error", //$NON-NLS-1$ + "Internal error: unknown state", //$NON-NLS-1$ + "Error: could not match input", //$NON-NLS-1$ + "Error: pushback value was too large" //$NON-NLS-1$ + }; + + /** + * YY_ATTRIBUTE[aState] contains the attributes of state + * <code>aState</code> + */ + private final static byte YY_ATTRIBUTE[] = {1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 9, 1, 9, 1, 1, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 9, 1, 1, 1, 1, 9, 1, 1, 1, 1, 1, 1, 9, 1, 1, 9, 1, 1, 1, 1, 1, 1, 9, 1, 1, 1, 1, 9, 1, 1, 1, 1, 1, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 1, 1, 1, 1, 1, 1, 9, 9, 1, 9, 9, 1, 0, 1, 0, 1, 0, 0, 0, 9, 1, 1, 9, 9, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 9, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 9, 0, 0, 0, 1, 0, 0, 0, 9, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 9, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 9, 0, 0, 9, 9, 9, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 9, 0, 1, 9, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 9, 9, 1, 1, 0, 9, 9, 9, 1, 1, 0, 1, 1, 9, 1, 1}; + + /** the input device */ + private java.io.Reader yy_reader; + + /** the current state of the DFA */ + private int yy_state; + + /** the current lexical state */ + private int yy_lexical_state = YYINITIAL; + + /** + * this buffer contains the current text to be matched and is the source + * of the yytext() string + */ + private char yy_buffer[] = new char[16384]; + + /** the textposition at the last accepting state */ + private int yy_markedPos; + + /** the textposition at the last state to be included in yytext */ + private int yy_pushbackPos; + + /** the current text position in the buffer */ + private int yy_currentPos; + + /** startRead marks the beginning of the yytext() string in the buffer */ + private int yy_startRead; + + /** + * endRead marks the last character in the buffer, that has been read from + * input + */ + private int yy_endRead; + + /** number of newlines encountered up to the start of the matched text */ + private int yyline; + + /** the number of characters up to the start of the matched text */ + private int yychar; + + /** + * the number of characters from the last newline up to the start of the + * matched text + */ + // private int yycolumn; + /** + * yy_atBOL == true <=>the scanner is currently at the beginning of a line + */ + // private boolean yy_atBOL; + /** yy_atEOF == true <=>the scanner has returned a value for EOF */ + private boolean yy_atEOF; + + /** denotes if the user-EOF-code has already been executed */ + private boolean yy_eof_done; + + /* user code: */ + private int fTokenCount = 0; + + // required holders for white-space compacting + private boolean fShouldLoadBuffered = false; + private String fBufferedContext = null; + private int fBufferedStart = 1; + private int fBufferedLength = 0; + private ContextRegionContainer fBufferedEmbeddedContainer = null; + private String f_context = null; + + // state stack for handling embedded regions + private IntStack fStateStack = new IntStack(); + // a "hint" as to what an embedded region should be evaluated + String fEmbeddedHint = UNDEFINED; + // a "hint" as to what state to enter once an embedded region has + // been completed + int fEmbeddedPostState = YYINITIAL; + // the container used to create embedded regions + private ContextRegionContainer fEmbeddedContainer = null; + private static final String PROXY_CONTEXT = "PROXY_CONTEXT"; + + private String context = null; + private int start = 0; + private int textLength = 0; + private int length = 0; + + // offset for tracking position specific block tags + private int fOffset = 0; + + // the name of the current tag being opened + private String fCurrentTagName = null; + + // the list of tag name BlockMarkers + private List fBlockMarkers = new ArrayList(); + + // required to not seek text blocks on an end tag + private boolean fIsBlockingEnabled = false; + private boolean fIsCaseSensitiveBlocking = true; + + private XMLParserRegionFactory fRegionFactory = new XMLParserRegionFactory(); + + static final String rcsver = "$Id: XMLTokenizer.java,v 1.3 2004/11/11 09:05:07 david_williams Exp $";//$NON-NLS-1$ + + /** + * user method + */ + public final void addBlockMarker(BlockMarker marker) { + if (containsTagName(marker.getTagName())) + return; + fBlockMarkers.add(marker); + } + + /** + * user method + */ + public final void removeBlockMarker(BlockMarker marker) { + fBlockMarkers.remove(marker); + } + + /** + * user method + */ + public final void removeBlockMarker(String tagname) { + if (fBlockMarkers != null) { + Iterator blocks = fBlockMarkers.iterator(); + while (blocks.hasNext()) { + if (((BlockMarker) blocks.next()).getTagName().equals(tagname)) + blocks.remove(); + } + } + } + + /* user method */ + public final boolean isCaseSensitiveBlocking() { + return fIsCaseSensitiveBlocking; + } + + /* user method */ + public final void setCaseSensitiveBlocking(boolean newValue) { + fIsCaseSensitiveBlocking = newValue; + } + + /* user method */ + public boolean getBlockMarkerCaseSensitivity() { + return getBlockMarkerCaseSensitivity(fCurrentTagName); + } + + /* user method */ + public boolean getBlockMarkerCaseSensitivity(String name) { + Iterator iterator = fBlockMarkers.iterator(); + while (iterator.hasNext()) { + BlockMarker marker = (BlockMarker) iterator.next(); + boolean casesensitive = marker.isCaseSensitive(); + if (casesensitive && marker.getTagName().equals(name)) + return casesensitive; + else if (!casesensitive && marker.getTagName().equalsIgnoreCase(name)) + return casesensitive; + } + return true; + } + + /* user method */ + public String getBlockMarkerContext() { + return getBlockMarkerContext(fCurrentTagName); + } + + /* user method */ + public String getBlockMarkerContext(String name) { + Iterator iterator = fBlockMarkers.iterator(); + while (iterator.hasNext()) { + BlockMarker marker = (BlockMarker) iterator.next(); + if (marker.getTagName().equals(name)) + return marker.getContext(); + } + return BLOCK_TEXT; + } + + /* user method */ + public List getBlockMarkers() { + return fBlockMarkers; + } + + /* user method */ + public final int getOffset() { + return fOffset + yychar; + } + + private final boolean isBlockMarker() { + return isBlockMarker(fCurrentTagName); + } + + private final boolean isBlockMarker(String tagName) { + if (!fIsBlockingEnabled) + return false; + return containsTagName(tagName); + } + + /** + * user method + */ + public final void beginBlockTagScan(String newTagName) { + beginBlockMarkerScan(newTagName, BLOCK_TEXT); + } + + /** + * user method + * + * Special tokenizer setup. Allows tokenization to be initiated at the + * start of a text block within a "newTagName" tag. + * + * Example: Tokenizer toker = new Tokenizer(); + * toker.setCaseSensitiveBlocking(false); toker.reset(new + * java.io.StringReader("afiuhqwkejhtasihgalkwhtq </scripter> </scr> + * </script>asgdasga")); toker.beginBlockMarkerScan("script", BLOCK_TEXT); + * toker.getRegions(); + * + * Returns: BLOCK_TEXT: 0-40 XML_END_TAG_OPEN: 41-42 XML_TAG_NAME: 43-48 + * XML_TAG_CLOSE: 49-49 XML_CONTENT: 50-57 + * + */ + public final void beginBlockMarkerScan(String newTagName, String blockcontext) { + yybegin(ST_BLOCK_TAG_SCAN); + fCurrentTagName = newTagName; + } + + /** + * Method doScan. + * + * Returns a context region for all of the text from the current position + * upto the end of input or to right *before* the first occurence of + * searchString + * + * @param searchString - + * target string to search for ex.: "-->", " </tagname" + * @param requireTailSeparator - + * whether the target must be immediately followed by + * whitespace or '>' + * @param context - + * the context of the scanned region if non-zero length + * @param exitState - + * the state to go to if the region was of non-zero length + * @param abortState - + * the state to go to if the searchString was found immediately + * @return String - the context found: the desired context on a non-zero + * length match, the abortContext on immediate success + * @throws IOException + */ + private final String doScan(String searchString, boolean requireTailSeparator, String searchContext, int exitState, int immediateFallbackState) throws IOException { + boolean stillSearching = true; + // Disable further block (probably) + fIsBlockingEnabled = false; + int searchStringLength = searchString.length(); + int n = 0; + char lastCheckChar; + int i; + boolean same = false; + while (stillSearching) { + n = 0; + // Ensure that enough data from the input exists to compare + // against the search String. + n = yy_advance(); + while (n != YYEOF && yy_currentPos < searchStringLength) + n = yy_advance(); + // If the input was too short or we've exhausted the input, stop + // immediately. + if (n == YYEOF) { + stillSearching = false; + } else { + same = true; + // Ensure that we've not encountered a complete block (<%%>) + // that was *shorter* than the closeTagString and + // thus found twice at current-targetLength [since the first + // scan would have come out this far anyway]. + // Check the characters in the target versus the last + // targetLength characters read from the buffer + // and see if it matches + + // safety check for array accesses (yy_currentPos is the + // *last* character we can check against) + if (yy_currentPos >= searchStringLength && yy_currentPos <= yy_buffer.length) { + for (i = 0; i < searchStringLength; i++) { + if (same && fIsCaseSensitiveBlocking) + same = yy_buffer[i + yy_currentPos - searchStringLength] == searchString.charAt(i); + else if (same && !fIsCaseSensitiveBlocking) + same = Character.toLowerCase(yy_buffer[i + yy_currentPos - searchStringLength]) == Character.toLowerCase(searchString.charAt(i)); + } + } + // safety check failed; no match is possible right now + else { + same = false; + } + if (same && requireTailSeparator && yy_currentPos < yy_buffer.length) { + // Additional check for close tags to ensure that + // targetString="</script" doesn't match + // "</scriptS" + lastCheckChar = yy_buffer[yy_currentPos]; + // Succeed on "</script>" and "</script " + if (lastCheckChar == '>' || Character.isWhitespace(lastCheckChar)) + stillSearching = false; + } else { + stillSearching = !same || (yy_currentPos < yy_startRead + searchStringLength); + } + } + } + if (n != YYEOF || same) { + // We've stopped short of the end or definitely found a match + yy_markedPos = yy_currentPos - searchStringLength; + yy_currentPos = yy_markedPos + 1; + // If the searchString occurs at the very beginning of what would + // have + // been a Block, resume scanning normally immediately + if (yy_markedPos == yy_startRead) { + yybegin(immediateFallbackState); + return primGetNextToken(); + } + } else { + // We ran through the rest of the input + yy_markedPos = yy_currentPos; + yy_currentPos++; + } + yybegin(exitState); + // If the ending occurs at the very beginning of what would have + // been a Block, resume scanning normally immediately + if (yy_markedPos == yy_startRead) + return primGetNextToken(); + return searchContext; + } + + /** + * user method + * + * A generic lookahead-like operation + */ + private final String doBlockScan(String target, String targetContext, int immediateFallbackState) throws IOException { + return doScan(target, false, targetContext, immediateFallbackState, immediateFallbackState); + } + + /** + * user method does a lookahead for the current tag name + */ + private final String doBlockTagScan() throws IOException { + fIsCaseSensitiveBlocking = getBlockMarkerCaseSensitivity(); + return doScan("</" + fCurrentTagName, true, getBlockMarkerContext(fCurrentTagName), YYINITIAL, YYINITIAL); + } + + /** + * user method + * + * Converts the raw context String returned by the primGetNextToken() + * method into a full ITextRegion by pulling in values for the current + * offset within the scanning text. + * + * Returns null when EOF is encountered and attaches intermittently + * discovered whitespace onto the end of useful regions. + * + * Note that this algorithm caches the token following the one being + * returned so that whitespace can be collapsed. + */ + public final ITextRegion getNextToken() throws IOException { + fEmbeddedContainer = null; + // load the starting non-whitespace token (assume that it is so) + if (fShouldLoadBuffered) { + if (fBufferedEmbeddedContainer != null) { + ITextRegion container = fBufferedEmbeddedContainer; + fBufferedEmbeddedContainer = null; + fShouldLoadBuffered = false; + return container; + } + context = fBufferedContext; + start = fBufferedStart; + textLength = length = fBufferedLength; + fShouldLoadBuffered = false; + } else { + context = primGetNextToken(); + if (context == PROXY_CONTEXT) { + return fEmbeddedContainer; + } else if (context == XML_TAG_NAME) { + if (containsTagName(yy_buffer, yy_startRead, yy_markedPos - yy_startRead)) + fCurrentTagName = yytext(); + else + fCurrentTagName = null; + } else if (context == XML_TAG_OPEN) { + fIsBlockingEnabled = true; + } else if (context == XML_END_TAG_OPEN) { + fIsBlockingEnabled = false; + } + start = yychar; + textLength = length = yylength(); + if (yy_atEOF) { + fTokenCount++; + return null; + } + } + // store the next token + f_context = primGetNextToken(); + if (f_context == PROXY_CONTEXT) { + fBufferedEmbeddedContainer = fEmbeddedContainer; + fShouldLoadBuffered = true; + } else if (f_context == XML_TAG_NAME) { + if (containsTagName(yy_buffer, yy_startRead, yy_markedPos - yy_startRead)) + fCurrentTagName = yytext(); + else + fCurrentTagName = null; + } else if (f_context == XML_TAG_OPEN) { + fIsBlockingEnabled = true; + } else if (f_context == XML_END_TAG_OPEN) { + fIsBlockingEnabled = false; + } + fBufferedContext = f_context; + fBufferedStart = yychar; + fBufferedLength = yylength(); + fShouldLoadBuffered = true; + if (fBufferedContext == WHITE_SPACE) { + fShouldLoadBuffered = false; + length += fBufferedLength; + } + if (context == null) { + // EOF + if (Debug.debugTokenizer) { + System.out.println(getClass().getName() + " discovered " + fTokenCount + " tokens."); //$NON-NLS-2$//$NON-NLS-1$ + } + return null; + } + fTokenCount++; + return fRegionFactory.createToken(context, start, textLength, length, null, fCurrentTagName); + } + + /* user method */ + public XMLTokenizer() { + super(); + } + + /* user method */ + public XMLTokenizer(char[] charArray) { + this(new CharArrayReader(charArray)); + } + + /* user method */ + public void reset(char[] charArray) { + reset(new CharArrayReader(charArray), 0); + } + + /* user method */ + public void reset(char[] charArray, int newOffset) { + reset(new CharArrayReader(charArray), newOffset); + } + + /* user method */ + public void reset(java.io.InputStream in) { + reset(new java.io.InputStreamReader(in), 0); + } + + /* user method */ + public void reset(java.io.InputStream in, int newOffset) { + reset(new java.io.InputStreamReader(in), newOffset); + } + + /* user method */ + public void reset(java.io.Reader in) { + reset(in, 0); + } + + /** + * user method * + * + * Reset internal counters and vars to "newly created" values, in the + * hopes that resetting a pre-existing tokenizer is faster than creating a + * new one. + * + * This method contains code blocks that were essentially duplicated from + * the <em>generated</em> output of this specification before this + * method was added. Those code blocks were under the above copyright. + */ + public void reset(java.io.Reader in, int newOffset) { + if (Debug.debugTokenizer) { + System.out.println("resetting tokenizer");//$NON-NLS-1$ + } + fOffset = newOffset; + + /* the input device */ + yy_reader = in; + + /* the current state of the DFA */ + yy_state = 0; + + /* the current lexical state */ + yy_lexical_state = YYINITIAL; + + /* + * this buffer contains the current text to be matched and is the + * source of the yytext() string + */ + java.util.Arrays.fill(yy_buffer, (char) 0); + + /* the textposition at the last accepting state */ + yy_markedPos = 0; + + /* the textposition at the last state to be included in yytext */ + yy_pushbackPos = 0; + + /* the current text position in the buffer */ + yy_currentPos = 0; + + /* startRead marks the beginning of the yytext() string in the buffer */ + yy_startRead = 0; + + /** + * endRead marks the last character in the buffer, that has been read + * from input + */ + yy_endRead = 0; + + /* number of newlines encountered up to the start of the matched text */ + yyline = 0; + + /* the number of characters up to the start of the matched text */ + yychar = 0; + + /* yy_atEOF == true <=> the scanner has returned a value for EOF */ + yy_atEOF = false; + + /* denotes if the user-EOF-code has already been executed */ + yy_eof_done = false; + + + /* user vars: */ + fTokenCount = 0; + + fShouldLoadBuffered = false; + fBufferedContext = null; + fBufferedStart = 1; + fBufferedLength = 0; + fStateStack = new IntStack(); + + context = null; + start = 0; + textLength = 0; + length = 0; + + fEmbeddedContainer = null; + } + + /** + * user method + * + * @see com.ibm.sed.parser.BlockTokenizer#newInstance() + */ + public BlockTokenizer newInstance() { + XMLTokenizer newInstance = new XMLTokenizer(); + // global tagmarkers can be shared; they have no state and + // are never destroyed (e.g. 'release') + for (int i = 0; i < fBlockMarkers.size(); i++) { + BlockMarker blockMarker = (BlockMarker) fBlockMarkers.get(i); + if (blockMarker.isGlobal()) + newInstance.addBlockMarker(blockMarker); + } + return newInstance; + } + + /* user method */ + private final String scanXMLCommentText() throws IOException { + // Scan for '-->' and return the text up to that point as + // XML_COMMENT_TEXT unless the string occurs IMMEDIATELY, in which + // case change to the ST_XML_COMMENT_END state and return the next + // context as usual. + return doScan("-->", false, XML_COMMENT_TEXT, ST_XML_COMMENT_END, ST_XML_COMMENT_END); + } + + + /** + * Creates a new scanner There is also a java.io.InputStream version of + * this constructor. + * + * @param in + * the java.io.Reader to read input from. + */ + public XMLTokenizer(java.io.Reader in) { + this.yy_reader = in; + } + + /** + * Creates a new scanner. There is also java.io.Reader version of this + * constructor. + * + * @param in + * the java.io.Inputstream to read input from. + */ + public XMLTokenizer(java.io.InputStream in) { + this(new java.io.InputStreamReader(in)); + } + + /** + * Unpacks the compressed DFA transition table. + * + * @param packed + * the packed transition table + * @return the unpacked transition table + */ + private static int[] yy_unpack(String packed) { + int[] trans = new int[9114]; + int i = 0; /* index in packed string */ + int j = 0; /* index in unpacked array */ + while (i < 3174) { + int count = packed.charAt(i++); + int value = packed.charAt(i++); + value--; + do + trans[j++] = value; + while (--count > 0); + } + return trans; + } + + /** + * Unpacks the compressed character translation table. + * + * @param packed + * the packed character translation table + * @return the unpacked character translation table + */ + private static char[] yy_unpack_cmap(String packed) { + char[] map = new char[0x10000]; + int i = 0; /* index in packed string */ + int j = 0; /* index in unpacked array */ + while (i < 1372) { + int count = packed.charAt(i++); + char value = packed.charAt(i++); + do + map[j++] = value; + while (--count > 0); + } + return map; + } + + + /** + * Gets the next input character. + * + * @return the next character of the input stream, EOF if the end of the + * stream is reached. + * @exception IOException + * if any I/O-Error occurs + */ + private int yy_advance() throws java.io.IOException { + + /* standard case */ + if (yy_currentPos < yy_endRead) + return yy_buffer[yy_currentPos++]; + + /* if the eof is reached, we don't need to work hard */ + if (yy_atEOF) + return YYEOF; + + /* otherwise: need to refill the buffer */ + + /* first: make room (if you can) */ + if (yy_startRead > 0) { + System.arraycopy(yy_buffer, yy_startRead, yy_buffer, 0, yy_endRead - yy_startRead); + + /* translate stored positions */ + yy_endRead -= yy_startRead; + yy_currentPos -= yy_startRead; + yy_markedPos -= yy_startRead; + yy_pushbackPos -= yy_startRead; + yy_startRead = 0; + } + + /* is the buffer big enough? */ + if (yy_currentPos >= yy_buffer.length) { + /* if not: blow it up */ + char newBuffer[] = new char[yy_currentPos * 2]; + System.arraycopy(yy_buffer, 0, newBuffer, 0, yy_buffer.length); + yy_buffer = newBuffer; + } + + /* finally: fill the buffer with new input */ + int numRead = yy_reader.read(yy_buffer, yy_endRead, yy_buffer.length - yy_endRead); + + if (numRead == -1) + return YYEOF; + + yy_endRead += numRead; + + return yy_buffer[yy_currentPos++]; + } + + + /** + * Closes the input stream. + */ + final public void yyclose() throws java.io.IOException { + yy_atEOF = true; /* indicate end of file */ + yy_endRead = yy_startRead; /* invalidate buffer */ + yy_reader.close(); + } + + + /** + * Returns the current lexical state. + */ + final public int yystate() { + return yy_lexical_state; + } + + /** + * Enters a new lexical state + * + * @param newState + * the new lexical state + */ + final public void yybegin(int newState) { + yy_lexical_state = newState; + } + + + /** + * Returns the text matched by the current regular expression. + */ + final public String yytext() { + return new String(yy_buffer, yy_startRead, yy_markedPos - yy_startRead); + } + + /** + * Returns the length of the matched text region. + */ + final public int yylength() { + return yy_markedPos - yy_startRead; + } + + + /** + * Reports an error that occured while scanning - from the SED JFlex + * skeleton + * + * @param errorCode + * the code of the errormessage to display + */ + private void yy_ScanError(int errorCode) { + try { + Logger.log(Logger.ERROR, YY_ERROR_MSG[errorCode]); + } catch (ArrayIndexOutOfBoundsException e) { + Logger.log(Logger.ERROR, YY_ERROR_MSG[YY_UNKNOWN_ERROR]); + } + // DO NOT EXIT the VM on an error + // System.exit(1); + } + + + /** + * Pushes the specified amount of characters back into the input stream. + * + * They will be read again by then next call of the scanning method + * + * @param number + * the number of characters to be read again. This number must + * not be greater than yylength()! + */ + void yypushback(int number) { + if (number > yylength()) + yy_ScanError(YY_PUSHBACK_2BIG); + + yy_markedPos -= number; + } + + /** + * user method - skeleton.sed + */ + protected final boolean containsTagName(char[] markerTagName, int offset, int tagnameLength) { + for (int j = 0; j < fBlockMarkers.size(); j++) { + BlockMarker marker = (BlockMarker) fBlockMarkers.get(j); + if (marker.getTagName().length() == tagnameLength) { + boolean matchesSoFar = true; + for (int i = 0; i < tagnameLength && matchesSoFar; i++) { + if (marker.isCaseSensitive()) { + if (marker.getTagName().charAt(i) != markerTagName[i + offset]) + matchesSoFar = false; + } else { + if (Character.toLowerCase(marker.getTagName().charAt(i)) != Character.toLowerCase(markerTagName[i + offset])) + matchesSoFar = false; + } + } + if (matchesSoFar) + return true; + } + } + return false; + } + + /** + * user method - skeleton.sed + * + * Return ALL of the regions scannable within the remaining text Note: for + * verification use + */ + public final List getRegions() { + List tokens = new ArrayList(); + ITextRegion region = null; + try { + region = getNextToken(); + while (region != null) { + if (region != null) { + tokens.add(region); + } + region = getNextToken(); + } + } catch (StackOverflowError e) { + Logger.logException(getClass().getName() + ": input could not be tokenized correctly at position " + getOffset(), e);//$NON-NLS-1$ + throw e; + } catch (Exception e) { + // Since this is convenience method and NOT the recommended + // way of getting tokens, many errors are simply hidden + Logger.logException("Exception not handled retrieving regions: " + e.getLocalizedMessage(), e);//$NON-NLS-1$ + } + return tokens; + } + + /** + * user method - skeleton.sed + */ + private final void dump(String s) { + if (Debug.debugTokenizer) { + System.out.println(s + " (" + yychar + "-" + //$NON-NLS-2$//$NON-NLS-1$ + (yylength() + yychar) + "):\'" + //$NON-NLS-1$ + StringUtils.escape(yytext()) + "\'");//$NON-NLS-1$ + } + } + + /* user method - skeleton.sed */ + public final boolean isEOF() { + return yy_atEOF; + } + + /* user method - skeleton.sed */ + protected final boolean containsTagName(String markerTagName) { + Iterator blocks = fBlockMarkers.iterator(); + while (blocks.hasNext()) { + BlockMarker marker = (BlockMarker) blocks.next(); + if (marker.isCaseSensitive()) { + if (marker.getTagName().equals(markerTagName)) + return true; + } else { + if (marker.getTagName().equalsIgnoreCase(markerTagName)) + return true; + } + } + return false; + } + + /** + * Contains user EOF-code, which will be executed exactly once, when the + * end of file is reached + */ + private void yy_do_eof() { + if (!yy_eof_done) { + yy_eof_done = true; + // do nothing, this is the downstream parser's job + + } + } + + + /** + * Resumes scanning until the next regular expression is matched, the end + * of input is encountered or an I/O-Error occurs. + * + * @return the next token + * @exception IOException + * if any I/O-Error occurs + */ + public String primGetNextToken() throws java.io.IOException { + int yy_input; + int yy_action; + + + while (true) { + + yychar += yylength(); + + boolean yy_counted = false; + for (yy_currentPos = yy_startRead; yy_currentPos < yy_markedPos; yy_currentPos++) { + switch (yy_buffer[yy_currentPos]) { + case '\r' : + yyline++; + yy_counted = true; + break; + case '\n' : + if (yy_counted) + yy_counted = false; + else { + yyline++; + } + break; + default : + yy_counted = false; + } + } + + if (yy_counted) { + if (yy_advance() == '\n') + yyline--; + if (!yy_atEOF) + yy_currentPos--; + } + + yy_action = -1; + + yy_currentPos = yy_startRead = yy_markedPos; + + yy_state = yy_lexical_state; + + + yy_forAction : { + while (true) { + + yy_input = yy_advance(); + + if (yy_input == YYEOF) + break yy_forAction; + + int yy_next = yytrans[yy_rowMap[yy_state] + yycmap[yy_input]]; + if (yy_next == -1) + break yy_forAction; + yy_state = yy_next; + + int yy_attributes = YY_ATTRIBUTE[yy_state]; + if ((yy_attributes & 1) > 0) { + yy_action = yy_state; + yy_markedPos = yy_currentPos; + if ((yy_attributes & 8) > 0) + break yy_forAction; + } + + } + } + + + switch (yy_action) { + + case 274 : + case 275 : + case 276 : { + if (Debug.debugTokenizer) + dump("\nCDATA start");//$NON-NLS-1$ + fStateStack.push(yystate()); + yybegin(ST_CDATA_TEXT); + return XML_CDATA_OPEN; + } + case 278 : + break; + case 268 : { + if (Debug.debugTokenizer) + dump("element");//$NON-NLS-1$ + yybegin(ST_XML_ELEMENT_DECLARATION); + return XML_ELEMENT_DECLARATION; + } + case 279 : + break; + case 267 : { + if (Debug.debugTokenizer) + dump("attlist");//$NON-NLS-1$ + yybegin(ST_XML_ATTLIST_DECLARATION); + return XML_ATTLIST_DECLARATION; + } + case 280 : + break; + case 266 : { + if (Debug.debugTokenizer) + dump("doctype");//$NON-NLS-1$ + yybegin(ST_XML_DOCTYPE_DECLARATION); + return XML_DOCTYPE_DECLARATION; + } + case 281 : + break; + case 262 : { + if (Debug.debugTokenizer) + dump("doctype external id");//$NON-NLS-1$ + fEmbeddedHint = XML_DOCTYPE_EXTERNAL_ID_PUBREF; + yybegin(ST_XML_DOCTYPE_ID_PUBLIC); + return XML_DOCTYPE_EXTERNAL_ID_PUBLIC; + } + case 282 : + break; + case 261 : { + if (Debug.debugTokenizer) + dump("doctype external id");//$NON-NLS-1$ + fEmbeddedHint = XML_DOCTYPE_EXTERNAL_ID_SYSREF; + yybegin(ST_XML_DOCTYPE_ID_SYSTEM); + return XML_DOCTYPE_EXTERNAL_ID_SYSTEM; + } + case 283 : + break; + case 257 : { + if (Debug.debugTokenizer) + dump("DHTML processing instruction target");//$NON-NLS-1$ + fEmbeddedHint = XML_TAG_ATTRIBUTE_NAME; + fEmbeddedPostState = ST_XML_EQUALS; + yybegin(ST_DHTML_ATTRIBUTE_NAME); + return XML_TAG_NAME; + } + case 284 : + break; + case 234 : { + if (Debug.debugTokenizer) + dump("\nCharRef");//$NON-NLS-1$ + return XML_CHAR_REFERENCE; + } + case 285 : + break; + case 231 : { + if (Debug.debugTokenizer) + dump("\ncomment start");//$NON-NLS-1$ + fEmbeddedHint = XML_COMMENT_TEXT; + fEmbeddedPostState = ST_XML_COMMENT; + yybegin(ST_XML_COMMENT); + return XML_COMMENT_OPEN; + } + case 286 : + break; + case 213 : { + if (Debug.debugTokenizer) + dump("XML processing instruction target");//$NON-NLS-1$ + fEmbeddedHint = XML_TAG_ATTRIBUTE_NAME; + fEmbeddedPostState = ST_XML_EQUALS; + yybegin(ST_XML_PI_ATTRIBUTE_NAME); + return XML_TAG_NAME; + } + case 287 : + break; + case 212 : { + if (Debug.debugTokenizer) + dump("comment end");//$NON-NLS-1$ + fEmbeddedHint = UNDEFINED; + yybegin(YYINITIAL); + return XML_COMMENT_CLOSE; + } + case 288 : + break; + case 211 : { + if (Debug.debugTokenizer) + dump("CDATA end");//$NON-NLS-1$ + yybegin(fStateStack.pop()); + return XML_CDATA_CLOSE; + } + case 289 : + break; + case 210 : { + if (Debug.debugTokenizer) + dump("\nPEReference");//$NON-NLS-1$ + return XML_PE_REFERENCE; + } + case 290 : + break; + case 207 : { + if (Debug.debugTokenizer) + dump("\nEntityRef");//$NON-NLS-1$ + return XML_ENTITY_REFERENCE; + } + case 291 : + break; + case 158 : + case 172 : + case 180 : { + return XML_DOCTYPE_INTERNAL_SUBSET; + } + case 292 : + break; + case 146 : { + yybegin(YYINITIAL); + fEmbeddedHint = UNDEFINED; + if (Debug.debugTokenizer) + dump("empty tag close");//$NON-NLS-1$ + return XML_EMPTY_TAG_CLOSE; + } + case 293 : + break; + case 131 : { + if (Debug.debugTokenizer) + dump("XML processing instruction end");//$NON-NLS-1$ + fEmbeddedHint = UNDEFINED; + yybegin(YYINITIAL); + return XML_PI_CLOSE; + } + case 294 : + break; + case 130 : { + // ended with nothing inside + fEmbeddedHint = UNDEFINED; + yybegin(YYINITIAL); + return XML_PI_CLOSE; + } + case 295 : + break; + case 127 : { + if (Debug.debugTokenizer) + dump("processing instruction end");//$NON-NLS-1$ + fEmbeddedHint = UNDEFINED; + yybegin(YYINITIAL); + return XML_PI_CLOSE; + } + case 296 : + break; + case 119 : { + fStateStack.push(yystate()); + if (Debug.debugTokenizer) + dump("\ndeclaration start");//$NON-NLS-1$ + yybegin(ST_XML_DECLARATION); + return XML_DECLARATION_OPEN; + } + case 297 : + break; + case 118 : { + if (Debug.debugTokenizer) + dump("\nprocessing instruction start");//$NON-NLS-1$ + yybegin(ST_PI); + return XML_PI_OPEN; + } + case 298 : + break; + case 62 : { + if (Debug.debugTokenizer) + dump("DHTML processing instruction end");//$NON-NLS-1$ + fEmbeddedHint = UNDEFINED; + yybegin(YYINITIAL); + return XML_PI_CLOSE; + } + case 299 : + break; + case 56 : + case 58 : + case 59 : + case 60 : + case 135 : { + if (Debug.debugTokenizer) + dump("XML processing instruction attribute value");//$NON-NLS-1$ + fEmbeddedHint = XML_TAG_ATTRIBUTE_NAME; + fEmbeddedPostState = ST_XML_EQUALS; + yybegin(ST_XML_PI_ATTRIBUTE_NAME); + return XML_TAG_ATTRIBUTE_VALUE; + } + case 300 : + break; + case 55 : { + if (Debug.debugTokenizer) + dump("XML processing instruction '='");//$NON-NLS-1$ + fEmbeddedHint = XML_TAG_ATTRIBUTE_VALUE; + fEmbeddedPostState = ST_XML_ATTRIBUTE_NAME; + yybegin(ST_XML_PI_ATTRIBUTE_VALUE); + return XML_TAG_ATTRIBUTE_EQUALS; + } + case 301 : + break; + case 54 : { + if (Debug.debugTokenizer) + dump("XML processing instruction attribute name");//$NON-NLS-1$ + yybegin(ST_XML_PI_EQUALS); + return XML_TAG_ATTRIBUTE_NAME; + } + case 302 : + break; + case 50 : + case 51 : + case 52 : { + // block scan until close is found + return doScan("?>", false, XML_PI_CONTENT, ST_XML_PI_TAG_CLOSE, ST_XML_PI_TAG_CLOSE); + } + case 303 : + break; + case 49 : { + yybegin(ST_PI_CONTENT); + return WHITE_SPACE; + } + case 304 : + break; + case 46 : + case 47 : + case 48 : + case 128 : + case 129 : + case 214 : + case 236 : + case 248 : { + if (Debug.debugTokenizer) + dump("processing instruction target");//$NON-NLS-1$ + fEmbeddedHint = XML_CONTENT; + yybegin(ST_PI_WS); + return XML_TAG_NAME; + } + case 305 : + break; + case 41 : + case 42 : { + if (Debug.debugTokenizer) + dump("comment content");//$NON-NLS-1$ + return scanXMLCommentText(); + } + case 306 : + break; + case 40 : { + if (Debug.debugTokenizer) + dump("LINE FEED");//$NON-NLS-1$ + return WHITE_SPACE; + } + case 307 : + break; + case 0 : + case 31 : + case 121 : + case 123 : + case 205 : + case 206 : + case 233 : { + if (Debug.debugTokenizer) + dump("\nXML content");//$NON-NLS-1$ + return XML_CONTENT; + } + case 308 : + break; + case 5 : + case 8 : + case 9 : + case 10 : + case 12 : + case 13 : + case 14 : + case 15 : + case 17 : + case 18 : + case 19 : + case 20 : + case 21 : + case 22 : + case 23 : + case 24 : + case 25 : + case 26 : + case 28 : + case 45 : { + if (Debug.debugTokenizer) + dump("white space");//$NON-NLS-1$ + return WHITE_SPACE; + } + case 309 : + break; + case 16 : + case 70 : { + if (Debug.debugTokenizer) + dump("inappropriate tag name");//$NON-NLS-1$ + yybegin(YYINITIAL); + return XML_CONTENT; + } + case 310 : + break; + case 27 : + case 105 : + case 106 : + case 191 : + case 226 : + case 244 : + case 254 : + case 263 : + case 269 : + case 272 : { + if (Debug.debugTokenizer) + dump("elementdecl contentspec");//$NON-NLS-1$ + return XML_ELEMENT_DECL_CONTENT; + } + case 311 : + break; + case 29 : + case 112 : + case 113 : + case 202 : + case 230 : + case 246 : + case 255 : + case 264 : + case 270 : + case 273 : { + if (Debug.debugTokenizer) + dump("attlist contentspec");//$NON-NLS-1$ + return XML_ATTLIST_DECL_CONTENT; + } + case 312 : + break; + case 32 : + case 71 : + case 82 : { + if (Debug.debugTokenizer) + dump("\nstart tag open");//$NON-NLS-1$ + fEmbeddedHint = XML_TAG_NAME; + fEmbeddedPostState = ST_XML_ATTRIBUTE_NAME; + yybegin(ST_XML_TAG_NAME); + return XML_TAG_OPEN; + } + case 313 : + break; + case 33 : + case 34 : + case 37 : + case 38 : + case 39 : + case 43 : + case 44 : + case 53 : + case 57 : + case 61 : + case 63 : + case 67 : + case 73 : + case 79 : + case 84 : + case 85 : + case 86 : + case 87 : + case 89 : + case 90 : + case 92 : + case 97 : + case 102 : + case 109 : { + if (Debug.debugTokenizer) + System.out.println("!!!unexpected!!!: \"" + yytext() + "\":" + //$NON-NLS-2$//$NON-NLS-1$ + yychar + "-" + (yychar + yylength()));//$NON-NLS-1$ + return UNDEFINED; + } + case 314 : + break; + case 35 : + case 36 : { + if (Debug.debugTokenizer) + dump("CDATA text");//$NON-NLS-1$ + fEmbeddedHint = XML_CDATA_TEXT; + fEmbeddedPostState = ST_CDATA_TEXT; + String blockContext = doBlockScan("]]>", XML_CDATA_TEXT, ST_CDATA_END);//$NON-NLS-1$ + if (blockContext == XML_CDATA_TEXT) + yybegin(ST_CDATA_END); + return blockContext; + } + case 315 : + break; + case 64 : { + if (Debug.debugTokenizer) + dump("DHTML processing instruction attribute name");//$NON-NLS-1$ + yybegin(ST_DHTML_EQUALS); + return XML_TAG_ATTRIBUTE_NAME; + } + case 316 : + break; + case 65 : { + if (Debug.debugTokenizer) + dump("DHTML processing instruction '='");//$NON-NLS-1$ + fEmbeddedHint = XML_TAG_ATTRIBUTE_VALUE; + fEmbeddedPostState = ST_XML_ATTRIBUTE_NAME; + yybegin(ST_DHTML_ATTRIBUTE_VALUE); + return XML_TAG_ATTRIBUTE_EQUALS; + } + case 317 : + break; + case 66 : + case 68 : + case 69 : + case 143 : { + if (Debug.debugTokenizer) + dump("DHTML processing instruction attribute value");//$NON-NLS-1$ + fEmbeddedHint = XML_TAG_ATTRIBUTE_NAME; + fEmbeddedPostState = ST_XML_EQUALS; + yybegin(ST_DHTML_ATTRIBUTE_NAME); + return XML_TAG_ATTRIBUTE_VALUE; + } + case 318 : + break; + case 72 : { + if (Debug.debugTokenizer) + dump("tag close");//$NON-NLS-1$ + fEmbeddedHint = UNDEFINED; + if (isBlockMarker()) { + fEmbeddedHint = getBlockMarkerContext(); + fEmbeddedPostState = ST_BLOCK_TAG_SCAN; + yybegin(ST_BLOCK_TAG_SCAN); + } else + yybegin(YYINITIAL); + return XML_TAG_CLOSE; + } + case 319 : + break; + case 74 : + case 75 : { + if (Debug.debugTokenizer) + dump("tag name");//$NON-NLS-1$ + fEmbeddedHint = XML_TAG_ATTRIBUTE_NAME; + fEmbeddedPostState = ST_XML_EQUALS; + yybegin(ST_XML_ATTRIBUTE_NAME); + return XML_TAG_NAME; + } + case 320 : + break; + case 76 : { + if (Debug.debugTokenizer) + dump("attr name");//$NON-NLS-1$ + fEmbeddedHint = XML_TAG_ATTRIBUTE_NAME; + fEmbeddedPostState = ST_XML_ATTRIBUTE_NAME; + yybegin(ST_XML_EQUALS); + return XML_TAG_ATTRIBUTE_NAME; + } + case 321 : + break; + case 77 : { + if (Debug.debugTokenizer) + dump("equals");//$NON-NLS-1$ + fEmbeddedHint = XML_TAG_ATTRIBUTE_VALUE; + fEmbeddedPostState = ST_XML_ATTRIBUTE_NAME; + yybegin(ST_XML_ATTRIBUTE_VALUE); + return XML_TAG_ATTRIBUTE_EQUALS; + } + case 322 : + break; + case 78 : + case 80 : + case 81 : + case 150 : { + if (Debug.debugTokenizer) + dump("attr value");//$NON-NLS-1$ + fEmbeddedHint = XML_TAG_ATTRIBUTE_NAME; + fEmbeddedPostState = ST_XML_EQUALS; + yybegin(ST_XML_ATTRIBUTE_NAME); + return XML_TAG_ATTRIBUTE_VALUE; + } + case 323 : + break; + case 83 : { + if (Debug.debugTokenizer) + dump("declaration end");//$NON-NLS-1$ + if (Debug.debugTokenizer) { + if (fStateStack.peek() != YYINITIAL) + System.out.println("end embedded region");//$NON-NLS-1$ + } + yybegin(fStateStack.pop()); + return XML_DECLARATION_CLOSE; + } + case 324 : + break; + case 88 : { + if (Debug.debugTokenizer) + dump("doctype type");//$NON-NLS-1$ + yybegin(ST_XML_DOCTYPE_EXTERNAL_ID); + return XML_DOCTYPE_NAME; + } + case 325 : + break; + case 91 : + case 93 : + case 94 : + case 95 : + case 164 : + case 165 : + case 168 : + case 169 : + case 221 : { + if (Debug.debugTokenizer) + dump("doctype public reference");//$NON-NLS-1$ + fEmbeddedHint = UNDEFINED; + fEmbeddedPostState = YYINITIAL; + yybegin(ST_XML_DOCTYPE_ID_SYSTEM); + return XML_DOCTYPE_EXTERNAL_ID_PUBREF; + } + case 326 : + break; + case 96 : + case 98 : + case 99 : + case 100 : + case 176 : { + if (Debug.debugTokenizer) + dump("doctype system reference");//$NON-NLS-1$ + fEmbeddedHint = UNDEFINED; + fEmbeddedPostState = YYINITIAL; + yybegin(ST_XML_DECLARATION_CLOSE); + return XML_DOCTYPE_EXTERNAL_ID_SYSREF; + } + case 327 : + break; + case 101 : + case 103 : + case 104 : + case 184 : + case 185 : + case 188 : + case 189 : + case 224 : { + if (Debug.debugTokenizer) + dump("elementdecl name");//$NON-NLS-1$ + fEmbeddedHint = UNDEFINED; + fEmbeddedPostState = YYINITIAL; + yybegin(ST_XML_ELEMENT_DECLARATION_CONTENT); + return XML_ELEMENT_DECL_NAME; + } + case 328 : + break; + case 107 : { + if (Debug.debugTokenizer) + dump("elementdecl close");//$NON-NLS-1$ + if (Debug.debugTokenizer) { + if (fStateStack.peek() != YYINITIAL) + System.out.println("end embedded region");//$NON-NLS-1$ + } + yybegin(fStateStack.pop()); + return XML_DECLARATION_CLOSE; + } + case 329 : + break; + case 108 : + case 110 : + case 111 : + case 195 : + case 196 : + case 199 : + case 200 : + case 228 : { + if (Debug.debugTokenizer) + dump("attlist name");//$NON-NLS-1$ + fEmbeddedHint = UNDEFINED; + fEmbeddedPostState = YYINITIAL; + yybegin(ST_XML_ATTLIST_DECLARATION_CONTENT); + return XML_ATTLIST_DECL_NAME; + } + case 330 : + break; + case 114 : { + if (Debug.debugTokenizer) + dump("attlist close");//$NON-NLS-1$ + if (Debug.debugTokenizer) { + if (fStateStack.peek() != YYINITIAL) + System.out.println("end embedded region");//$NON-NLS-1$ + } + yybegin(fStateStack.pop()); + return XML_DECLARATION_CLOSE; + } + case 331 : + break; + case 117 : { + if (Debug.debugTokenizer) + dump("\nend tag open");//$NON-NLS-1$ + fEmbeddedHint = XML_TAG_NAME; + fEmbeddedPostState = ST_XML_ATTRIBUTE_NAME; + yybegin(ST_XML_TAG_NAME); + return XML_END_TAG_OPEN; + } + case 332 : + break; + case 115 : + case 116 : { + return doBlockTagScan(); + } + case 333 : + break; + default : + if (yy_input == YYEOF && yy_startRead == yy_currentPos) { + yy_atEOF = true; + yy_do_eof(); + return null; + } else { + yy_ScanError(YY_NO_MATCH); + } + } + } + } + + +}
\ No newline at end of file diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/AttributeEqualsRegion.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/AttributeEqualsRegion.java new file mode 100644 index 0000000000..2a577768b8 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/AttributeEqualsRegion.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.parser.regions; + +import org.eclipse.wst.sse.core.events.StructuredDocumentEvent; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; + + + +public class AttributeEqualsRegion implements ITextRegion { + static private final byte fTextLength = 1; + static private final String fType = XMLRegionContext.XML_TAG_ATTRIBUTE_EQUALS; + private short fLength; + private int fStart; + + + public AttributeEqualsRegion() { + super(); + } + + public AttributeEqualsRegion(int start, int textLength, int length) { + this(); + fStart = start; + fLength = (short) length; + } + + + public void adjustLengthWith(int i) { + fLength += i; + + } + + public void adjustStart(int i) { + fStart += i; + + } + + public void adjustTextLength(int i) { + // not supported + + } + + public void equatePositions(ITextRegion region) { + fStart = region.getStart(); + fLength = (short) region.getLength(); + } + + public int getEnd() { + return fStart + fLength; + } + + public int getLength() { + return fLength; + } + + public int getStart() { + return fStart; + } + + public int getTextEnd() { + return fStart + fTextLength; + } + + public int getTextLength() { + return fTextLength; + } + + public String getType() { + return fType; + } + + public String toString() { + return RegionToStringUtil.toString(this); + } + + public StructuredDocumentEvent updateModel(Object requester, IStructuredDocumentRegion parent, String changes, int requestStart, int lengthToReplace) { + // can never be updated + return null; + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/AttributeNameRegion.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/AttributeNameRegion.java new file mode 100644 index 0000000000..fd678bd02c --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/AttributeNameRegion.java @@ -0,0 +1,170 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.parser.regions; + +import org.eclipse.wst.sse.core.events.RegionChangedEvent; +import org.eclipse.wst.sse.core.events.StructuredDocumentEvent; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.core.util.Debug; +import org.eclipse.wst.sse.core.util.Utilities; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; + + +public class AttributeNameRegion implements ITextRegion { + // specify correct type + static private final String fType = XMLRegionContext.XML_TAG_ATTRIBUTE_NAME; + private int fLength; + private int fStart; + private int fTextLength; + + public AttributeNameRegion() { + super(); + } + + public AttributeNameRegion(int start, int textLength, int length) { + this(); + fStart = start; + fTextLength = textLength; + fLength = length; + } + + public void adjustLengthWith(int i) { + fLength += i; + + } + + public void adjustStart(int i) { + fStart += i; + + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegion#adjustTextLength(int) + */ + public void adjustTextLength(int i) { + fTextLength += 1; + + } + + public void equatePositions(ITextRegion region) { + fStart = region.getStart(); + fLength = region.getLength(); + fTextLength = region.getTextLength(); + } + + public int getEnd() { + return fStart + fLength; + } + + public int getLength() { + return fLength; + } + + public int getStart() { + return fStart; + } + + public int getTextEnd() { + return fStart + fTextLength; + } + + public int getTextLength() { + return fTextLength; + } + + public String getType() { + return fType; + } + + public String toString() { + return RegionToStringUtil.toString(this); + } + + public StructuredDocumentEvent updateModel(Object requester, IStructuredDocumentRegion parent, String changes, int requestStart, int lengthToReplace) { + RegionChangedEvent result = null; + // if the region is an easy type (e.g. attribute value), + // and the requested changes are all + // alphanumeric, then make the change here locally. + // (This can obviously be made more sophisticated as the need arises, + // but should + // always follow this pattern.) + if (Debug.debugStructuredDocument) { + System.out.println("\t\tContextRegion::updateModel"); //$NON-NLS-1$ + System.out.println("\t\t\tregion type is " + fType); //$NON-NLS-1$ + } + boolean canHandle = false; + // note: we'll always handle deletes from these + // regions ... if its already that region, + // deleting something from it won't change its + // type. (remember, the calling program needs + // to insure we are not called, if not all contained + // on one region. + if ((changes == null) || (changes.length() == 0)) { + // delete case + // We can not do the quick delete, if + // if all the text in a region is to be deleted. + // Or, if the delete starts in the white space region. + // In these cases, a reparse is needed. + // Minor note, we use textEnd-start since it always + // less than or equal to end-start. This might + // cause us to miss a few cases we could have handled, + // but will prevent us from trying to handle funning cases + // involving whitespace. + if ((fStart >= getTextEnd()) || (Math.abs(lengthToReplace) >= getTextEnd() - getStart())) { + canHandle = false; + } else { + canHandle = true; + } + } else { + if ((RegionUpdateRule.canHandleAsWhiteSpace(this, parent, changes, requestStart, lengthToReplace)) || RegionUpdateRule.canHandleAsLetterOrDigit(this, parent, changes, requestStart, lengthToReplace)) { + canHandle = true; + } else { + canHandle = false; + } + + } + if (canHandle) { + // at this point, we still have the old region. We won't create a + // new instance, we'll just update the one we have, by changing + // its end postion, + // The parent flatnode, upon return, has responsibility + // for updating sibling regions. + // and in turn, the structuredDocument itself has responsibility + // for + // updating the text store and down stream flatnodes. + if (Debug.debugStructuredDocument) { + System.out.println("change handled by region"); //$NON-NLS-1$ + } + int lengthDifference = Utilities.calculateLengthDifference(changes, lengthToReplace); + // Note: we adjust both end and text end, because for any change + // that is in only the trailing whitespace region, we should not + // do a quick change, + // so 'canHandle' should have been false for those case. + // TO_DO_FUTURE: cache value of canHandleAsWhiteSpace from above + // If we are handling as whitespace, there is no need to increase + // the text length, only + // the total length is changing. + if (!RegionUpdateRule.canHandleAsWhiteSpace(this, parent, changes, requestStart, lengthToReplace)) { + fTextLength += lengthDifference; + } + fLength += lengthDifference; + result = new RegionChangedEvent(parent.getParentDocument(), requester, parent, this, changes, requestStart, lengthToReplace); + } + + return result; + } + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/AttributeValueRegion.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/AttributeValueRegion.java new file mode 100644 index 0000000000..03eb4634da --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/AttributeValueRegion.java @@ -0,0 +1,167 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.parser.regions; + +import org.eclipse.wst.sse.core.events.RegionChangedEvent; +import org.eclipse.wst.sse.core.events.StructuredDocumentEvent; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.core.util.Debug; +import org.eclipse.wst.sse.core.util.Utilities; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; + + +public class AttributeValueRegion implements ITextRegion { + // specify correct type + static private final String fType = XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE; + private int fLength; + private int fStart; + private int fTextLength; + + public AttributeValueRegion() { + super(); + } + + public AttributeValueRegion(int start, int textLength, int length) { + this(); + fStart = start; + fTextLength = textLength; + fLength = length; + } + + public void adjustLengthWith(int i) { + fLength += i; + } + + public void adjustStart(int i) { + fStart += i; + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegion#adjustTextLength(int) + */ + public void adjustTextLength(int i) { + fTextLength += 1; + } + + public void equatePositions(ITextRegion region) { + fStart = region.getStart(); + fLength = region.getLength(); + fTextLength = region.getTextLength(); + } + + public int getEnd() { + return fStart + fLength; + } + + public int getLength() { + return fLength; + } + + public int getStart() { + return fStart; + } + + public int getTextEnd() { + return fStart + fTextLength; + } + + public int getTextLength() { + return fTextLength; + } + + public String getType() { + return fType; + } + + public String toString() { + return RegionToStringUtil.toString(this); + } + + public StructuredDocumentEvent updateModel(Object requester, IStructuredDocumentRegion parent, String changes, int requestStart, int lengthToReplace) { + RegionChangedEvent result = null; + // if the region is an easy type (e.g. attribute value), + // and the requested changes are all + // alphanumeric, then make the change here locally. + // (This can obviously be made more sophisticated as the need arises, + // but should + // always follow this pattern.) + if (Debug.debugStructuredDocument) { + System.out.println("\t\tContextRegion::updateModel"); //$NON-NLS-1$ + System.out.println("\t\t\tregion type is " + fType); //$NON-NLS-1$ + } + boolean canHandle = false; + // note: we'll always handle deletes from these + // regions ... if its already that region, + // deleting something from it won't change its + // type. (remember, the calling program needs + // to insure we are not called, if not all contained + // on one region. + if ((changes == null) || (changes.length() == 0)) { + // delete case + // We can not do the quick delete, if + // if all the text in a region is to be deleted. + // Or, if the delete starts in the white space region. + // In these cases, a reparse is needed. + // Minor note, we use textEnd-start since it always + // less than or equal to end-start. This might + // cause us to miss a few cases we could have handled, + // but will prevent us from trying to handle funning cases + // involving whitespace. + if ((fStart >= getTextEnd()) || (Math.abs(lengthToReplace) >= getTextEnd() - getStart())) { + canHandle = false; + } else { + canHandle = true; + } + } else { + if ((RegionUpdateRule.canHandleAsWhiteSpace(this, parent, changes, requestStart, lengthToReplace)) || RegionUpdateRule.canHandleAsLetterOrDigit(this, parent, changes, requestStart, lengthToReplace)) { + canHandle = true; + } else { + canHandle = false; + } + } + if (canHandle) { + // at this point, we still have the old region. We won't create a + // new instance, we'll just update the one we have, by changing + // its end postion, + // The parent flatnode, upon return, has responsibility + // for updating sibling regions. + // and in turn, the structuredDocument itself has responsibility + // for + // updating the text store and down stream flatnodes. + if (Debug.debugStructuredDocument) { + System.out.println("change handled by region"); //$NON-NLS-1$ + } + int lengthDifference = Utilities.calculateLengthDifference(changes, lengthToReplace); + // Note: we adjust both end and text end, because for any change + // that is in only the trailing whitespace region, we should not + // do a quick change, + // so 'canHandle' should have been false for those case. + // TO_DO_FUTURE: cache value of canHandleAsWhiteSpace from above + // If we are handling as whitespace, there is no need to increase + // the text length, only + // the total length is changing. + if (!RegionUpdateRule.canHandleAsWhiteSpace(this, parent, changes, requestStart, lengthToReplace)) { + fTextLength += lengthDifference; + } + // update length (and end) after above check for white space, + // since + // it looks to determine if at end of region. + fLength += lengthDifference; + result = new RegionChangedEvent(parent.getParentDocument(), requester, parent, this, changes, requestStart, lengthToReplace); + } + return result; + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/BlockTextRegion.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/BlockTextRegion.java new file mode 100644 index 0000000000..b382257d5a --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/BlockTextRegion.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.parser.regions; + +import org.eclipse.wst.sse.core.internal.parser.ForeignRegion; + + + +public class BlockTextRegion extends ForeignRegion { + + /** + * BlockTextRegion constructor comment. + */ + public BlockTextRegion() { + super(); + } + + public BlockTextRegion(String newContext, int newStart, int newTextLength, int newLength) { + super(newContext, newStart, newTextLength, newLength); + } + + public BlockTextRegion(String newContext, int newStart, int newTextLength, int newLength, String newLanguage) { + super(newContext, newStart, newTextLength, newLength, newLanguage); + } + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/GenericTemplateRegion.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/GenericTemplateRegion.java new file mode 100644 index 0000000000..291a3411e7 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/GenericTemplateRegion.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.parser.regions; + +import org.eclipse.wst.sse.core.events.StructuredDocumentEvent; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; + + +/** + * + * This class is not intended to be used, its just present to server as a + * generic starting point for adding new specific region types. + */ + +public class GenericTemplateRegion implements ITextRegion { + // specify correct type + static private final String fType = XMLRegionContext.UNDEFINED; + private int fLength; + private int fStart; + private int fTextLength; + + + public GenericTemplateRegion() { + super(); + } + + public GenericTemplateRegion(int start, int textLength, int length) { + this(); + fStart = start; + fTextLength = textLength; + fLength = length; + } + + public void adjustLengthWith(int i) { + fLength += i; + + } + + public void adjustStart(int i) { + fStart += i; + + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegion#adjustTextLength(int) + */ + public void adjustTextLength(int i) { + fTextLength += 1; + + } + + public void equatePositions(ITextRegion region) { + fStart = region.getStart(); + fLength = region.getLength(); + fTextLength = region.getTextLength(); + } + + public int getEnd() { + return fStart + fLength; + } + + public int getLength() { + return fLength; + } + + public int getStart() { + return fStart; + } + + public int getTextEnd() { + return fStart + fTextLength; + } + + public int getTextLength() { + return fTextLength; + } + + public String getType() { + return fType; + } + + public String toString() { + return RegionToStringUtil.toString(this); + } + + public StructuredDocumentEvent updateModel(Object requester, IStructuredDocumentRegion parent, String changes, int requestStart, int lengthToReplace) { + // can never be updated + return null; + } + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/RegionToStringUtil.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/RegionToStringUtil.java new file mode 100644 index 0000000000..9693beb913 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/RegionToStringUtil.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.parser.regions; + +import org.eclipse.wst.sse.core.text.ITextRegion; + + +public class RegionToStringUtil { + static public String toString(ITextRegion region) { + String className = region.getClass().getName(); + String shortClassName = className.substring(className.lastIndexOf(".") + 1); //$NON-NLS-1$ + // ==> // String resultText = null; + String result = shortClassName + "--> " + region.getType() + ": " + region.getStart() + "-" + region.getTextEnd() + (region.getTextEnd() != region.getEnd() ? ("/" + region.getEnd()) : ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ + // NOTE: if the document held by any region has been updated and the + // region offsets have not + // yet been updated, the output from this method invalid. + //return com.ibm.sed.util.StringUtils.escape("('"+(getFirstRegion() + // == null || document == null? "" : + // getText(getFirstRegion()))+"'"+getStart()+" - + // "+getEnd()+"'"+(getClose() == null || document == null || + // getRegions().size()<2 ? "" : getText(getClose()))+"') + // "+getRegions()); + return result; + } + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/RegionUpdateRule.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/RegionUpdateRule.java new file mode 100644 index 0000000000..8692688ea3 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/RegionUpdateRule.java @@ -0,0 +1,205 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.parser.regions; + +import org.eclipse.wst.sse.core.events.RegionChangedEvent; +import org.eclipse.wst.sse.core.events.StructuredDocumentEvent; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.core.util.Debug; +import org.eclipse.wst.sse.core.util.Utilities; + + +/** + * + * This is a utility class to centralize 'region' update. Note: care must be + * taken that is is not used for StructuredDocumentRegions, or container + * regions, its only for "token regions" + * + */ +public class RegionUpdateRule { + + static public boolean allLetterOrDigit(String changes) { + boolean result = true; + for (int i = 0; i < changes.length(); i++) { + // TO_DO_FUTURE: check that a Java Letter or Digit is + // the same thing as an XML letter or digit + if (!(Character.isLetterOrDigit(changes.charAt(i)))) { + result = false; + break; + } + } + return result; + } + + static public boolean allWhiteSpace(String changes) { + boolean result = true; + for (int i = 0; i < changes.length(); i++) { + if (!Character.isWhitespace(changes.charAt(i))) { + result = false; + break; + } + } + return result; + } + + static public boolean canHandleAsLetterOrDigit(ITextRegion region, IStructuredDocumentRegion parent, String changes, int requestStart, int lengthToReplace) { + if (parent == null) + return canHandleAsLetterOrDigit(region, changes, requestStart, lengthToReplace); + boolean result = false; + // Make sure we are in a non-white space area + if ((requestStart <= (parent.getTextEndOffset(region))) && (allLetterOrDigit(changes))) { + result = true; + } + return result; + } + + static public boolean canHandleAsLetterOrDigit(ITextRegion region, String changes, int requestStart, int lengthToReplace) { + boolean result = false; + // Make sure we are in a non-white space area + if ((requestStart <= (region.getTextEnd())) && (allLetterOrDigit(changes))) { + result = true; + } + return result; + } + + static public boolean canHandleAsWhiteSpace(ITextRegion region, IStructuredDocumentRegion parent, String changes, int requestStart, int lengthToReplace) { + // we don't explect a null parent, but just in case! + // (in which case, we must be dealing with regions that are + // structuredDocumentRegions). + if (parent == null) + return canHandleAsWhiteSpace(region, changes, requestStart, lengthToReplace); + boolean result = false; + // if we are in the "white space" area of a region, then + // we don't want to handle, a reparse is needed. + // the white space region is consider anywhere that would + // leave whitespace between this character and the text part. + // and of course, we can insert whitespace in whitespace region + // + // if there is no whitespace in this region, no need to look further + if (region.getEnd() > region.getTextEnd()) { + // no need to add one to end of text, as we used to, since we + // change definition of length to equate to offset plus one. + if (requestStart > parent.getTextEndOffset(region)) { + // ok, we are in the whitespace region, so we can't handle, + // unless + // we are just inserting whitespace. + if (allWhiteSpace(changes)) { + result = true; + } else { + result = false; + } + } + } + return result; + } + + static public boolean canHandleAsWhiteSpace(ITextRegion region, String changes, int requestStart, int lengthToReplace) { + boolean result = false; + // if we are in the "white space" area of a region, then + // we don't want to handle, a reparse is needed. + // the white space region is consider anywhere that would + // leave whitespace between this character and the text part. + // and of course, we can insert whitespace in whitespace region + // + // if there is no whitespace in this region, no need to look further + if (region.getEnd() > region.getTextEnd()) { + // no need to add one to end of text, as we used to, since we + // change definition of length to equate to offset plus one. + if (requestStart > region.getTextEnd()) { + // ok, we are in the whitespace region, so we can't handle, + // unless + // we are just inserting whitespace. + if (allWhiteSpace(changes)) { + result = true; + } else { + result = false; + } + } + } + return result; + } + + // need an adjust text length API before this can be used + static public StructuredDocumentEvent updateModel(ITextRegion region, Object requester, IStructuredDocumentRegion parent, String changes, int requestStart, int lengthToReplace) { + RegionChangedEvent result = null; + // if the region is an easy type (e.g. attribute value), + // and the requested changes are all + // alphanumeric, then make the change here locally. + // (This can obviously be made more sophisticated as the need arises, + // but should + // always follow this pattern.) + if (Debug.debugStructuredDocument) { + System.out.println("\t\tContextRegion::updateModel"); //$NON-NLS-1$ + System.out.println("\t\t\tregion type is " + region.getType()); //$NON-NLS-1$ + } + boolean canHandle = false; + // note: we'll always handle deletes from these + // regions ... if its already that region, + // deleting something from it won't change its + // type. (remember, the calling program needs + // to insure we are not called, if not all contained + // on one region. + if ((changes == null) || (changes.length() == 0)) { + // delete case + // We can not do the quick delete, if + // if all the text in a region is to be deleted. + // Or, if the delete starts in the white space region. + // In these cases, a reparse is needed. + // Minor note, we use textEnd-start since it always + // less than or equal to end-start. This might + // cause us to miss a few cases we could have handled, + // but will prevent us from trying to handle funning cases + // involving whitespace. + if ((region.getStart() >= region.getTextEnd()) || (Math.abs(lengthToReplace) >= region.getTextEnd() - region.getStart())) { + canHandle = false; + } else { + canHandle = true; + } + } else { + if ((RegionUpdateRule.canHandleAsWhiteSpace(region, parent, changes, requestStart, lengthToReplace)) || RegionUpdateRule.canHandleAsLetterOrDigit(region, parent, changes, requestStart, lengthToReplace)) { + canHandle = true; + } else { + canHandle = false; + } + } + if (canHandle) { + // at this point, we still have the old region. We won't create a + // new instance, we'll just update the one we have, by changing + // its end postion, + // The parent flatnode, upon return, has responsibility + // for updating sibling regions. + // and in turn, the structuredDocument itself has responsibility + // for + // updating the text store and down stream flatnodes. + if (Debug.debugStructuredDocument) { + System.out.println("change handled by region"); //$NON-NLS-1$ + } + int lengthDifference = Utilities.calculateLengthDifference(changes, lengthToReplace); + // Note: we adjust both end and text end, because for any change + // that is in only the trailing whitespace region, we should not + // do a quick change, + // so 'canHandle' should have been false for those case. + region.adjustLengthWith(lengthDifference); + // TO_DO_FUTURE: cache value of canHandleAsWhiteSpace from above + // If we are handling as whitespace, there is no need to increase + // the text length, only + // the total length is changing. + if (!RegionUpdateRule.canHandleAsWhiteSpace(region, parent, changes, region.getStart(), lengthToReplace)) { + // region.adjustTextLength(lengthDifference); + } + result = new RegionChangedEvent(parent.getParentDocument(), requester, parent, region, changes, requestStart, lengthToReplace); + } + return result; + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/TagCloseRegion.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/TagCloseRegion.java new file mode 100644 index 0000000000..87044ddc5c --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/TagCloseRegion.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.parser.regions; + +import org.eclipse.wst.sse.core.events.StructuredDocumentEvent; +import org.eclipse.wst.sse.core.exceptions.SourceEditingRuntimeException; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; + + +public class TagCloseRegion implements ITextRegion { + static private final byte fLength = 1; + static private final byte fTextLength = 1; + static private final String fType = XMLRegionContext.XML_TAG_CLOSE; + private int fStart; + + + public TagCloseRegion() { + super(); + } + + public TagCloseRegion(int start) { + this(); + fStart = start; + } + + public void adjustLengthWith(int i) { + throw new SourceEditingRuntimeException("invalid for this region type"); //$NON-NLS-1$ + + } + + public void adjustStart(int i) { + fStart += i; + + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegion#adjustTextLength(int) + */ + public void adjustTextLength(int i) { + // not supported + + } + + public void equatePositions(ITextRegion region) { + fStart = region.getStart(); + } + + public int getEnd() { + return fStart + fLength; + } + + public int getLength() { + return fLength; + } + + public int getStart() { + return fStart; + } + + public int getTextEnd() { + return fStart + fTextLength; + } + + public int getTextLength() { + return fTextLength; + } + + public String getType() { + return fType; + } + + public String toString() { + return RegionToStringUtil.toString(this); + } + + public StructuredDocumentEvent updateModel(Object requester, IStructuredDocumentRegion parent, String changes, int requestStart, int lengthToReplace) { + // can never be updated + return null; + } + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/TagNameRegion.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/TagNameRegion.java new file mode 100644 index 0000000000..f01e5b017a --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/TagNameRegion.java @@ -0,0 +1,98 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.parser.regions; + +import org.eclipse.wst.sse.core.events.StructuredDocumentEvent; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; + + +public class TagNameRegion implements ITextRegion { + static private final String fType = XMLRegionContext.XML_TAG_NAME; + private short fLength; + private int fStart; + private short fTextLength; + + + public TagNameRegion() { + super(); + } + + public TagNameRegion(int start, int textLength, int length) { + this(); + fStart = start; + fTextLength = (short) textLength; + fLength = (short) length; + } + + public void adjustLengthWith(int i) { + fLength += i; + + } + + public void adjustStart(int i) { + fStart += i; + + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegion#adjustTextLength(int) + */ + public void adjustTextLength(int i) { + fTextLength += i; + + } + + public void equatePositions(ITextRegion region) { + fStart = region.getStart(); + fLength = (short) region.getLength(); + fTextLength = (short) region.getTextLength(); + } + + public int getEnd() { + return fStart + fLength; + } + + public int getLength() { + return fLength; + } + + public int getStart() { + return fStart; + } + + public int getTextEnd() { + return fStart + fTextLength; + } + + public int getTextLength() { + return fTextLength; + } + + public String getType() { + return fType; + } + + public String toString() { + return RegionToStringUtil.toString(this); + } + + public StructuredDocumentEvent updateModel(Object requester, IStructuredDocumentRegion parent, String changes, int requestStart, int lengthToReplace) { + // can never be updated + return null; + } + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/TagOpenRegion.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/TagOpenRegion.java new file mode 100644 index 0000000000..f09c83dadd --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/TagOpenRegion.java @@ -0,0 +1,98 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.parser.regions; + +import org.eclipse.wst.sse.core.events.StructuredDocumentEvent; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; + + +public class TagOpenRegion implements ITextRegion { + static private final String fType = XMLRegionContext.XML_TAG_OPEN; + private int fLength; + private int fStart; + private int fTextLength; + + + public TagOpenRegion() { + super(); + } + + public TagOpenRegion(int start, int textLength, int length) { + this(); + fStart = start; + fTextLength = textLength; + fLength = length; + } + + public void adjustLengthWith(int i) { + fLength += i; + + } + + public void adjustStart(int i) { + fStart += i; + + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegion#adjustTextLength(int) + */ + public void adjustTextLength(int i) { + fTextLength += 1; + + } + + public void equatePositions(ITextRegion region) { + fStart = region.getStart(); + fLength = region.getLength(); + fTextLength = region.getTextLength(); + } + + public int getEnd() { + return fStart + fLength; + } + + public int getLength() { + return fLength; + } + + public int getStart() { + return fStart; + } + + public int getTextEnd() { + return fStart + fTextLength; + } + + public int getTextLength() { + return fTextLength; + } + + public String getType() { + return fType; + } + + public String toString() { + return RegionToStringUtil.toString(this); + } + + public StructuredDocumentEvent updateModel(Object requester, IStructuredDocumentRegion parent, String changes, int requestStart, int lengthToReplace) { + // can never be updated + return null; + } + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/WhiteSpaceOnlyRegion.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/WhiteSpaceOnlyRegion.java new file mode 100644 index 0000000000..2727095457 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/WhiteSpaceOnlyRegion.java @@ -0,0 +1,190 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.parser.regions; + + + +import org.eclipse.wst.sse.core.events.RegionChangedEvent; +import org.eclipse.wst.sse.core.events.StructuredDocumentEvent; +import org.eclipse.wst.sse.core.exceptions.SourceEditingRuntimeException; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.core.util.Debug; +import org.eclipse.wst.sse.core.util.Utilities; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; + + +public class WhiteSpaceOnlyRegion implements ITextRegion { + static private final byte fTextLength = 0; + + static private final String fType = XMLRegionContext.WHITE_SPACE; + protected int fLength; + protected int fStart; + + public WhiteSpaceOnlyRegion(int start, int length) { + super(); + fStart = start; + fLength = length; + } + + public void adjust(int i) { + fStart += i; + } + + public void adjustLengthWith(int i) { + fLength += i; + } + + public void adjustStart(int i) { + fStart += i; + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegion#adjustTextLength(int) + */ + public void adjustTextLength(int i) { + // not supported + + } + + public boolean contains(int position) { + + return fStart <= position && position < fStart + fLength; + } + + public void equatePositions(ITextRegion region) { + fStart = region.getStart(); + fLength = region.getLength(); + } + + public int getEnd() { + return fStart + fLength; + } + + public int getLength() { + return fLength; + } + + public int getStart() { + return fStart; + } + + public int getTextEnd() { + return fStart + fTextLength; + } + + public int getTextLength() { + return fTextLength; + } + + public String getType() { + return fType; + } + + public void setLength(int i) { + fLength = i; + } + + public void setStart(int i) { + fStart = i; + } + + public void setTextLength(short i) { + throw new SourceEditingRuntimeException("invalid call"); //$NON-NLS-1$ + } + + public void setType(String string) { + throw new SourceEditingRuntimeException("invalid call"); //$NON-NLS-1$ + } + + public String toString() { + return RegionToStringUtil.toString(this); + } + + /** + * For this ITextRegion type, the start must in terms of what the region + * expects ... that is, its not document offset, but start relative to + * what ever contains it. + */ + public StructuredDocumentEvent updateModel(Object requester, IStructuredDocumentRegion parent, String changes, int requestStart, int lengthToReplace) { + // if the region is an easy type (e.g. attribute value), + // and the requested changes are all + // alphanumeric, then make the change here locally. + // (This can obviously be made more sophisticated as the need arises, + // but should + // always follow this pattern.) + if (Debug.debugStructuredDocument) { + System.out.println("\t\tContextRegion::updateModel"); //$NON-NLS-1$ + System.out.println("\t\t\tregion type is " + fType); //$NON-NLS-1$ + } + boolean canHandle = false; + // note: we'll always handle deletes from these + // regions ... if its already that region, + // deleting something from it won't change its + // type. (remember, the calling program needs + // to insure we are not called, if not all contained + // on one region. + if ((changes == null) || (changes.length() == 0)) { + // delete case + // We can not do the quick delete, if + // if all the text in a region is to be deleted. + // Or, if the delete starts in the white space region. + // In these cases, a reparse is needed. + // Minor note, we use textEnd-start since it always + // less than or equal to end-start. This might + // cause us to miss a few cases we could have handled, + // but will prevent us from trying to handle funning cases + // involving whitespace. + if ((fStart >= getTextEnd()) || (Math.abs(lengthToReplace) >= getTextEnd() - getStart())) { + canHandle = false; + } else { + canHandle = true; + } + } else { + if (RegionUpdateRule.canHandleAsWhiteSpace(this, parent, changes, requestStart, lengthToReplace)) { + canHandle = true; + } else { + canHandle = false; + } + + } + RegionChangedEvent result = null; + + if (canHandle) { + // at this point, we still have the old region. We won't create a + // new instance, we'll just update the one we have, by changing + // its end postion, + // The parent flatnode, upon return, has responsibility + // for updating sibling regions. + // and in turn, the structuredDocument itself has responsibility + // for + // updating the text store and down stream flatnodes. + if (Debug.debugStructuredDocument) { + System.out.println("change handled by region"); //$NON-NLS-1$ + } + int lengthDifference = Utilities.calculateLengthDifference(changes, lengthToReplace); + // Note: we adjust both end and text end, because for any change + // that is in only the trailing whitespace region, we should not + // do a quick change, + // so 'canHandle' should have been false for those case. + fLength += lengthDifference; + + result = new RegionChangedEvent(parent.getParentDocument(), requester, parent, this, changes, requestStart, lengthToReplace); + } + + return result; + } + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/XMLCDataTextRegion.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/XMLCDataTextRegion.java new file mode 100644 index 0000000000..e6f3cbecef --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/XMLCDataTextRegion.java @@ -0,0 +1,179 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.parser.regions; + +import org.eclipse.wst.sse.core.events.RegionChangedEvent; +import org.eclipse.wst.sse.core.events.StructuredDocumentEvent; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.core.util.Debug; +import org.eclipse.wst.sse.core.util.Utilities; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; + + +public class XMLCDataTextRegion implements ITextRegion { + static private final String fType = XMLRegionContext.XML_CDATA_TEXT; + private int fLength; + private int fStart; + private int fTextLength; + + + public XMLCDataTextRegion() { + super(); + } + + public XMLCDataTextRegion(int start, int textLength, int length) { + this(); + fStart = start; + fTextLength = textLength; + fLength = length; + } + + public void adjustLengthWith(int i) { + fLength += i; + + } + + public void adjustStart(int i) { + fStart += i; + + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegion#adjustTextLength(int) + */ + public void adjustTextLength(int i) { + fTextLength += i; + + } + + public void equatePositions(ITextRegion region) { + fStart = region.getStart(); + fLength = region.getLength(); + fTextLength = region.getTextLength(); + } + + public int getEnd() { + return fStart + fLength; + } + + public int getLength() { + // TODO: shouldn't cdata be like XML Content ... length and text + // length + // always be the same, regardless of whitespace? + return fLength; + } + + public int getStart() { + return fStart; + } + + public int getTextEnd() { + return fStart + fTextLength; + } + + public int getTextLength() { + return fTextLength; + } + + public String getType() { + return fType; + } + + public String toString() { + return RegionToStringUtil.toString(this); + } + + + public StructuredDocumentEvent updateModel(Object requester, IStructuredDocumentRegion parent, String changes, int requestStart, int lengthToReplace) { + // TODO: this is a pretty lame method, since XML CData region can have + // a much + // better rule for region update, but this is what previous + // (unfactored) + // version had, so I'll carry it over, of now. + RegionChangedEvent result = null; + // if the region is an easy type (e.g. attribute value), + // and the requested changes are all + // alphanumeric, then make the change here locally. + // (This can obviously be made more sophisticated as the need arises, + // but should + // always follow this pattern.) + if (Debug.debugStructuredDocument) { + System.out.println("\t\tContextRegion::updateModel"); //$NON-NLS-1$ + System.out.println("\t\t\tregion type is " + fType); //$NON-NLS-1$ + } + boolean canHandle = false; + // note: we'll always handle deletes from these + // regions ... if its already that region, + // deleting something from it won't change its + // type. (remember, the calling program needs + // to insure we are not called, if not all contained + // on one region. + if ((changes == null) || (changes.length() == 0)) { + // delete case + // We can not do the quick delete, if + // if all the text in a region is to be deleted. + // Or, if the delete starts in the white space region. + // In these cases, a reparse is needed. + // Minor note, we use textEnd-start since it always + // less than or equal to end-start. This might + // cause us to miss a few cases we could have handled, + // but will prevent us from trying to handle funning cases + // involving whitespace. + if ((fStart >= getTextEnd()) || (Math.abs(lengthToReplace) >= getTextEnd() - getStart())) { + canHandle = false; + } else { + canHandle = true; + } + } else { + if ((RegionUpdateRule.canHandleAsWhiteSpace(this, parent, changes, requestStart, lengthToReplace)) || RegionUpdateRule.canHandleAsLetterOrDigit(this, parent, changes, requestStart, lengthToReplace)) { + canHandle = true; + } else { + canHandle = false; + } + + } + if (canHandle) { + // at this point, we still have the old region. We won't create a + // new instance, we'll just update the one we have, by changing + // its end postion, + // The parent flatnode, upon return, has responsibility + // for updating sibling regions. + // and in turn, the structuredDocument itself has responsibility + // for + // updating the text store and down stream flatnodes. + if (Debug.debugStructuredDocument) { + System.out.println("change handled by region"); //$NON-NLS-1$ + } + int lengthDifference = Utilities.calculateLengthDifference(changes, lengthToReplace); + // Note: we adjust both end and text end, because for any change + // that is in only the trailing whitespace region, we should not + // do a quick change, + // so 'canHandle' should have been false for those case. + // TO_DO_FUTURE: cache value of canHandleAsWhiteSpace from above + // If we are handling as whitespace, there is no need to increase + // the text length, only + // the total length is changing. + if (!RegionUpdateRule.canHandleAsWhiteSpace(this, parent, changes, requestStart, lengthToReplace)) { + fTextLength += lengthDifference; + } + fLength += lengthDifference; + result = new RegionChangedEvent(parent.getParentDocument(), requester, parent, this, changes, requestStart, lengthToReplace); + } + + return result; + } + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/XMLContentRegion.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/XMLContentRegion.java new file mode 100644 index 0000000000..7155dfcedf --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/XMLContentRegion.java @@ -0,0 +1,179 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.parser.regions; + +import org.eclipse.wst.sse.core.events.RegionChangedEvent; +import org.eclipse.wst.sse.core.events.StructuredDocumentEvent; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.core.util.Debug; +import org.eclipse.wst.sse.core.util.Utilities; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; + + + +public class XMLContentRegion implements ITextRegion { + static private final String fType = XMLRegionContext.XML_CONTENT; + // length and textLength are always the same for content region + //private int fTextLength; + private int fLength; + private int fStart; + + + public XMLContentRegion() { + super(); + } + + public XMLContentRegion(int start, int length) { + this(); + fStart = start; + fLength = length; + } + + + public void adjustLengthWith(int i) { + fLength += i; + + } + + public void adjustStart(int i) { + fStart += i; + + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegion#adjustTextLength(int) + */ + public void adjustTextLength(int i) { + // not supported + + } + + public void equatePositions(ITextRegion region) { + fStart = region.getStart(); + fLength = region.getLength(); + } + + public int getEnd() { + return fStart + fLength; + } + + public int getLength() { + return fLength; + } + + public int getStart() { + return fStart; + } + + public int getTextEnd() { + return fStart + fLength; + } + + public int getTextLength() { + return fLength; + } + + public String getType() { + return fType; + } + + public String toString() { + return RegionToStringUtil.toString(this); + } + + + public StructuredDocumentEvent updateModel(Object requester, IStructuredDocumentRegion parent, String changes, int requestStart, int lengthToReplace) { + // TODO: this is a pretty lame method, since XML Content can have a + // much + // better rule for region update, but this is what previous + // (unfactored) + // version had, so I'll carry it over, of now. + RegionChangedEvent result = null; + // if the region is an easy type (e.g. attribute value), + // and the requested changes are all + // alphanumeric, then make the change here locally. + // (This can obviously be made more sophisticated as the need arises, + // but should + // always follow this pattern.) + if (Debug.debugStructuredDocument) { + System.out.println("\t\tContextRegion::updateModel"); //$NON-NLS-1$ + System.out.println("\t\t\tregion type is " + fType); //$NON-NLS-1$ + } + boolean canHandle = false; + // note: we'll always handle deletes from these + // regions ... if its already that region, + // deleting something from it won't change its + // type. (remember, the calling program needs + // to insure we are not called, if not all contained + // on one region. + if ((changes == null) || (changes.length() == 0)) { + // delete case + // We can not do the quick delete, if + // if all the text in a region is to be deleted. + // Or, if the delete starts in the white space region. + // In these cases, a reparse is needed. + // Minor note, we use textEnd-start since it always + // less than or equal to end-start. This might + // cause us to miss a few cases we could have handled, + // but will prevent us from trying to handle funning cases + // involving whitespace. + if ((fStart >= getTextEnd()) || (Math.abs(lengthToReplace) >= getTextEnd() - getStart())) { + canHandle = false; + } else { + canHandle = true; + } + } else { + if ((RegionUpdateRule.canHandleAsWhiteSpace(this, parent, changes, requestStart, lengthToReplace)) || RegionUpdateRule.canHandleAsLetterOrDigit(this, parent, changes, requestStart, lengthToReplace)) { + canHandle = true; + } else { + canHandle = false; + } + + } + if (canHandle) { + // at this point, we still have the old region. We won't create a + // new instance, we'll just update the one we have, by changing + // its end postion, + // The parent flatnode, upon return, has responsibility + // for updating sibling regions. + // and in turn, the structuredDocument itself has responsibility + // for + // updating the text store and down stream flatnodes. + if (Debug.debugStructuredDocument) { + System.out.println("change handled by region"); //$NON-NLS-1$ + } + int lengthDifference = Utilities.calculateLengthDifference(changes, lengthToReplace); + // Note: we adjust both end and text end, because for any change + // that is in only the trailing whitespace region, we should not + // do a quick change, + // so 'canHandle' should have been false for those case. + fLength += lengthDifference; + // TO_DO_FUTURE: cache value of canHandleAsWhiteSpace from above + // If we are handling as whitespace, there is no need to increase + // the text length, only + // the total length is changing. + // don't need for content region + // if (!RegionUpdateRule.canHandleAsWhiteSpace(this, changes, + // fStart, lengthToReplace)) { + // fTextLength += lengthDifference; + // } + result = new RegionChangedEvent(parent.getParentDocument(), requester, parent, this, changes, requestStart, lengthToReplace); + } + + return result; + } + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/XMLHeadParserFactory.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/XMLHeadParserFactory.java new file mode 100644 index 0000000000..66d9ee9413 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/XMLHeadParserFactory.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.parser.regions; + +import org.eclipse.wst.sse.core.text.ITextRegion; + +public class XMLHeadParserFactory { + public ITextRegion createToken(String context, int start, int textLength, int length, String text) { + ITextRegion newRegion = null; + // if (context == XMLRegionContext.XML_CDATA_TEXT) { + newRegion = new XMLHeadParserRegion(context, start, textLength, length, text); + // } + return newRegion; + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/XMLHeadParserRegion.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/XMLHeadParserRegion.java new file mode 100644 index 0000000000..98dad747b4 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/XMLHeadParserRegion.java @@ -0,0 +1,111 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.parser.regions; + +import org.eclipse.wst.sse.core.events.StructuredDocumentEvent; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; + + +/** + * + * This class is not intended to be used, its just present to server as a + * generic starting point for adding new specific region types. + */ + +public class XMLHeadParserRegion implements ITextRegion { + private int fLength; + private int fStart; + private String fText; + private int fTextLength; + // specify correct type + private String fType = XMLRegionContext.UNDEFINED; + + public XMLHeadParserRegion() { + super(); + } + + public XMLHeadParserRegion(String context, int start, int textLength, int length, String text) { + this(); + fType = context; + fStart = start; + fTextLength = textLength; + fLength = length; + fText = text; + } + + public void adjustLengthWith(int i) { + fLength += i; + + } + + public void adjustStart(int i) { + fStart += i; + + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.structured.text.ITextRegion#adjustTextLength(int) + */ + public void adjustTextLength(int i) { + fTextLength += 1; + + } + + public void equatePositions(ITextRegion region) { + fStart = region.getStart(); + fLength = region.getLength(); + fTextLength = region.getTextLength(); + } + + public int getEnd() { + return fStart + fLength; + } + + public int getLength() { + return fLength; + } + + public int getStart() { + return fStart; + } + + public String getText() { + return fText; + } + + public int getTextEnd() { + return fStart + fTextLength; + } + + public int getTextLength() { + return fTextLength; + } + + public String getType() { + return fType; + } + + public String toString() { + return RegionToStringUtil.toString(this); + } + + public StructuredDocumentEvent updateModel(Object requester, IStructuredDocumentRegion parent, String changes, int requestStart, int lengthToReplace) { + // can never be updated + return null; + } + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/XMLParserRegionFactory.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/XMLParserRegionFactory.java new file mode 100644 index 0000000000..6b03796502 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/parser/regions/XMLParserRegionFactory.java @@ -0,0 +1,86 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.parser.regions; + + + +import org.eclipse.wst.sse.core.internal.parser.ContextRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.core.text.ITextRegionContainer; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; + + +/** + * + * This region factory is very specific to the parser output, and the specific + * implementation classes for various regions. + */ + +public class XMLParserRegionFactory { + + public XMLParserRegionFactory() { + super(); + } + + public ITextRegion createToken(ITextRegionContainer parent, String context, int start, int textLength, int length) { + return this.createToken(parent, context, start, textLength, length, null, null); + } + + public ITextRegion createToken(ITextRegionContainer parent, String context, int start, int textLength, int length, String lang, String surroundingTag) { + ITextRegion newRegion = createToken(context, start, textLength, length); + // DW, 4/16/2003 token regions no longer have parents + //newRegion.setParent(parent); + return newRegion; + } + + public ITextRegion createToken(String context, int start, int textLength, int length) { + return this.createToken(context, start, textLength, length, null, null); + } + + public ITextRegion createToken(String context, int start, int textLength, int length, String lang, String surroundingTag) { + ITextRegion newRegion = null; + if (context == XMLRegionContext.XML_CDATA_TEXT) { + newRegion = new XMLCDataTextRegion(start, textLength, length); + } else if (context == XMLRegionContext.XML_CONTENT) { + newRegion = new XMLContentRegion(start, length); + } else if (context == XMLRegionContext.XML_TAG_NAME) { + newRegion = new TagNameRegion(start, textLength, length); + } else if (context == XMLRegionContext.XML_TAG_ATTRIBUTE_NAME) { + newRegion = new AttributeNameRegion(start, textLength, length); + } else if (context == XMLRegionContext.XML_TAG_ATTRIBUTE_EQUALS) { + newRegion = new AttributeEqualsRegion(start, textLength, length); + } else if (context == XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE) { + newRegion = new AttributeValueRegion(start, textLength, length); + } else if (context == XMLRegionContext.XML_TAG_OPEN) { + newRegion = new TagOpenRegion(start, textLength, length); + } else if (context == XMLRegionContext.XML_TAG_CLOSE) { + newRegion = new TagCloseRegion(start); + } else if (context == XMLRegionContext.WHITE_SPACE) { + newRegion = new WhiteSpaceOnlyRegion(start, length); + } else + // removed this condition during transition, and implemented in + // subclass + // if (context == XMLJSPRegionContexts.JSP_CONTENT) { + // newRegion = new JSPCodeRegion(context, start, textLength, length); + // } else + if (context == XMLRegionContext.BLOCK_TEXT) { + newRegion = new BlockTextRegion(context, start, textLength, length); + ((BlockTextRegion) newRegion).setSurroundingTag(surroundingTag); + } else { + newRegion = new ContextRegion(context, start, textLength, length); + } + return newRegion; + } + + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/propagate/PropagatingAdapterFactoryImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/propagate/PropagatingAdapterFactoryImpl.java new file mode 100644 index 0000000000..ed13b8a959 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/propagate/PropagatingAdapterFactoryImpl.java @@ -0,0 +1,113 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.propagate; + + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.wst.sse.core.AbstractAdapterFactory; +import org.eclipse.wst.sse.core.AdapterFactory; +import org.eclipse.wst.sse.core.INodeAdapter; +import org.eclipse.wst.sse.core.INodeNotifier; +import org.eclipse.wst.sse.core.PropagatingAdapter; +import org.eclipse.wst.sse.core.PropagatingAdapterFactory; + + +/** + * The PropagatingAdapterFactory is part of the "adapt on create" mechanism. A + * PropagatingAdapter, once added to a node, will cause proagating adapters to + * be created for all child nodes. A side effect of creating a + * PropagatingAdapter for a node is that is is also creates adapters for and + * adapts the Node for all other registered 'create on adapt' Adapters. This + * other adapters are registered by registering their factories via plugin + * extension point. + */ +public class PropagatingAdapterFactoryImpl extends AbstractAdapterFactory implements PropagatingAdapterFactory { + + private PropagatingAdapter adapterInstance; + protected List contributedFactories = null; + + /** + * PropagatingAdapterFactory constructor comment. + */ + public PropagatingAdapterFactoryImpl() { + this(PropagatingAdapter.class, true); + } + + protected PropagatingAdapterFactoryImpl(Object adapterKey, boolean registerAdapters) { //, + // Object + // modelType) + // { + super(adapterKey, registerAdapters); + } + + public void addContributedFactories(AdapterFactory factory) { + if (contributedFactories != null) { + contributedFactories.add(factory); + } + + } + + public AdapterFactory copy() { + PropagatingAdapterFactory clonedInstance = new PropagatingAdapterFactoryImpl(this.adapterKey, this.shouldRegisterAdapter); + // clone this adapters specific list of adapter factories too + if (contributedFactories != null) { + Iterator iterator = contributedFactories.iterator(); + clonedInstance.setContributedFactories(new ArrayList()); + while (iterator.hasNext()) { + AdapterFactory existingFactory = (AdapterFactory) iterator.next(); + clonedInstance.addContributedFactories(existingFactory.copy()); + } + } + return clonedInstance; + } + + /** + * createAdapter method comment. + */ + protected INodeAdapter createAdapter(INodeNotifier target) { + // every notifier get's one of these + // (and the same instance of it) + return getAdapterInstance(); + } + + /** + * Gets the adapterInstance. + * + * @return Returns a PropagatingAdapter + */ + protected PropagatingAdapter getAdapterInstance() { + if (adapterInstance == null) { + adapterInstance = new PropagatingAdapterImpl(); + if (contributedFactories != null) { + for (int i = 0; i < contributedFactories.size(); i++) + adapterInstance.addAdaptOnCreateFactory((PropagatingAdapterFactory) contributedFactories.get(i)); + } + } + return adapterInstance; + } + + public void release() { + // give the adapter instance a chance to release its factories + getAdapterInstance().release(); + + } + + public void setContributedFactories(ArrayList list) { + contributedFactories = list; + + } + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/propagate/PropagatingAdapterImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/propagate/PropagatingAdapterImpl.java new file mode 100644 index 0000000000..4f0b3201f0 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/propagate/PropagatingAdapterImpl.java @@ -0,0 +1,168 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.propagate; + + + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.wst.sse.core.AdapterFactory; +import org.eclipse.wst.sse.core.INodeNotifier; +import org.eclipse.wst.sse.core.PropagatingAdapter; +import org.eclipse.wst.xml.core.document.XMLNode; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + + +public class PropagatingAdapterImpl implements PropagatingAdapter { + + public static final Class PropagatingAdapterClass = PropagatingAdapter.class; + // because so many of these are created in huge file, + // Jeffrey Liu suggested these be done lazily, since not all + // models and not all nodes actually have a list of factories. + private List adaptOnCreateFactories = null; + + /** + * AbstractPropagatingAdapterImpl constructor comment. + */ + public PropagatingAdapterImpl() { + super(); + } + + protected void adaptOnCreate(XMLNode node) { + // give each of the factories a chance to adapt the node, if it + // chooses to + if (adaptOnCreateFactories != null) { + Iterator iterator = adaptOnCreateFactories.iterator(); + while (iterator.hasNext()) { + AdapterFactory factory = (AdapterFactory) iterator.next(); + factory.adapt(node); + } + } + + } + + /** + * This mechanism can be made "easier to use" later. + */ + public void addAdaptOnCreateFactory(AdapterFactory factory) { + //adaptOnCreateFactories.add(factory); + getAdaptOnCreateFactories().add(factory); + } + + /** + * Gets the adaptOnCreateFactories. + * + * @return Returns a List + */ + public List getAdaptOnCreateFactories() { + if (adaptOnCreateFactories == null) + adaptOnCreateFactories = new ArrayList(); + return adaptOnCreateFactories; + } + + // protected void unadaptOnRemove(INodeNotifier node) { + // // give each of the factories a chance to process remove event + // // This is a bit out of the normal adapter pattern, but I couldn't + // // think of a better way to "remove" pageDirectiveWatchers, if and + // // when the page directive was 'removed' (edited). + // // + // Iterator iterator = adaptOnCreateFactories.iterator(); + // while (iterator.hasNext()) { + // AdapterFactory factory = (AdapterFactory) iterator.next(); + // if (factory instanceof PropagatingAdapterFactory) { + // ((PropagatingAdapterFactory)factory).unadapt(node); + // } + // } + // + // } + + /** + * @see PropagatingAdapter#initializeForFactory(AdapterFactory, + * INodeNotifier) + */ + public void initializeForFactory(AdapterFactory factory, INodeNotifier node) { + // we're DOM specific implimentation + if (node instanceof XMLNode) { + XMLNode xmlNode = (XMLNode) node; + propagateTo(xmlNode); + } + } + + /** + * Allowing the INodeAdapter to compare itself against the type allows it + * to return true in more than one case. + */ + public boolean isAdapterForType(Object type) { + return type.equals(PropagatingAdapterClass); + } + + protected boolean isInteresting(Object newValue) { + return (newValue != null && (newValue instanceof Element || newValue instanceof Document || newValue instanceof DocumentType)); + } + + /** + */ + public void notifyChanged(INodeNotifier notifier, int eventType, Object changedFeature, Object oldValue, Object newValue, int pos) { + // DMW, 2002.8.10. I changed this so we only propagate to Elements ... + // not attributes too! + // I'm assuming this will help performance and memory, but don't know + // if anyone was depending on + // this being proagate to attributes. + if (eventType == INodeNotifier.ADD && isInteresting(newValue)) { + propagateTo((XMLNode) newValue); + } + // else if (eventType == INodeNotifier.CONTENT_CHANGED) { + // notifier.getAdapterFor(PropagatingAdapterClass); + // } + // else if (eventType == INodeNotifier.CHANGE) { + // } + // else if (eventType == INodeNotifier.REMOVE && + // isInteresting(oldValue)) { + // unadaptOnRemove((XMLNode)oldValue); + // } + // else if (eventType == INodeNotifier.STRUCTURE_CHANGED) { + // } + } + + protected void propagateTo(XMLNode node) { + // get adapter to ensure its created + node.getAdapterFor(PropagatingAdapterClass); + adaptOnCreate(node); + propagateToChildren(node); + } + + protected void propagateToChildren(XMLNode parent) { + for (Node child = parent.getFirstChild(); child != null; child = child.getNextSibling()) { + propagateTo((XMLNode) child); + } + } + + /** + * @see PropagatingAdapter#release() + */ + public void release() { + if (adaptOnCreateFactories != null) { + Iterator iterator = adaptOnCreateFactories.iterator(); + while (iterator.hasNext()) { + AdapterFactory factory = (AdapterFactory) iterator.next(); + factory.release(); + } + } + } + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/text/XMLStructuredDocumentRegion.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/text/XMLStructuredDocumentRegion.java new file mode 100644 index 0000000000..77de14a4e7 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/text/XMLStructuredDocumentRegion.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.text; + +import org.eclipse.wst.sse.core.internal.text.BasicStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; + + +public class XMLStructuredDocumentRegion extends BasicStructuredDocumentRegion implements IStructuredDocumentRegion { + + public XMLStructuredDocumentRegion() { + super(); + } + + public String getType() { + String result = super.getType(); + // normally, we want the second region as the flatnode type ... since + // the + // first one is usually just "open tag". + if ((result != XMLRegionContext.XML_PI_OPEN) && (getRegions().size() > 1)) { + result = getRegions().get(1).getType(); + } + return result; + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/util/DebugDocument.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/util/DebugDocument.java new file mode 100644 index 0000000000..13afbc8647 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/util/DebugDocument.java @@ -0,0 +1,104 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.util; + +import java.io.PrintStream; + +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.xml.core.document.XMLNode; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + + +public class DebugDocument { + + public static void dump(Document document) { + if (document == null) + return; + System.out.println("Dump of DOM"); //$NON-NLS-1$ + + dump(document, System.out); + + // + System.out.println(); + System.out.println("= = = = = ="); //$NON-NLS-1$ + System.out.println(); + + } + + public static void dump(Document document, PrintStream out) { + Node node = document.getFirstChild(); + while (node != null) { + dump(node, out); + node = node.getNextSibling(); + } + + } + + public static void dump(Node topNode) { + dump(topNode, System.out); + } + + public static void dump(Node topNode, PrintStream out) { + if (topNode == null) + return; + // print out this node + // + printNode(topNode, out); + + // now print out its children + //NodeList nodes = topNode.getChildNodes(); + //int len = nodes.getLength(); + //for (int i = 0; i < len; i++) { + + //Node node = nodes.item(i); + //dump(node, out); + //} + } + + public static void printNode(Node topNode) { + printNode(topNode, System.out); + + } + + public static void printNode(Node topNode, PrintStream out) { + // print out this node + // + IStructuredDocumentRegion firstStructuredDocumentRegion = ((XMLNode) topNode).getFirstStructuredDocumentRegion(); + IStructuredDocumentRegion lastStructuredDocumentRegion = ((XMLNode) topNode).getLastStructuredDocumentRegion(); + if ((firstStructuredDocumentRegion == null) || (lastStructuredDocumentRegion == null)) { + // no text to output + } else { + int start = firstStructuredDocumentRegion.getStart(); + int end = lastStructuredDocumentRegion.getEnd(); + + String outString = topNode.toString(); + outString = org.eclipse.wst.sse.core.util.StringUtils.escape(outString); + out.println("[" + start + ", " + end + "]" + outString); //$NON-NLS-3$//$NON-NLS-2$//$NON-NLS-1$ + } + // now do its children + NodeList nodes = topNode.getChildNodes(); + int len = nodes.getLength(); + for (int i = 0; i < len; i++) { + Node childNode = nodes.item(i); + printNode(childNode, out); + } + + } + + public DebugDocument() { + super(); + } + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/validate/AbstractPropagatingValidator.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/validate/AbstractPropagatingValidator.java new file mode 100644 index 0000000000..9144662bd2 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/validate/AbstractPropagatingValidator.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.validate; + +import org.eclipse.wst.sse.core.IndexedRegion; +import org.eclipse.wst.sse.core.validate.ValidationAdapter; +import org.w3c.dom.Node; + + +public abstract class AbstractPropagatingValidator extends ValidationComponent { + + /** + * Constructor for AbstractPropagatingValidator. + */ + public AbstractPropagatingValidator() { + super(); + } + + protected abstract ValidationComponent getPropagatee(); + + protected abstract ValidationAdapter getValidator(); + + /** + * @see com.ibm.sed.adapters.validate.ValidationAdapter#validate(IndexedRegion) + */ + public void validate(IndexedRegion node) { + if (node == null) + return; + getValidator().validate(node); + + + Propagator.propagateToChildElements(getPropagatee(), (Node) node); + } + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/validate/Propagator.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/validate/Propagator.java new file mode 100644 index 0000000000..3cdcca5312 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/validate/Propagator.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.validate; + +import org.eclipse.wst.sse.core.INodeNotifier; +import org.eclipse.wst.sse.core.IndexedRegion; +import org.eclipse.wst.sse.core.validate.ValidationAdapter; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + + +public class Propagator { + + public static void propagateToChildElements(ValidationComponent validator, Node parent) { + if (parent == null) + return; + Class clazz = validator.getClass(); + + NodeList children = parent.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Node child = children.item(i); + if (child == null || child.getNodeType() != Node.ELEMENT_NODE) + continue; + + INodeNotifier notifier = (INodeNotifier) child; + ValidationAdapter va = (ValidationAdapter) notifier.getExistingAdapter(clazz); + if (va == null) { + notifier.addAdapter(validator); + va = validator; + } + va.validate((IndexedRegion) child); + } + } + + /** + * Propagator is just a placeholder of utilities. Don't instantiate. + */ + private Propagator() { + super(); + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/validate/ValidationComponent.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/validate/ValidationComponent.java new file mode 100644 index 0000000000..797d9cbf0a --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/internal/validate/ValidationComponent.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.internal.validate; + + + +import org.eclipse.wst.sse.core.validate.ValidationAdapter; +import org.eclipse.wst.sse.core.validate.ValidationReporter; + +public abstract class ValidationComponent implements ValidationAdapter { + + protected ValidationReporter reporter = null; + + /** + * ValidationComponent constructor comment. + */ + public ValidationComponent() { + super(); + } + + /** + * Allowing the INodeAdapter to compare itself against the type allows it + * to return true in more than one case. + */ + public boolean isAdapterForType(Object type) { + return (type == ValidationAdapter.class); + } + + /** + */ + public void notifyChanged(org.eclipse.wst.sse.core.INodeNotifier notifier, int eventType, Object changedFeature, Object oldValue, Object newValue, int pos) { + // This method will be implemented in the V2. + } + + /** + */ + public void setReporter(ValidationReporter reporter) { + this.reporter = reporter; + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/jsp/model/parser/temp/XMLJSPRegionContexts.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/jsp/model/parser/temp/XMLJSPRegionContexts.java new file mode 100644 index 0000000000..26a8e1ca96 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/jsp/model/parser/temp/XMLJSPRegionContexts.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.jsp.model.parser.temp; + +import org.eclipse.wst.xml.core.parser.XMLRegionContext; + + +/** + * //TODO + * + * @deprecated - marked as deprecated to warn of pending changes. See the + * package.html file for full explaination. + */ + +public interface XMLJSPRegionContexts extends XMLRegionContext { + public static final String JSP_CLOSE = "JSP_CLOSE"; //$NON-NLS-1$ + public static final String JSP_COMMENT_CLOSE = "JSP_COMMENT_CLOSE"; //$NON-NLS-1$ + + public static final String JSP_COMMENT_OPEN = "JSP_COMMENT_OPEN"; //$NON-NLS-1$ + public static final String JSP_COMMENT_TEXT = "JSP_COMMENT_TEXT"; //$NON-NLS-1$ + + public static final String JSP_CONTENT = "JSP_CONTENT"; //$NON-NLS-1$ + public static final String JSP_DECLARATION_OPEN = "JSP_DECLARATION_OPEN"; //$NON-NLS-1$ + public static final String JSP_DIRECTIVE_CLOSE = "JSP_DIRECTIVE_CLOSE"; //$NON-NLS-1$ + public static final String JSP_DIRECTIVE_NAME = "JSP_DIRECTIVE_NAME"; //$NON-NLS-1$ + + public static final String JSP_DIRECTIVE_OPEN = "JSP_DIRECTIVE_OPEN"; //$NON-NLS-1$ + public static final String JSP_EL_CLOSE = "JSP_EL_CLOSE"; //$NON-NLS-1$ + public static final String JSP_EL_CONTENT = "JSP_EL_CONTENT"; //$NON-NLS-1$ + public static final String JSP_EL_DQUOTE = "JSP_EL_DQUOTE"; //$NON-NLS-1$ + + public static final String JSP_EL_OPEN = "JSP_EL_OPEN"; //$NON-NLS-1$ + public static final String JSP_EL_QUOTED_CONTENT = "JSP_EL_QUOTED_CONTENT"; //$NON-NLS-1$ + public static final String JSP_EL_SQUOTE = "JSP_EL_SQUOTE"; //$NON-NLS-1$ + public static final String JSP_EXPRESSION_OPEN = "JSP_EXPRESSION_OPEN"; //$NON-NLS-1$ + + public static final String JSP_ROOT_TAG_NAME = "JSP_ROOT_TAG_NAME"; //$NON-NLS-1$ + + public static final String JSP_SCRIPTLET_OPEN = "JSP_SCRIPTLET_OPEN"; //$NON-NLS-1$ + public static final String JSP_VBL_CLOSE = "JSP_VBL_CLOSE"; //$NON-NLS-1$ + public static final String JSP_VBL_CONTENT = "JSP_VBL_CONTENT"; //$NON-NLS-1$ + public static final String JSP_VBL_DQUOTE = "JSP_VBL_DQUOTE"; //$NON-NLS-1$ + public static final String JSP_VBL_OPEN = "JSP_VBL_OPEN"; //$NON-NLS-1$ + public static final String JSP_VBL_QUOTED_CONTENT = "JSP_VBL_QUOTED_CONTENT"; //$NON-NLS-1$ + public static final String JSP_VBL_SQUOTE = "JSP_VBL_SQUOTE"; //$NON-NLS-1$ + public static final String XML_TAG_ATTRIBUTE_VALUE_DQUOTE = "XML_TAG_ATTRIBUTE_VALUE_DQUOTE"; //$NON-NLS-1$ + + public static final String XML_TAG_ATTRIBUTE_VALUE_SQUOTE = "XML_TAG_ATTRIBUTE_VALUE_SQUOTE"; //$NON-NLS-1$ +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/jsp/model/parser/temp/package.html b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/jsp/model/parser/temp/package.html new file mode 100644 index 0000000000..8e9ef20b30 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/jsp/model/parser/temp/package.html @@ -0,0 +1,8 @@ +<HTML> +This package is located here in the XML project +temporarily. Once the DOM Parser is cleaningly split +to XML and JSP components, this package will move +back to JSP project. (If its not here temporarily, +its easy to get circluar references in plugin.xml +dependancies. +</HTML>
\ No newline at end of file diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/modelhandler/EmbeddedXML.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/modelhandler/EmbeddedXML.java new file mode 100644 index 0000000000..db6917779e --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/modelhandler/EmbeddedXML.java @@ -0,0 +1,89 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.modelhandler; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.wst.sse.core.IFactoryRegistry; +import org.eclipse.wst.sse.core.modelhandler.EmbeddedTypeHandler; +import org.eclipse.wst.sse.core.parser.JSPCapableParser; +import org.eclipse.wst.xml.core.modelquery.ModelQueryAdapterFactoryForEmbeddedXML; + + +public class EmbeddedXML implements EmbeddedTypeHandler { + + private static List supportedMimeTypes; + public String ContentTypeID_EmbeddedXML = "org.eclipse.wst.xml.core.contenttype.EmbeddedXML"; //$NON-NLS-1$ + + /** + * Constructor for EmbeddedXML. + */ + public EmbeddedXML() { + super(); + } + + /* + * @see EmbeddedContentType#getAdapterFactories() + */ + public List getAdapterFactories() { + List factories = new ArrayList(); + factories.add(new ModelQueryAdapterFactoryForEmbeddedXML()); + // factories.addAll(PluginContributedFactoryReader.getInstance().getFactories(this)); + return factories; + } + + /** + * @see EmbeddedContentType#getFamilyId() + */ + public String getFamilyId() { + return ModelHandlerForXML.AssociatedContentTypeID; + } + + public List getSupportedMimeTypes() { + if (supportedMimeTypes == null) { + supportedMimeTypes = new ArrayList(); + supportedMimeTypes.add("text/xml"); //$NON-NLS-1$ + } + return supportedMimeTypes; + } + + public void initializeFactoryRegistry(IFactoryRegistry registry) { + //TODO: initialize + } + + /* + * @see EmbeddedContentType#initializeParser(RegionParser) + */ + public void initializeParser(JSPCapableParser parser) { + // nothing to initialize for "pure" XML + // compare with XHTML + } + + public boolean isDefault() { + return false; + } + + public EmbeddedTypeHandler newInstance() { + return new EmbeddedXML(); + } + + public void uninitializeFactoryRegistry(IFactoryRegistry registry) { + // TODO: need to undo anything we did in initialize + + } + + public void uninitializeParser(JSPCapableParser parser) { + // need to undo anything we did in initialize + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/modelhandler/ModelHandlerForXML.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/modelhandler/ModelHandlerForXML.java new file mode 100644 index 0000000000..5589f6d15d --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/modelhandler/ModelHandlerForXML.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.modelhandler; + +import org.eclipse.wst.sse.core.ModelLoader; +import org.eclipse.wst.sse.core.document.IDocumentCharsetDetector; +import org.eclipse.wst.sse.core.document.IDocumentLoader; +import org.eclipse.wst.sse.core.modelhandler.AbstractModelHandler; +import org.eclipse.wst.sse.core.modelhandler.IModelHandler; +import org.eclipse.wst.xml.core.document.DocumentLoaderForXML; +import org.eclipse.wst.xml.core.encoding.XMLDocumentCharsetDetector; +import org.eclipse.wst.xml.core.encoding.XMLDocumentLoader; + + +/** + * Provides generic XML model handling. It is also marked as the default + * content type handler. There should be only one implementation of the + * default. + */ +public class ModelHandlerForXML extends AbstractModelHandler implements IModelHandler { + /** + * Needs to match what's in plugin registry. In fact, can be overwritten + * at run time with what's in registry! (so should never be 'final') + */ + static String AssociatedContentTypeID = "org.eclipse.wst.xml.core.xmlsource"; //$NON-NLS-1$ + /** + * Needs to match what's in plugin registry. In fact, can be overwritten + * at run time with what's in registry! (so should never be 'final') + */ + private static String ModelHandlerID = "org.eclipse.wst.sse.core.handler.xml"; //$NON-NLS-1$ + + public ModelHandlerForXML() { + super(); + setId(ModelHandlerID); + setAssociatedContentTypeId(AssociatedContentTypeID); + } + + public IDocumentLoader getDocumentLoader() { + if (USE_FILE_BUFFERS) + return new DocumentLoaderForXML(); + else + return new XMLDocumentLoader(); + } + + public IDocumentCharsetDetector getEncodingDetector() { + return new XMLDocumentCharsetDetector(); + } + + public ModelLoader getModelLoader() { + return new XMLModelLoader(); + } + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/modelhandler/XMLModelLoader.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/modelhandler/XMLModelLoader.java new file mode 100644 index 0000000000..dc50328715 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/modelhandler/XMLModelLoader.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.modelhandler; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.wst.sse.core.AbstractModelLoader; +import org.eclipse.wst.sse.core.AdapterFactory; +import org.eclipse.wst.sse.core.INodeNotifier; +import org.eclipse.wst.sse.core.IStructuredModel; +import org.eclipse.wst.sse.core.ModelLoader; +import org.eclipse.wst.sse.core.PropagatingAdapter; +import org.eclipse.wst.sse.core.document.IDocumentLoader; +import org.eclipse.wst.sse.core.util.Debug; +import org.eclipse.wst.xml.core.document.XMLModel; +import org.eclipse.wst.xml.core.encoding.XMLDocumentLoader; +import org.eclipse.wst.xml.core.internal.DebugAdapterFactory; +import org.eclipse.wst.xml.core.internal.document.XMLModelImpl; +import org.eclipse.wst.xml.core.internal.propagate.PropagatingAdapterFactoryImpl; +import org.eclipse.wst.xml.core.modelquery.ModelQueryAdapterFactoryForXML; + + +/** + * This class reads an XML file and creates an XML Structured Model. + * + */ +public class XMLModelLoader extends AbstractModelLoader { + + // private static final String STR_ENCODING = "encoding"; //$NON-NLS-1$ + + /** + * XMLLoader constructor comment. + */ + public XMLModelLoader() { + super(); + } + + public List getAdapterFactories() { + List result = new ArrayList(); + AdapterFactory factory = null; + // TODO different ModelQueryAdapterFactories need to be made for each + // type/loader + factory = new ModelQueryAdapterFactoryForXML(); + result.add(factory); + // Does XML need propagating adapter? Or just JSP? + factory = new PropagatingAdapterFactoryImpl(); + result.add(factory); + return result; + } + + public IDocumentLoader getDocumentLoader() { + if (documentLoaderInstance == null) { + documentLoaderInstance = new XMLDocumentLoader(); + } + return documentLoaderInstance; + } + + public ModelLoader newInstance() { + return new XMLModelLoader(); + } + + public IStructuredModel newModel() { + return new XMLModelImpl(); + } + + protected void preLoadAdapt(IStructuredModel structuredModel) { + super.preLoadAdapt(structuredModel); + XMLModel domModel = (XMLModel) structuredModel; + // if there is a model in the adapter, this will adapt it to + // first node. After that the PropagatingAdater spreads over the + // children being + // created. Each time that happends, a side effect is to + // also "spread" sprecific registered adapters, + // they two can propigate is needed. + ((INodeNotifier) domModel.getDocument()).getAdapterFor(PropagatingAdapter.class); + + if (Debug.debugNotificationAndEvents) { + PropagatingAdapter propagatingAdapter = (PropagatingAdapter) ((INodeNotifier) domModel.getDocument()).getAdapterFor(PropagatingAdapter.class); + propagatingAdapter.addAdaptOnCreateFactory(new DebugAdapterFactory()); + } + + } + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/modelquery/ModelQueryAdapterFactoryForEmbeddedXML.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/modelquery/ModelQueryAdapterFactoryForEmbeddedXML.java new file mode 100644 index 0000000000..f5b28101ac --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/modelquery/ModelQueryAdapterFactoryForEmbeddedXML.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.modelquery; + + + +import org.eclipse.wst.common.contentmodel.modelquery.CMDocumentManager; +import org.eclipse.wst.sse.core.AdapterFactory; +import org.eclipse.wst.sse.core.INodeAdapter; +import org.eclipse.wst.sse.core.INodeNotifier; +import org.eclipse.wst.sse.core.modelquery.ModelQueryAdapter; + + +public class ModelQueryAdapterFactoryForEmbeddedXML extends ModelQueryAdapterFactoryForXML { + + + /** + * Constructor for ModelQueryAdapterFactoryForEmbeddedXML. + */ + public ModelQueryAdapterFactoryForEmbeddedXML() { + this(ModelQueryAdapter.class, false); + } + + /** + * Constructor for ModelQueryAdapterFactoryForEmbeddedXML. + * + * @param adapterKey + * @param registerAdapters + */ + protected ModelQueryAdapterFactoryForEmbeddedXML(Object adapterKey, boolean registerAdapters) { + super(adapterKey, registerAdapters); + } + + /** + * @see AdapterFactory#adapt(INodeNotifier) + */ + public INodeAdapter adapt(INodeNotifier object) { + return adaptNew(object); + } + + protected void configureDocumentManager(CMDocumentManager mgr) { + super.configureDocumentManager(mgr); + mgr.setPropertyEnabled(CMDocumentManager.PROPERTY_ASYNC_LOAD, true); + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/modelquery/ModelQueryAdapterFactoryForXML.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/modelquery/ModelQueryAdapterFactoryForXML.java new file mode 100644 index 0000000000..eed96c316d --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/modelquery/ModelQueryAdapterFactoryForXML.java @@ -0,0 +1,161 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.modelquery; + + + +import org.eclipse.wst.common.contentmodel.modelquery.CMDocumentManager; +import org.eclipse.wst.common.contentmodel.modelquery.ModelQuery; +import org.eclipse.wst.common.contentmodel.util.CMDocumentCache; +import org.eclipse.wst.sse.core.AbstractAdapterFactory; +import org.eclipse.wst.sse.core.AdapterFactory; +import org.eclipse.wst.sse.core.IModelStateListener; +import org.eclipse.wst.sse.core.INodeAdapter; +import org.eclipse.wst.sse.core.INodeNotifier; +import org.eclipse.wst.sse.core.IStructuredModel; +import org.eclipse.wst.sse.core.modelquery.ModelQueryAdapter; +import org.eclipse.wst.sse.core.modelquery.ModelQueryAdapterImpl; +import org.eclipse.wst.xml.core.document.XMLNode; +import org.eclipse.wst.xml.uriresolver.util.IdResolver; + + +public class ModelQueryAdapterFactoryForXML extends AbstractAdapterFactory implements IModelStateListener { + + protected ModelQueryAdapterImpl modelQueryAdapterImpl; + protected IStructuredModel stateNotifier = null; + + /** + * ModelQueryAdapterFactoryForXML constructor comment. + */ + public ModelQueryAdapterFactoryForXML() { + this(ModelQueryAdapter.class, true); + } + + /** + * ModelQueryAdapterFactoryForXML constructor comment. + * + * @param adapterKey + * java.lang.Object + * @param registerAdapters + * boolean + */ + public ModelQueryAdapterFactoryForXML(Object adapterKey, boolean registerAdapters) { + super(adapterKey, registerAdapters); + } + + protected boolean autoLoadCM() { + // until the existence of a CMDocumentRequesterFactory to create the + // load requests, + // return true + return true; + } + + protected void configureDocumentManager(CMDocumentManager mgr) { + // this depends on there being a CMDocumentRequesterFactory installed + mgr.setPropertyEnabled(CMDocumentManager.PROPERTY_AUTO_LOAD, autoLoadCM()); + } + + public AdapterFactory copy() { + + return new ModelQueryAdapterFactoryForXML(this.adapterKey, this.shouldRegisterAdapter); + } + + /** + * createAdapter method comment. + */ + protected INodeAdapter createAdapter(INodeNotifier target) { + + if (org.eclipse.wst.sse.core.util.Debug.displayInfo) + System.out.println("-----------------------ModelQueryAdapterFactoryForXML.createAdapter" + target); //$NON-NLS-1$ + if (modelQueryAdapterImpl == null) { + if (target instanceof XMLNode) { + XMLNode xmlNode = (XMLNode) target; + IStructuredModel model = stateNotifier = xmlNode.getModel(); + stateNotifier.addModelStateListener(this); + String baseLocation = model.getBaseLocation(); + if (org.eclipse.wst.sse.core.util.Debug.displayInfo) + System.out.println("----------------ModelQueryAdapterFactoryForXML... baseLocation : " + baseLocation); //$NON-NLS-1$ + + CMDocumentCache cmDocumentCache = new CMDocumentCache(); + ModelQuery modelQuery = null; + IdResolver idResolver = null; + + if (org.eclipse.wst.sse.core.util.Debug.displayInfo) + System.out.println("********XMLModelQueryImpl"); //$NON-NLS-1$ + idResolver = new XMLCatalogIdResolver(baseLocation, model.getResolver()); + modelQuery = new XMLModelQueryImpl(cmDocumentCache, idResolver); + + // cs todo... + // for now we create a CMDocumentCache on a 'per editor' basis + // in the future we need to support a CMDocumentCache that is + // shared between editors + // nsd comment: may not be appropriate depending on + CMDocumentManager documentManager = modelQuery.getCMDocumentManager(); + if (documentManager != null) { + configureDocumentManager(documentManager); + } + modelQueryAdapterImpl = new ModelQueryAdapterImpl(cmDocumentCache, modelQuery, idResolver); + } + } + return modelQueryAdapterImpl; + } + + /** + * @see IModelStateListener#modelAboutToBeChanged(IStructuredModel) + */ + public void modelAboutToBeChanged(IStructuredModel model) { + } + + /** + * @see IModelStateListener#modelChanged(IStructuredModel) + */ + public void modelChanged(IStructuredModel model) { + } + + /** + * @see IModelStateListener#modelDirtyStateChanged(IStructuredModel, + * boolean) + */ + public void modelDirtyStateChanged(IStructuredModel model, boolean isDirty) { + } + + /** + * @see IModelStateListener#modelResourceDeleted(IStructuredModel) + */ + public void modelResourceDeleted(IStructuredModel model) { + } + + /** + * @see IModelStateListener#modelResourceMoved(IStructuredModel, + * IStructuredModel) + */ + public void modelResourceMoved(IStructuredModel oldModel, IStructuredModel newModel) { + stateNotifier.removeModelStateListener(this); + stateNotifier = newModel; + updateResolver(stateNotifier); + stateNotifier.addModelStateListener(this); + } + + public void release() { + super.release(); + if (stateNotifier != null) + stateNotifier.removeModelStateListener(this); + stateNotifier = null; + if (modelQueryAdapterImpl != null) + modelQueryAdapterImpl.release(); + } + + protected void updateResolver(IStructuredModel model) { + modelQueryAdapterImpl.setIdResolver(new XMLCatalogIdResolver(model.getBaseLocation(), model.getResolver())); + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/modelquery/ModelQueryUtil.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/modelquery/ModelQueryUtil.java new file mode 100644 index 0000000000..61f8cd4d32 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/modelquery/ModelQueryUtil.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.modelquery; + + + +import org.eclipse.wst.common.contentmodel.modelquery.ModelQuery; +import org.eclipse.wst.common.contentmodel.util.CMDocumentCache; +import org.eclipse.wst.sse.core.INodeNotifier; +import org.eclipse.wst.sse.core.IStructuredModel; +import org.eclipse.wst.sse.core.modelquery.ModelQueryAdapter; +import org.eclipse.wst.xml.core.document.XMLModel; +import org.eclipse.wst.xml.uriresolver.util.IdResolver; +import org.w3c.dom.Document; + + +/** + * This class is used to associate ModelQuery (and related data) with a + * Document (or IStructuredModel). + */ +public class ModelQueryUtil { + + public static CMDocumentCache getCMDocumentCache(Document node) { + ModelQueryAdapter modelQueryAdapter = getModelQueryAdapter(node); + return modelQueryAdapter != null ? modelQueryAdapter.getCMDocumentCache() : null; + } + + public static IdResolver getIdResolver(Document node) { + ModelQueryAdapter modelQueryAdapter = getModelQueryAdapter(node); + return modelQueryAdapter != null ? modelQueryAdapter.getIdResolver() : null; + } + + public static ModelQuery getModelQuery(Document node) { + ModelQueryAdapter modelQueryAdapter = getModelQueryAdapter(node); + return modelQueryAdapter != null ? modelQueryAdapter.getModelQuery() : null; + } + + public static ModelQuery getModelQuery(IStructuredModel model) { + if ((!(model instanceof XMLModel)) || model == null) + return null; + return getModelQuery(((XMLModel) model).getDocument()); + } + + public static ModelQueryAdapter getModelQueryAdapter(Document node) { + ModelQueryAdapter result = null; + + if (node instanceof INodeNotifier) { + INodeNotifier notifier = (INodeNotifier) node; + result = (ModelQueryAdapter) notifier.getAdapterFor(ModelQueryAdapter.class); + } + + return result; + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/modelquery/XMLCatalogIdResolver.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/modelquery/XMLCatalogIdResolver.java new file mode 100644 index 0000000000..cc8da655bb --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/modelquery/XMLCatalogIdResolver.java @@ -0,0 +1,89 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.modelquery; + +import org.eclipse.wst.sse.core.util.URIResolver; +import org.eclipse.wst.xml.uriresolver.XMLCatalog; +import org.eclipse.wst.xml.uriresolver.XMLCatalogPlugin; +import org.eclipse.wst.xml.uriresolver.util.IdResolver; +import org.eclipse.wst.xml.uriresolver.util.URIHelper; + + +public class XMLCatalogIdResolver implements IdResolver { + protected String resourceLocation; + + protected URIResolver uriresolver; + + public XMLCatalogIdResolver(String resourceLocation) { + this.resourceLocation = resourceLocation; + } + + public XMLCatalogIdResolver(String resourceLocation, URIResolver uriresolver) { + this.resourceLocation = resourceLocation; + this.uriresolver = uriresolver; + } + + + /** + * Gets the resourceLocation. + * + * @return Returns a String + */ + public String getResourceLocation() { + String location = resourceLocation; + if (location == null) { + if (uriresolver != null) + location = uriresolver.getFileBaseLocation(); + } + return location; + } + + /** + * @deprecated in superclass + */ + public String resolveId(String publicId, String systemId) { + return resolveId(getResourceLocation(), publicId, systemId); + } + + public String resolveId(String base, String publicId, String systemId) { + // first see if we can map the publicId to an alternative systemId + // note: should probably verify the mappedSystemId before ignoring the + // systemId + XMLCatalog xmlCatalog = XMLCatalogPlugin.getInstance().getDefaultXMLCatalog(); + String mappedSystemId = xmlCatalog.getMappedSystemId(publicId, systemId); + if (mappedSystemId != null) { + systemId = mappedSystemId; + } + + // normalize the systemId + boolean normalized = false; + // account for Web Projects and others where *any* string may legally + // resolve somehow + if (this.uriresolver != null && systemId != null) { + // check the provided URIResolver + String resolvedValue = this.uriresolver.getLocationByURI(systemId, base); + if (resolvedValue != null && resolvedValue.length() > 0) { + systemId = resolvedValue; + normalized = true; + } + } + if (!normalized) { + // no URIResolver available; ask the URIHelper directly + systemId = URIHelper.normalize(systemId, base, null); + normalized = true; + } + return systemId; + } + + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/modelquery/XMLModelQueryAssociationProvider.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/modelquery/XMLModelQueryAssociationProvider.java new file mode 100644 index 0000000000..b5a55d6d7b --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/modelquery/XMLModelQueryAssociationProvider.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.modelquery; + + + +import org.eclipse.wst.common.contentmodel.modelqueryimpl.XMLAssociationProvider; +import org.eclipse.wst.common.contentmodel.util.CMDocumentCache; +import org.eclipse.wst.xml.uriresolver.util.IdResolver; +import org.w3c.dom.Document; + +/** + * XMLModelQueryAssociationProvider + */ +class XMLModelQueryAssociationProvider extends XMLAssociationProvider { + + protected IdResolver idResolver; + + public XMLModelQueryAssociationProvider(CMDocumentCache cache, IdResolver idResolver) { + super(cache); + this.idResolver = idResolver; + } + + protected String resolveGrammarURI(Document document, String publicId, String systemId) { + return idResolver.resolveId(publicId, systemId); + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/modelquery/XMLModelQueryImpl.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/modelquery/XMLModelQueryImpl.java new file mode 100644 index 0000000000..1ac1c16d78 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/modelquery/XMLModelQueryImpl.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.modelquery; + + + +import org.eclipse.wst.common.contentmodel.modelqueryimpl.ModelQueryImpl; +import org.eclipse.wst.common.contentmodel.util.CMDocumentCache; +import org.eclipse.wst.sse.core.modelquery.MovableModelQuery; +import org.eclipse.wst.xml.uriresolver.util.IdResolver; + + +public class XMLModelQueryImpl extends ModelQueryImpl implements MovableModelQuery { + + protected CMDocumentCache fCache = null; + + public XMLModelQueryImpl(CMDocumentCache cache, IdResolver idResolver) { + super(new XMLModelQueryAssociationProvider(cache, idResolver)); + fCache = cache; + } + + /** + * @see MovableModelQuery#setIdResolver(IdResolver) + */ + public void setIdResolver(IdResolver newIdResolver) { + modelQueryAssociationProvider = new XMLModelQueryAssociationProvider(fCache, newIdResolver); + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/parser/XMLRegionContext.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/parser/XMLRegionContext.java new file mode 100644 index 0000000000..d0b42040e2 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/parser/XMLRegionContext.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.parser; + +public interface XMLRegionContext { + + public static final String BLOCK_TEXT = "BLOCK_TEXT"; //$NON-NLS-1$ + + public static final String UNDEFINED = "UNDEFINED"; //$NON-NLS-1$ + + public static final String WHITE_SPACE = "WHITE_SPACE"; //$NON-NLS-1$ + public static final String XML_ATTLIST_DECL_CLOSE = "XML_ATTLIST_DECL_CLOSE"; //$NON-NLS-1$ + public static final String XML_ATTLIST_DECL_CONTENT = "XML_ATTLIST_DECL_CONTENT"; //$NON-NLS-1$ + public static final String XML_ATTLIST_DECL_NAME = "XML_ATTLIST_DECL_NAME"; //$NON-NLS-1$ + + public static final String XML_ATTLIST_DECLARATION = "XML_ATTLIST_DECLARATION"; //$NON-NLS-1$ + public static final String XML_CDATA_CLOSE = "XML_CDATA_CLOSE"; //$NON-NLS-1$ + public static final String XML_CDATA_OPEN = "XML_CDATA_OPEN"; //$NON-NLS-1$ + public static final String XML_CDATA_TEXT = "XML_CDATA_TEXT"; //$NON-NLS-1$ + public static final String XML_CHAR_REFERENCE = "XML_CHAR_REFERENCE"; //$NON-NLS-1$ + public static final String XML_COMMENT_CLOSE = "XML_COMMENT_CLOSE"; //$NON-NLS-1$ + + public static final String XML_COMMENT_OPEN = "XML_COMMENT_OPEN"; //$NON-NLS-1$ + public static final String XML_COMMENT_TEXT = "XML_COMMENT_TEXT"; //$NON-NLS-1$ + + public static final String XML_CONTENT = "XML_CONTENT"; //$NON-NLS-1$ + public static final String XML_DECLARATION_CLOSE = "XML_DECLARATION_CLOSE"; //$NON-NLS-1$ + + public static final String XML_DECLARATION_OPEN = "XML_DECLARATION_OPEN"; //$NON-NLS-1$ + + public static final String XML_DOCTYPE_DECLARATION = "XML_DOCTYPE_DECLARATION"; //$NON-NLS-1$ + public static final String XML_DOCTYPE_DECLARATION_CLOSE = "XML_DOCTYPE_DECLARATION_CLOSE"; //$NON-NLS-1$ + public static final String XML_DOCTYPE_EXTERNAL_ID_PUBLIC = "XML_DOCTYPE_EXTERNAL_ID_PUBLIC"; //$NON-NLS-1$ + public static final String XML_DOCTYPE_EXTERNAL_ID_PUBREF = "XML_DOCTYPE_EXTERNAL_ID_PUBREF"; //$NON-NLS-1$ + public static final String XML_DOCTYPE_EXTERNAL_ID_SYSREF = "XML_DOCTYPE_EXTERNAL_ID_SYSREF"; //$NON-NLS-1$ + public static final String XML_DOCTYPE_EXTERNAL_ID_SYSTEM = "XML_DOCTYPE_EXTERNAL_ID_SYSTEM"; //$NON-NLS-1$ + public static final String XML_DOCTYPE_INTERNAL_SUBSET = "XML_DOCTYPE_INTERNAL_SUBSET"; //$NON-NLS-1$ + public static final String XML_DOCTYPE_NAME = "XML_DOCTYPE_NAME"; //$NON-NLS-1$ + public static final String XML_ELEMENT_DECL_CLOSE = "XML_ELEMENT_DECL_CLOSE"; //$NON-NLS-1$ + public static final String XML_ELEMENT_DECL_CONTENT = "XML_ELEMENT_DECL_CONTENT"; //$NON-NLS-1$ + public static final String XML_ELEMENT_DECL_NAME = "XML_ELEMENT_DECL_NAME"; //$NON-NLS-1$ + + public static final String XML_ELEMENT_DECLARATION = "XML_ELEMENT_DECLARATION"; //$NON-NLS-1$ + public static final String XML_EMPTY_TAG_CLOSE = "XML_EMPTY_TAG_CLOSE"; //$NON-NLS-1$ + public static final String XML_END_TAG_OPEN = "XML_END_TAG_OPEN"; //$NON-NLS-1$ + public static final String XML_ENTITY_REFERENCE = "XML_ENTITY_REFERENCE"; //$NON-NLS-1$ + + public static final String XML_PE_REFERENCE = "XML_PE_REFERENCE"; //$NON-NLS-1$ + public static final String XML_PI_CLOSE = "XML_PI_CLOSE"; //$NON-NLS-1$ + public static final String XML_PI_CONTENT = "XML_PI_CONTENT"; //$NON-NLS-1$ + public static final String XML_PI_OPEN = "XML_PI_OPEN"; //$NON-NLS-1$ + public static final String XML_TAG_ATTRIBUTE_EQUALS = "XML_TAG_ATTRIBUTE_EQUALS"; //$NON-NLS-1$ + public static final String XML_TAG_ATTRIBUTE_NAME = "XML_TAG_ATTRIBUTE_NAME"; //$NON-NLS-1$ + public static final String XML_TAG_ATTRIBUTE_VALUE = "XML_TAG_ATTRIBUTE_VALUE"; //$NON-NLS-1$ + public static final String XML_TAG_CLOSE = "XML_TAG_CLOSE"; //$NON-NLS-1$ + public static final String XML_TAG_NAME = "XML_TAG_NAME"; //$NON-NLS-1$ + + public static final String XML_TAG_OPEN = "XML_TAG_OPEN"; //$NON-NLS-1$ +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/text/rules/StructuredTextPartitionerForXML.java b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/text/rules/StructuredTextPartitionerForXML.java new file mode 100644 index 0000000000..471629675c --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/eclipse/wst/xml/core/text/rules/StructuredTextPartitionerForXML.java @@ -0,0 +1,139 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.core.text.rules; + +import org.eclipse.jface.text.IDocumentPartitioner; +import org.eclipse.wst.sse.core.internal.parser.ForeignRegion; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.IStructuredTextPartitioner; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.core.text.rules.StructuredTextPartitioner; +import org.eclipse.wst.xml.core.internal.parser.regions.BlockTextRegion; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; + + +public class StructuredTextPartitionerForXML extends StructuredTextPartitioner implements IStructuredTextPartitioner { + public final static String ST_DEFAULT_XML = "org.eclipse.wst.xml.DEFAULT_XML"; //$NON-NLS-1$ + public final static String ST_XML_CDATA = "org.eclipse.wst.xml.XML_CDATA"; //$NON-NLS-1$ + public final static String ST_XML_PI = "org.eclipse.wst.xml.XML_PI"; //$NON-NLS-1$ + public final static String ST_XML_DECLARATION = "org.eclipse.wst.xml.XML_DECL"; //$NON-NLS-1$ + public final static String ST_XML_COMMENT = "org.eclipse.wst.xml.XML_COMMENT"; //$NON-NLS-1$ + + /** + * Should match + * org.eclipse.wst.sse.core.dtd.partitioning.StructuredTextPartitionerForDTD.ST_DTD_SUBSET + */ + public static final String ST_DTD_SUBSET = "org.eclipse.wst.xml.dtd.internal_subset"; //$NON-NLS-1$ + + private final static String[] configuredContentTypes = new String[]{ST_DEFAULT_XML, ST_XML_CDATA, ST_XML_PI, ST_XML_DECLARATION, ST_XML_COMMENT, ST_DTD_SUBSET}; + + /** + * Constructor for JSPDocumentPartioner. + */ + public StructuredTextPartitionerForXML() { + super(); + } + + protected void setInternalPartition(int offset, int length, String type) { + super.setInternalPartition(offset, length, type); + } + + protected void initLegalContentTypes() { + fSupportedTypes = configuredContentTypes; + } + + /** + * @see com.ibm.sed.model.StructuredTextPartitioner#getPartitionType(com.ibm.sed.structuredDocument.ITextRegion) + */ + public String getPartitionType(ITextRegion region, int offset) { + String result = null; + if (region.getType() == XMLRegionContext.XML_COMMENT_TEXT) + result = ST_XML_COMMENT; + else if (region.getType() == XMLRegionContext.XML_CDATA_TEXT) + result = ST_XML_CDATA; + else if (region.getType() == XMLRegionContext.XML_PI_OPEN) + result = ST_XML_PI; + else if (region.getType() == XMLRegionContext.XML_DOCTYPE_DECLARATION) + result = ST_XML_DECLARATION; + else if (region.getType() == XMLRegionContext.XML_DOCTYPE_INTERNAL_SUBSET) + result = ST_DTD_SUBSET; + else + result = super.getPartitionType(region, offset); + return result; + } + + protected String getPartitionType(ForeignRegion region, int offset) { + // temp added just to dis-ambiguate call from subclass + return super.getPartitionType(region, offset); + } + + /** + * @see com.ibm.sed.structuredDocument.partition.IStructuredTextPartitioner#getPartitionTypeBetween(com.ibm.sed.structuredDocument.ITextRegion, + * com.ibm.sed.structuredDocument.ITextRegion) + */ + public String getPartitionTypeBetween(IStructuredDocumentRegion previousNode, ITextRegion previousStartTagNameRegion, IStructuredDocumentRegion nextNode, ITextRegion nextEndTagNameRegion) { + return super.getPartitionTypeBetween(previousNode, previousStartTagNameRegion, nextNode, nextEndTagNameRegion); + } + + public String getDefault() { + return ST_DEFAULT_XML; + } + + public IDocumentPartitioner newInstance() { + StructuredTextPartitionerForXML instance = new StructuredTextPartitionerForXML(); + return instance; + } + + /** + * @return + */ + public static String[] getConfiguredContentTypes() { + return configuredContentTypes; + } + + protected String getPartitionFromBlockedText(ITextRegion region, int offset, String result) { + // was moved to subclass for quick transition + String newResult = result; + // nsd_TODO: David and I need to discuss, design, and implement this + // for all block tags and comments + // and make sure is part of "extensible" design of block tags + if (region.getType() == XMLRegionContext.BLOCK_TEXT) { + // for code safety, we'll always check instanceof, but I think + // always true. + if (region instanceof BlockTextRegion) { + // super is used below so won't be ambiguous + newResult = getPartitionType((BlockTextRegion) region, offset); + } else if (region instanceof ForeignRegion) { + newResult = getPartitionType((ForeignRegion) region, offset); + } else { + newResult = getUnknown(); + } + } + return newResult; + } + + protected boolean doParserSpecificCheck(int offset, boolean partitionFound, IStructuredDocumentRegion sdRegion, IStructuredDocumentRegion previousStructuredDocumentRegion, ITextRegion next, ITextRegion previousStart) { + // this was moved down to subclass of StructuredTextPartioner + // for quick fix to transition problems. Heirarchy needs lots of + // cleanup. + if (previousStart != null && previousStart.getType() == XMLRegionContext.XML_TAG_OPEN && next.getType() == XMLRegionContext.XML_END_TAG_OPEN) { + ITextRegion previousName = previousStructuredDocumentRegion.getRegionAtCharacterOffset(previousStructuredDocumentRegion.getEndOffset(previousStart)); + ITextRegion nextName = sdRegion.getRegionAtCharacterOffset(sdRegion.getEndOffset(next)); + if (previousName != null && nextName != null && previousName.getType() == XMLRegionContext.XML_TAG_NAME && nextName.getType() == XMLRegionContext.XML_TAG_NAME) { + setInternalPartition(offset, 0, getPartitionTypeBetween(previousStructuredDocumentRegion, previousName, sdRegion, nextName)); + partitionFound = true; + } + } + return partitionFound; + } +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/ranges/COPYRIGHT.html b/bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/ranges/COPYRIGHT.html new file mode 100644 index 0000000000..26049b750f --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/ranges/COPYRIGHT.html @@ -0,0 +1,100 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" + "http://www.w3.org/TR/REC-html40/loose.dtd"> +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <title>W3C IPR SOFTWARE NOTICE</title> + </head> + <body bgcolor="#FFFFFF" text="#000000"> + <h1> + W3C IPR SOFTWARE NOTICE + </h1> + <h3> + Copyright © 2000 <loc href="http://www.w3.org/">World Wide Web + Consortium</loc>, (<loc href="http://www.lcs.mit.edu/">Massachusetts + Institute of Technology</loc>, <loc href="http://www.inria.fr/">Institut + National de Recherche en Informatique et en Automatique</loc>, <loc + href="http://www.keio.ac.jp/">Keio University</loc>). All Rights + Reserved. + </h3> + <p> + The DOM bindings are published under the W3C Software Copyright Notice + and License. The software license requires "Notice of any changes or + modifications to the W3C files, including the date changes were made." + Consequently, modified versions of the DOM bindings must document that + they do not conform to the W3C standard; in the case of the IDL binding, + the pragma prefix can no longer be 'w3c.org'; in the case of the Java + binding, the package names can no longer be in the 'org.w3c' package. + </p> + <p> + <b>Note:</b> The original version of the W3C Software Copyright Notice + and License could be found at <a + href='http://www.w3.org/Consortium/Legal/copyright-software-19980720'>http://www.w3.org/Consortium/Legal/copyright-software-19980720</a> + </p> + <h3> + Copyright © 1994-2000 <a href="http://www.w3.org/">World Wide Web + Consortium</a>, (<a href="http://www.lcs.mit.edu/">Massachusetts + Institute of Technology</a>, <a href="http://www.inria.fr/">Institut + National de Recherche en Informatique et en Automatique</a>, <a + href="http://www.keio.ac.jp/">Keio University</a>). All Rights + Reserved. http://www.w3.org/Consortium/Legal/ + </h3> + <p> + This W3C work (including software, documents, or other related items) is + being provided by the copyright holders under the following license. By + obtaining, using and/or copying this work, you (the licensee) agree that + you have read, understood, and will comply with the following terms and + conditions: + </p> + <p> + Permission to use, copy, and modify this software and its documentation, + with or without modification, for any purpose and without fee or + royalty is hereby granted, provided that you include the following on ALL + copies of the software and documentation or portions thereof, including + modifications, that you make: + </p> + <ol> + <li> + The full text of this NOTICE in a location viewable to users of the + redistributed or derivative work. + </li> + <li> + Any pre-existing intellectual property disclaimers, notices, or terms + and conditions. If none exist, a short notice of the following form + (hypertext is preferred, text is permitted) should be used within the + body of any redistributed or derivative code: "Copyright © + [$date-of-software] <a href="http://www.w3.org/">World Wide Web + Consortium</a>, (<a href="http://www.lcs.mit.edu/">Massachusetts + Institute of Technology</a>, <a href="http://www.inria.fr/">Institut + National de Recherche en Informatique et en Automatique</a>, <a + href="http://www.keio.ac.jp/">Keio University</a>). All Rights + Reserved. http://www.w3.org/Consortium/Legal/" + </li> + <li> + Notice of any changes or modifications to the W3C files, including the + date changes were made. (We recommend you provide URIs to the location + from which the code is derived.) + </li> + </ol> + <p> + THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT + HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS + FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR + DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, + TRADEMARKS OR OTHER RIGHTS. + </p> + <p> + COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR + CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR + DOCUMENTATION. + </p> + <p> + The name and trademarks of copyright holders may NOT be used in + advertising or publicity pertaining to the software without specific, + written prior permission. Title to copyright in this software and any + associated documentation will at all times remain with copyright + holders. + </p> + </body> +</html> diff --git a/bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/ranges/DocumentRange.java b/bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/ranges/DocumentRange.java new file mode 100644 index 0000000000..e40d080700 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/ranges/DocumentRange.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ + +package org.w3c.dom.ranges; + +/** + * <p> + * See also the <a + * href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Traversal-Range-20001113'>Document + * Object Model (DOM) Level 2 Traversal and Range Specification </a>. + * + * @since DOM Level 2 + */ +public interface DocumentRange { + /** + * This interface can be obtained from the object implementing the + * <code>Document</code> interface using binding-specific casting + * methods. + * + * @return The initial state of the Range returned from this method is + * such that both of its boundary-points are positioned at the + * beginning of the corresponding Document, before any content. + * The Range returned can only be used to select content + * associated with this Document, or with DocumentFragments and + * Attrs for which this Document is the <code>ownerDocument</code>. + */ + public Range createRange(); + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/ranges/Range.java b/bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/ranges/Range.java new file mode 100644 index 0000000000..63c366533f --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/ranges/Range.java @@ -0,0 +1,434 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ + +package org.w3c.dom.ranges; + +import org.w3c.dom.DOMException; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.Node; + +/** + * <p> + * See also the <a + * href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Traversal-Range-20001113'>Document + * Object Model (DOM) Level 2 Traversal and Range Specification </a>. + * + * @since DOM Level 2 + */ +public interface Range { + /** + * Compare end boundary-point of <code>sourceRange</code> to end + * boundary-point of Range on which <code>compareBoundaryPoints</code> + * is invoked. + */ + public static final short END_TO_END = 2; + /** + * Compare end boundary-point of <code>sourceRange</code> to start + * boundary-point of Range on which <code>compareBoundaryPoints</code> + * is invoked. + */ + public static final short END_TO_START = 3; + /** + * Compare start boundary-point of <code>sourceRange</code> to end + * boundary-point of Range on which <code>compareBoundaryPoints</code> + * is invoked. + */ + public static final short START_TO_END = 1; + + // CompareHow + /** + * Compare start boundary-point of <code>sourceRange</code> to start + * boundary-point of Range on which <code>compareBoundaryPoints</code> + * is invoked. + */ + public static final short START_TO_START = 0; + + /** + * Duplicates the contents of a Range + * + * @return A DocumentFragment that contains content equivalent to this + * Range. + * @exception DOMException + * HIERARCHY_REQUEST_ERR: Raised if a DocumentType node + * would be extracted into the new DocumentFragment. <br> + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public DocumentFragment cloneContents() throws DOMException; + + /** + * Produces a new Range whose boundary-points are equal to the + * boundary-points of the Range. + * + * @return The duplicated Range. + * @exception DOMException + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public Range cloneRange() throws DOMException; + + /** + * Collapse a Range onto one of its boundary-points + * + * @param toStartIf + * TRUE, collapses the Range onto its start; if FALSE, + * collapses it onto its end. + * @exception DOMException + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public void collapse(boolean toStart) throws DOMException; + + /** + * Compare the boundary-points of two Ranges in a document. + * + * @param howA + * code representing the type of comparison, as defined above. + * @param sourceRangeThe + * <code>Range</code> on which this current + * <code>Range</code> is compared to. + * @return -1, 0 or 1 depending on whether the corresponding + * boundary-point of the Range is respectively before, equal to, + * or after the corresponding boundary-point of + * <code>sourceRange</code>. + * @exception DOMException + * WRONG_DOCUMENT_ERR: Raised if the two Ranges are not in + * the same Document or DocumentFragment. <br> + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public short compareBoundaryPoints(short how, Range sourceRange) throws DOMException; + + /** + * Removes the contents of a Range from the containing document or + * document fragment without returning a reference to the removed content. + * + * @exception DOMException + * NO_MODIFICATION_ALLOWED_ERR: Raised if any portion of + * the content of the Range is read-only or any of the + * nodes that contain any of the content of the Range are + * read-only. <br> + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public void deleteContents() throws DOMException; + + /** + * Called to indicate that the Range is no longer in use and that the + * implementation may relinquish any resources associated with this Range. + * Subsequent calls to any methods or attribute getters on this Range will + * result in a <code>DOMException</code> being thrown with an error code + * of <code>INVALID_STATE_ERR</code>. + * + * @exception DOMException + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public void detach() throws DOMException; + + /** + * Moves the contents of a Range from the containing document or document + * fragment to a new DocumentFragment. + * + * @return A DocumentFragment containing the extracted contents. + * @exception DOMException + * NO_MODIFICATION_ALLOWED_ERR: Raised if any portion of + * the content of the Range is read-only or any of the + * nodes which contain any of the content of the Range are + * read-only. <br> + * HIERARCHY_REQUEST_ERR: Raised if a DocumentType node + * would be extracted into the new DocumentFragment. <br> + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public DocumentFragment extractContents() throws DOMException; + + /** + * TRUE if the Range is collapsed + * + * @exception DOMException + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public boolean getCollapsed() throws DOMException; + + /** + * The deepest common ancestor container of the Range's two + * boundary-points. + * + * @exception DOMException + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public Node getCommonAncestorContainer() throws DOMException; + + /** + * Node within which the Range ends + * + * @exception DOMException + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public Node getEndContainer() throws DOMException; + + /** + * Offset within the ending node of the Range. + * + * @exception DOMException + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public int getEndOffset() throws DOMException; + + /** + * Node within which the Range begins + * + * @exception DOMException + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public Node getStartContainer() throws DOMException; + + /** + * Offset within the starting node of the Range. + * + * @exception DOMException + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public int getStartOffset() throws DOMException; + + /** + * Inserts a node into the Document or DocumentFragment at the start of + * the Range. If the container is a Text node, this will be split at the + * start of the Range (as if the Text node's splitText method was + * performed at the insertion point) and the insertion will occur between + * the two resulting Text nodes. Adjacent Text nodes will not be + * automatically merged. If the node to be inserted is a DocumentFragment + * node, the children will be inserted rather than the DocumentFragment + * node itself. + * + * @param newNodeThe + * node to insert at the start of the Range + * @exception DOMException + * NO_MODIFICATION_ALLOWED_ERR: Raised if an ancestor + * container of the start of the Range is read-only. <br> + * WRONG_DOCUMENT_ERR: Raised if <code>newNode</code> and + * the container of the start of the Range were not created + * from the same document. <br> + * HIERARCHY_REQUEST_ERR: Raised if the container of the + * start of the Range is of a type that does not allow + * children of the type of <code>newNode</code> or if + * <code>newNode</code> is an ancestor of the container. + * <br> + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + * @exception RangeException + * INVALID_NODE_TYPE_ERR: Raised if <code>newNode</code> + * is an Attr, Entity, Notation, or Document node. + */ + public void insertNode(Node newNode) throws DOMException, RangeException; + + /** + * Select a node and its contents + * + * @param refNodeThe + * node to select. + * @exception RangeException + * INVALID_NODE_TYPE_ERR: Raised if an ancestor of + * <code>refNode</code> is an Entity, Notation or + * DocumentType node or if <code>refNode</code> is a + * Document, DocumentFragment, Attr, Entity, or Notation + * node. + * @exception DOMException + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public void selectNode(Node refNode) throws RangeException, DOMException; + + /** + * Select the contents within a node + * + * @param refNodeNode + * to select from + * @exception RangeException + * INVALID_NODE_TYPE_ERR: Raised if <code>refNode</code> + * or an ancestor of <code>refNode</code> is an Entity, + * Notation or DocumentType node. + * @exception DOMException + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public void selectNodeContents(Node refNode) throws RangeException, DOMException; + + /** + * Sets the attributes describing the end of a Range. + * + * @param refNodeThe + * <code>refNode</code> value. This parameter must be + * different from <code>null</code>. + * @param offsetThe + * <code>endOffset</code> value. + * @exception RangeException + * INVALID_NODE_TYPE_ERR: Raised if <code>refNode</code> + * or an ancestor of <code>refNode</code> is an Entity, + * Notation, or DocumentType node. + * @exception DOMException + * INDEX_SIZE_ERR: Raised if <code>offset</code> is + * negative or greater than the number of child units in + * <code>refNode</code>. Child units are 16-bit units if + * <code>refNode</code> is a type of CharacterData node + * (e.g., a Text or Comment node) or a + * ProcessingInstruction node. Child units are Nodes in all + * other cases. <br> + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public void setEnd(Node refNode, int offset) throws RangeException, DOMException; + + /** + * Sets the end of a Range to be after a node + * + * @param refNodeRange + * ends after <code>refNode</code>. + * @exception RangeException + * INVALID_NODE_TYPE_ERR: Raised if the root container of + * <code>refNode</code> is not an Attr, Document or + * DocumentFragment node or if <code>refNode</code> is a + * Document, DocumentFragment, Attr, Entity, or Notation + * node. + * @exception DOMException + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public void setEndAfter(Node refNode) throws RangeException, DOMException; + + /** + * Sets the end position to be before a node. + * + * @param refNodeRange + * ends before <code>refNode</code> + * @exception RangeException + * INVALID_NODE_TYPE_ERR: Raised if the root container of + * <code>refNode</code> is not an Attr, Document, or + * DocumentFragment node or if <code>refNode</code> is a + * Document, DocumentFragment, Attr, Entity, or Notation + * node. + * @exception DOMException + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public void setEndBefore(Node refNode) throws RangeException, DOMException; + + /** + * Sets the attributes describing the start of the Range. + * + * @param refNodeThe + * <code>refNode</code> value. This parameter must be + * different from <code>null</code>. + * @param offsetThe + * <code>startOffset</code> value. + * @exception RangeException + * INVALID_NODE_TYPE_ERR: Raised if <code>refNode</code> + * or an ancestor of <code>refNode</code> is an Entity, + * Notation, or DocumentType node. + * @exception DOMException + * INDEX_SIZE_ERR: Raised if <code>offset</code> is + * negative or greater than the number of child units in + * <code>refNode</code>. Child units are 16-bit units if + * <code>refNode</code> is a type of CharacterData node + * (e.g., a Text or Comment node) or a + * ProcessingInstruction node. Child units are Nodes in all + * other cases. <br> + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public void setStart(Node refNode, int offset) throws RangeException, DOMException; + + /** + * Sets the start position to be after a node + * + * @param refNodeRange + * starts after <code>refNode</code> + * @exception RangeException + * INVALID_NODE_TYPE_ERR: Raised if the root container of + * <code>refNode</code> is not an Attr, Document, or + * DocumentFragment node or if <code>refNode</code> is a + * Document, DocumentFragment, Attr, Entity, or Notation + * node. + * @exception DOMException + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public void setStartAfter(Node refNode) throws RangeException, DOMException; + + /** + * Sets the start position to be before a node + * + * @param refNodeRange + * starts before <code>refNode</code> + * @exception RangeException + * INVALID_NODE_TYPE_ERR: Raised if the root container of + * <code>refNode</code> is not an Attr, Document, or + * DocumentFragment node or if <code>refNode</code> is a + * Document, DocumentFragment, Attr, Entity, or Notation + * node. + * @exception DOMException + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public void setStartBefore(Node refNode) throws RangeException, DOMException; + + /** + * Reparents the contents of the Range to the given node and inserts the + * node at the position of the start of the Range. + * + * @param newParentThe + * node to surround the contents with. + * @exception DOMException + * NO_MODIFICATION_ALLOWED_ERR: Raised if an ancestor + * container of either boundary-point of the Range is + * read-only. <br> + * WRONG_DOCUMENT_ERR: Raised if <code> newParent</code> + * and the container of the start of the Range were not + * created from the same document. <br> + * HIERARCHY_REQUEST_ERR: Raised if the container of the + * start of the Range is of a type that does not allow + * children of the type of <code>newParent</code> or if + * <code>newParent</code> is an ancestor of the container + * or if <code>node</code> would end up with a child node + * of a type not allowed by the type of <code>node</code>. + * <br> + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + * @exception RangeException + * BAD_BOUNDARYPOINTS_ERR: Raised if the Range partially + * selects a non-text node. <br> + * INVALID_NODE_TYPE_ERR: Raised if <code> node</code> is + * an Attr, Entity, DocumentType, Notation, Document, or + * DocumentFragment node. + */ + public void surroundContents(Node newParent) throws DOMException, RangeException; + + /** + * Returns the contents of a Range as a string. This string contains only + * the data characters, not any markup. + * + * @return The contents of the Range. + * @exception DOMException + * INVALID_STATE_ERR: Raised if <code>detach()</code> has + * already been invoked on this object. + */ + public String toString() throws DOMException; + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/ranges/RangeException.java b/bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/ranges/RangeException.java new file mode 100644 index 0000000000..54d29d7d78 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/ranges/RangeException.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ + +package org.w3c.dom.ranges; + +/** + * Range operations may throw a <code>RangeException</code> as specified in + * their method descriptions. + * <p> + * See also the <a + * href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Traversal-Range-20001113'>Document + * Object Model (DOM) Level 2 Traversal and Range Specification </a>. + * + * @since DOM Level 2 + */ +public class RangeException extends RuntimeException { + // RangeExceptionCode + /** + * If the boundary-points of a Range do not meet specific requirements. + */ + public static final short BAD_BOUNDARYPOINTS_ERR = 1; + /** + * If the container of an boundary-point of a Range is being set to either + * a node of an invalid type or a node with an ancestor of an invalid + * type. + */ + public static final short INVALID_NODE_TYPE_ERR = 2; + + public short code; + + public RangeException(short code, String message) { + super(message); + this.code = code; + } + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/ranges/package.html b/bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/ranges/package.html new file mode 100644 index 0000000000..d8fbae65d9 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/ranges/package.html @@ -0,0 +1,3 @@ +<html> +This package contains unmodified sources provided by http://www.w3.org/TR/2000/REC-DOM-Level-2-Traversal-Range-20001113/java-binding.zip +</html>
\ No newline at end of file diff --git a/bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/traversal/COPYRIGHT.html b/bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/traversal/COPYRIGHT.html new file mode 100644 index 0000000000..26049b750f --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/traversal/COPYRIGHT.html @@ -0,0 +1,100 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" + "http://www.w3.org/TR/REC-html40/loose.dtd"> +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <title>W3C IPR SOFTWARE NOTICE</title> + </head> + <body bgcolor="#FFFFFF" text="#000000"> + <h1> + W3C IPR SOFTWARE NOTICE + </h1> + <h3> + Copyright © 2000 <loc href="http://www.w3.org/">World Wide Web + Consortium</loc>, (<loc href="http://www.lcs.mit.edu/">Massachusetts + Institute of Technology</loc>, <loc href="http://www.inria.fr/">Institut + National de Recherche en Informatique et en Automatique</loc>, <loc + href="http://www.keio.ac.jp/">Keio University</loc>). All Rights + Reserved. + </h3> + <p> + The DOM bindings are published under the W3C Software Copyright Notice + and License. The software license requires "Notice of any changes or + modifications to the W3C files, including the date changes were made." + Consequently, modified versions of the DOM bindings must document that + they do not conform to the W3C standard; in the case of the IDL binding, + the pragma prefix can no longer be 'w3c.org'; in the case of the Java + binding, the package names can no longer be in the 'org.w3c' package. + </p> + <p> + <b>Note:</b> The original version of the W3C Software Copyright Notice + and License could be found at <a + href='http://www.w3.org/Consortium/Legal/copyright-software-19980720'>http://www.w3.org/Consortium/Legal/copyright-software-19980720</a> + </p> + <h3> + Copyright © 1994-2000 <a href="http://www.w3.org/">World Wide Web + Consortium</a>, (<a href="http://www.lcs.mit.edu/">Massachusetts + Institute of Technology</a>, <a href="http://www.inria.fr/">Institut + National de Recherche en Informatique et en Automatique</a>, <a + href="http://www.keio.ac.jp/">Keio University</a>). All Rights + Reserved. http://www.w3.org/Consortium/Legal/ + </h3> + <p> + This W3C work (including software, documents, or other related items) is + being provided by the copyright holders under the following license. By + obtaining, using and/or copying this work, you (the licensee) agree that + you have read, understood, and will comply with the following terms and + conditions: + </p> + <p> + Permission to use, copy, and modify this software and its documentation, + with or without modification, for any purpose and without fee or + royalty is hereby granted, provided that you include the following on ALL + copies of the software and documentation or portions thereof, including + modifications, that you make: + </p> + <ol> + <li> + The full text of this NOTICE in a location viewable to users of the + redistributed or derivative work. + </li> + <li> + Any pre-existing intellectual property disclaimers, notices, or terms + and conditions. If none exist, a short notice of the following form + (hypertext is preferred, text is permitted) should be used within the + body of any redistributed or derivative code: "Copyright © + [$date-of-software] <a href="http://www.w3.org/">World Wide Web + Consortium</a>, (<a href="http://www.lcs.mit.edu/">Massachusetts + Institute of Technology</a>, <a href="http://www.inria.fr/">Institut + National de Recherche en Informatique et en Automatique</a>, <a + href="http://www.keio.ac.jp/">Keio University</a>). All Rights + Reserved. http://www.w3.org/Consortium/Legal/" + </li> + <li> + Notice of any changes or modifications to the W3C files, including the + date changes were made. (We recommend you provide URIs to the location + from which the code is derived.) + </li> + </ol> + <p> + THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT + HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS + FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR + DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, + TRADEMARKS OR OTHER RIGHTS. + </p> + <p> + COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR + CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR + DOCUMENTATION. + </p> + <p> + The name and trademarks of copyright holders may NOT be used in + advertising or publicity pertaining to the software without specific, + written prior permission. Title to copyright in this software and any + associated documentation will at all times remain with copyright + holders. + </p> + </body> +</html> diff --git a/bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/traversal/DocumentTraversal.java b/bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/traversal/DocumentTraversal.java new file mode 100644 index 0000000000..dec93312af --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/traversal/DocumentTraversal.java @@ -0,0 +1,101 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ + +package org.w3c.dom.traversal; + +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; + +/** + * <code>DocumentTraversal</code> contains methods that create iterators and + * tree-walkers to traverse a node and its children in document order (depth + * first, pre-order traversal, which is equivalent to the order in which the + * start tags occur in the text representation of the document). In DOMs which + * support the Traversal feature, <code>DocumentTraversal</code> will be + * implemented by the same objects that implement the Document interface. + * <p> + * See also the <a + * href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Traversal-Range-20001113'>Document + * Object Model (DOM) Level 2 Traversal and Range Specification </a>. + * + * @since DOM Level 2 + */ +public interface DocumentTraversal { + /** + * Create a new <code>NodeIterator</code> over the subtree rooted at the + * specified node. + * + * @param rootThe + * node which will be iterated together with its children. The + * iterator is initially positioned just before this node. The + * <code>whatToShow</code> flags and the filter, if any, are + * not considered when setting this position. The root must not + * be <code>null</code>. + * @param whatToShowThis + * flag specifies which node types may appear in the logical + * view of the tree presented by the iterator. See the + * description of <code>NodeFilter</code> for the set of + * possible <code>SHOW_</code> values.These flags can be + * combined using <code>OR</code>. + * @param filterThe + * <code>NodeFilter</code> to be used with this + * <code>TreeWalker</code>, or <code>null</code> to + * indicate no filter. + * @param entityReferenceExpansionThe + * value of this flag determines whether entity reference nodes + * are expanded. + * @return The newly created <code>NodeIterator</code>. + * @exception DOMException + * NOT_SUPPORTED_ERR: Raised if the specified + * <code>root</code> is <code>null</code>. + */ + public NodeIterator createNodeIterator(Node root, int whatToShow, NodeFilter filter, boolean entityReferenceExpansion) throws DOMException; + + /** + * Create a new <code>TreeWalker</code> over the subtree rooted at the + * specified node. + * + * @param rootThe + * node which will serve as the <code>root</code> for the + * <code>TreeWalker</code>. The <code>whatToShow</code> + * flags and the <code>NodeFilter</code> are not considered + * when setting this value; any node type will be accepted as + * the <code>root</code>. The <code>currentNode</code> of + * the <code>TreeWalker</code> is initialized to this node, + * whether or not it is visible. The <code>root</code> + * functions as a stopping point for traversal methods that + * look upward in the document structure, such as + * <code>parentNode</code> and nextNode. The + * <code>root</code> must not be <code>null</code>. + * @param whatToShowThis + * flag specifies which node types may appear in the logical + * view of the tree presented by the tree-walker. See the + * description of <code>NodeFilter</code> for the set of + * possible SHOW_ values.These flags can be combined using + * <code>OR</code>. + * @param filterThe + * <code>NodeFilter</code> to be used with this + * <code>TreeWalker</code>, or <code>null</code> to + * indicate no filter. + * @param entityReferenceExpansionIf + * this flag is false, the contents of + * <code>EntityReference</code> nodes are not presented in + * the logical view. + * @return The newly created <code>TreeWalker</code>. + * @exception DOMException + * NOT_SUPPORTED_ERR: Raised if the specified + * <code>root</code> is <code>null</code>. + */ + public TreeWalker createTreeWalker(Node root, int whatToShow, NodeFilter filter, boolean entityReferenceExpansion) throws DOMException; + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/traversal/NodeFilter.java b/bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/traversal/NodeFilter.java new file mode 100644 index 0000000000..48c746a1bd --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/traversal/NodeFilter.java @@ -0,0 +1,151 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ + +package org.w3c.dom.traversal; + +import org.w3c.dom.Node; + +/** + * Filters are objects that know how to "filter out" nodes. If a + * <code>NodeIterator</code> or <code>TreeWalker</code> is given a + * <code>NodeFilter</code>, it applies the filter before it returns the + * next node. If the filter says to accept the node, the traversal logic + * returns it; otherwise, traversal looks for the next node and pretends that + * the node that was rejected was not there. + * <p> + * The DOM does not provide any filters. <code>NodeFilter</code> is just an + * interface that users can implement to provide their own filters. + * <p> + * <code>NodeFilters</code> do not need to know how to traverse from node to + * node, nor do they need to know anything about the data structure that is + * being traversed. This makes it very easy to write filters, since the only + * thing they have to know how to do is evaluate a single node. One filter may + * be used with a number of different kinds of traversals, encouraging code + * reuse. + * <p> + * See also the <a + * href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Traversal-Range-20001113'>Document + * Object Model (DOM) Level 2 Traversal and Range Specification </a>. + * + * @since DOM Level 2 + */ +public interface NodeFilter { + // Constants returned by acceptNode + /** + * Accept the node. Navigation methods defined for + * <code>NodeIterator</code> or <code>TreeWalker</code> will return + * this node. + */ + public static final short FILTER_ACCEPT = 1; + /** + * Reject the node. Navigation methods defined for + * <code>NodeIterator</code> or <code>TreeWalker</code> will not + * return this node. For <code>TreeWalker</code>, the children of this + * node will also be rejected. <code>NodeIterators</code> treat this as + * a synonym for <code>FILTER_SKIP</code>. + */ + public static final short FILTER_REJECT = 2; + /** + * Skip this single node. Navigation methods defined for + * <code>NodeIterator</code> or <code>TreeWalker</code> will not + * return this node. For both <code>NodeIterator</code> and + * <code>TreeWalker</code>, the children of this node will still be + * considered. + */ + public static final short FILTER_SKIP = 3; + + // Constants for whatToShow + /** + * Show all <code>Nodes</code>. + */ + public static final int SHOW_ALL = 0xFFFFFFFF; + /** + * Show <code>Element</code> nodes. + */ + public static final int SHOW_ELEMENT = 0x00000001; + /** + * Show <code>Attr</code> nodes. This is meaningful only when creating + * an iterator or tree-walker with an attribute node as its + * <code>root</code>; in this case, it means that the attribute node + * will appear in the first position of the iteration or traversal. Since + * attributes are never children of other nodes, they do not appear when + * traversing over the document tree. + */ + public static final int SHOW_ATTRIBUTE = 0x00000002; + /** + * Show <code>Text</code> nodes. + */ + public static final int SHOW_TEXT = 0x00000004; + /** + * Show <code>CDATASection</code> nodes. + */ + public static final int SHOW_CDATA_SECTION = 0x00000008; + /** + * Show <code>EntityReference</code> nodes. + */ + public static final int SHOW_ENTITY_REFERENCE = 0x00000010; + /** + * Show <code>Entity</code> nodes. This is meaningful only when creating + * an iterator or tree-walker with an <code> Entity</code> node as its + * <code>root</code>; in this case, it means that the + * <code>Entity</code> node will appear in the first position of the + * traversal. Since entities are not part of the document tree, they do + * not appear when traversing over the document tree. + */ + public static final int SHOW_ENTITY = 0x00000020; + /** + * Show <code>ProcessingInstruction</code> nodes. + */ + public static final int SHOW_PROCESSING_INSTRUCTION = 0x00000040; + /** + * Show <code>Comment</code> nodes. + */ + public static final int SHOW_COMMENT = 0x00000080; + /** + * Show <code>Document</code> nodes. + */ + public static final int SHOW_DOCUMENT = 0x00000100; + /** + * Show <code>DocumentType</code> nodes. + */ + public static final int SHOW_DOCUMENT_TYPE = 0x00000200; + /** + * Show <code>DocumentFragment</code> nodes. + */ + public static final int SHOW_DOCUMENT_FRAGMENT = 0x00000400; + /** + * Show <code>Notation</code> nodes. This is meaningful only when + * creating an iterator or tree-walker with a <code>Notation</code> node + * as its <code>root</code>; in this case, it means that the + * <code>Notation</code> node will appear in the first position of the + * traversal. Since notations are not part of the document tree, they do + * not appear when traversing over the document tree. + */ + public static final int SHOW_NOTATION = 0x00000800; + + /** + * Test whether a specified node is visible in the logical view of a + * <code>TreeWalker</code> or <code>NodeIterator</code>. This + * function will be called by the implementation of + * <code>TreeWalker</code> and <code>NodeIterator</code>; it is not + * normally called directly from user code. (Though you could do so if you + * wanted to use the same filter to guide your own application logic.) + * + * @param nThe + * node to check to see if it passes the filter or not. + * @return a constant to determine whether the node is accepted, rejected, + * or skipped, as defined above. + */ + public short acceptNode(Node n); + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/traversal/NodeIterator.java b/bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/traversal/NodeIterator.java new file mode 100644 index 0000000000..b34a39c8e2 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/traversal/NodeIterator.java @@ -0,0 +1,113 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ + +package org.w3c.dom.traversal; + +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; + +/** + * <code>Iterators</code> are used to step through a set of nodes, e.g. the + * set of nodes in a <code>NodeList</code>, the document subtree governed + * by a particular <code>Node</code>, the results of a query, or any other + * set of nodes. The set of nodes to be iterated is determined by the + * implementation of the <code>NodeIterator</code>. DOM Level 2 specifies a + * single <code>NodeIterator</code> implementation for document-order + * traversal of a document subtree. Instances of these iterators are created + * by calling <code>DocumentTraversal</code> + * <code>.createNodeIterator()</code>. + * <p> + * See also the <a + * href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Traversal-Range-20001113'>Document + * Object Model (DOM) Level 2 Traversal and Range Specification </a>. + * + * @since DOM Level 2 + */ +public interface NodeIterator { + /** + * The root node of the <code>NodeIterator</code>, as specified when it + * was created. + */ + public Node getRoot(); + + /** + * This attribute determines which node types are presented via the + * iterator. The available set of constants is defined in the + * <code>NodeFilter</code> interface. Nodes not accepted by + * <code>whatToShow</code> will be skipped, but their children may still + * be considered. Note that this skip takes precedence over the filter, if + * any. + */ + public int getWhatToShow(); + + /** + * The <code>NodeFilter</code> used to screen nodes. + */ + public NodeFilter getFilter(); + + /** + * The value of this flag determines whether the children of entity + * reference nodes are visible to the iterator. If false, they and their + * descendants will be rejected. Note that this rejection takes precedence + * over <code>whatToShow</code> and the filter. Also note that this is + * currently the only situation where <code>NodeIterators</code> may + * reject a complete subtree rather than skipping individual nodes. <br> + * <br> + * To produce a view of the document that has entity references expanded + * and does not expose the entity reference node itself, use the + * <code>whatToShow</code> flags to hide the entity reference node and + * set <code>expandEntityReferences</code> to true when creating the + * iterator. To produce a view of the document that has entity reference + * nodes but no entity expansion, use the <code>whatToShow</code> flags + * to show the entity reference node and set + * <code>expandEntityReferences</code> to false. + */ + public boolean getExpandEntityReferences(); + + /** + * Returns the next node in the set and advances the position of the + * iterator in the set. After a <code>NodeIterator</code> is created, + * the first call to <code>nextNode()</code> returns the first node in + * the set. + * + * @return The next <code>Node</code> in the set being iterated over, or + * <code>null</code> if there are no more members in that set. + * @exception DOMException + * INVALID_STATE_ERR: Raised if this method is called after + * the <code>detach</code> method was invoked. + */ + public Node nextNode() throws DOMException; + + /** + * Returns the previous node in the set and moves the position of the + * <code>NodeIterator</code> backwards in the set. + * + * @return The previous <code>Node</code> in the set being iterated + * over, or <code>null</code> if there are no more members in + * that set. + * @exception DOMException + * INVALID_STATE_ERR: Raised if this method is called after + * the <code>detach</code> method was invoked. + */ + public Node previousNode() throws DOMException; + + /** + * Detaches the <code>NodeIterator</code> from the set which it iterated + * over, releasing any computational resources and placing the iterator in + * the INVALID state. After <code>detach</code> has been invoked, calls + * to <code>nextNode</code> or <code>previousNode</code> will raise + * the exception INVALID_STATE_ERR. + */ + public void detach(); + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/traversal/TreeWalker.java b/bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/traversal/TreeWalker.java new file mode 100644 index 0000000000..3747d603be --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/traversal/TreeWalker.java @@ -0,0 +1,185 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ + +package org.w3c.dom.traversal; + +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; + +/** + * <code>TreeWalker</code> objects are used to navigate a document tree or + * subtree using the view of the document defined by their + * <code>whatToShow</code> flags and filter (if any). Any function which + * performs navigation using a <code>TreeWalker</code> will automatically + * support any view defined by a <code>TreeWalker</code>. + * <p> + * Omitting nodes from the logical view of a subtree can result in a structure + * that is substantially different from the same subtree in the complete, + * unfiltered document. Nodes that are siblings in the <code>TreeWalker</code> + * view may be children of different, widely separated nodes in the original + * view. For instance, consider a <code>NodeFilter</code> that skips all + * nodes except for Text nodes and the root node of a document. In the logical + * view that results, all text nodes will be siblings and appear as direct + * children of the root node, no matter how deeply nested the structure of the + * original document. + * <p> + * See also the <a + * href='http://www.w3.org/TR/2000/REC-DOM-Level-2-Traversal-Range-20001113'>Document + * Object Model (DOM) Level 2 Traversal and Range Specification </a>. + * + * @since DOM Level 2 + */ +public interface TreeWalker { + /** + * The <code>root</code> node of the <code>TreeWalker</code>, as + * specified when it was created. + */ + public Node getRoot(); + + /** + * This attribute determines which node types are presented via the + * <code>TreeWalker</code>. The available set of constants is defined + * in the <code>NodeFilter</code> interface. Nodes not accepted by + * <code>whatToShow</code> will be skipped, but their children may still + * be considered. Note that this skip takes precedence over the filter, if + * any. + */ + public int getWhatToShow(); + + /** + * The filter used to screen nodes. + */ + public NodeFilter getFilter(); + + /** + * The value of this flag determines whether the children of entity + * reference nodes are visible to the <code>TreeWalker</code>. If + * false, they and their descendants will be rejected. Note that this + * rejection takes precedence over <code>whatToShow</code> and the + * filter, if any. <br> + * To produce a view of the document that has entity references expanded + * and does not expose the entity reference node itself, use the + * <code>whatToShow</code> flags to hide the entity reference node and + * set <code>expandEntityReferences</code> to true when creating the + * <code>TreeWalker</code>. To produce a view of the document that has + * entity reference nodes but no entity expansion, use the + * <code>whatToShow</code> flags to show the entity reference node and + * set <code>expandEntityReferences</code> to false. + */ + public boolean getExpandEntityReferences(); + + /** + * The node at which the <code>TreeWalker</code> is currently + * positioned. <br> + * Alterations to the DOM tree may cause the current node to no longer be + * accepted by the <code>TreeWalker</code>'s associated filter. + * <code>currentNode</code> may also be explicitly set to any node, + * whether or not it is within the subtree specified by the + * <code>root</code> node or would be accepted by the filter and + * <code>whatToShow</code> flags. Further traversal occurs relative to + * <code>currentNode</code> even if it is not part of the current view, + * by applying the filters in the requested direction; if no traversal is + * possible, <code>currentNode</code> is not changed. + * + * @exception DOMException + * NOT_SUPPORTED_ERR: Raised if an attempt is made to set + * <code>currentNode</code> to <code>null</code>. + */ + public Node getCurrentNode(); + + public void setCurrentNode(Node currentNode) throws DOMException; + + /** + * Moves to and returns the closest visible ancestor node of the current + * node. If the search for <code>parentNode</code> attempts to step + * upward from the <code>TreeWalker</code>'s<code>root</code> node, + * or if it fails to find a visible ancestor node, this method retains the + * current position and returns <code>null</code>. + * + * @return The new parent node, or <code>null</code> if the current node + * has no parent in the <code>TreeWalker</code>'s logical view. + */ + public Node parentNode(); + + /** + * Moves the <code>TreeWalker</code> to the first visible child of the + * current node, and returns the new node. If the current node has no + * visible children, returns <code>null</code>, and retains the current + * node. + * + * @return The new node, or <code>null</code> if the current node has no + * visible children in the <code>TreeWalker</code>'s logical + * view. + */ + public Node firstChild(); + + /** + * Moves the <code>TreeWalker</code> to the last visible child of the + * current node, and returns the new node. If the current node has no + * visible children, returns <code>null</code>, and retains the current + * node. + * + * @return The new node, or <code>null</code> if the current node has no + * children in the <code>TreeWalker</code>'s logical view. + */ + public Node lastChild(); + + /** + * Moves the <code>TreeWalker</code> to the previous sibling of the + * current node, and returns the new node. If the current node has no + * visible previous sibling, returns <code>null</code>, and retains the + * current node. + * + * @return The new node, or <code>null</code> if the current node has no + * previous sibling. in the <code>TreeWalker</code>'s logical + * view. + */ + public Node previousSibling(); + + /** + * Moves the <code>TreeWalker</code> to the next sibling of the current + * node, and returns the new node. If the current node has no visible next + * sibling, returns <code>null</code>, and retains the current node. + * + * @return The new node, or <code>null</code> if the current node has no + * next sibling. in the <code>TreeWalker</code>'s logical view. + */ + public Node nextSibling(); + + /** + * Moves the <code>TreeWalker</code> to the previous visible node in + * document order relative to the current node, and returns the new node. + * If the current node has no previous node, or if the search for + * <code>previousNode</code> attempts to step upward from the + * <code>TreeWalker</code>'s<code>root</code> node, returns + * <code>null</code>, and retains the current node. + * + * @return The new node, or <code>null</code> if the current node has no + * previous node in the <code>TreeWalker</code>'s logical view. + */ + public Node previousNode(); + + /** + * Moves the <code>TreeWalker</code> to the next visible node in + * document order relative to the current node, and returns the new node. + * If the current node has no next node, or if the search for nextNode + * attempts to step upward from the <code>TreeWalker</code>'s + * <code>root</code> node, returns <code>null</code>, and retains the + * current node. + * + * @return The new node, or <code>null</code> if the current node has no + * next node in the <code>TreeWalker</code>'s logical view. + */ + public Node nextNode(); + +} diff --git a/bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/traversal/package.html b/bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/traversal/package.html new file mode 100644 index 0000000000..d8fbae65d9 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.core/src/org/w3c/dom/traversal/package.html @@ -0,0 +1,3 @@ +<html> +This package contains unmodified sources provided by http://www.w3.org/TR/2000/REC-DOM-Level-2-Traversal-Range-20001113/java-binding.zip +</html>
\ No newline at end of file diff --git a/bundles/org.eclipse.wst.xml.ui/.classpath b/bundles/org.eclipse.wst.xml.ui/.classpath new file mode 100644 index 0000000000..c5a45758cf --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/.classpath @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" path="src/"/> + <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> + <classpathentry kind="src" path="src-multipage"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/bundles/org.eclipse.wst.xml.ui/.compatibility b/bundles/org.eclipse.wst.xml.ui/.compatibility new file mode 100644 index 0000000000..2e4834a775 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/.compatibility @@ -0,0 +1,2 @@ +#Wed Mar 24 13:53:52 EST 2004
+.project=6269
diff --git a/bundles/org.eclipse.wst.xml.ui/.cvsignore b/bundles/org.eclipse.wst.xml.ui/.cvsignore new file mode 100644 index 0000000000..c244b73b57 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/.cvsignore @@ -0,0 +1,7 @@ +bin +temp.folder +xmleditor.jar +.project +org.eclipse.wst.xml.ui_6.0.0.jar +dev.properties +build.xml diff --git a/bundles/org.eclipse.wst.xml.ui/build.properties b/bundles/org.eclipse.wst.xml.ui/build.properties new file mode 100644 index 0000000000..9372072cea --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/build.properties @@ -0,0 +1,24 @@ +############################################################################### +# Copyright (c) 2001, 2004 IBM Corporation and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# IBM Corporation - initial API and implementation +# Jens Lukowski/Innoopract - initial renaming/restructuring +# +############################################################################### +bin.includes = plugin.xml,\ + *.jar,\ + xml.jar,\ + icons/,\ + plugin.properties,\ + templates/ +source.xmleditor.jar = src/ +src.includes = plugin.xml,\ + plugin.properties,\ + icons/,\ + build.xml,\ + templates/ diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/dtool16/collapse.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/dtool16/collapse.gif Binary files differnew file mode 100644 index 0000000000..ce74721ea2 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/dtool16/collapse.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/dtool16/collapse_all.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/dtool16/collapse_all.gif Binary files differnew file mode 100644 index 0000000000..7dc0de5130 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/dtool16/collapse_all.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/dtool16/constrainoff.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/dtool16/constrainoff.gif Binary files differnew file mode 100644 index 0000000000..4bdceb84e9 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/dtool16/constrainoff.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/dtool16/constrainon.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/dtool16/constrainon.gif Binary files differnew file mode 100644 index 0000000000..e823d572a3 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/dtool16/constrainon.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/dtool16/expand.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/dtool16/expand.gif Binary files differnew file mode 100644 index 0000000000..bc37b7a4e5 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/dtool16/expand.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/dtool16/expand_all.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/dtool16/expand_all.gif Binary files differnew file mode 100644 index 0000000000..492c14f6e1 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/dtool16/expand_all.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/dtool16/new_xml.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/dtool16/new_xml.gif Binary files differnew file mode 100644 index 0000000000..e1cfdf7eb3 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/dtool16/new_xml.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/dtool16/rldgrmr.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/dtool16/rldgrmr.gif Binary files differnew file mode 100644 index 0000000000..49325dd8ea --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/dtool16/rldgrmr.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/dtool16/validate.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/dtool16/validate.gif Binary files differnew file mode 100644 index 0000000000..561d1463ef --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/dtool16/validate.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/etool16/collapse.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/etool16/collapse.gif Binary files differnew file mode 100644 index 0000000000..b75bc19602 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/etool16/collapse.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/etool16/collapse_all.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/etool16/collapse_all.gif Binary files differnew file mode 100644 index 0000000000..a2d80a9044 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/etool16/collapse_all.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/etool16/constrainoff.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/etool16/constrainoff.gif Binary files differnew file mode 100644 index 0000000000..c1ab04c81c --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/etool16/constrainoff.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/etool16/constrainon.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/etool16/constrainon.gif Binary files differnew file mode 100644 index 0000000000..082f9c0ae8 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/etool16/constrainon.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/etool16/expand.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/etool16/expand.gif Binary files differnew file mode 100644 index 0000000000..b2f45306c9 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/etool16/expand.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/etool16/expand_all.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/etool16/expand_all.gif Binary files differnew file mode 100644 index 0000000000..0205b29176 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/etool16/expand_all.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/etool16/new_xml.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/etool16/new_xml.gif Binary files differnew file mode 100644 index 0000000000..9dfb62d35b --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/etool16/new_xml.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/etool16/rldgrmr.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/etool16/rldgrmr.gif Binary files differnew file mode 100644 index 0000000000..049cac696c --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/etool16/rldgrmr.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/etool16/validate.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/etool16/validate.gif Binary files differnew file mode 100644 index 0000000000..2b347ac458 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/etool16/validate.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/XSDFile.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/XSDFile.gif Binary files differnew file mode 100644 index 0000000000..cc0eeb7196 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/XSDFile.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/add_correction.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/add_correction.gif Binary files differnew file mode 100644 index 0000000000..252d7ebcb8 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/add_correction.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/att_req_obj.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/att_req_obj.gif Binary files differnew file mode 100644 index 0000000000..a8c66d5016 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/att_req_obj.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/attribute_obj.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/attribute_obj.gif Binary files differnew file mode 100644 index 0000000000..79d49d037b --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/attribute_obj.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/cdatasection.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/cdatasection.gif Binary files differnew file mode 100644 index 0000000000..6b0872c909 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/cdatasection.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/choice.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/choice.gif Binary files differnew file mode 100644 index 0000000000..d13ba2e5b0 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/choice.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/comment_obj.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/comment_obj.gif Binary files differnew file mode 100644 index 0000000000..28c2ccb1e7 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/comment_obj.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/correction_change.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/correction_change.gif Binary files differnew file mode 100644 index 0000000000..af83c528dd --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/correction_change.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/doctype.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/doctype.gif Binary files differnew file mode 100644 index 0000000000..3300f82862 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/doctype.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/dtdfile.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/dtdfile.gif Binary files differnew file mode 100644 index 0000000000..3c0acadd2d --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/dtdfile.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/element_obj.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/element_obj.gif Binary files differnew file mode 100644 index 0000000000..3567815907 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/element_obj.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/entity.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/entity.gif Binary files differnew file mode 100644 index 0000000000..61fd3d4caa --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/entity.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/entity_reference.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/entity_reference.gif Binary files differnew file mode 100644 index 0000000000..3af9149125 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/entity_reference.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/enum.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/enum.gif Binary files differnew file mode 100644 index 0000000000..5c0a48115b --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/enum.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/error-overlay.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/error-overlay.gif Binary files differnew file mode 100644 index 0000000000..119dcccd5a --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/error-overlay.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/localvariable_obj.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/localvariable_obj.gif Binary files differnew file mode 100644 index 0000000000..3244b26ef4 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/localvariable_obj.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/notation.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/notation.gif Binary files differnew file mode 100644 index 0000000000..57ad089a69 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/notation.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/occurone_obj.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/occurone_obj.gif Binary files differnew file mode 100644 index 0000000000..7bb65c9d51 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/occurone_obj.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/proinst_obj.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/proinst_obj.gif Binary files differnew file mode 100644 index 0000000000..74436d8d3c --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/proinst_obj.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/tag-generic.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/tag-generic.gif Binary files differnew file mode 100644 index 0000000000..65f516e80a --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/tag-generic.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/tag-macro.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/tag-macro.gif Binary files differnew file mode 100644 index 0000000000..5d1f81b6d4 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/tag-macro.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/text.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/text.gif Binary files differnew file mode 100644 index 0000000000..efa7a38014 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/text.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/txtext.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/txtext.gif Binary files differnew file mode 100644 index 0000000000..b226e41c52 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/txtext.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/warning_obj.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/warning_obj.gif Binary files differnew file mode 100644 index 0000000000..1e5f5eb367 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/obj16/warning_obj.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/ovr16/error_ovr.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/ovr16/error_ovr.gif Binary files differnew file mode 100644 index 0000000000..119dcccd5a --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/ovr16/error_ovr.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/ovr16/stale_error_ovr.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/ovr16/stale_error_ovr.gif Binary files differnew file mode 100644 index 0000000000..5b0471b5eb --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/ovr16/stale_error_ovr.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/ovr16/warn_ovr.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/ovr16/warn_ovr.gif Binary files differnew file mode 100644 index 0000000000..c350704fa1 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/ovr16/warn_ovr.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/full/view16/attibute.gif b/bundles/org.eclipse.wst.xml.ui/icons/full/view16/attibute.gif Binary files differnew file mode 100644 index 0000000000..79d49d037b --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/full/view16/attibute.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/sourceEditor.gif b/bundles/org.eclipse.wst.xml.ui/icons/sourceEditor.gif Binary files differnew file mode 100644 index 0000000000..75ebdb8586 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/sourceEditor.gif diff --git a/bundles/org.eclipse.wst.xml.ui/icons/xmldoc.gif b/bundles/org.eclipse.wst.xml.ui/icons/xmldoc.gif Binary files differnew file mode 100644 index 0000000000..14eb1be095 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/icons/xmldoc.gif diff --git a/bundles/org.eclipse.wst.xml.ui/plugin.properties b/bundles/org.eclipse.wst.xml.ui/plugin.properties new file mode 100644 index 0000000000..1ad158bcac --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/plugin.properties @@ -0,0 +1,40 @@ +############################################################################### +# Copyright (c) 2001, 2004 IBM Corporation and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# IBM Corporation - initial API and implementation +# Jens Lukowski/Innoopract - initial renaming/restructuring +# +############################################################################### +SSE_XML_Source_Editor.name=SSE XML Source Editor +SSE_XML_Source_Editor_NL_Support.name=SSE XML Source Editor NL Support +XML_Source_Page_Editor.name=XML Source Page Editor +XML_Files.name=XML Files +XML_Source.name=XML Source +XML_Templates.name=XML Templates +XML_Styles.name=XML Styles +XML_Annotations.name=XML Annotations +############################################################################### +SSE_XML_Editor.name=SSE XML Editor +SSE_XML_Editor_NL_Support.name=SSE XML Editor NL Support +XML_Editor.name=XML Editor +############################################################################### +XMLTableTreeViewer.0=Design +XMLMultiPageEditorPart.0=Source +XMLTreeExtension.0=Structure +XMLTreeExtension.1=Value +XMLTreeExtension.3=The document is empty. +XMLTreeExtension.4=Right mouse click here to insert content. +XMLTableTreeActionBarContributor.0=&XML +XMLTableTreeActionBarContributor.1=&Expand All +XMLTableTreeActionBarContributor.2=&Collapse All +XMLTableTreeActionBarContributor.3=Turn Grammar Constraints Off +XMLTableTreeActionBarContributor.4=&Turn Grammar Constraints Off +XMLTableTreeActionBarContributor.5=Turn Grammar Constraints On +XMLTableTreeActionBarContributor.6=&Turn Grammar Constraints On +XMLTableTreeActionBarContributor.7=Reload Dependencies +XMLTableTreeActionBarContributor.8=&Reload Dependencies
\ No newline at end of file diff --git a/bundles/org.eclipse.wst.xml.ui/plugin.xml b/bundles/org.eclipse.wst.xml.ui/plugin.xml new file mode 100644 index 0000000000..38f7fe765c --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/plugin.xml @@ -0,0 +1,248 @@ +<?xml version="1.0" encoding="UTF-8"?> +<?eclipse version="3.0"?> +<plugin + id="org.eclipse.wst.xml.ui" + name="%SSE_XML_Source_Editor.name" + version="1.0.0" + provider-name="IBM" + class="org.eclipse.wst.xml.ui.XMLEditorPlugin"> + + <runtime> + <library name="xmleditor.jar"> + <export name="*"/> + </library> + </runtime> + <requires> + <import plugin="org.eclipse.core.runtime.compatibility"/> + <import plugin="org.eclipse.ui.ide"/> + <import plugin="org.eclipse.ui.views"/> + <import plugin="org.eclipse.jface.text"/> + <import plugin="org.eclipse.ui.workbench.texteditor"/> + <import plugin="org.eclipse.ui.editors"/> + <import plugin="org.eclipse.wst.sse.ui"/> + <import plugin="org.eclipse.wst.dtd.ui"/> + <import plugin="org.eclipse.wst.sse.core"/> + <import plugin="org.eclipse.ui"/> + <import plugin="org.eclipse.wst.common.contentmodel"/> + <import plugin="org.eclipse.core.resources"/> + <import plugin="org.eclipse.core.runtime"/> + <import plugin="org.eclipse.wst.common.encoding"/> + <import plugin="org.eclipse.wst.xml.uriresolver.ui"/> + <import plugin="org.eclipse.wst.uriresolver"/> + <import plugin="org.eclipse.wst.xml.uriresolver"/> + <import plugin="org.eclipse.wst.xml.core"/> + <import plugin="org.eclipse.wst.ui"/> + </requires> + + + <extension + point="org.eclipse.ui.editors"> + <editor + name="%XML_Source_Page_Editor.name" + icon="icons/sourceEditor.gif" + extensions="tld, nst, xmi, dadx, wsdl" + contributorClass="org.eclipse.wst.xml.ui.actions.ActionContributorXML" + class="org.eclipse.wst.xml.ui.StructuredTextEditorXML" + symbolicFontName="org.eclipse.wst.sse.ui.textfont" + id="org.eclipse.wst.xml.ui.StructuredTextEditorXML2"> + </editor> + <!-- Separate editor definition for xml source page to mark it as the default editor --> + <editor + name="%XML_Source_Page_Editor.name" + icon="icons/sourceEditor.gif" + extensions="xml" + default="true" + contributorClass="org.eclipse.wst.xml.ui.actions.ActionContributorXML" + class="org.eclipse.wst.xml.ui.StructuredTextEditorXML" + symbolicFontName="org.eclipse.wst.sse.ui.textfont" + id="org.eclipse.wst.xml.ui.StructuredTextEditorXML"> + </editor> + </extension> + <extension + point="org.eclipse.wst.sse.ui.extendedconfiguration"> + <textviewerconfiguration + class="org.eclipse.wst.xml.ui.StructuredTextViewerConfigurationXML" + target="org.eclipse.wst.xml.core.xmlsource"> + </textviewerconfiguration> + <contentoutlineconfiguration + class="org.eclipse.wst.xml.ui.views.contentoutline.XMLContentOutlineConfiguration" + target="org.eclipse.wst.xml.core.xmlsource"> + </contentoutlineconfiguration> + <propertysheetconfiguration + class="org.eclipse.wst.xml.ui.views.properties.XMLPropertySheetConfiguration" + target="org.eclipse.wst.xml.core.xmlsource"> + </propertysheetconfiguration> + <spellchecktarget + class="org.eclipse.wst.xml.ui.XMLSpellCheckTarget" + target="org.eclipse.wst.xml.core.xmlsource"> + </spellchecktarget> + <sourceeditingtexttools + class="org.eclipse.wst.xml.ui.extensions.XMLSourceEditingTextTools" + target="org.eclipse.wst.xml.core.xmlsource"> + </sourceeditingtexttools> + <characterpairmatcher + class="org.eclipse.wst.xml.ui.text.XMLDocumentRegionEdgeMatcher" + target="org.eclipse.wst.xml.core.xmlsource"> + </characterpairmatcher> + <preferencepages + preferenceids="org.eclipse.wst.sse.ui.preferences/org.eclipse.wst.sse.ui.preferences.xml" + target="org.eclipse.wst.xml.core.xmlsource"> + </preferencepages> + </extension> + <extension + point="org.eclipse.core.filebuffers.annotationModelCreation"> + <factory + contentTypeId="org.eclipse.wst.xml.core.xmlsource" + class="org.eclipse.wst.sse.ui.StructuredResourceMarkerAnnotationModelFactory"/> + </extension> + <extension + point="org.eclipse.wst.sse.ui.adapterFactoryDescription"> + <adapterFactoryDescription + class="org.eclipse.wst.xml.ui.registry.AdapterFactoryProviderForXML"> + <contentType id="org.eclipse.wst.xml.core.xmlsource"/> + </adapterFactoryDescription> + </extension> + <extension + point="org.eclipse.wst.sse.ui.embeddedAdapterFactoryProvider"> + <embeddedAdapterFactoryProvider + class="org.eclipse.wst.xml.ui.registry.AdapterFactoryProviderForEmbeddedXML"> + </embeddedAdapterFactoryProvider> + </extension> + <extension + point="org.eclipse.ui.preferencePages"> +<!-- XML PREFERENCE PAGES --> + <page + name="%XML_Files.name" + category="org.eclipse.wst.sse.ui.preferences" + class="org.eclipse.wst.xml.ui.preferences.XMLFilesPreferencePage" + id="org.eclipse.wst.sse.ui.preferences.xml"> + </page> + <page + name="%XML_Source.name" + category="org.eclipse.wst.sse.ui.preferences.xml" + class="org.eclipse.wst.xml.ui.preferences.XMLSourcePreferencePage" + id="org.eclipse.wst.sse.ui.preferences.xml.source"> + </page> + <page + name="%XML_Templates.name" + category="org.eclipse.wst.sse.ui.preferences.xml" + class="org.eclipse.wst.xml.ui.preferences.XMLTemplatePreferencePage" + id="org.eclipse.wst.sse.ui.preferences.xml.templates"> + </page> + <page + name="%XML_Styles.name" + category="org.eclipse.wst.sse.ui.preferences.xml" + class="org.eclipse.wst.xml.ui.preferences.XMLColorPage" + id="org.eclipse.wst.sse.ui.preferences.xml.colors"> + </page> + </extension> +<!-- Editor actionsets --> + <extension + point="org.eclipse.ui.actionSetPartAssociations"> + <actionSetPartAssociation + targetID="org.eclipse.ui.edit.text.actionSet.annotationNavigation"> + <part + id="org.eclipse.wst.xml.ui.StructuredTextEditorXML"> + </part> + <part + id="org.eclipse.wst.xml.ui.StructuredTextEditorXML2"> + </part> + </actionSetPartAssociation> + <actionSetPartAssociation + targetID="org.eclipse.ui.NavigateActionSet"> + <part + id="org.eclipse.wst.xml.ui.StructuredTextEditorXML"> + </part> + <part + id="org.eclipse.wst.xml.ui.StructuredTextEditorXML2"> + </part> + </actionSetPartAssociation> + </extension> + <extension + point="org.eclipse.ui.perspectiveExtensions"> +<!-- added to enable "Navigator > Show In" for various views... --> + <perspectiveExtension + targetID="com.ibm.etools.xml.tools.XMLPerspective"> + <showInPart + id="org.eclipse.ui.views.ResourceNavigator"> + </showInPart> +<!-- add the "navigate" action set (Navigate > Open Resource...) --> + <actionSet + id="org.eclipse.ui.NavigateActionSet"> + </actionSet> + </perspectiveExtension> + </extension> +<!-- add a default open on action for xml content type --> + <extension + point="org.eclipse.wst.sse.ui.openon"> + <openon + class="org.eclipse.wst.xml.ui.openon.DefaultOpenOnXML" + id="org.eclipse.wst.xml.ui.openon.DefaultOpenOnXML"> + <contenttypeidentifier + id="org.eclipse.wst.xml.core.xmlsource"> + </contenttypeidentifier> + </openon> + </extension> +<!-- Templates --> + <extension + point="org.eclipse.ui.editors.templates"> + <contextType + name="All XML context type" + class="org.eclipse.wst.xml.ui.templates.TemplateContextTypeXML" + id="xml_all"> + </contextType> + <contextType + name="XML Tag context type" + class="org.eclipse.wst.xml.ui.templates.TemplateContextTypeXMLTag" + id="xml_tag"> + </contextType> + <contextType + name="XML Attribute context type" + class="org.eclipse.wst.xml.ui.templates.TemplateContextTypeXMLAttribute" + id="xml_attribute"> + </contextType> + <contextType + name="XML Attribute value context type" + class="org.eclipse.wst.xml.ui.templates.TemplateContextTypeXMLAttributeValue" + id="xml_attribute_value"> + </contextType> + <include + file="templates/xmldefault-templates.xml" + translations="templates/xmldefault-templates.properties"> + </include> + </extension> + + + + + + <extension + point="org.eclipse.ui.editors"> + <editor + name="%XML_Editor.name" + icon="icons/xmldoc.gif" + extensions="xml, tld, nst, xmi" + contributorClass="org.eclipse.wst.xml.internal.ui.XMLMultiPageEditorActionBarContributor" + class="org.eclipse.wst.xml.internal.ui.XMLMultiPageEditorPart" + id="org.eclipse.wst.xml.internal.ui.XMLMultiPageEditorPart"> + </editor> + </extension> +<!-- Editor actionsets --> + <extension + point="org.eclipse.ui.actionSetPartAssociations"> + <actionSetPartAssociation + targetID="org.eclipse.ui.edit.text.actionSet.annotationNavigation"> + <part + id="org.eclipse.wst.xml.internal.ui.XMLMultiPageEditorPart"> + </part> + </actionSetPartAssociation> + <actionSetPartAssociation + targetID="org.eclipse.ui.NavigateActionSet"> + <part + id="org.eclipse.wst.xml.internal.ui.XMLMultiPageEditorPart"> + </part> + </actionSetPartAssociation> + </extension> + + +</plugin> diff --git a/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/internal/ui/IDesignViewer.java b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/internal/ui/IDesignViewer.java new file mode 100644 index 0000000000..493b8fddcf --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/internal/ui/IDesignViewer.java @@ -0,0 +1,26 @@ +/***************************************************************************** + * Copyright (c) 2004 IBM Corporation and others. All rights reserved. This + * program and the accompanying materials are made available under the terms + * of the Eclipse Public License v1.0 which accompanies this distribution, and + * is available at http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: IBM Corporation - initial API and implementation + ****************************************************************************/ +package org.eclipse.wst.xml.internal.ui; + + + +import org.eclipse.swt.widgets.Control; +import org.eclipse.wst.sse.core.IStructuredModel; +import org.eclipse.wst.sse.ui.ViewerSelectionManager; + + +public interface IDesignViewer { + public Control getControl(); + + String getTitle(); + + void setModel(IStructuredModel model); + + void setViewerSelectionManager(ViewerSelectionManager viewerSelectionManager); +}
\ No newline at end of file diff --git a/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/internal/ui/IDesignViewerActionBarContributor.java b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/internal/ui/IDesignViewerActionBarContributor.java new file mode 100644 index 0000000000..ac191b354b --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/internal/ui/IDesignViewerActionBarContributor.java @@ -0,0 +1,19 @@ +/***************************************************************************** + * Copyright (c) 2004 IBM Corporation and others. All rights reserved. This + * program and the accompanying materials are made available under the terms + * of the Eclipse Public License v1.0 which accompanies this distribution, and + * is available at http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: IBM Corporation - initial API and implementation + ****************************************************************************/ +package org.eclipse.wst.xml.internal.ui; + + + +import org.eclipse.ui.IActionBars; +import org.eclipse.wst.sse.ui.ISourceViewerActionBarContributor; + + +public interface IDesignViewerActionBarContributor extends ISourceViewerActionBarContributor { + public void initViewerSpecificContributions(IActionBars bars); +}
\ No newline at end of file diff --git a/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/internal/ui/SourceEditorActionBarContributor.java b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/internal/ui/SourceEditorActionBarContributor.java new file mode 100644 index 0000000000..bfd080a657 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/internal/ui/SourceEditorActionBarContributor.java @@ -0,0 +1,211 @@ +/***************************************************************************** + * Copyright (c) 2004 IBM Corporation and others. All rights reserved. This + * program and the accompanying materials are made available under the terms + * of the Eclipse Public License v1.0 which accompanies this distribution, and + * is available at http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: IBM Corporation - initial API and implementation + ****************************************************************************/ +package org.eclipse.wst.xml.internal.ui; + +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.IStatusLineManager; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.ui.IActionBars; +import org.eclipse.ui.IEditorActionBarContributor; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.part.EditorActionBarContributor; +import org.eclipse.ui.part.MultiPageEditorActionBarContributor; +import org.eclipse.wst.sse.ui.ISourceViewerActionBarContributor; +import org.eclipse.wst.sse.ui.StructuredTextEditor; +import org.eclipse.wst.sse.ui.extension.ExtendedEditorActionBuilder; +import org.eclipse.wst.sse.ui.extension.IExtendedContributor; + + +public class SourceEditorActionBarContributor extends MultiPageEditorActionBarContributor implements IExtendedContributor { + + protected IEditorActionBarContributor designViewerActionBarContributor = null; + protected IEditorActionBarContributor sourceViewerActionContributor = null; + protected XMLMultiPageEditorPart multiPageEditor = null; + + // EditorExtension + private static final String EDITOR_ID = "org.eclipse.wst.xml.ui.XMLMultiPageEditorPart"; //$NON-NLS-1$ + private IExtendedContributor extendedContributor; + + public SourceEditorActionBarContributor() { + super(); + + sourceViewerActionContributor = new SourcePageActionContributor(); + + // Read action extensions. + ExtendedEditorActionBuilder builder = new ExtendedEditorActionBuilder(); + extendedContributor = builder.readActionExtensions(EDITOR_ID); + } + + public void init(IActionBars actionBars) { + super.init(actionBars); + + if (actionBars != null) { + initDesignViewerActionBarContributor(actionBars); + initSourceViewerActionContributor(actionBars); + } + } + + protected void initDesignViewerActionBarContributor(IActionBars actionBars) { + if (designViewerActionBarContributor != null) + designViewerActionBarContributor.init(actionBars, getPage()); + } + + protected void initSourceViewerActionContributor(IActionBars actionBars) { + if (sourceViewerActionContributor != null) + sourceViewerActionContributor.init(actionBars, getPage()); + } + + public void dispose() { + super.dispose(); + + if (designViewerActionBarContributor != null) + designViewerActionBarContributor.dispose(); + + if (sourceViewerActionContributor != null) + sourceViewerActionContributor.dispose(); + + if (extendedContributor != null) + extendedContributor.dispose(); + } + + /** + * @see EditorActionBarContributor#contributeToMenu(IMenuManager) + */ + public final void contributeToMenu(IMenuManager menu) { + super.contributeToMenu(menu); + + addToMenu(menu); + + if (extendedContributor != null) + extendedContributor.contributeToMenu(menu); + } + + protected void addToMenu(IMenuManager menu) { + } + + /** + * @see IExtendedContributor#contributeToPopupMenu(IMenuManager) + */ + public final void contributeToPopupMenu(IMenuManager menu) { + + addToPopupMenu(menu); + + if (extendedContributor != null) + extendedContributor.contributeToPopupMenu(menu); + } + + protected void addToPopupMenu(IMenuManager menu) { + } + + /** + * @see EditorActionBarContributor#contributeToToolBar(IToolBarManager) + */ + public final void contributeToToolBar(IToolBarManager toolBarManager) { + super.contributeToToolBar(toolBarManager); + + addToToolBar(toolBarManager); + + if (extendedContributor != null) + extendedContributor.contributeToToolBar(toolBarManager); + } + + protected void addToToolBar(IToolBarManager toolBarManager) { + } + + /** + * @see EditorActionBarContributor#contributeToStatusLine(IStatusLineManager) + */ + public final void contributeToStatusLine(IStatusLineManager manager) { + super.contributeToStatusLine(manager); + + addToStatusLine(manager); + + if (extendedContributor != null) + extendedContributor.contributeToStatusLine(manager); + } + + protected void addToStatusLine(IStatusLineManager manager) { + } + + /** + * @see IExtendedContributor#updateToolbarActions() + */ + public void updateToolbarActions() { + if (extendedContributor != null) + extendedContributor.updateToolbarActions(); + } + + public void setActiveEditor(IEditorPart targetEditor) { + // save multiPageEditor before calling + // super.setActiveEditor(targetEditor) + // super.setActiveEditor will call setActivePage(IEditorPart + // activeEditor) + // multiPageEditor is needed in setActivePage(IEditorPart + // activeEditor) + if (targetEditor instanceof XMLMultiPageEditorPart) + multiPageEditor = (XMLMultiPageEditorPart) targetEditor; + + super.setActiveEditor(targetEditor); + + updateToolbarActions(); + + if (extendedContributor != null) + extendedContributor.setActiveEditor(targetEditor); + } + + public void setActivePage(IEditorPart activeEditor) { + // This contributor is designed for StructuredTextMultiPageEditorPart. + // To safe-guard this from problems caused by unexpected usage by + // other editors, the following + // check is added. + if (multiPageEditor != null) { + if (activeEditor != null && activeEditor instanceof StructuredTextEditor) + activateSourcePage(activeEditor); + else + activateDesignPage(activeEditor); + } + + updateToolbarActions(); + + IActionBars actionBars = getActionBars(); + if (actionBars != null) { + // update menu bar and tool bar + actionBars.updateActionBars(); + } + } + + protected void activateDesignPage(IEditorPart activeEditor) { + if (designViewerActionBarContributor != null && designViewerActionBarContributor instanceof IDesignViewerActionBarContributor) { + designViewerActionBarContributor.setActiveEditor(multiPageEditor); + } + + if (sourceViewerActionContributor != null && sourceViewerActionContributor instanceof ISourceViewerActionBarContributor) { + // if design page is not really an IEditorPart, activeEditor == + // null, so pass in multiPageEditor instead (d282414) + if (activeEditor == null) { + sourceViewerActionContributor.setActiveEditor(multiPageEditor); + } else { + sourceViewerActionContributor.setActiveEditor(activeEditor); + } + ((ISourceViewerActionBarContributor) sourceViewerActionContributor).setViewerSpecificContributionsEnabled(false); + } + } + + protected void activateSourcePage(IEditorPart activeEditor) { + if (designViewerActionBarContributor != null && designViewerActionBarContributor instanceof IDesignViewerActionBarContributor) { + designViewerActionBarContributor.setActiveEditor(multiPageEditor); + } + + if (sourceViewerActionContributor != null && sourceViewerActionContributor instanceof ISourceViewerActionBarContributor) { + sourceViewerActionContributor.setActiveEditor(activeEditor); + ((ISourceViewerActionBarContributor) sourceViewerActionContributor).setViewerSpecificContributionsEnabled(true); + } + } + +}
\ No newline at end of file diff --git a/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/internal/ui/SourcePageActionContributor.java b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/internal/ui/SourcePageActionContributor.java new file mode 100644 index 0000000000..949a1557e0 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/internal/ui/SourcePageActionContributor.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.wst.xml.internal.ui; + + + +import org.eclipse.ui.IActionBars; +import org.eclipse.wst.xml.ui.actions.ActionContributorXML; + + +/** + * SourcePageActionContributor + * + * This class is for multi page editor's source page contributor. + * + * Use XMLEditorActionContributor for single page editor. + */ +public class SourcePageActionContributor extends ActionContributorXML { + + private IActionBars fBars; + + /** + * This method calls: + * <ul> + * <li><code>contributeToMenu</code> with <code>bars</code>' menu + * manager</li> + * <li><code>contributeToToolBar</code> with <code>bars</code>' tool + * bar manager</li> + * <li><code>contributeToStatusLine</code> with <code>bars</code>' + * status line manager</li> + * </ul> + * The given action bars are also remembered and made accessible via + * <code>getActionBars</code>. + * + * @param bars + * the action bars + * + */ + public void init(IActionBars bars) { + fBars = bars; + contributeToMenu(bars.getMenuManager()); + contributeToToolBar(bars.getToolBarManager()); + contributeToStatusLine(bars.getStatusLineManager()); + } + + /** + * Returns this contributor's action bars. + * + * @return the action bars + */ + public IActionBars getActionBars() { + return fBars; + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/internal/ui/XMLEditorActionDefinitionIds.java b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/internal/ui/XMLEditorActionDefinitionIds.java new file mode 100644 index 0000000000..391183654b --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/internal/ui/XMLEditorActionDefinitionIds.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.wst.xml.internal.ui; + + + +/** + * Defines the definitions ids for the XML editor actions. + */ +public interface XMLEditorActionDefinitionIds { + public final static String CLEANUP_DOCUMENT = "org.eclipse.wst.sse.ui.edit.ui.cleanup.document";//$NON-NLS-1$ + public final static String FORMAT_DOCUMENT = "org.eclipse.wst.sse.ui.edit.ui.format.document";//$NON-NLS-1$ + public final static String FORMAT_ACTIVE_ELEMENTS = "org.eclipse.wst.sse.ui.edit.ui.format.active.elements";//$NON-NLS-1$ + public final static String OPEN_FILE = "org.eclipse.wst.sse.ui.edit.ui.open.file.from.source";//$NON-NLS-1$ + // public final static String INFORMATION = + // "org.eclipse.wst.sse.ui.edit.ui.show.tooltip.information";//$NON-NLS-1$ + public final static String INFORMATION = "org.eclipse.jdt.ui.edit.text.java.show.javadoc";//$NON-NLS-1$ + public final static String ADD_BREAKPOINTS = "org.eclipse.wst.sse.ui.edit.ui.add.breakpoints";//$NON-NLS-1$ + public final static String MANAGE_BREAKPOINTS = "org.eclipse.wst.sse.ui.edit.ui.manage.breakpoints";//$NON-NLS-1$ + public final static String ENABLE_BREAKPOINTS = "org.eclipse.wst.sse.ui.edit.ui.enable.breakpoints";//$NON-NLS-1$ + public final static String DISABLE_BREAKPOINTS = "org.eclipse.wst.sse.ui.edit.ui.disable.breakpoints";//$NON-NLS-1$ +}
\ No newline at end of file diff --git a/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/internal/ui/XMLEditorPluginHOLD_OLD.java b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/internal/ui/XMLEditorPluginHOLD_OLD.java new file mode 100644 index 0000000000..18a781ce31 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/internal/ui/XMLEditorPluginHOLD_OLD.java @@ -0,0 +1,127 @@ +/***************************************************************************** + * Copyright (c) 2004 IBM Corporation and others. All rights reserved. This + * program and the accompanying materials are made available under the terms + * of the Eclipse Public License v1.0 which accompanies this distribution, and + * is available at http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: IBM Corporation - initial API and implementation + ****************************************************************************/ +package org.eclipse.wst.xml.internal.ui; + + + +import org.eclipse.core.runtime.IPluginDescriptor; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.preference.PreferenceConverter; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.eclipse.ui.texteditor.AbstractDecoratedTextEditorPreferenceConstants; +import org.eclipse.wst.sse.ui.preferences.CommonEditorPreferenceNames; +import org.eclipse.wst.sse.ui.registry.AdapterFactoryRegistry; +import org.eclipse.wst.sse.ui.registry.AdapterFactoryRegistryImpl; +import org.eclipse.wst.sse.ui.registry.embedded.EmbeddedAdapterFactoryRegistryImpl; +import org.eclipse.wst.xml.core.XMLPreferenceNames; + + +public class XMLEditorPluginHOLD_OLD extends AbstractUIPlugin { + + public final static String PLUGIN_ID = "org.eclipse.wst.xml.ui.internal.XMLEditorPluginHOLD_OLD"; //$NON-NLS-1$ + protected static XMLEditorPluginHOLD_OLD instance = null; + + /** + * XMLEditorPlugin constructor comment. + * + * @param descriptor + * com.ibm.itp.core.api.plugins.IPluginDescriptor + */ + public XMLEditorPluginHOLD_OLD(IPluginDescriptor descriptor) { + super(descriptor); + instance = this; + + // reference the preference store so + // initializeDefaultPreferences(IPreferenceStore preferenceStore) is + // called + getPreferenceStore(); + } + + public static XMLEditorPluginHOLD_OLD getDefault() { + return instance; + } + + public synchronized static XMLEditorPluginHOLD_OLD getInstance() { + return instance; + } + + public AdapterFactoryRegistry getAdapterFactoryRegistry() { + return AdapterFactoryRegistryImpl.getInstance(); + + } + + public AdapterFactoryRegistry getEmbeddedAdapterFactoryRegistry() { + return EmbeddedAdapterFactoryRegistryImpl.getInstance(); + + } + + /** + * Creates XML Preference store and initializes its default values + */ + protected void initializeDefaultPreferences(IPreferenceStore preferenceStore) { + preferenceStore.setDefault(XMLPreferenceNames.LAST_ACTIVE_PAGE, 0); + + // editor prefs + preferenceStore.setDefault(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_LINE_NUMBER_RULER, false); + preferenceStore.setDefault(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_OVERVIEW_RULER, true); + preferenceStore.setDefault(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_CURRENT_LINE, false); + + preferenceStore.setDefault(CommonEditorPreferenceNames.CONTENT_ASSIST_SUPPORTED, false); + preferenceStore.setDefault(CommonEditorPreferenceNames.AUTO_PROPOSE, true); + preferenceStore.setDefault(CommonEditorPreferenceNames.AUTO_PROPOSE_CODE, CommonEditorPreferenceNames.LT); + + preferenceStore.setDefault(CommonEditorPreferenceNames.MATCHING_BRACKETS, true); + PreferenceConverter.setDefault(preferenceStore, CommonEditorPreferenceNames.MATCHING_BRACKETS_COLOR, new RGB(192, 192, 192)); + + preferenceStore.setDefault(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_CURRENT_LINE, true); + PreferenceConverter.setDefault(preferenceStore, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_CURRENT_LINE_COLOR, new RGB(225, 235, 224)); + + preferenceStore.setDefault(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_PRINT_MARGIN, true); + PreferenceConverter.setDefault(preferenceStore, AbstractDecoratedTextEditorPreferenceConstants.EDITOR_PRINT_MARGIN_COLOR, new RGB(176, 180, 185)); + + preferenceStore.setDefault(AbstractDecoratedTextEditorPreferenceConstants.EDITOR_PRINT_MARGIN_COLUMN, 80); + + preferenceStore.setDefault(CommonEditorPreferenceNames.EDITOR_USE_INFERRED_GRAMMAR, true); + + initializeDefaultAnnotationPrefs(preferenceStore); + } + + /* + * Using this method for all content types initialize methods since + * they're all the same (for now) @param preferenceStore + */ + private void initializeDefaultAnnotationPrefs(IPreferenceStore preferenceStore) { + + preferenceStore.setDefault(CommonEditorPreferenceNames.ERROR_INDICATION, true); + PreferenceConverter.setDefault(preferenceStore, CommonEditorPreferenceNames.ERROR_INDICATION_COLOR, new RGB(255, 0, 128)); + + preferenceStore.setDefault(CommonEditorPreferenceNames.WARNING_INDICATION, true); + PreferenceConverter.setDefault(preferenceStore, CommonEditorPreferenceNames.WARNING_INDICATION_COLOR, new RGB(244, 200, 45)); + + preferenceStore.setDefault(CommonEditorPreferenceNames.TASK_INDICATION, false); + PreferenceConverter.setDefault(preferenceStore, CommonEditorPreferenceNames.TASK_INDICATION_COLOR, new RGB(0, 128, 255)); + + preferenceStore.setDefault(CommonEditorPreferenceNames.BOOKMARK_INDICATION, false); + PreferenceConverter.setDefault(preferenceStore, CommonEditorPreferenceNames.BOOKMARK_INDICATION_COLOR, new RGB(34, 164, 99)); + + preferenceStore.setDefault(CommonEditorPreferenceNames.SEARCH_RESULT_INDICATION, true); + PreferenceConverter.setDefault(preferenceStore, CommonEditorPreferenceNames.SEARCH_RESULT_INDICATION_COLOR, new RGB(192, 192, 192)); + + preferenceStore.setDefault(CommonEditorPreferenceNames.UNKNOWN_INDICATION, false); + PreferenceConverter.setDefault(preferenceStore, CommonEditorPreferenceNames.UNKNOWN_INDICATION_COLOR, new RGB(0, 0, 0)); + + preferenceStore.setDefault(CommonEditorPreferenceNames.ERROR_INDICATION_IN_OVERVIEW_RULER, true); + preferenceStore.setDefault(CommonEditorPreferenceNames.WARNING_INDICATION_IN_OVERVIEW_RULER, true); + preferenceStore.setDefault(CommonEditorPreferenceNames.TASK_INDICATION_IN_OVERVIEW_RULER, true); + preferenceStore.setDefault(CommonEditorPreferenceNames.BOOKMARK_INDICATION_IN_OVERVIEW_RULER, true); + preferenceStore.setDefault(CommonEditorPreferenceNames.SEARCH_RESULT_INDICATION_IN_OVERVIEW_RULER, true); + preferenceStore.setDefault(CommonEditorPreferenceNames.UNKNOWN_INDICATION_IN_OVERVIEW_RULER, false); + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/internal/ui/XMLEditorPluginImageHelper.java b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/internal/ui/XMLEditorPluginImageHelper.java new file mode 100644 index 0000000000..2e813eb6b7 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/internal/ui/XMLEditorPluginImageHelper.java @@ -0,0 +1,152 @@ +/******************************************************************************* + * Copyright (c) 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.wst.xml.internal.ui; + +import java.util.HashMap; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.resource.ImageRegistry; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.swt.graphics.Image; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.eclipse.wst.xml.ui.XMLEditorPlugin; + +/** + * Helper class to handle images provided by this plug-in. + * + * NOTE: For internal use only. For images used externally, please use the + * Shared***ImageHelper class instead. + * + * @author amywu + */ +public class XMLEditorPluginImageHelper { + private final String PLUGINID = XMLEditorPlugin.ID; + private static XMLEditorPluginImageHelper instance = null; + + // save a descriptor for each image + private HashMap fImageDescRegistry = null; + + /** + * Gets the instance. + * + * @return Returns a XMLEditorPluginImageHelper + */ + public synchronized static XMLEditorPluginImageHelper getInstance() { + if (instance == null) + instance = new XMLEditorPluginImageHelper(); + return instance; + } + + /** + * Retrieves the image associated with resource from the image registry. + * If the image cannot be retrieved, attempt to find and load the image at + * the location specified in resource. + * + * @param resource + * the image to retrieve + * @return Image the image associated with resource or null if one could + * not be found + */ + public Image getImage(String resource) { + Image image = getImageRegistry().get(resource); + if (image == null) { + // create an image + image = createImage(resource); + } + return image; + } + + /** + * Retrieves the image descriptor associated with resource from the image + * descriptor registry. If the image descriptor cannot be retrieved, + * attempt to find and load the image descriptor at the location specified + * in resource. + * + * @param resource + * the image descriptor to retrieve + * @return ImageDescriptor the image descriptor assocated with resource or + * the default "missing" image descriptor if one could not be + * found + */ + public ImageDescriptor getImageDescriptor(String resource) { + ImageDescriptor imageDescriptor = null; + Object o = getImageDescriptorRegistry().get(resource); + if (o == null) { + //create a descriptor + imageDescriptor = createImageDescriptor(resource); + } else { + imageDescriptor = (ImageDescriptor) o; + } + return imageDescriptor; + } + + /** + * Returns the image descriptor registry for this plugin. + * + * @return HashMap - image descriptor registry for this plugin + */ + private HashMap getImageDescriptorRegistry() { + if (fImageDescRegistry == null) + fImageDescRegistry = new HashMap(); + return fImageDescRegistry; + } + + /** + * Returns the image registry for this plugin. + * + * @return ImageRegistry - image registry for this plugin + */ + private ImageRegistry getImageRegistry() { + return JFaceResources.getImageRegistry(); + } + + /** + * Creates an image from the given resource and adds the image to the + * image registry. + * + * @param resource + * @return Image + */ + private Image createImage(String resource) { + ImageDescriptor desc = getImageDescriptor(resource); + Image image = null; + + if (desc != null) { + image = desc.createImage(); + // dont add the missing image descriptor image to the image + // registry + if (!desc.equals(ImageDescriptor.getMissingImageDescriptor())) + getImageRegistry().put(resource, image); + } + return image; + } + + /** + * Creates an image descriptor from the given imageFilePath and adds the + * image descriptor to the image descriptor registry. If an image + * descriptor could not be created, the default "missing" image descriptor + * is returned but not added to the image descriptor registry. + * + * @param imageFilePath + * @return ImageDescriptor image descriptor for imageFilePath or default + * "missing" image descriptor if resource could not be found + */ + private ImageDescriptor createImageDescriptor(String imageFilePath) { + ImageDescriptor imageDescriptor = AbstractUIPlugin.imageDescriptorFromPlugin(PLUGINID, imageFilePath); + if (imageDescriptor != null) { + getImageDescriptorRegistry().put(imageFilePath, imageDescriptor); + } else { + imageDescriptor = ImageDescriptor.getMissingImageDescriptor(); + } + + return imageDescriptor; + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/internal/ui/XMLEditorPluginImages.java b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/internal/ui/XMLEditorPluginImages.java new file mode 100644 index 0000000000..b1ee193ec4 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/internal/ui/XMLEditorPluginImages.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.wst.xml.internal.ui; + +/** + * Bundle of most images used by the XML Editor plug-in. + */ +public class XMLEditorPluginImages { + public static final String IMG_DTOOL_COLLAPSE = "icons/full/dtool16/collapse.gif"; //$NON-NLS-1$ + public static final String IMG_ETOOL_COLLAPSE = "icons/full/etool16/collapse.gif"; //$NON-NLS-1$ + public static final String IMG_DTOOL_COLLAPSEALL = "icons/full/dtool16/collapse_all.gif"; //$NON-NLS-1$ + public static final String IMG_ETOOL_COLLAPSEALL = "icons/full/etool16/collapse_all.gif"; //$NON-NLS-1$ + public static final String IMG_DTOOL_EXPAND = "icons/full/dtool16/expand.gif"; //$NON-NLS-1$ + public static final String IMG_ETOOL_EXPAND = "icons/full/etool16/expand.gif"; //$NON-NLS-1$ + public static final String IMG_DTOOL_EXPANDALL = "icons/full/dtool16/expand_all.gif"; //$NON-NLS-1$ + public static final String IMG_ETOOL_EXPANDALL = "icons/full/etool16/expand_all.gif"; //$NON-NLS-1$ + public static final String IMG_DTOOL_NEW_XML = "icons/full/dtool16/new_xml.gif"; //$NON-NLS-1$ + public static final String IMG_ETOOL_NEW_XML = "icons/full/etool16/new_xml.gif"; //$NON-NLS-1$ +}
\ No newline at end of file diff --git a/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/internal/ui/XMLMultiPageEditorActionBarContributor.java b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/internal/ui/XMLMultiPageEditorActionBarContributor.java new file mode 100644 index 0000000000..8eb0240f9c --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/internal/ui/XMLMultiPageEditorActionBarContributor.java @@ -0,0 +1,89 @@ +/***************************************************************************** + * Copyright (c) 2004 IBM Corporation and others. All rights reserved. This + * program and the accompanying materials are made available under the terms + * of the Eclipse Public License v1.0 which accompanies this distribution, and + * is available at http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: IBM Corporation - initial API and implementation + ****************************************************************************/ +package org.eclipse.wst.xml.internal.ui; + + + +import org.eclipse.ui.IActionBars; +import org.eclipse.ui.IEditorPart; +import org.eclipse.wst.sse.ui.ISourceViewerActionBarContributor; +import org.eclipse.wst.xml.ui.internal.tabletree.XMLTableTreeActionBarContributor; + + +public class XMLMultiPageEditorActionBarContributor extends SourceEditorActionBarContributor { + + private boolean needsMultiInit = true; + + public XMLMultiPageEditorActionBarContributor() { + super(); + } + + protected void initDesignViewerActionBarContributor(IActionBars actionBars) { + super.initDesignViewerActionBarContributor(actionBars); + + if (designViewerActionBarContributor != null) + if (designViewerActionBarContributor instanceof IDesignViewerActionBarContributor) + ((IDesignViewerActionBarContributor) designViewerActionBarContributor).initViewerSpecificContributions(actionBars); + } + + protected void activateDesignPage(IEditorPart activeEditor) { + if (sourceViewerActionContributor != null && sourceViewerActionContributor instanceof ISourceViewerActionBarContributor) { + // if design page is not really an IEditorPart, activeEditor == + // null, so pass in multiPageEditor instead (d282414) + if (activeEditor == null) { + sourceViewerActionContributor.setActiveEditor(multiPageEditor); + } else { + sourceViewerActionContributor.setActiveEditor(activeEditor); + } + ((ISourceViewerActionBarContributor) sourceViewerActionContributor).setViewerSpecificContributionsEnabled(false); + } + + if (designViewerActionBarContributor != null && designViewerActionBarContributor instanceof IDesignViewerActionBarContributor) { + designViewerActionBarContributor.setActiveEditor(multiPageEditor); + ((IDesignViewerActionBarContributor) designViewerActionBarContributor).setViewerSpecificContributionsEnabled(true); + } + } + + protected void activateSourcePage(IEditorPart activeEditor) { + if (designViewerActionBarContributor != null && designViewerActionBarContributor instanceof IDesignViewerActionBarContributor) { + designViewerActionBarContributor.setActiveEditor(multiPageEditor); + ((IDesignViewerActionBarContributor) designViewerActionBarContributor).setViewerSpecificContributionsEnabled(false); + } + + if (sourceViewerActionContributor != null && sourceViewerActionContributor instanceof ISourceViewerActionBarContributor) { + sourceViewerActionContributor.setActiveEditor(activeEditor); + ((ISourceViewerActionBarContributor) sourceViewerActionContributor).setViewerSpecificContributionsEnabled(true); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ui.part.EditorActionBarContributor#init(org.eclipse.ui.IActionBars) + */ + public void init(IActionBars actionBars) { + super.init(actionBars); + needsMultiInit = true; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ui.IEditorActionBarContributor#setActiveEditor(org.eclipse.ui.IEditorPart) + */ + public void setActiveEditor(IEditorPart targetEditor) { + if (needsMultiInit) { + designViewerActionBarContributor = new XMLTableTreeActionBarContributor(); + initDesignViewerActionBarContributor(getActionBars()); + needsMultiInit = false; + } + super.setActiveEditor(targetEditor); + } + +}
\ No newline at end of file diff --git a/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/internal/ui/XMLMultiPageEditorPart.java b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/internal/ui/XMLMultiPageEditorPart.java new file mode 100644 index 0000000000..c49a95b8d3 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/internal/ui/XMLMultiPageEditorPart.java @@ -0,0 +1,773 @@ +/***************************************************************************** + * Copyright (c) 2004 IBM Corporation and others. All rights reserved. This + * program and the accompanying materials are made available under the terms + * of the Eclipse Public License v1.0 which accompanies this distribution, and + * is available at http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: IBM Corporation - initial API and implementation + ****************************************************************************/ +package org.eclipse.wst.xml.internal.ui; + +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceStatus; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.ITextInputListener; +import org.eclipse.swt.events.ShellAdapter; +import org.eclipse.swt.events.ShellEvent; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IEditorActionBarContributor; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IEditorSite; +import org.eclipse.ui.IFileEditorInput; +import org.eclipse.ui.IPartListener; +import org.eclipse.ui.IPropertyListener; +import org.eclipse.ui.IStorageEditorInput; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.help.WorkbenchHelp; +import org.eclipse.ui.ide.IGotoMarker; +import org.eclipse.ui.part.MultiPageEditorPart; +import org.eclipse.ui.part.MultiPageEditorSite; +import org.eclipse.wst.sse.core.IStructuredModel; +import org.eclipse.wst.sse.core.exceptions.SourceEditingRuntimeException; +import org.eclipse.wst.sse.ui.StructuredTextEditor; +import org.eclipse.wst.sse.ui.nls.ResourceHandler; +import org.eclipse.wst.xml.core.XMLPreferenceNames; +import org.eclipse.wst.xml.ui.Logger; +import org.eclipse.wst.xml.ui.StructuredTextEditorXML; +import org.eclipse.wst.xml.ui.XMLEditorPlugin; +import org.eclipse.wst.xml.ui.internal.tabletree.XMLTableTreeHelpContextIds; +import org.eclipse.wst.xml.ui.internal.tabletree.XMLTableTreeViewer; +import org.w3c.dom.Document; +import org.w3c.dom.Node; + + +public class XMLMultiPageEditorPart extends MultiPageEditorPart implements IPropertyListener { + + /** + * Internal part activation listener + */ + class PartListener extends ShellAdapter implements IPartListener { + private IWorkbenchPart fActivePart; + private boolean fIsHandlingActivation = false; + + private void handleActivation() { + + if (fIsHandlingActivation) + return; + + if (fActivePart == XMLMultiPageEditorPart.this) { + fIsHandlingActivation = true; + try { + safelySanityCheckState(); + } finally { + fIsHandlingActivation = false; + } + } + } + + /** + * @see IPartListener#partActivated(IWorkbenchPart) + */ + public void partActivated(IWorkbenchPart part) { + fActivePart = part; + handleActivation(); + } + + /** + * @see IPartListener#partBroughtToTop(IWorkbenchPart) + */ + public void partBroughtToTop(IWorkbenchPart part) { + } + + /** + * @see IPartListener#partClosed(IWorkbenchPart) + */ + public void partClosed(IWorkbenchPart part) { + } + + /** + * @see IPartListener#partDeactivated(IWorkbenchPart) + */ + public void partDeactivated(IWorkbenchPart part) { + fActivePart = null; + } + + /** + * @see IPartListener#partOpened(IWorkbenchPart) + */ + public void partOpened(IWorkbenchPart part) { + } + + /* + * @see ShellListener#shellActivated(ShellEvent) + */ + public void shellActivated(ShellEvent e) { + handleActivation(); + } + } + + class TextInputListener implements ITextInputListener { + public void inputDocumentAboutToBeChanged(IDocument oldInput, IDocument newInput) { + } + + public void inputDocumentChanged(IDocument oldInput, IDocument newInput) { + if (fDesignViewer != null && newInput != null) + fDesignViewer.setModel(getModel()); + } + } + + /** The design page index. */ + private int fDesignPageIndex; + + /** The design viewer */ + private IDesignViewer fDesignViewer; + + /** The source page index. */ + private int fSourcePageIndex; + /** The text editor. */ + private StructuredTextEditor fTextEditor; + + private PartListener partListener; + + /** + * StructuredTextMultiPageEditorPart constructor comment. + */ + public XMLMultiPageEditorPart() { + super(); + } + + /* + * This method is just to make firePropertyChanged accessbible from some + * (anonomous) inner classes. + */ + protected void _firePropertyChange(int property) { + super.firePropertyChange(property); + } + + /** + * Adds the source page of the multi-page editor. + */ + protected void addSourcePage() throws PartInitException { + try { + fSourcePageIndex = addPage(fTextEditor, getEditorInput()); + setPageText(fSourcePageIndex, org.eclipse.wst.xml.ui.nls2.ResourceHandler.getString("XMLMultiPageEditorPart.0")); //$NON-NLS-1$ + // the update's critical, to get viewer selection manager and + // highlighting to work + fTextEditor.update(); + + firePropertyChange(PROP_TITLE); + + // Changes to the Text Viewer's document instance should also + // force an + // input refresh + fTextEditor.getTextViewer().addTextInputListener(new TextInputListener()); + } catch (PartInitException exception) { + // dispose editor + dispose(); + + throw new SourceEditingRuntimeException(ResourceHandler.getString("An_error_has_occurred_when1_ERROR_")); //$NON-NLS-1$ + } + } + + /** + * Connects the design viewer with the viewer selection manager. Should be + * done after createSourcePage() is done because we need to get the + * ViewerSelectionManager from the TextEditor. setModel is also done here + * because getModel() needs to reference the TextEditor. + */ + protected void connectDesignPage() { + if (fDesignViewer != null) { + fDesignViewer.setViewerSelectionManager(fTextEditor.getViewerSelectionManager()); + fDesignViewer.setModel(getModel()); + } + } + + /** + * Create and Add the Design Page using a registered factory + * + * @throws PartInitException + */ + protected void createAndAddDesignPage() { + XMLTableTreeViewer tableTreeViewer = new XMLTableTreeViewer(getContainer()); + // Set the default infopop for XML design viewer. + WorkbenchHelp.setHelp(tableTreeViewer.getControl(), XMLTableTreeHelpContextIds.XML_DESIGN_VIEW_HELPID); + + fDesignViewer = tableTreeViewer; + // note: By adding the design page as a Control instead of an + // IEditorPart, page switches will indicate + // a "null" active editor when the design page is made active + fDesignPageIndex = addPage(tableTreeViewer.getControl()); + setPageText(fDesignPageIndex, tableTreeViewer.getTitle()); + } + + /** + * Creates the pages of this multi-page editor. + * <p> + * Subclasses of <code>MultiPageEditor</code> must implement this + * method. + * </p> + */ + protected void createPages() { + try { + // source page MUST be created before design page, now + createSourcePage(); + createAndAddDesignPage(); + addSourcePage(); + connectDesignPage(); + + setActivePage(); + + // future_TODO: add a catch block here for any exception the + // design + // page throws and convert it into a more informative message. + } catch (PartInitException e) { + Logger.logException(e); + throw new RuntimeException(e); + } + } + + /** + * @see org.eclipse.ui.part.MultiPageEditorPart#createSite(org.eclipse.ui.IEditorPart) + */ + protected IEditorSite createSite(IEditorPart editor) { + IEditorSite site = null; + if (editor == fTextEditor) { + site = new MultiPageEditorSite(this, editor) { + /** + * @see org.eclipse.ui.part.MultiPageEditorSite#getActionBarContributor() + */ + public IEditorActionBarContributor getActionBarContributor() { + IEditorActionBarContributor contributor = super.getActionBarContributor(); + IEditorActionBarContributor multiContributor = XMLMultiPageEditorPart.this.getEditorSite().getActionBarContributor(); + if (multiContributor instanceof XMLMultiPageEditorActionBarContributor) { + contributor = ((XMLMultiPageEditorActionBarContributor) multiContributor).sourceViewerActionContributor; + } + return contributor; + } + }; + } else { + site = super.createSite(editor); + } + return site; + } + + /** + * Creates the source page of the multi-page editor. + */ + protected void createSourcePage() throws PartInitException { + fTextEditor = createTextEditor(); + fTextEditor.setEditorPart(this); + + // Set the SourceViewerConfiguration now so the text editor won't use + // the default configuration first + // and switch to the StructuredTextViewerConfiguration later. + // DMW removed setSourceViewerConfiguration 3/26/2003 since added + // createPartControl to our text editor. + // fTextEditor.setSourceViewerConfiguration(); + fTextEditor.addPropertyListener(this); + } + + /** + * Method createTextEditor. + * + * @return StructuredTextEditor + */ + protected StructuredTextEditor createTextEditor() { + return new StructuredTextEditorXML(); + } + + protected void disconnectDesignPage() { + if (fDesignViewer != null) { + fDesignViewer.setModel(null); + fDesignViewer.setViewerSelectionManager(null); + } + } + + public void dispose() { + Logger.trace("Source Editor", "StructuredTextMultiPageEditorPart::dispose entry"); //$NON-NLS-1$ //$NON-NLS-2$ + + disconnectDesignPage(); + + IWorkbenchWindow window = getSite().getWorkbenchWindow(); + window.getPartService().removePartListener(partListener); + window.getShell().removeShellListener(partListener); + + getSite().getPage().removePartListener(partListener); + if (fTextEditor != null) { + fTextEditor.removePropertyListener(this); + } + + // moved to last when added window ... seems like + // we'd be in danger of losing some data, like site, + // or something. + super.dispose(); + + Logger.trace("Source Editor", "StructuredTextMultiPageEditorPart::dispose exit"); //$NON-NLS-1$ //$NON-NLS-2$ + + } + + /* + * (non-Javadoc) Saves the contents of this editor. <p> Subclasses must + * override this method to implement the open-save-close lifecycle for an + * editor. For greater details, see <code> IEditorPart </code></p> + * + * @see IEditorPart + */ + public void doSave(IProgressMonitor monitor) { + fTextEditor.doSave(monitor); + // // this is a temporary way to force validation. + // // when the validator is a workbench builder, the following lines + // can be removed + // if (fDesignViewer != null) + // fDesignViewer.saveOccurred(); + + } + + /* + * (non-Javadoc) Saves the contents of this editor to another object. <p> + * Subclasses must override this method to implement the open-save-close + * lifecycle for an editor. For greater details, see <code> IEditorPart + * </code></p> + * + * @see IEditorPart + */ + public void doSaveAs() { + fTextEditor.doSaveAs(); + // 253619 + // following used to be executed here, but is + // now called "back" from text editor (since + // mulitiple paths to the performSaveAs in StructuredTextEditor. + //doSaveAsForStructuredTextMulitPagePart(); + } + + private void editorInputIsAcceptable(IEditorInput input) throws PartInitException { + if (input instanceof IFileEditorInput) { + // verify that it can be opened + CoreException[] coreExceptionArray = new CoreException[1]; + if (fileDoesNotExist((IFileEditorInput) input, coreExceptionArray)) { + CoreException coreException = coreExceptionArray[0]; + if (coreException.getStatus().getCode() == IResourceStatus.FAILED_READ_LOCAL) { + // I'm assuming this is always 'does not exist' + // we'll refresh local go mimic behavior of default + // editor, where the + // troublesome file is refreshed (and will cause it to + // 'disappear' from Navigator. + try { + ((IFileEditorInput) input).getFile().refreshLocal(IResource.DEPTH_ZERO, new NullProgressMonitor()); + } catch (CoreException ce) { + // very unlikely + Logger.logException(ce); + } + throw new PartInitException(ResourceHandler.getString("23concat_EXC_", (new Object[]{input.getName()}))); //$NON-NLS-1$ + //$NON-NLS-1$ = "Resource {0} does not exist." + } else { + throw new PartInitException(ResourceHandler.getString("32concat_EXC_", (new Object[]{input.getName()}))); //$NON-NLS-1$ + //$NON-NLS-1$ = "Editor could not be open on {0}" + } + } + } else if (input instanceof IStorageEditorInput) { + InputStream contents = null; + try { + contents = ((IStorageEditorInput) input).getStorage().getContents(); + } catch (CoreException noStorageExc) { + } + if (contents == null) { + throw new PartInitException(ResourceHandler.getString("32concat_EXC_", (new Object[]{input.getName()}))); //$NON-NLS-1$ + } else { + try { + contents.close(); + } catch (IOException e) { + } + } + } + } + + // void doSaveAsForStructuredTextMulitPagePart() { + // setPageText(getActivePage(), fTextEditor.getTitle()); + // setInput(fTextEditor.getEditorInput()); + // if (fDesignViewer != null) { + // //fDesignViewer.setEditorInput(fTextEditor.getEditorInput()); + // fDesignViewer.setModel(getModel()); + // fDesignViewer.saveAsOccurred(); + // } + // // even though we've set title etc., several times already! + // // only now is all prepared for it. + // firePropertyChange(IWorkbenchPart.PROP_TITLE); + // firePropertyChange(PROP_DIRTY); + // } + /* + * (non-Javadoc) Initializes the editor part with a site and input. <p> + * Subclasses of <code> EditorPart </code> must implement this method. + * Within the implementation subclasses should verify that the input type + * is acceptable and then save the site and input. Here is sample code: + * </p><pre> if (!(input instanceof IFileEditorInput)) throw new + * PartInitException("Invalid Input: Must be IFileEditorInput"); + * setSite(site); setInput(editorInput); </pre> + */ + protected boolean fileDoesNotExist(IFileEditorInput input, Throwable[] coreException) { + boolean result = false; + InputStream inStream = null; + if ((!(input.exists())) || (!(input.getFile().exists()))) { + result = true; + } else { + try { + inStream = input.getFile().getContents(true); + } catch (CoreException e) { + // very likely to be file not found + result = true; + coreException[0] = e; + } finally { + if (input != null) { + try { + if (inStream != null) { + inStream.close(); + } + } catch (IOException e) { + Logger.logException(e); + } + } + } + } + return result; + } + + public Object getAdapter(Class key) { + Object result = null; + if (key == IDesignViewer.class) { + result = fDesignViewer; + } else { + // DMW: I'm bullet-proofing this because + // its been reported (on 4.03 version) a null pointer sometimes + // happens here on startup, when an editor has been left + // open when workbench shutdown. + if (fTextEditor != null) { + result = fTextEditor.getAdapter(key); + } + } + return result; + } + + /** + * IExtendedMarkupEditor method + */ + public Node getCaretNode() { + if (getTextEditor() == null) + return null; + + return getTextEditor().getCaretNode(); + } + + /** + * IExtendedSimpleEditor method + */ + public int getCaretPosition() { + if (getTextEditor() == null) + return -1; + + return getTextEditor().getCaretPosition(); + } + + /** + * IExtendedSimpleEditor method + */ + public IDocument getDocument() { + if (getTextEditor() == null) + return null; + + return getTextEditor().getDocument(); + } + + /** + * IExtendedMarkupEditor method + */ + public Document getDOMDocument() { + if (getTextEditor() == null) + return null; + + return getTextEditor().getDOMDocument(); + } + + /** + * IExtendedSimpleEditor method + */ + public IEditorPart getEditorPart() { + return this; + } + + protected IStructuredModel getModel() { + IStructuredModel model = null; + if (fTextEditor != null) + model = fTextEditor.getModel(); + return model; + } + + protected IPreferenceStore getPreferenceStore() { + return XMLEditorPlugin.getDefault().getPreferenceStore(); + } + + /** + * IExtendedMarkupEditor method + */ + public List getSelectedNodes() { + if (getTextEditor() == null) + return null; + return getTextEditor().getSelectedNodes(); + } + + /** + * IExtendedSimpleEditor method + */ + public Point getSelectionRange() { + if (getTextEditor() == null) + return new Point(-1, -1); + + return getTextEditor().getSelectionRange(); + } + + public StructuredTextEditor getTextEditor() { + return fTextEditor; + } + + /* + * (non-Javadoc) Method declared on IWorkbenchPart. + */ + public String getTitle() { + String title = null; + if (getTextEditor() == null) { + if (getEditorInput() != null) { + title = getEditorInput().getName(); + } + } else { + title = getTextEditor().getTitle(); + } + if (title == null) { + title = getPartName(); + } + return title; + } + + /* + * (non-Javadoc) Sets the cursor and selection state for this editor to + * the passage defined by the given marker. <p> Subclasses may override. + * For greater details, see <code> IEditorPart </code></p> + * + * @see IEditorPart + */ + public void gotoMarker(IMarker marker) { + // (pa) 20020217 this was null when opening an editor that was + // already open + if (fTextEditor != null) { + IGotoMarker markerGotoer = (IGotoMarker) fTextEditor.getAdapter(IGotoMarker.class); + markerGotoer.gotoMarker(marker); + } + } + + public void init(IEditorSite site, IEditorInput input) throws PartInitException { + editorInputIsAcceptable(input); + try { + super.init(site, input); + if (partListener == null) { + partListener = new PartListener(); + } + //getSite().getPage().addPartListener(partListner); + // we want to listen for our own activation + IWorkbenchWindow window = getSite().getWorkbenchWindow(); + window.getPartService().addPartListener(partListener); + window.getShell().addShellListener(partListener); + } catch (Exception e) { + if (e instanceof SourceEditingRuntimeException) { + Throwable t = ((SourceEditingRuntimeException) e).getOriginalException(); + if (t instanceof IOException) { + System.out.println(t); + // file not found + } + } + } + setPartName(input.getName()); + } + + /* + * (non-Javadoc) Returns whether the "save as" operation is supported by + * this editor. <p> Subclasses must override this method to implement the + * open-save-close lifecycle for an editor. For greater details, see + * <code> IEditorPart </code></p> + * + * @see IEditorPart + */ + public boolean isSaveAsAllowed() { + return fTextEditor != null && fTextEditor.isSaveAsAllowed(); + } + + /* + * (non-Javadoc) Returns whether the contents of this editor should be + * saved when the editor is closed. <p> This method returns <code> true + * </code> if and only if the editor is dirty ( <code> isDirty </code> ). + * </p> + */ + public boolean isSaveOnCloseNeeded() { + // overriding super class since it does a lowly isDirty! + if (fTextEditor != null) + return fTextEditor.isSaveOnCloseNeeded(); + return isDirty(); + } + + /** + * Notifies this multi-page editor that the page with the given id has + * been activated. This method is called when the user selects a different + * tab. + * + * @param newPageIndex + * the index of the activated page + */ + protected void pageChange(int newPageIndex) { + super.pageChange(newPageIndex); + + saveLastActivePageIndex(newPageIndex); + } + + /** + * Posts the update code "behind" the running operation. + */ + protected void postOnDisplayQue(Runnable runnable) { + IWorkbench workbench = PlatformUI.getWorkbench(); + IWorkbenchWindow[] windows = workbench.getWorkbenchWindows(); + if (windows != null && windows.length > 0) { + Display display = windows[0].getShell().getDisplay(); + display.asyncExec(runnable); + } else + runnable.run(); + } + + /** + * Indicates that a property has changed. + * + * @param source + * the object whose property has changed + * @param propId + * the id of the property which has changed; property ids are + * generally defined as constants on the source class + */ + public void propertyChanged(Object source, int propId) { + switch (propId) { + // had to implement input changed "listener" so that + // strucutedText could tell it containing editor that + // the input has change, when a 'resource moved' event is + // found. + case IEditorPart.PROP_INPUT : + case IEditorPart.PROP_DIRTY : { + if (source == fTextEditor) { + if (fTextEditor.getEditorInput() != getEditorInput()) { + setInput(fTextEditor.getEditorInput()); + // title should always change when input changes. + // create runnable for following post call + Runnable runnable = new Runnable() { + public void run() { + _firePropertyChange(IWorkbenchPart.PROP_TITLE); + } + }; + // Update is just to post things on the display queue + // (thread). We have to do this to get the dirty + // property to get updated after other things on the + // queue are executed. + postOnDisplayQue(runnable); + } + } + break; + } + case IWorkbenchPart.PROP_TITLE : { + // update the input if the title is changed + if (source == fTextEditor) { + if (fTextEditor.getEditorInput() != getEditorInput()) { + setInput(fTextEditor.getEditorInput()); + } + } + break; + } + default : { + // propagate changes. Is this needed? Answer: Yes. + if (source == fTextEditor) { + firePropertyChange(propId); + } + break; + } + } + + } + + protected void safelySanityCheckState() { + // If we're called before editor is created, simply ignore since we + // delegate this function to our embedded TextEditor + if (getTextEditor() == null) + return; + + getTextEditor().safelySanityCheckState(getEditorInput()); + + } + + protected void saveLastActivePageIndex(int newPageIndex) { + // save the last active page index to preference manager + getPreferenceStore().setValue(XMLPreferenceNames.LAST_ACTIVE_PAGE, newPageIndex); + } + + /** + * Sets the currently active page. + */ + protected void setActivePage() { + // retrieve the last active page index from preference manager + int activePageIndex = getPreferenceStore().getInt(XMLPreferenceNames.LAST_ACTIVE_PAGE); + + // We check this range since someone could hand edit the XML + // preference file to an invalid value ... which I know from + // experience :( ... if they do, we'll reset to default and continue + // rather than throw an assertion error in the setActivePage(int) + // method. + if (activePageIndex < 0 || activePageIndex >= getPageCount()) { + activePageIndex = fDesignPageIndex; + } + setActivePage(activePageIndex); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ui.part.EditorPart#setInput(org.eclipse.ui.IEditorInput) + */ + protected void setInput(IEditorInput input) { + // If driven from the Source page, it's "model" may not be up to date + // with the input just yet. We'll rely on later notification from the + // TextViewer to set us straight + super.setInput(input); + if (fDesignViewer != null) + fDesignViewer.setModel(getModel()); + setPartName(input.getName()); + } + + /** + * IExtendedMarkupEditor method + */ + public IStatus validateEdit(Shell context) { + if (getTextEditor() == null) + return new Status(IStatus.ERROR, XMLEditorPlugin.ID, IStatus.INFO, "", null); //$NON-NLS-1$ + + return getTextEditor().validateEdit(context); + } + +}
\ No newline at end of file diff --git a/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/DOMPropertyDescriptorFactory.java b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/DOMPropertyDescriptorFactory.java new file mode 100644 index 0000000000..dfa592378b --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/DOMPropertyDescriptorFactory.java @@ -0,0 +1,138 @@ +/***************************************************************************** + * Copyright (c) 2004 IBM Corporation and others. All rights reserved. This + * program and the accompanying materials are made available under the terms + * of the Eclipse Public License v1.0 which accompanies this distribution, and + * is available at http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: IBM Corporation - initial API and implementation + ****************************************************************************/ +package org.eclipse.wst.xml.ui.internal.tabletree; + +import org.eclipse.ui.views.properties.IPropertyDescriptor; +import org.eclipse.ui.views.properties.TextPropertyDescriptor; +import org.eclipse.wst.common.contentmodel.CMAttributeDeclaration; +import org.eclipse.wst.common.contentmodel.modelquery.ModelQuery; +import org.eclipse.wst.sse.ui.views.properties.EnumeratedStringPropertyDescriptor; +import org.w3c.dom.Attr; +import org.w3c.dom.CDATASection; +import org.w3c.dom.Comment; +import org.w3c.dom.DocumentType; +import org.w3c.dom.Element; +import org.w3c.dom.EntityReference; +import org.w3c.dom.Node; +import org.w3c.dom.ProcessingInstruction; +import org.w3c.dom.Text; + + +public class DOMPropertyDescriptorFactory { + + protected static final String HACK = "hack"; //$NON-NLS-1$ + private ModelQuery fModelQuery = null; + + public DOMPropertyDescriptorFactory(ModelQuery modelQuery) { + fModelQuery = modelQuery; + } + + public IPropertyDescriptor createAttributePropertyDescriptor(Attr attr) { + IPropertyDescriptor result = null; + + String attributeName = attr.getName(); + + CMAttributeDeclaration ad = fModelQuery.getCMAttributeDeclaration(attr); + if (ad != null) { + String[] valuesArray = fModelQuery.getPossibleDataTypeValues(attr.getOwnerElement(), ad); + if (valuesArray != null && valuesArray.length > 0) { + result = new EnumeratedStringPropertyDescriptor(attributeName, attributeName, valuesArray); + } + } + + if (result == null) { + result = createDefaultPropertyDescriptor(attributeName); + } + return result; + } + + public IPropertyDescriptor createCDATASectionPropertyDescriptor(CDATASection cdataSection) { + return createDefaultPropertyDescriptor(HACK); + } + + public IPropertyDescriptor createCommentPropertyDescriptor(Comment comment) { + return createDefaultPropertyDescriptor(HACK); + } + + protected IPropertyDescriptor createDefaultPropertyDescriptor(String attributeName) { + TextPropertyDescriptor descriptor = new TextPropertyDescriptor(attributeName, attributeName); + return descriptor; + } + + public IPropertyDescriptor createDocumentTypePropertyDescriptor(DocumentType documentType) { + return null; //new TextPropertyDescriptor(HACK, HACK); + } + + public IPropertyDescriptor createElementPropertyDescriptor(Element element) { + return createDefaultPropertyDescriptor(HACK); + } + + public IPropertyDescriptor createEntityReferencePropertyDescriptor(EntityReference entityReference) { + return createDefaultPropertyDescriptor(HACK); + } + + public IPropertyDescriptor createProcessingInstructionPropertyDescriptor(ProcessingInstruction pi) { + return createDefaultPropertyDescriptor(HACK); + } + + public IPropertyDescriptor createPropertyDescriptor(Object object) { + IPropertyDescriptor result = null; + if (object instanceof Node) { + Node node = (Node) object; + int nodeType = node.getNodeType(); + switch (nodeType) { + case Node.ATTRIBUTE_NODE : { + result = createAttributePropertyDescriptor((Attr) node); + break; + } + case Node.CDATA_SECTION_NODE : { + result = createCDATASectionPropertyDescriptor((CDATASection) node); + break; + } + case Node.COMMENT_NODE : { + result = createCommentPropertyDescriptor((Comment) node); + break; + } + case Node.DOCUMENT_TYPE_NODE : { + result = createDocumentTypePropertyDescriptor((DocumentType) node); + break; + } + case Node.ELEMENT_NODE : { + result = createElementPropertyDescriptor((Element) node); + break; + } + case Node.ENTITY_REFERENCE_NODE : { + result = createEntityReferencePropertyDescriptor((EntityReference) node); + break; + } + case Node.PROCESSING_INSTRUCTION_NODE : { + result = createProcessingInstructionPropertyDescriptor((ProcessingInstruction) node); + break; + } + case Node.TEXT_NODE : { + result = createTextPropertyDescriptor((Text) node); + break; + } + } + } + return result; + } + + public IPropertyDescriptor createTextPropertyDescriptor(Text text) { + return createDefaultPropertyDescriptor(HACK); + } + + /** + * @return + */ + public ModelQuery getModelQuery() { + return fModelQuery; + } + +}
\ No newline at end of file diff --git a/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/TreeContentHelper.java b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/TreeContentHelper.java new file mode 100644 index 0000000000..d042bc2a8c --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/TreeContentHelper.java @@ -0,0 +1,431 @@ +/******************************************************************************* + * Copyright (c) 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + + +package org.eclipse.wst.xml.ui.internal.tabletree; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Vector; + +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.PlatformUI; +import org.eclipse.wst.common.contentmodel.util.DOMWriter; +import org.eclipse.wst.xml.core.document.XMLModel; +import org.eclipse.wst.xml.core.document.XMLNode; +import org.w3c.dom.Attr; +import org.w3c.dom.CharacterData; +import org.w3c.dom.DOMException; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.ProcessingInstruction; +import org.w3c.dom.Text; + + +/** + * This performs the work of taking a DOM tree and converting it to a + * displayable 'UI' tree. + * + * For example : - white space text nodes are ommited from the 'UI' tree - + * adjacent Text and EntityReference nodes are combined into a single 'UI' + * node - Elements with 'text only' children are diplayed without children + * + */ +public class TreeContentHelper { + + public static final int HIDE_WHITE_SPACE_TEXT_NODES = 8; + public static final int COMBINE_ADJACENT_TEXT_AND_ENTITY_REFERENCES = 16; + public static final int HIDE_ELEMENT_CHILD_TEXT_NODES = 32; + + protected int style = HIDE_WHITE_SPACE_TEXT_NODES | COMBINE_ADJACENT_TEXT_AND_ENTITY_REFERENCES | HIDE_ELEMENT_CHILD_TEXT_NODES; + + /** + * + */ + public boolean hasStyleFlag(int flag) { + return (style & flag) != 0; + } + + /** + * + */ + public Object[] getChildren(Object element) { + Object[] result = null; + + if (element instanceof Node) { + Node node = (Node) element; + List list = new ArrayList(); + boolean textContentOnly = true; + + NamedNodeMap map = node.getAttributes(); + if (map != null) { + int length = map.getLength(); + for (int i = 0; i < length; i++) { + list.add(map.item(i)); + textContentOnly = false; + } + } + + Node prevIncludedNode = null; + for (Node childNode = node.getFirstChild(); childNode != null; childNode = childNode.getNextSibling()) { + int childNodeType = childNode.getNodeType(); + boolean includeNode = true; + + if (includeNode && hasStyleFlag(HIDE_WHITE_SPACE_TEXT_NODES)) { + if (isIgnorableText(childNode)) { + // filter out the ignorable text node + includeNode = false; + } + } + + if (includeNode && hasStyleFlag(COMBINE_ADJACENT_TEXT_AND_ENTITY_REFERENCES)) { + if (isTextOrEntityReferenceNode(childNode) && prevIncludedNode != null && isTextOrEntityReferenceNode(prevIncludedNode)) { + // we only show the first of a list of adjacent text + // or entity reference node in the tree + // so we filter out this subsequent one + includeNode = false; + } + } + + if (hasStyleFlag(HIDE_ELEMENT_CHILD_TEXT_NODES)) { + if (childNodeType != Node.TEXT_NODE && childNodeType != Node.ENTITY_REFERENCE_NODE) { + textContentOnly = false; + } + } + + if (includeNode) { + list.add(childNode); + prevIncludedNode = childNode; + } + } + + if (hasStyleFlag(HIDE_ELEMENT_CHILD_TEXT_NODES) && textContentOnly) { + result = new Object[0]; + } else { + result = list.toArray(); + } + } + return result; + } + + /** + * + */ + protected boolean isTextOrEntityReferenceNode(Node node) { + return node.getNodeType() == Node.TEXT_NODE || node.getNodeType() == Node.ENTITY_REFERENCE_NODE; + } + + /** + * + */ + public boolean isIgnorableText(Node node) { + boolean result = false; + if (node.getNodeType() == Node.TEXT_NODE) { + String data = ((Text) node).getData(); + result = (data == null || data.trim().length() == 0); + } + return result; + } + + /** + * + */ + public boolean isCombinedTextNode(Node node) { + boolean result = false; + if (node.getNodeType() == Node.TEXT_NODE) { + Node nextNode = node.getNextSibling(); + if (nextNode != null) { + if (nextNode.getNodeType() == Node.ENTITY_REFERENCE_NODE) { + result = true; + } + } + } else if (node.getNodeType() == Node.ENTITY_REFERENCE_NODE) { + result = true; + } + return result; + } + + /** + * + */ + public List getCombinedTextNodeList(Node theNode) { + List list = new Vector(); + boolean prevIsEntity = false; + for (Node node = theNode; node != null; node = node.getNextSibling()) { + int nodeType = node.getNodeType(); + if (nodeType == Node.ENTITY_REFERENCE_NODE) { + prevIsEntity = true; + list.add(node); + } else if (nodeType == Node.TEXT_NODE && (prevIsEntity || node == theNode)) { + prevIsEntity = false; + list.add(node); + } else { + break; + } + } + return list; + } + + /** + * If the element is has 'text only' content this method will return the + * list of elements that compose the text only content + */ + public List getElementTextContent(Element element) { + List result = null; + if (!element.hasAttributes()) { + for (Node node = element.getFirstChild(); node != null; node = node.getNextSibling()) { + if (node.getNodeType() == Node.TEXT_NODE || node.getNodeType() == Node.ENTITY_REFERENCE_NODE) { + if (result == null) { + result = new Vector(); + } + result.add(node); + } else { + result = null; + break; + } + } + } + return result; + } + + /** + * + */ + public String getNodeValue(Node node) { + String result = null; + int nodeType = node.getNodeType(); + switch (nodeType) { + case Node.ATTRIBUTE_NODE : { + result = ((Attr) node).getValue(); + break; + } + case Node.CDATA_SECTION_NODE : + // drop thru + case Node.COMMENT_NODE : { + result = ((CharacterData) node).getData(); + break; + } + case Node.DOCUMENT_TYPE_NODE : { + result = getDocumentTypeValue((DocumentType) node); + break; + } + case Node.ELEMENT_NODE : { + result = getElementNodeValue((Element) node); + break; + } + case Node.ENTITY_REFERENCE_NODE : + // drop thru + case Node.TEXT_NODE : { + result = getTextNodeValue(node); + break; + } + case Node.PROCESSING_INSTRUCTION_NODE : { + result = ((ProcessingInstruction) node).getData(); + break; + } + } + return result; + } + + /** + * + */ + public void setNodeValue(Node node, String value) { + int nodeType = node.getNodeType(); + try { + switch (nodeType) { + case Node.ATTRIBUTE_NODE : { + ((Attr) node).setValue(value); + break; + } + case Node.CDATA_SECTION_NODE : + // drop thru + case Node.COMMENT_NODE : { + ((CharacterData) node).setData(value); + break; + } + case Node.ELEMENT_NODE : { + setElementNodeValue((Element) node, value); + break; + } + case Node.ENTITY_REFERENCE_NODE : + // drop thru + case Node.TEXT_NODE : { + setTextNodeValue(node, value); + break; + } + case Node.PROCESSING_INSTRUCTION_NODE : { + ((ProcessingInstruction) node).setData(value); + break; + } + } + } catch (DOMException e) { + Display d = getDisplay(); + if (d != null) + d.beep(); + } + } + + private Display getDisplay() { + + return PlatformUI.getWorkbench().getDisplay(); + } + + + /** + * + */ + protected String getDocumentTypeValue(DocumentType documentType) { + return DOMWriter.getDocumentTypeData(documentType); + } + + /** + * + */ + protected String getElementNodeValue(Element element) { + String result = null; + List list = getElementTextContent(element); + if (list != null) { + result = getValueForTextContent(list); + } + return result; + } + + /** + * + */ + protected void setElementNodeValue(Element element, String value) { + List list = getElementTextContent(element); + if (list != null) { + setValueForTextContent(list, value); + } else { + Document document = element.getOwnerDocument(); + Text text = document.createTextNode(value); + element.appendChild(text); + } + } + + /** + * + */ + protected String getTextNodeValue(Node node) { + String result = null; + List list = null; + if (isCombinedTextNode(node)) { + list = getCombinedTextNodeList(node); + } else { + list = new Vector(); + list.add(node); + } + result = getValueForTextContent(list); + return result; + } + + /** + * + */ + protected void setTextNodeValue(Node node, String value) { + List list = null; + if (isCombinedTextNode(node)) { + list = getCombinedTextNodeList(node); + } else { + list = new Vector(); + list.add(node); + } + setValueForTextContent(list, value); + } + + public Text getEffectiveTextNodeForCombinedNodeList(List list) { + Text result = null; + for (Iterator i = list.iterator(); i.hasNext();) { + Node node = (Node) i.next(); + if (node.getNodeType() == Node.TEXT_NODE) { + result = (Text) node; + break; + } + } + return result; + } + + /** + * + */ + protected String getValueForTextContent(List list) { + String result = null; + if (list.size() > 0) { + XMLNode first = (XMLNode) list.get(0); + XMLNode last = (XMLNode) list.get(list.size() - 1); + XMLModel model = first.getModel(); + int start = first.getStartOffset(); + int end = last.getEndOffset(); + try { + result = model.getStructuredDocument().get(start, end - start); + } catch (Exception e) { + } + } + + // we trim the content so that it looks nice when viewed + // we need to be carfull to preserve the 'trimmed' text when the value + // is set (see setValueForTextContent) + if (result != null) { + result = result.trim(); + } + return result; + } + + /** + * + */ + protected void setValueForTextContent(List list, String value) { + //String oldValue = getValueForTextContent(); + // we worry about preserving trimmed text + if (list.size() > 0) { + XMLNode first = (XMLNode) list.get(0); + XMLNode last = (XMLNode) list.get(list.size() - 1); + int start = first.getStartOffset(); + int end = last.getEndOffset(); + first.getModel().getStructuredDocument().replaceText(this, start, end - start, value); + } + } + + /** + * + */ + public boolean isEditable(Node node) { + int nodeType = node.getNodeType(); + boolean result = false; + switch (nodeType) { + case Node.ATTRIBUTE_NODE : + // drop thru + case Node.CDATA_SECTION_NODE : + // drop thru + case Node.COMMENT_NODE : + // drop thru + case Node.ENTITY_REFERENCE_NODE : + // drop thru + case Node.TEXT_NODE : + // drop thru + case Node.PROCESSING_INSTRUCTION_NODE : { + result = true; + break; + } + case Node.ELEMENT_NODE : { + result = getElementTextContent((Element) node) != null || node.getChildNodes().getLength() == 0; + break; + } + } + return result; + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/TreeExtension.java b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/TreeExtension.java new file mode 100644 index 0000000000..bd3c54e938 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/TreeExtension.java @@ -0,0 +1,512 @@ +/***************************************************************************** + * Copyright (c) 2004 IBM Corporation and others. All rights reserved. This + * program and the accompanying materials are made available under the terms + * of the Eclipse Public License v1.0 which accompanies this distribution, and + * is available at http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: IBM Corporation - initial API and implementation + ****************************************************************************/ + + +package org.eclipse.wst.xml.ui.internal.tabletree; + +import java.util.Iterator; +import java.util.List; +import java.util.Vector; + +import org.eclipse.jface.viewers.CellEditor; +import org.eclipse.jface.viewers.ICellEditorListener; +import org.eclipse.jface.viewers.ICellModifier; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.FocusEvent; +import org.eclipse.swt.events.FocusListener; +import org.eclipse.swt.events.KeyAdapter; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.KeyListener; +import org.eclipse.swt.events.MouseAdapter; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseMoveListener; +import org.eclipse.swt.events.PaintEvent; +import org.eclipse.swt.events.PaintListener; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Cursor; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.ScrollBar; +import org.eclipse.swt.widgets.Text; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.swt.widgets.TreeItem; +import org.eclipse.ui.PlatformUI; + + +public class TreeExtension implements PaintListener { + + protected Tree tree; + protected EditManager editManager; + protected String[] columnProperties; + protected ICellModifier cellModifier; + protected int columnPosition = 300; + protected int columnHitWidth = 5; + protected Color tableLineColor; + protected int controlWidth; + protected DelayedDrawTimer delayedDrawTimer; + + public TreeExtension(Tree tree) { + this.tree = tree; + InternalMouseListener listener = new InternalMouseListener(); + tree.addMouseMoveListener(listener); + tree.addMouseListener(listener); + tree.addPaintListener(this); + editManager = new EditManager(tree); + delayedDrawTimer = new DelayedDrawTimer(tree); + + tableLineColor = tree.getDisplay().getSystemColor(SWT.COLOR_LIST_FOREGROUND); + } + + public void dispose() { + tableLineColor.dispose(); + } + + public void setCellModifier(ICellModifier modifier) { + cellModifier = modifier; + } + + public void resetCachedData() { + } + + public ICellModifier getCellModifier() { + return cellModifier; + } + + public List getItemList() { + List list = new Vector(); + getItemListHelper(tree.getItems(), list); + return list; + } + + protected void getItemListHelper(TreeItem[] items, List list) { + for (int i = 0; i < items.length; i++) { + TreeItem item = items[i]; + list.add(item); + getItemListHelper(item.getItems(), list); + } + } + + protected TreeItem getTreeItemOnRow(int px, int py) { + TreeItem result = null; + List list = getItemList(); + for (Iterator i = list.iterator(); i.hasNext();) { + TreeItem item = (TreeItem) i.next(); + Rectangle r = item.getBounds(); + if (r != null && px >= r.x && py >= r.y && py <= r.y + r.height) { + result = item; + } + } + return result; + } + + protected class InternalMouseListener extends MouseAdapter implements MouseMoveListener { + protected int columnDragged = -1; + protected boolean isDown = false; + protected int prevX = -1; + protected Cursor cursor = null; + + public void mouseMove(MouseEvent e) { + if (e.x > columnPosition - columnHitWidth && e.x < columnPosition + columnHitWidth) { + if (cursor == null) { + cursor = new Cursor(tree.getDisplay(), SWT.CURSOR_SIZEWE); + tree.setCursor(cursor); + } + } else { + if (cursor != null) { + tree.setCursor(null); + cursor.dispose(); + cursor = null; + } + } + + if (columnDragged != -1) { + // using the delay timer will make redraws less flickery + if (e.x > 20) { + columnPosition = e.x; + delayedDrawTimer.reset(20); + } + } + } + + public void mouseDown(MouseEvent e) { + // here we handle the column resizing by detect if the user has + // click on a column separator + // + columnDragged = -1; + editManager.deactivateCellEditor(); + + if (e.x > columnPosition - columnHitWidth && e.x < columnPosition + columnHitWidth) { + columnDragged = 0; + } + + // here we handle selecting tree items when any thing on the 'row' + // is clicked + // + TreeItem item = tree.getItem(new Point(e.x, e.y)); + if (item == null) { + item = getTreeItemOnRow(e.x, e.y); + if (item != null) { + TreeItem[] items = new TreeItem[1]; + items[0] = item; + tree.setSelection(items); + } + } + } + + public void mouseUp(MouseEvent e) { + columnDragged = -1; + } + } + + public String[] getColumnProperties() { + return columnProperties; + } + + public void setColumnProperties(String[] columnProperties) { + this.columnProperties = columnProperties; + } + + public void paintControl(PaintEvent event) { + GC gc = event.gc; + Rectangle treeBounds = tree.getBounds(); + + controlWidth = treeBounds.width; + Color bg = tree.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND); + Color bg2 = tree.getDisplay().getSystemColor(SWT.COLOR_LIST_SELECTION); + + gc.setBackground(bg2); + + // // This next part causes problems on LINUX, so let's not do it + // there + // if (B2BHacks.IS_UNIX == false) { + // TreeItem[] selectedItems = tree.getSelection(); + // if (selectedItems.length > 0) { + // for (int i = 0; i < selectedItems.length; i++) { + // TreeItem item = selectedItems[i]; + // Rectangle bounds = item.getBounds(); + // if (bounds != null) { + // gc.fillRectangle(bounds.x + bounds.width, bounds.y, controlWidth, + // bounds.height); + // } + // } + // } + // } + // + TreeItem[] items = tree.getItems(); + if (items.length > 0) { + gc.setForeground(tableLineColor); + gc.setBackground(bg); + + gc.fillRectangle(columnPosition, treeBounds.x, treeBounds.width, treeBounds.height); + + Rectangle itemBounds = items[0].getBounds(); + int height = computeTreeItemHeight(); + + if (itemBounds != null) { + int startY = itemBounds.y < treeBounds.y ? itemBounds.y : treeBounds.y + ((treeBounds.y - itemBounds.y) % height); + + for (int i = startY; i < treeBounds.height; i += height) { + if (i >= treeBounds.y) { + gc.drawLine(0, i, treeBounds.width, i); + } + } + } + gc.drawLine(columnPosition, 0, columnPosition, treeBounds.height); + } else { + addEmptyTreeMessage(gc); + } + + paintItems(gc, items, treeBounds); + } + + protected int computeTreeItemHeight() { + int result = -1; + + // On GTK tree.getItemHeight() seems to lie to us. It reports that the + // tree item occupies a few pixles less + // vertical space than it should. This which foils our code that draw + // the 'row' lines since we assume that + // lines should be drawn at 'itemHeight' increments. In the case of + // LINUX we don't trust getItemHeight() + // to compute the increment... instead we compute the value based on + // distance between two TreeItems. + // if (B2BHacks.IS_UNIX) { + // TreeItem[] items = tree.getItems(); + // Rectangle itemBounds = items[0].getBounds(); + // + // if (items[0].getExpanded()) { + // TreeItem[] children = items[0].getItems(); + // if (children.length > 0) { + // result = children[0].getBounds().y - itemBounds.y; + // } + // } + // else if (items.length > 1) { + // result = items[1].getBounds().y - itemBounds.y; + // } + // } + + result = result != -1 ? result : tree.getItemHeight(); + return result; + } + + protected void addEmptyTreeMessage(GC gc) { + } + + public void paintItems(GC gc, TreeItem[] items, Rectangle treeBounds) { + if (items != null) { + for (int i = 0; i < items.length; i++) { + TreeItem item = items[i]; + if (item != null) { + Rectangle bounds = item.getBounds(); + if (bounds != null) { + if (treeBounds.intersects(bounds)) { + paintItem(gc, item, bounds); + } + } + + // defect 241039 + // + if (item.getExpanded()) { + paintItems(gc, item.getItems(), treeBounds); + } + } + } + } + } + + protected void paintItem(GC gc, TreeItem item, Rectangle bounds) { + } + + public interface ICellEditorProvider { + CellEditor getCellEditor(Object o, int col); + } + + /** + * This class is used to improve drawing during a column resize. + */ + public class DelayedDrawTimer implements Runnable { + protected Control control; + + public DelayedDrawTimer(Control control) { + this.control = control; + } + + public void reset(int milliseconds) { + getDisplay().timerExec(milliseconds, this); + } + + public void run() { + control.redraw(); + } + } + + private Display getDisplay() { + + return PlatformUI.getWorkbench().getDisplay(); + } + + /** + * EditManager + */ + public class EditManager { + protected Tree tree; + protected Control cellEditorHolder; + protected CellEditorState cellEditorState; + + public EditManager(Tree tree) { + this.tree = tree; + this.cellEditorHolder = new Composite(tree, SWT.NONE); + + final Tree theTree = tree; + + MouseAdapter theMouseAdapter = new MouseAdapter() { + public void mouseDown(MouseEvent e) { + deactivateCellEditor(); + + if (e.x > columnPosition + columnHitWidth) { + TreeItem[] items = theTree.getSelection(); + // No edit if more than one row is selected. + if (items.length == 1) { + Rectangle bounds = items[0].getBounds(); + if (bounds != null && e.y >= bounds.y && e.y <= bounds.y + bounds.height) { + int columnToEdit = 1; + activateCellEditor(items[0], columnToEdit); + } + } + } + } + }; + + SelectionListener selectionListener = new SelectionListener() { + public void widgetDefaultSelected(SelectionEvent e) { + applyCellEditorValue(); + } + + public void widgetSelected(SelectionEvent e) { + applyCellEditorValue(); + } + }; + + KeyListener keyListener = new KeyAdapter() { + public void keyPressed(KeyEvent e) { + if (e.character == SWT.CR) { + deactivateCellEditor(); + TreeItem[] items = theTree.getSelection(); + if (items.length == 1) { + activateCellEditor(items[0], 1); + } + } + } + }; + + tree.addMouseListener(theMouseAdapter); + tree.addKeyListener(keyListener); + ScrollBar hBar = tree.getHorizontalBar(); + if (hBar != null) + hBar.addSelectionListener(selectionListener); + ScrollBar vBar = tree.getVerticalBar(); + if (vBar != null) + vBar.addSelectionListener(selectionListener); + } + + public boolean isCellEditorActive() { + return cellEditorState != null; + } + + public void applyCellEditorValue() { + if (cellEditorState != null && cellModifier != null) { + TreeItem treeItem = cellEditorState.treeItem; + + // The area below the cell editor needs to be explicity + // repainted on Linux + // + // Rectangle r = B2BHacks.IS_UNIX ? treeItem.getBounds() : + // null; + + Object value = cellEditorState.cellEditor.getValue(); + String property = cellEditorState.property; + + deactivateCellEditor(); + + cellModifier.modify(treeItem, property, value); + + // if (r != null) { + // tree.redraw(r.x, r.y, tree.getBounds().width, r.height, + // false); + // } + } + } + + public void deactivateCellEditor() { + // Clean up any previous editor control + if (cellEditorState != null) { + cellEditorState.deactivate(); + cellEditorState = null; + } + } + + public void activateCellEditor(TreeItem treeItem, int column) { + if (cellModifier instanceof ICellEditorProvider) { + ICellEditorProvider cellEditorProvider = (ICellEditorProvider) cellModifier; + Object data = treeItem.getData(); + if (columnProperties.length > column) { + String property = columnProperties[column]; + if (cellModifier.canModify(data, property)) { + CellEditor newCellEditor = cellEditorProvider.getCellEditor(data, column); + if (newCellEditor != null) { + // The control that will be the editor must be a + // child of the columnPosition + Control control = newCellEditor.getControl(); + if (control != null) { + cellEditorState = new CellEditorState(newCellEditor, control, treeItem, column, property); + cellEditorState.activate(); + } + } + } + } + } + } + + /** + * this class holds the state that is need on a per cell editor + * invocation basis + */ + public class CellEditorState implements ICellEditorListener, FocusListener { + public CellEditor cellEditor; + public Control control; + public TreeItem treeItem; + public int columnNumber; + public String property; + + public CellEditorState(CellEditor cellEditor, Control control, TreeItem treeItem, int columnNumber, String property) { + this.cellEditor = cellEditor; + this.control = control; + this.treeItem = treeItem; + this.columnNumber = columnNumber; + this.property = property; + } + + public void activate() { + Object element = treeItem.getData(); + String value = cellModifier.getValue(element, property).toString(); + if (control instanceof Text) { + Text text = (Text) control; + int requiredSize = value.length() + 100; + if (text.getTextLimit() < requiredSize) { + text.setTextLimit(requiredSize); + } + } + Rectangle r = treeItem.getBounds(); + if (r != null) { + control.setBounds(columnPosition + 5, r.y + 1, tree.getClientArea().width - (columnPosition + 5), r.height - 1); + control.setVisible(true); + cellEditor.setValue(value); + cellEditor.addListener(this); + cellEditor.setFocus(); + control.addFocusListener(this); + } + } + + public void deactivate() { + cellEditor.removeListener(this); + control.removeFocusListener(this); + cellEditor.deactivate(); + tree.forceFocus(); + } + + // ICellEditorListener methods + // + public void applyEditorValue() { + applyCellEditorValue(); + } + + public void cancelEditor() { + deactivateCellEditor(); + } + + public void editorValueChanged(boolean oldValidState, boolean newValidState) { + } + + // FocusListener methods + // + public void focusGained(FocusEvent e) { + } + + public void focusLost(FocusEvent e) { + applyCellEditorValue(); + } + } + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/ViewerExpandCollapseAction.java b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/ViewerExpandCollapseAction.java new file mode 100644 index 0000000000..956c7dee2c --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/ViewerExpandCollapseAction.java @@ -0,0 +1,69 @@ +/***************************************************************************** + * Copyright (c) 2004 IBM Corporation and others. All rights reserved. This + * program and the accompanying materials are made available under the terms + * of the Eclipse Public License v1.0 which accompanies this distribution, and + * is available at http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: IBM Corporation - initial API and implementation + ****************************************************************************/ + + +package org.eclipse.wst.xml.ui.internal.tabletree; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.viewers.AbstractTreeViewer; +import org.eclipse.wst.xml.internal.ui.XMLEditorPluginImageHelper; +import org.eclipse.wst.xml.internal.ui.XMLEditorPluginImages; +import org.eclipse.wst.xml.ui.util.XMLCommonResources; + + + +public class ViewerExpandCollapseAction extends Action { + + protected boolean isExpandAction; + protected AbstractTreeViewer viewer = null; + + public ViewerExpandCollapseAction(boolean isExpandAction) { + this.isExpandAction = isExpandAction; + if (isExpandAction) { + ImageDescriptor e_imageDescriptor = XMLEditorPluginImageHelper.getInstance().getImageDescriptor(XMLEditorPluginImages.IMG_ETOOL_EXPANDALL); + ImageDescriptor d_imageDescriptor = XMLEditorPluginImageHelper.getInstance().getImageDescriptor(XMLEditorPluginImages.IMG_DTOOL_EXPANDALL); + + setImageDescriptor(e_imageDescriptor); + setDisabledImageDescriptor(d_imageDescriptor); + setToolTipText(XMLCommonResources.getInstance().getString("_UI_INFO_EXPAND_ALL")); //$NON-NLS-1$ + } else { + ImageDescriptor e_imageDescriptor = XMLEditorPluginImageHelper.getInstance().getImageDescriptor(XMLEditorPluginImages.IMG_ETOOL_COLLAPSEALL); + ImageDescriptor d_imageDescriptor = XMLEditorPluginImageHelper.getInstance().getImageDescriptor(XMLEditorPluginImages.IMG_DTOOL_COLLAPSEALL); + + setImageDescriptor(e_imageDescriptor); + setDisabledImageDescriptor(d_imageDescriptor); + setToolTipText(XMLCommonResources.getInstance().getString("_UI_INFO_COLLAPSE_ALL")); //$NON-NLS-1$ + } + } + + public void setViewer(AbstractTreeViewer viewer) { + this.viewer = viewer; + } + + public void run() { + if (viewer != null) { + // temporarily set the visibility to false + // this has a HUGE performance benefit + boolean isVisible = viewer.getControl().getVisible(); + viewer.getControl().setVisible(false); + + if (isExpandAction) { + viewer.expandAll(); + } else { + viewer.collapseAll(); + } + + // restore the previous visibility state + // + viewer.getControl().setVisible(isVisible); + } + } +} + diff --git a/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLTableTreeActionBarContributor.java b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLTableTreeActionBarContributor.java new file mode 100644 index 0000000000..02675f7956 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLTableTreeActionBarContributor.java @@ -0,0 +1,325 @@ +/******************************************************************************* + * Copyright (c) 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.wst.xml.ui.internal.tabletree; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.action.IContributionManager; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.action.Separator; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.ui.IActionBars; +import org.eclipse.ui.IEditorActionBarContributor; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IEditorSite; +import org.eclipse.ui.IWorkbenchActionConstants; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPartSite; +import org.eclipse.ui.texteditor.ITextEditor; +import org.eclipse.ui.texteditor.ITextEditorActionConstants; +import org.eclipse.wst.common.contentmodel.modelquery.ModelQuery; +import org.eclipse.wst.common.contentmodel.modelqueryimpl.CMDocumentLoader; +import org.eclipse.wst.common.contentmodel.modelqueryimpl.InferredGrammarBuildingCMDocumentLoader; +import org.eclipse.wst.sse.core.IStructuredModel; +import org.eclipse.wst.sse.ui.StructuredTextEditor; +import org.eclipse.wst.xml.core.document.XMLModel; +import org.eclipse.wst.xml.core.modelquery.ModelQueryUtil; +import org.eclipse.wst.xml.internal.ui.IDesignViewer; +import org.eclipse.wst.xml.internal.ui.IDesignViewerActionBarContributor; +import org.eclipse.wst.xml.internal.ui.XMLMultiPageEditorPart; +import org.eclipse.wst.xml.ui.nls2.ResourceHandler; +import org.eclipse.wst.xml.ui.util.SharedXMLEditorPluginImageHelper; +import org.w3c.dom.Document; + + +/** + * + */ +public class XMLTableTreeActionBarContributor implements IDesignViewerActionBarContributor { + + protected IEditorPart editorPart; + protected final static String DESIGN_VIEWER_SEPARATOR_1_ID = "sed.tabletree.separator.1"; //$NON-NLS-1$ + protected final static String DESIGN_VIEWER_SEPARATOR_2_ID = "sed.tabletree.separator.2"; //$NON-NLS-1$ + protected final static String VALIDATE_XML_ID = "sed.tabletree.validateXML"; //$NON-NLS-1$ + protected final static String RELOAD_GRAMMAR_ID = "sed.tabletree.reloadGrammar"; //$NON-NLS-1$ + protected final static String TOGGLE_EDIT_MODE_ID = "sed.tabletree.toggleEditMode"; //$NON-NLS-1$ + protected final static String EXPAND_ALL_ID = "sed.tabletree.expandAll"; //$NON-NLS-1$ + protected final static String COLLAPSE_ALL_ID = "sed.tabletree.collapseAll"; //$NON-NLS-1$ + + protected ToggleEditModeAction toggleAction; + protected ReloadGrammarAction reloadGrammarAction; + // protected ValidateXMLAction validateXMLAction; + protected ViewerExpandCollapseAction expandAction; + protected ViewerExpandCollapseAction collapseAction; + protected ViewerExpandCollapseAction xmlMenuExpandAction; + protected ViewerExpandCollapseAction xmlMenuCollapseAction; + + public XMLTableTreeActionBarContributor() { + } + + protected void removeContributions(IContributionManager manager) { + try { + doRemove(manager, DESIGN_VIEWER_SEPARATOR_1_ID); + doRemove(manager, DESIGN_VIEWER_SEPARATOR_2_ID); + doRemove(manager, VALIDATE_XML_ID); + doRemove(manager, RELOAD_GRAMMAR_ID); + doRemove(manager, TOGGLE_EDIT_MODE_ID); + doRemove(manager, EXPAND_ALL_ID); + doRemove(manager, COLLAPSE_ALL_ID); + } catch (Exception e) { + } + } + + protected void doRemove(IContributionManager manager, String id) { + try { + if (manager.find(id) != null) { + manager.remove(id); + } + } catch (Exception e) { + } + } + + public void init(IActionBars bars, IWorkbenchPage page) { + init(bars); + } + + public void init(IActionBars bars) { + IToolBarManager tbm = bars.getToolBarManager(); + + IMenuManager xmlMenu = bars.getMenuManager().findMenuUsingPath("com.ibm.etools.sed.editor.xmlmenu"); //$NON-NLS-1$ + + if (xmlMenu == null) { + xmlMenu = new MenuManager(ResourceHandler.getString("XMLTableTreeActionBarContributor.0"), "com.ibm.etools.sed.editor.xmlmenu"); //$NON-NLS-1$ //$NON-NLS-2$ + bars.getMenuManager().insertBefore(IWorkbenchActionConstants.M_WINDOW, xmlMenu); + } else { + removeContributions(xmlMenu); + } + + tbm.add(new Separator("DESIGN_VIEWER_SEPARATOR_1_ID")); //$NON-NLS-1$ + + // ValidateXMLAction + // + // ugly hack ... we don't contribute the generic XML validator if we + // already + // have a DAD validator contribution (in the case of the DAD editor). + // This hack will be removed when defect 212448 is fixed. + // + // if (tbm.find("validate.dad.validateDAD") == null) { + // validateXMLAction = new ValidateXMLAction(); + // tbm.add(validateXMLAction); + // xmlMenu.add(validateXMLAction); + // } + + // ToggleEditModeAction + // + toggleAction = new ToggleEditModeAction(); + toggleAction.setId(TOGGLE_EDIT_MODE_ID); + xmlMenu.add(toggleAction); + tbm.add(toggleAction); + + // ReloadGrammarAction + // + reloadGrammarAction = new ReloadGrammarAction(); + reloadGrammarAction.setId(RELOAD_GRAMMAR_ID); + tbm.add(reloadGrammarAction); + xmlMenu.add(reloadGrammarAction); + + xmlMenu.add(new Separator()); + + // ExpandCollapseAction + // + xmlMenuExpandAction = new ViewerExpandCollapseAction(true); + xmlMenuExpandAction.setId(EXPAND_ALL_ID); + xmlMenuExpandAction.setText(ResourceHandler.getString("XMLTableTreeActionBarContributor.1")); //$NON-NLS-1$ + xmlMenu.add(xmlMenuExpandAction); + + xmlMenuCollapseAction = new ViewerExpandCollapseAction(false); + xmlMenuCollapseAction.setId(COLLAPSE_ALL_ID); + xmlMenuCollapseAction.setId(EXPAND_ALL_ID); + xmlMenuCollapseAction.setText(ResourceHandler.getString("XMLTableTreeActionBarContributor.2")); //$NON-NLS-1$ + xmlMenu.add(xmlMenuCollapseAction); + } + + protected void addActionWithId(IMenuManager menuManager, Action action, String id) { + action.setId(id); + menuManager.add(action); + } + + public void initViewerSpecificContributions(IActionBars bars) { + IToolBarManager tbm = bars.getToolBarManager(); + tbm.add(new Separator(DESIGN_VIEWER_SEPARATOR_2_ID)); + + expandAction = new ViewerExpandCollapseAction(true); + expandAction.setId(EXPAND_ALL_ID); + tbm.add(expandAction); + + collapseAction = new ViewerExpandCollapseAction(false); + collapseAction.setId(COLLAPSE_ALL_ID); + tbm.add(collapseAction); + } + + public void setViewerSpecificContributionsEnabled(boolean enabled) { + if (expandAction != null) { + expandAction.setEnabled(enabled); + xmlMenuExpandAction.setEnabled(enabled); + } + + if (collapseAction != null) { + collapseAction.setEnabled(enabled); + xmlMenuCollapseAction.setEnabled(enabled); + } + } + + public void setActiveEditor(IEditorPart targetEditor) { + editorPart = targetEditor; + + IStructuredModel model = getModelForEditorPart(targetEditor); + reloadGrammarAction.setModel(model); + toggleAction.setModelQuery(ModelQueryUtil.getModelQuery(model)); + + XMLTableTreeViewer tableTreeViewer = getTableTreeViewerForEditorPart(editorPart); + if (tableTreeViewer != null) { + expandAction.setViewer(tableTreeViewer); + collapseAction.setViewer(tableTreeViewer); + + xmlMenuExpandAction.setViewer(tableTreeViewer); + xmlMenuCollapseAction.setViewer(tableTreeViewer); + } + + if (editorPart instanceof XMLMultiPageEditorPart) { + IWorkbenchPartSite site = editorPart.getSite(); + if (site instanceof IEditorSite) { + ITextEditor textEditor = ((XMLMultiPageEditorPart) editorPart).getTextEditor(); + IActionBars actionBars = ((IEditorSite) site).getActionBars(); + actionBars.setGlobalActionHandler(ITextEditorActionConstants.UNDO, getAction(textEditor, ITextEditorActionConstants.UNDO)); + actionBars.setGlobalActionHandler(ITextEditorActionConstants.REDO, getAction(textEditor, ITextEditorActionConstants.REDO)); + } + } + + // TODO... uncomment this and investigate NPE + // + // add the cut/copy/paste for text fields + // ActionHandlerPlugin.connectPart(editorPart); + } + + protected final IAction getAction(ITextEditor editor, String actionId) { + return (editor == null ? null : editor.getAction(actionId)); + } + + protected IStructuredModel getModelForEditorPart(IEditorPart targetEditor) { + IStructuredModel result = null; + if (editorPart instanceof XMLMultiPageEditorPart) { + StructuredTextEditor textEditor = ((XMLMultiPageEditorPart) targetEditor).getTextEditor(); + result = (textEditor != null) ? textEditor.getModel() : null; + } + return result; + } + + protected XMLTableTreeViewer getTableTreeViewerForEditorPart(IEditorPart targetEditor) { + XMLTableTreeViewer result = null; + Object object = targetEditor.getAdapter(IDesignViewer.class); + if (object instanceof XMLTableTreeViewer) { + result = (XMLTableTreeViewer) object; + } + return result; + } + + /** + * + */ + public class ToggleEditModeAction extends Action { + protected ImageDescriptor onImage = SharedXMLEditorPluginImageHelper.getImageDescriptor(SharedXMLEditorPluginImageHelper.IMG_ETOOL_CONSTRAINON); + protected ImageDescriptor offImage = SharedXMLEditorPluginImageHelper.getImageDescriptor(SharedXMLEditorPluginImageHelper.IMG_ETOOL_CONSTRAINOFF); + protected ModelQuery modelQuery; + + public ToggleEditModeAction() { + setAppearanceForEditMode(ModelQuery.EDIT_MODE_CONSTRAINED_STRICT); + } + + public void run() { + if (modelQuery != null) { + int newState = getNextState(modelQuery.getEditMode()); + modelQuery.setEditMode(newState); + setAppearanceForEditMode(newState); + } + } + + public void setModelQuery(ModelQuery newModelQuery) { + modelQuery = newModelQuery; + if (modelQuery != null) { + setAppearanceForEditMode(modelQuery.getEditMode()); + } + } + + public void setAppearanceForEditMode(int editMode) { + if (editMode == ModelQuery.EDIT_MODE_CONSTRAINED_STRICT) { + setToolTipText(ResourceHandler.getString("XMLTableTreeActionBarContributor.3")); //$NON-NLS-1$ + setText(ResourceHandler.getString("XMLTableTreeActionBarContributor.4")); //$NON-NLS-1$ + setImageDescriptor(onImage); + } else { + setToolTipText(ResourceHandler.getString("XMLTableTreeActionBarContributor.5")); //$NON-NLS-1$ + setText(ResourceHandler.getString("XMLTableTreeActionBarContributor.6")); //$NON-NLS-1$ + setImageDescriptor(offImage); + } + } + + public int getNextState(int editMode) { + int result = -1; + if (editMode == ModelQuery.EDIT_MODE_CONSTRAINED_STRICT) { + result = ModelQuery.EDIT_MODE_UNCONSTRAINED; + } else { + result = ModelQuery.EDIT_MODE_CONSTRAINED_STRICT; + } + return result; + } + } + + /** + * + */ + public class ReloadGrammarAction extends Action { + protected IStructuredModel model; + + public ReloadGrammarAction() { + setDisabledImageDescriptor(SharedXMLEditorPluginImageHelper.getImageDescriptor(SharedXMLEditorPluginImageHelper.IMG_DTOOL_RLDGRMR)); + setImageDescriptor(SharedXMLEditorPluginImageHelper.getImageDescriptor(SharedXMLEditorPluginImageHelper.IMG_ETOOL_RLDGRMR)); + setToolTipText(ResourceHandler.getString("XMLTableTreeActionBarContributor.7")); //$NON-NLS-1$ + setText(ResourceHandler.getString("XMLTableTreeActionBarContributor.8")); //$NON-NLS-1$ + } + + public void setModel(IStructuredModel newModel) { + this.model = newModel; + } + + public void run() { + if (model != null) { + ModelQuery modelQuery = ModelQueryUtil.getModelQuery(model); + Document document = ((XMLModel) model).getDocument(); + if (modelQuery != null && modelQuery.getCMDocumentManager() != null) { + modelQuery.getCMDocumentManager().getCMDocumentCache().clear(); + // TODO... need to figure out how to access the + // DOMObserver via ModelQuery + // ...why? + CMDocumentLoader loader = new InferredGrammarBuildingCMDocumentLoader(document, modelQuery); + loader.loadCMDocuments(); + } + } + } + } + + /** + * @see IEditorActionBarContributor#dispose() + */ + public void dispose() { + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLTableTreeContentProvider.java b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLTableTreeContentProvider.java new file mode 100644 index 0000000000..7255aaa7e2 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLTableTreeContentProvider.java @@ -0,0 +1,367 @@ +/***************************************************************************** + * Copyright (c) 2004 IBM Corporation and others. All rights reserved. This + * program and the accompanying materials are made available under the terms + * of the Eclipse Public License v1.0 which accompanies this distribution, and + * is available at http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: IBM Corporation - initial API and implementation + ****************************************************************************/ + + +package org.eclipse.wst.xml.ui.internal.tabletree; + +import java.util.Iterator; +import java.util.List; +import java.util.Vector; + +import org.eclipse.jface.viewers.ILabelProvider; +import org.eclipse.jface.viewers.ILabelProviderListener; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.StructuredViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Control; +import org.eclipse.wst.common.contentmodel.CMDocument; +import org.eclipse.wst.common.contentmodel.modelquery.CMDocumentManager; +import org.eclipse.wst.common.contentmodel.modelquery.CMDocumentManagerListener; +import org.eclipse.wst.common.contentmodel.modelquery.ModelQuery; +import org.eclipse.wst.common.contentmodel.util.CMDocumentCache; +import org.eclipse.wst.sse.core.AbstractAdapterFactory; +import org.eclipse.wst.sse.core.INodeAdapter; +import org.eclipse.wst.sse.core.INodeNotifier; +import org.eclipse.wst.xml.core.modelquery.ModelQueryUtil; +import org.eclipse.wst.xml.ui.Logger; +import org.eclipse.wst.xml.ui.util.SharedXMLEditorPluginImageHelper; +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.ProcessingInstruction; +import org.w3c.dom.Text; + + +public class XMLTableTreeContentProvider implements ITreeContentProvider, ITableLabelProvider, ILabelProvider, CMDocumentManagerListener { + + protected ViewerNotifyingAdapterFactory viewerNotifyingAdapterFactory = new ViewerNotifyingAdapterFactory(); + protected XMLTableTreePropertyDescriptorFactory propertyDescriptorFactory; + // protected ImageFactory imageFactory = + // XMLCommonUIPlugin.getInstance().getImageFactory(); + protected List viewerList = new Vector(); + protected TreeContentHelper treeContentHelper = new TreeContentHelper(); + + protected CMDocumentManager documentManager; + + public XMLTableTreeContentProvider() { + } + + public void getDecendantList(Object element, List list) { + Object[] children = getChildren(element); + if (children != null) { + for (int i = 0; i < children.length; i++) { + Object child = children[i]; + list.add(child); + getDecendantList(child, list); + } + } + } + + public void addViewer(Viewer viewer) { + viewerList.add(viewer); + } + + public Object[] getChildren(Object element) { + viewerNotifyingAdapterFactory.doAdapt(element); + return treeContentHelper.getChildren(element); + } + + public Object getParent(Object o) { + Object result = null; + if (o instanceof Node) { + Node node = (Node) o; + if (node.getNodeType() == Node.ATTRIBUTE_NODE) { + result = ((Attr) node).getOwnerElement(); + } else { + result = node.getParentNode(); + } + } + return result; + } + + public boolean hasChildren(Object element) { + viewerNotifyingAdapterFactory.doAdapt(element); + return getChildren(element).length > 0; + } + + public Object[] getElements(Object element) { + viewerNotifyingAdapterFactory.doAdapt(element); + return getChildren(element); + } + + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + // remove our listeners to the old state + if (oldInput != null) { + propertyDescriptorFactory = null; + Document domDoc = (Document) oldInput; + ModelQuery mq = ModelQueryUtil.getModelQuery(domDoc); + if (mq != null) { + documentManager = mq.getCMDocumentManager(); + if (documentManager != null) { + documentManager.removeListener(this); + } + } + } + + if (newInput != null) { + Document domDoc = (Document) newInput; + ModelQuery mq = ModelQueryUtil.getModelQuery(domDoc); + + if (mq != null) { + propertyDescriptorFactory = new XMLTableTreePropertyDescriptorFactory(mq); + documentManager = mq.getCMDocumentManager(); + if (documentManager != null) { + documentManager.setPropertyEnabled(CMDocumentManager.PROPERTY_ASYNC_LOAD, true); + documentManager.addListener(this); + } + } + } + } + + public boolean isDeleted(Object element) { + return element != null; + } + + // + // ILabelProvider stuff + // + public void addListener(ILabelProviderListener listener) { + } + + public void dispose() { + viewerList = new Vector(); + } + + public Element getRootElement(Document document) { + Element rootElement = null; + + for (Node childNode = document.getFirstChild(); childNode != null; childNode = childNode.getNextSibling()) { + if (childNode.getNodeType() == Node.ELEMENT_NODE) { + rootElement = (Element) childNode; + break; + } + } + return rootElement; + } + + public Image getImage(Object object) { + viewerNotifyingAdapterFactory.doAdapt(object); + Image image = null; + if (object instanceof Node) { + Node node = (Node) object; + switch (node.getNodeType()) { + case Node.ATTRIBUTE_NODE : { + image = SharedXMLEditorPluginImageHelper.getImage(SharedXMLEditorPluginImageHelper.IMG_OBJ_ATTRIBUTE); + break; + } + case Node.CDATA_SECTION_NODE : { + image = SharedXMLEditorPluginImageHelper.getImage(SharedXMLEditorPluginImageHelper.IMG_OBJ_CDATASECTION); + break; + } + case Node.COMMENT_NODE : { + image = SharedXMLEditorPluginImageHelper.getImage(SharedXMLEditorPluginImageHelper.IMG_OBJ_COMMENT); + break; + } + case Node.DOCUMENT_TYPE_NODE : { + image = SharedXMLEditorPluginImageHelper.getImage(SharedXMLEditorPluginImageHelper.IMG_OBJ_DOCTYPE); + break; + } + case Node.ELEMENT_NODE : { + image = SharedXMLEditorPluginImageHelper.getImage(SharedXMLEditorPluginImageHelper.IMG_OBJ_ELEMENT); + break; + } + case Node.PROCESSING_INSTRUCTION_NODE : { + image = SharedXMLEditorPluginImageHelper.getImage(SharedXMLEditorPluginImageHelper.IMG_OBJ_PROCESSINGINSTRUCTION); + break; + } + case Node.TEXT_NODE : { + image = SharedXMLEditorPluginImageHelper.getImage(SharedXMLEditorPluginImageHelper.IMG_OBJ_TXTEXT); + break; + } + case Node.ENTITY_REFERENCE_NODE : { + image = image = SharedXMLEditorPluginImageHelper.getImage(SharedXMLEditorPluginImageHelper.IMG_OBJ_ENTITY_REFERENCE); + break; + } + } + + // if (image != null) { + // Image markerOverlayImage = + // overlayIconManager.getOverlayImageForObject(node); + // if (markerOverlayImage != null) { + // image = imageFactory.createCompositeImage(image, + // markerOverlayImage, ImageFactory.BOTTOM_LEFT); + // } + // } + } + return image; + } + + public String getText(Object object) { + viewerNotifyingAdapterFactory.doAdapt(object); + String result = null; + if (object instanceof Node) { + Node node = (Node) object; + switch (node.getNodeType()) { + case Node.ATTRIBUTE_NODE : { + result = node.getNodeName(); + break; + } + case Node.DOCUMENT_TYPE_NODE : { + result = "DOCTYPE"; //$NON-NLS-1$ + break; + } + case Node.ELEMENT_NODE : { + result = node.getNodeName(); + break; + } + case Node.PROCESSING_INSTRUCTION_NODE : { + result = ((ProcessingInstruction) node).getTarget(); + break; + } + } + } + return result != null ? result : ""; //$NON-NLS-1$ + } + + // + // ITableLabelProvider stuff + // + public String getColumnText(Object object, int column) { + viewerNotifyingAdapterFactory.doAdapt(object); + String result = null; + if (column == 0) { + result = getText(object); + } else if (column == 1 && object instanceof Node) { + result = treeContentHelper.getNodeValue((Node) object); + } + return result != null ? result : ""; //$NON-NLS-1$ + } + + public Image getColumnImage(Object object, int columnIndex) { + viewerNotifyingAdapterFactory.doAdapt(object); + return (columnIndex == 0) ? getImage(object) : null; + } + + public boolean isLabelProperty(Object object, String property) { + return false; + } + + public void removeListener(ILabelProviderListener listener) { + } + + // There is only 1 adapter associated with this factory. This single + // adapter gets added + // to the adapter lists of many nodes. + public class ViewerNotifyingAdapterFactory extends AbstractAdapterFactory { + protected ViewerNotifyingAdapter viewerNotifyingAdapter = new ViewerNotifyingAdapter(); + + protected INodeAdapter createAdapter(INodeNotifier target) { + return viewerNotifyingAdapter; + } + + protected ViewerNotifyingAdapter doAdapt(Object object) { + ViewerNotifyingAdapter result = null; + if (object instanceof INodeNotifier) { + result = (ViewerNotifyingAdapter) adapt((INodeNotifier) object); + } + return result; + } + } + + public class ViewerNotifyingAdapter implements INodeAdapter { + public boolean isAdapterForType(Object type) { + return type.equals(viewerNotifyingAdapterFactory); + } + + public void notifyChanged(INodeNotifier notifier, int eventType, Object changedFeature, Object oldValue, Object newValue, int pos) { + switch (eventType) { + //case INodeNotifier.ADD: // ignore + //case INodeNotifier.REMOVE: // ignore + case INodeNotifier.CHANGE : + case INodeNotifier.STRUCTURE_CHANGED : + case INodeNotifier.CONTENT_CHANGED : { + Node node = (Node) notifier; + if (node.getNodeType() == Node.ELEMENT_NODE || node.getNodeType() == Node.DOCUMENT_NODE) { + for (Iterator i = viewerList.iterator(); i.hasNext();) { + Viewer viewer = (Viewer) i.next(); + + if (viewer instanceof StructuredViewer) { + ((StructuredViewer) viewer).refresh(node); + } else { + // todo... consider doing a time delayed + // refresh here!! + viewer.refresh(); + } + } + } + break; + } + } + } + } + + // the following methods handle filtering aspects of the viewer + // + // + public boolean isIgnorableText(Node node) { + boolean result = false; + try { + if (node.getNodeType() == Node.TEXT_NODE) { + String data = ((Text) node).getData(); + result = (data == null || data.trim().length() == 0); + } + } catch (Exception e) { + Logger.logException(e); + } + return result; + } + + public static Text getHiddenChildTextNode(Node node) { + return null; + } + + // CMDocumentManagerListener + // + public void cacheCleared(CMDocumentCache cache) { + doDelayedRefreshForViewers(); + } + + public void cacheUpdated(CMDocumentCache cache, final String uri, int oldStatus, int newStatus, CMDocument cmDocument) { + if (newStatus == CMDocumentCache.STATUS_LOADED || newStatus == CMDocumentCache.STATUS_ERROR) { + doDelayedRefreshForViewers(); + } + } + + public void propertyChanged(CMDocumentManager cmDocumentManager, String propertyName) { + if (cmDocumentManager.getPropertyEnabled(CMDocumentManager.PROPERTY_AUTO_LOAD)) { + doDelayedRefreshForViewers(); + } + } + + protected void doDelayedRefreshForViewers() { + List list = new Vector(); + list.addAll(viewerList); + + for (Iterator i = list.iterator(); i.hasNext();) { + final Viewer viewer = (Viewer) i.next(); + Control control = viewer.getControl(); + Runnable runnable = new Runnable() { + public void run() { + viewer.refresh(); + } + }; + // we need to ensure that this is run via 'asyncExec' since these + // notifications can come from a non-ui thread + control.getDisplay().asyncExec(runnable); + } + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLTableTreeHelpContextIds.java b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLTableTreeHelpContextIds.java new file mode 100644 index 0000000000..7f2730e9d0 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLTableTreeHelpContextIds.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.wst.xml.ui.internal.tabletree; + + + +/** + * Help context ids for the TableTree view. + * <p> + * This interface contains constants only; it is not intended to be + * implemented or extended. + * </p> + * + */ +public interface XMLTableTreeHelpContextIds { + + public static final String PREFIX = "com.ibm.etools.sed.tabletree."; //$NON-NLS-1$ + + // XML Design View + public static final String XML_DESIGN_VIEW_HELPID = PREFIX + "xmlm3000"; //$NON-NLS-1$ +}
\ No newline at end of file diff --git a/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLTableTreePropertyDescriptorFactory.java b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLTableTreePropertyDescriptorFactory.java new file mode 100644 index 0000000000..65fe7554f7 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLTableTreePropertyDescriptorFactory.java @@ -0,0 +1,97 @@ +/***************************************************************************** + * Copyright (c) 2004 IBM Corporation and others. All rights reserved. This + * program and the accompanying materials are made available under the terms + * of the Eclipse Public License v1.0 which accompanies this distribution, and + * is available at http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: IBM Corporation - initial API and implementation + ****************************************************************************/ + + +package org.eclipse.wst.xml.ui.internal.tabletree; + +import java.util.List; + +import org.eclipse.ui.views.properties.IPropertyDescriptor; +import org.eclipse.ui.views.properties.TextPropertyDescriptor; +import org.eclipse.wst.common.contentmodel.CMAttributeDeclaration; +import org.eclipse.wst.common.contentmodel.CMElementDeclaration; +import org.eclipse.wst.common.contentmodel.CMNode; +import org.eclipse.wst.common.contentmodel.modelquery.ModelQuery; +import org.eclipse.wst.sse.ui.views.properties.EnumeratedStringPropertyDescriptor; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.Text; + + +public class XMLTableTreePropertyDescriptorFactory extends DOMPropertyDescriptorFactory { + + protected TreeContentHelper treeContentHelper = new TreeContentHelper(); + + public XMLTableTreePropertyDescriptorFactory(ModelQuery modelQuery) { + super(modelQuery); + } + + protected IPropertyDescriptor createPropertyDescriptorHelper(String name, Element element, CMNode cmNode) { + IPropertyDescriptor result = null; + + String[] valuesArray = getModelQuery().getPossibleDataTypeValues(element, cmNode); + if (valuesArray != null && valuesArray.length > 0) { + result = new EnumeratedStringPropertyDescriptor(name, name, valuesArray); + } + + return result; + } + + public IPropertyDescriptor createTextPropertyDescriptor(Text text) { + IPropertyDescriptor result = null; + Node parentNode = text.getParentNode(); + if (parentNode != null && parentNode.getNodeType() == Node.ELEMENT_NODE) { + Element parentElement = (Element) parentNode; + CMElementDeclaration ed = getModelQuery().getCMElementDeclaration(parentElement); + if (ed != null) { + result = createPropertyDescriptorHelper(HACK, parentElement, ed); + } + } + + if (result == null) { + result = new TextPropertyDescriptor(HACK, HACK); + } + + return result; + } + + public IPropertyDescriptor createAttributePropertyDescriptor(Attr attr) { + IPropertyDescriptor result = null; + + String attributeName = attr.getName(); + + CMAttributeDeclaration ad = getModelQuery().getCMAttributeDeclaration(attr); + if (ad != null) { + result = createPropertyDescriptorHelper(attributeName, attr.getOwnerElement(), ad); + } + + if (result == null) { + result = new TextPropertyDescriptor(attributeName, attributeName); + } + + return result; + } + + public IPropertyDescriptor createElementPropertyDescriptor(Element element) { + IPropertyDescriptor result = null; + List list = treeContentHelper.getElementTextContent(element); + if (list != null) { + Text text = treeContentHelper.getEffectiveTextNodeForCombinedNodeList(list); + if (text != null) { + result = createTextPropertyDescriptor(text); + } + } + + if (result == null) { + result = new TextPropertyDescriptor(HACK, HACK); + } + return result; + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLTableTreeViewer.java b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLTableTreeViewer.java new file mode 100644 index 0000000000..271fb80c06 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLTableTreeViewer.java @@ -0,0 +1,334 @@ +/***************************************************************************** + * Copyright (c) 2004 IBM Corporation and others. All rights reserved. This + * program and the accompanying materials are made available under the terms + * of the Eclipse Public License v1.0 which accompanies this distribution, and + * is available at http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: IBM Corporation - initial API and implementation + ****************************************************************************/ +package org.eclipse.wst.xml.ui.internal.tabletree; + +import java.util.List; + +import org.eclipse.jface.action.IMenuListener; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.action.Separator; +import org.eclipse.jface.viewers.CellEditor; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.ui.PlatformUI; +import org.eclipse.wst.common.contentmodel.modelquery.ModelQuery; +import org.eclipse.wst.sse.core.IModelStateListener; +import org.eclipse.wst.sse.core.IStructuredModel; +import org.eclipse.wst.sse.ui.ViewerSelectionManager; +import org.eclipse.wst.sse.ui.view.events.INodeSelectionListener; +import org.eclipse.wst.sse.ui.view.events.NodeSelectionChangedEvent; +import org.eclipse.wst.xml.core.document.XMLModel; +import org.eclipse.wst.xml.core.modelquery.ModelQueryUtil; +import org.eclipse.wst.xml.internal.ui.IDesignViewer; +import org.eclipse.wst.xml.ui.actions.NodeAction; +import org.eclipse.wst.xml.ui.dnd.XMLDragAndDropManager; +import org.eclipse.wst.xml.ui.nls2.ResourceHandler; +import org.eclipse.wst.xml.ui.views.contentoutline.XMLNodeActionManager; +import org.w3c.dom.Document; + + +public class XMLTableTreeViewer extends TreeViewer implements IDesignViewer { + + /** + * This class is used to improve source editing performance by coalescing + * multiple notifications for an element change into a single refresh + */ + class DelayedRefreshTimer implements Runnable { + private final int delta = 2000; + protected Object objectPendingRefresh; + protected ISelection pendingSelection; + protected Object prevObject; + protected XMLTableTreeViewer viewer; + + public DelayedRefreshTimer(XMLTableTreeViewer viewer) { + this.viewer = viewer; + } + + public boolean isRefreshPending() { + return objectPendingRefresh != null; + } + + public void refresh(Object object) { + if (prevObject == object) { + objectPendingRefresh = object; + getDisplay().timerExec(delta, this); + } else { + if (objectPendingRefresh != null) { + viewer.doRefresh(objectPendingRefresh, false); + objectPendingRefresh = null; + } + viewer.doRefresh(object, false); + } + prevObject = object; + } + + private Display getDisplay() { + + return PlatformUI.getWorkbench().getDisplay(); + } + + public void run() { + // defect 239677 ensure that the viewer's control is not disposed + // + if (objectPendingRefresh != null && !viewer.getTree().isDisposed()) { + viewer.doRefresh(objectPendingRefresh, true); + if (pendingSelection != null) { + // see fireSelectionChanged comment about jumping cursor + // problem + // + viewer.setSelection(pendingSelection, true); + pendingSelection = null; + } + objectPendingRefresh = null; + prevObject = null; + } + } + + public void setSelection(ISelection selection) { + pendingSelection = selection; + } + } + + class DelayingNodeSelectionListener implements INodeSelectionListener { + public void nodeSelectionChanged(NodeSelectionChangedEvent event) { + // if (isNodeSelectionListenerEnabled && + // !event.getSource().equals(this)) { + if (!event.getSource().equals(XMLTableTreeViewer.this)) { + List selectedNodes = event.getSelectedNodes(); + ISelection selection = new StructuredSelection(selectedNodes); + + // for performance purposes avoid large multi-selections + // + if (selectedNodes.size() < 100) { + if (timer.isRefreshPending()) { + timer.setSelection(selection); + } else { + setSelection(selection, true); + } + } + } + } + } + + class InternalModelStateListener implements IModelStateListener { + + public void modelAboutToBeChanged(IStructuredModel model) { + ignoreRefresh = true; + } + + public void modelChanged(IStructuredModel model) { + ignoreRefresh = false; + refresh(); + } + + public void modelDirtyStateChanged(IStructuredModel model, boolean isDirty) { + } + + public void modelResourceDeleted(IStructuredModel model) { + } + + public void modelResourceMoved(IStructuredModel originalmodel, IStructuredModel movedmodel) { + } + } + + class NodeActionMenuListener implements IMenuListener { + public void menuAboutToShow(IMenuManager menuManager) { + // used to disable NodeSelection listening while running + // NodeAction + XMLNodeActionManager nodeActionManager = new XMLNodeActionManager(fModel, XMLTableTreeViewer.this) { + public void beginNodeAction(NodeAction action) { + super.beginNodeAction(action); + } + + public void endNodeAction(NodeAction action) { + super.endNodeAction(action); + } + }; + nodeActionManager.fillContextMenu(menuManager, getSelection()); + } + } + + protected CellEditor cellEditor; + + int count = 0; + + protected IModelStateListener fInternalModelStateListener = new InternalModelStateListener(); + protected IStructuredModel fModel = null; + protected INodeSelectionListener fNodeSelectionListener; + + protected ViewerSelectionManager fViewerSelectionManager; + + protected boolean ignoreRefresh; + + protected DelayedRefreshTimer timer; + protected XMLTreeExtension treeExtension; + + public XMLTableTreeViewer(Composite parent) { + super(parent, SWT.FULL_SELECTION | SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); + + // set up providers + this.treeExtension = new XMLTreeExtension(getTree()); + + XMLTableTreeContentProvider provider = new XMLTableTreeContentProvider(); + provider.addViewer(this); + setContentProvider(provider); + setLabelProvider(provider); + + createContextMenu(); + + XMLDragAndDropManager.addDragAndDropSupport(this); + timer = new DelayedRefreshTimer(this); + } + + /** + * This creates a context menu for the viewer and adds a listener as well + * registering the menu for extension. + */ + protected void createContextMenu() { + MenuManager contextMenu = new MenuManager("#PopUp"); //$NON-NLS-1$ + contextMenu.add(new Separator("additions")); //$NON-NLS-1$ + contextMenu.setRemoveAllWhenShown(true); + contextMenu.addMenuListener(new NodeActionMenuListener()); + Menu menu = contextMenu.createContextMenu(getControl()); + getControl().setMenu(menu); + } + + protected void doRefresh(Object o, boolean fromDelayed) { + treeExtension.resetCachedData(); + super.refresh(o); + } + + protected void fireSelectionChanged(SelectionChangedEvent event) { + if (!getTree().isDisposed() && !getTree().isFocusControl()) { + // defect 246094 + // Various jumping cursor problems are caused when a selection + // 'delayed' selection occurs. + // These delayed selections are caused two ways: + // + // - when DelayedRefreshTimer calls doRefresh() ... the + // 'preserveSelection' causes selection to occur + // - when DelayedRefreshTimer performs a 'pending' selection + // + // Since we only want to update the selectionManager on an explict + // user action + // (and not some selection that is merely a resonse to the + // selection manager) + // we ensure that the tree has focus control before firing events + // to the selectionManager. + // + removeSelectionChangedListener(fViewerSelectionManager); + super.fireSelectionChanged(event); + addSelectionChangedListener(fViewerSelectionManager); + } else { + super.fireSelectionChanged(event); + } + } + + /** + * @return + */ + public INodeSelectionListener getNodeSelectionListener() { + if (fNodeSelectionListener == null) + fNodeSelectionListener = new DelayingNodeSelectionListener(); + return fNodeSelectionListener; + } + + public String getTitle() { + return ResourceHandler.getString("XMLTableTreeViewer.0"); //$NON-NLS-1$ + } + + protected void handleDispose(DisposeEvent event) { + super.handleDispose(event); + treeExtension.dispose(); + setModel(null); + setViewerSelectionManager(null); + + // if (fViewerSelectionManager != null) { + // fViewerSelectionManager.removeNodeSelectionListener(getNodeSelectionListener()); + // } + // + // fOverlayIconManager.setResource(null); + // super.handleDispose(event); + // + // if (fModel != null) + // fModel.removeModelStateListener(fInternalModelStateListener); + } + + public void refresh() { + if (!ignoreRefresh && !getControl().isDisposed()) { + treeExtension.resetCachedData(); + super.refresh(); + + // if (B2BHacks.IS_UNIX) { + // this is required to fix defect 193792 + // this fixes the problem where the 'paintHandler'drawn portions + // of tree weren't repainted properly + // + getTree().redraw(0, 0, getTree().getBounds().width, getTree().getBounds().height, false); + getTree().update(); + // } + } + } + + public void refresh(Object o) { + if (!ignoreRefresh && !getControl().isDisposed() && timer != null) { + if (getTree().isVisible()) { + doRefresh(o, false); + } else { + timer.refresh(o); + } + } + } + + public void setModel(IStructuredModel model) { + // remove + if (fModel != null) { + fModel.removeModelStateListener(fInternalModelStateListener); + } + + fModel = model; + Document domDoc = null; + + if (fModel != null && fModel instanceof XMLModel) { + model.addModelStateListener(fInternalModelStateListener); + ModelQuery mq = ModelQueryUtil.getModelQuery(model); + treeExtension.setModelQuery(mq); + domDoc = ((XMLModel) fModel).getDocument(); + setInput(domDoc); + } + } + + // the following methods implement the IDesignViewer interface + // - getControl() is implemented via AdvancedTableTreeViewer + // + public void setViewerSelectionManager(ViewerSelectionManager viewerSelectionManager) { + // disconnect from old one + if (fViewerSelectionManager != null) { + fViewerSelectionManager.removeNodeSelectionListener(getNodeSelectionListener()); + removeSelectionChangedListener(fViewerSelectionManager); + } + + fViewerSelectionManager = viewerSelectionManager; + + // connect to new one + if (fViewerSelectionManager != null) { + fViewerSelectionManager.addNodeSelectionListener(getNodeSelectionListener()); + addSelectionChangedListener(fViewerSelectionManager); + } + } + +}
\ No newline at end of file diff --git a/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLTreeExtension.java b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLTreeExtension.java new file mode 100644 index 0000000000..f1b842d0eb --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/internal/tabletree/XMLTreeExtension.java @@ -0,0 +1,184 @@ +/***************************************************************************** + * Copyright (c) 2004 IBM Corporation and others. All rights reserved. This + * program and the accompanying materials are made available under the terms + * of the Eclipse Public License v1.0 which accompanies this distribution, and + * is available at http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: IBM Corporation - initial API and implementation + ****************************************************************************/ + + +package org.eclipse.wst.xml.ui.internal.tabletree; + +import org.eclipse.jface.viewers.CellEditor; +import org.eclipse.jface.viewers.ICellModifier; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Item; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.swt.widgets.TreeItem; +import org.eclipse.ui.views.properties.IPropertyDescriptor; +import org.eclipse.wst.common.contentmodel.CMElementDeclaration; +import org.eclipse.wst.common.contentmodel.modelquery.ModelQuery; +import org.eclipse.wst.common.contentmodel.util.CMDescriptionBuilder; +import org.eclipse.wst.xml.ui.nls2.ResourceHandler; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + + +public class XMLTreeExtension extends TreeExtension { + + public final static String STRUCTURE_PROPERTY = ResourceHandler.getString("XMLTreeExtension.0"); //$NON-NLS-1$ + public final static String VALUE_PROPERTY = ResourceHandler.getString("XMLTreeExtension.1"); //$NON-NLS-1$ + + protected Composite control; + protected MyCellModifier modifier; + protected XMLTableTreePropertyDescriptorFactory propertyDescriptorFactory; + protected CMDescriptionBuilder decriptionBuilder = new CMDescriptionBuilder(); + protected TreeContentHelper treeContentHelper = new TreeContentHelper(); + + protected Color f1, f2, b1, b2; + protected boolean cachedDataIsValid = true; + private ModelQuery fModelQuery; + + public XMLTreeExtension(Tree tree) { + super(tree); + control = tree; + modifier = new MyCellModifier(); + setCellModifier(modifier); + String[] properties = {STRUCTURE_PROPERTY, VALUE_PROPERTY}; + setColumnProperties(properties); + + f1 = tree.getDisplay().getSystemColor(SWT.COLOR_BLACK); + Color background = tree.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND); + + int r = Math.abs(background.getRed() - 125); + int g = Math.abs(background.getGreen() - 85); + int b = Math.abs(background.getBlue() - 105); + + f2 = new Color(tree.getDisplay(), r, g, b); + b1 = tree.getDisplay().getSystemColor(SWT.COLOR_LIST_SELECTION); + b2 = background; + } + + public void dispose() { + super.dispose(); + f2.dispose(); + } + + public void resetCachedData() { + cachedDataIsValid = false; + } + + public void paintItems(GC gc, TreeItem[] items, Rectangle treeBounds) { + super.paintItems(gc, items, treeBounds); + cachedDataIsValid = true; + } + + protected Object[] computeTreeExtensionData(Object object) { + Color color = f1; + String string = ""; //$NON-NLS-1$ + if (string.length() == 0) { + string = (String) modifier.getValue(object, VALUE_PROPERTY); + color = f1; + } + if (string.length() == 0 && object instanceof Element) { + string = getElementValueHelper((Element) object); + color = f2; + } + Object[] data = new Object[2]; + data[0] = string; + data[1] = color; + return data; + } + + protected void paintItem(GC gc, TreeItem item, Rectangle bounds) { + super.paintItem(gc, item, bounds); + Object[] data = computeTreeExtensionData(item.getData()); + if (data != null && data.length == 2) { + gc.setClipping(columnPosition, bounds.y + 1, controlWidth, bounds.height); + gc.setForeground((Color) data[1]); + gc.drawString((String) data[0], columnPosition + 5, bounds.y + 1); + gc.setClipping((Rectangle) null); + } + } + + protected void addEmptyTreeMessage(GC gc) { + // here we print a message when the document is empty just to give the + // user a visual cue + // so that they know how to proceed to edit the blank view + gc.setForeground(tree.getDisplay().getSystemColor(SWT.COLOR_BLACK)); + gc.setBackground(tree.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND)); + gc.drawString(ResourceHandler.getString("XMLTreeExtension.3"), 10, 10); //$NON-NLS-1$ + gc.drawString(ResourceHandler.getString("XMLTreeExtension.4"), 10, 10 + gc.getFontMetrics().getHeight()); //$NON-NLS-1$ + } + + public String getElementValueHelper(Element element) { + String result = null; + + if (result == null && getModelQuery() != null) { + CMElementDeclaration ed = getModelQuery().getCMElementDeclaration(element); + if (ed != null && !Boolean.TRUE.equals(ed.getProperty("isInferred"))) { //$NON-NLS-1$ + result = decriptionBuilder.buildDescription(ed); + } + } + return result != null ? result : ""; //$NON-NLS-1$ + } + + /** + * + */ + public class MyCellModifier implements ICellModifier, TreeExtension.ICellEditorProvider { + public boolean canModify(Object element, String property) { + boolean result = false; + if (element instanceof Node) { + Node node = (Node) element; + result = property == VALUE_PROPERTY && treeContentHelper.isEditable(node); + } + return result; + } + + public Object getValue(Object object, String property) { + String result = null; + if (object instanceof Node) { + result = treeContentHelper.getNodeValue((Node) object); + } + return (result != null) ? result : ""; //$NON-NLS-1$ + } + + public void modify(Object element, String property, Object value) { + //enableNodeSelectionListener(false); + Item item = (Item) element; + String oldValue = treeContentHelper.getNodeValue((Node) item.getData()); + String newValue = value.toString(); + if (newValue != null && !newValue.equals(oldValue)) { + treeContentHelper.setNodeValue((Node) item.getData(), value.toString()); + } + //enableNodeSelectionListener(true); + } + + public CellEditor getCellEditor(Object o, int col) { + IPropertyDescriptor pd = propertyDescriptorFactory.createPropertyDescriptor(o); + return pd != null ? pd.createPropertyEditor(control) : null; + } + } + + /** + * @return + */ + public ModelQuery getModelQuery() { + return fModelQuery; + } + + /** + * @param query + */ + public void setModelQuery(ModelQuery query) { + fModelQuery = query; + propertyDescriptorFactory = new XMLTableTreePropertyDescriptorFactory(query); + } + +}
\ No newline at end of file diff --git a/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/nls2/ResourceHandler.java b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/nls2/ResourceHandler.java new file mode 100644 index 0000000000..1eae6c1f6e --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src-multipage/org/eclipse/wst/xml/ui/nls2/ResourceHandler.java @@ -0,0 +1,64 @@ +/***************************************************************************** + * Copyright (c) 2004 IBM Corporation and others. All rights reserved. This + * program and the accompanying materials are made available under the terms + * of the Eclipse Public License v1.0 which accompanies this distribution, and + * is available at http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: IBM Corporation - initial API and implementation + ****************************************************************************/ +package org.eclipse.wst.xml.ui.nls2; + +import java.text.MessageFormat; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +public class ResourceHandler { + + + private static ResourceBundle fgResourceBundle; + + /** + * Returns the resource bundle used by all classes in this Project + */ + public static ResourceBundle getResourceBundle() { + try { + return ResourceBundle.getBundle("xmleditor");//$NON-NLS-1$ + } catch (MissingResourceException e) { + // does nothing - this method will return null and + // getString(String) will return the key + // it was called with + } + return null; + } + + public static String getString(String key) { + if (fgResourceBundle == null) { + fgResourceBundle = getResourceBundle(); + } + + if (fgResourceBundle != null) { + try { + return fgResourceBundle.getString(key); + } catch (MissingResourceException e) { + return "!" + key + "!";//$NON-NLS-2$//$NON-NLS-1$ + } + } else { + return "!" + key + "!";//$NON-NLS-2$//$NON-NLS-1$ + } + } + + public static String getString(String key, Object[] args) { + + try { + return MessageFormat.format(getString(key), args); + } catch (IllegalArgumentException e) { + return getString(key); + } + + } + + public static String getString(String key, Object[] args, int x) { + + return getString(key); + } +}
\ No newline at end of file diff --git a/bundles/org.eclipse.wst.xml.ui/src/EditingXML.properties b/bundles/org.eclipse.wst.xml.ui/src/EditingXML.properties new file mode 100644 index 0000000000..8371547a7e --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/EditingXML.properties @@ -0,0 +1,230 @@ +############################################################################### +# Copyright (c) 2001, 2004 IBM Corporation and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# IBM Corporation - initial API and implementation +# Jens Lukowski/Innoopract - initial renaming/restructuring +# +############################################################################### +## The following line is a sample XML document. Please translate only the following parts: +## begin color definitions +## Normal text content. +Sample_XML_doc=<?xml version=\"1.0\"?>\n<?customProcessingInstruction\n\tXML processor specific\n\tcontent ?>\n<!DOCTYPE colors\n\tPUBLIC \"//IBM/XML/COLORS/\" \"colors.dtd\">\n<colors>\n\t<!-- begin color definitions -->\n\t<color name=\"plaintext\" foreground=\"#000000\"\n\t\tbackground=\"#D4D0C8\" />\n\t<color name=\"bold\" foreground=\"#000000\"\n\t\tbackground=\"#B3ACA0\" />\n\t<![CDATA[<123456789>]]>\n\tNormal text content.\n\t<color name=\"inverse\" foreground=\"#F0F0F0\"\n\t\tbackground=\"#D4D0C8\" />\n\n</colors>\n +Comment_Delimiters_UI_=Comment Delimiters +Comment_Content_UI_=Comment Content +Tag_Delimiters_UI_=Tag Delimiters +Tag_Names_UI_=Tag Names +Attribute_Names_UI_=Attribute Names +Attribute_Values_UI_=Attribute Values +Declaration_Delimiters_UI_=Declaration Delimiters +Content_UI_=Content +## on the following 2 lines, do not translate CDATA +CDATA_Delimiters_UI_=CDATA Delimiters +CDATA_Content_UI_=CDATA Content +Processing_Instruction_Del_UI_=Processing Instruction Delimiters +Processing_Instruction_Con_UI__UI_=Processing Instruction Content +## on the following line solely translate: Name +DOCTYPE_Name_UI_=DOCTYPE Name +## on the following line solely translate: Keyword +DOCTYPE_SYSTEM/PUBLIC_Keyw_UI_=DOCTYPE SYSTEM/PUBLIC Keyword +## on the following line solely translate: Public Reference +DOCTYPE_Public_Reference_UI_=DOCTYPE Public Reference +## on the following line solely translate: System Reference +DOCTYPE_System_Reference_UI_=DOCTYPE System Reference +# XML Common UI +# Constants for strings + +NEW=New +DELETE=Remove +ADD_TEXT=Add Text +ADD_CDATA_SECTION=Add CDATA Section +ADD_COMMENT=Add Commen&t +ADD_PROCESSING_INSTRUCTION=Add Processing Instruction + +_UI_MENU_ADD_AFTER=Add &After +_UI_MENU_ADD_ATTRIBUTE=Add A&ttribute +_UI_MENU_ADD_BEFORE=Add &Before +_UI_MENU_ADD_CHILD=Add &Child +_UI_MENU_REMOVE=Re&move +_UI_MENU_REPLACE_WITH=Re&place With +_UI_MENU_ADD_DOCTYPE=Add DOCTYPE... +_UI_MENU_EDIT_DOCTYPE=Edit DOCTYPE... +_UI_MENU_ADD_GRAMMAR_INFORMATION=Add Grammar Information +_UI_MENU_VALIDATE_XML=Validate XML File +_UI_LABEL_UNDO_ADD_DESCRIPTION=Add +_UI_LABEL_UNDO_REPLACE_DESCRIPTION=Replace +_UI_LABEL_EDIT_DOCTYPE=Edit DOCTYPE +_UI_INFO_EXPAND_ALL=IWAK0108I Expand All +_UI_INFO_COLLAPSE_ALL=IWAK0109I Collapse All + +_UI_MENU_ADD_DTD_INFORMATION=Add DTD Information... +_UI_MENU_ADD_SCHEMA_INFORMATION=Add Schema Information... +_UI_MENU_EDIT_SCHEMA_INFORMATION=Edit &Schema Information... +_UI_MENU_EDIT_PROCESSING_INSTRUCTION=Edit Process&ing Instruction... +_UI_MENU_EDIT_NAMESPACES=Edit &Namespaces... + +_UI_MENU_ADD_DTD_INFORMATION_TITLE=Add DTD Information +_UI_MENU_EDIT_PROCESSING_INSTRUCTION_TITLE=Edit Processing Instruction +_UI_MENU_EDIT_SCHEMA_INFORMATION_TITLE=Edit Schema Information + +_UI_MENU_NEW_ATTRIBUTE=&New Attribute... +_UI_MENU_NEW_ATTRIBUTE_TITLE=New Attribute +_UI_MENU_EDIT_ATTRIBUTE=Edit Attribute... +_UI_MENU_EDIT_ATTRIBUTE_TITLE=Edit Attribute +_UI_MENU_NEW_ELEMENT=New &Element... +_UI_MENU_NEW_ELEMENT_TITLE=New Element +_UI_MENU_RENAME=R&ename +_UI_MENU_RENAME_TITLE=Rename +_UI_LABEL_ELEMENT_NAME=Element name: +_UI_LABEL_LOADING_GRAMMAR=Loading grammar: + +_UI_MENU_ADD_COMMENT=Add Comment +_UI_MENU_ADD_PROCESSING_INSTRUCTION=Add Processing Instruction +_UI_MENU_ADD_CDATA_SECTION=Add CDATA Section +_UI_MENU_ADD_PCDATA=Add #PCDATA; + +_UI_MENU_COMMENT=C&omment +_UI_MENU_PROCESSING_INSTRUCTION=P&rocessing Instruction +_UI_MENU_CDATA_SECTION=CDATA Section +_UI_MENU_PCDATA=#PC&DATA; + +_UI_MENU_ADD=Add + +_UI_COMMENT_VALUE=comment +_UI_PI_TARGET_VALUE=target +_UI_PI_DATA_VALUE=data +_UI_LABEL_ROOT_ELEMENT_VALUE=RootElement + +_UI_LABEL_TARGET_COLON=Target: +_UI_LABEL_DATA_COLON=Data: +_UI_LABEL_ROOT_ELEMENT_NAME_COLON=Root element name: +_UI_LABEL_PUBLIC_ID_COLON=Public ID: +_UI_LABEL_SYSTEM_ID_COLON=System ID: +_UI_LABEL_BROWSE=Browse... +_UI_LABEL_SELECT_XML_CATALOG_ENTRY=Select XML Catalog Entry +_UI_LABEL_SPECIFY_SYSTEM_ID=Specify System ID +_UI_LABEL_SELECT_FILE=Select File + +_UI_LABEL_KEY=Key +_UI_LABEL_URI=URI: +_UI_LABEL_XML_CATALOG_COLON=XML Catalog +_UI_LABEL_NAMESPACE_NAME=Namespace Name +_UI_LABEL_LOCATION_HINT=Location Hint +_UI_LABEL_PREFIX=Prefix +_UI_LABEL_NAMESPACE_NAME_COLON=Namespace Name: +_UI_LABEL_LOCATION_HINT_COLON=Location Hint: +_UI_LABEL_PREFIX_COLON=Prefix: +_UI_NO_NAMESPACE_NAME=<no namespace name> +_UI_NO_PREFIX=<no prefix> + +_UI_LABEL_XML_SCHEMA_INFORMATION=XML Schema Information +_UI_LABEL_NAMESPACE_INFORMATION=Namespace Information + +_UI_LABEL_NAME_COLON=Name: +_UI_LABEL_VALUE_COLON=Value: + +_UI_BUTTON_DELETE=Delete +_UI_BUTTON_NEW=New... +_UI_BUTTON_EDIT=Edit... + +_UI_LABEL_NEW_NAMESPACE_INFORMATION=New Namespace Information +_UI_LABEL_EDIT_NAMESPACE_INFORMATION=Edit Namespace Information + +# +# Assign links to an XML file +# +_UI_WORK_BENCH=Workbench Files... +_UI_FILE_SYSTEM=Import Files... +_UI_ASSIGN_XSL=Assign An XSL Stylesheet To The XML File +_UI_ASSIGN_DTD=Assign A DTD file To The XML File +_UI_ASSIGN_XSD=Assign An XML schema To The XML File +_UI_SELECT_XSL_TITLE=Select an XSL File +_UI_SELECT_XSL_DESC=Select an XSL file from the workbench. + +_UI_ASSIGN=Assign +_UI_XSD=XML Schema... +_UI_DTD=DTD... +_UI_XSL=XSL Stylesheet... + +# XMLValidator.java +_UI_XML_VALIDATOR=XML Validator +# SelectFileOrXMLCatalogIdPanel.java + +_UI_RADIO_BUTTON_SELECT_FROM_WORKSPACE=Select file from workbench +_UI_RADIO_BUTTON_SELECT_FROM_CATALOG=Select XML Catalog entry + +_UI_WARNING_TITLE_ROOT_ELEMENT_REQUIRED=Root Element Required +_UI_WARNING_DOCUMENT_REQUIRES_ROOT=The document requires a root element in order to add schema information. +_UI_WARNING_MORE_THAN_ONE_NS_WITH_NAME=More than one namespace has been specified with the namespace name : +_UI_WARNING_MORE_THAN_ONE_NS_WITHOUT_NAME=More than one schema has been specified without a namespace name +_UI_WARNING_MORE_THAN_ONE_NS_WITHOUT_PREFIX=More than one namespace has been specificed without a prefix +_UI_WARNING_MORE_THAN_ONE_NS_WITH_PREFIX=More than one namespace has been specified with the prefix : +_UI_WARNING_SCHEMA_CAN_NOT_BE_LOCATED=The specified schema can not be located : +_UI_WARNING_LOCATION_HINT_NOT_SPECIFIED=A location hint has not been specified for the namespace with name +_UI_WARNING_NAMESPACE_NAME_NOT_SPECIFIED=A name must be specified for the namespace with prefix : +_UI_WARNING_PREFIX_NOT_SPECIFIED=A prefix must be specified for the namespace named : +_UI_WARNING_ROOT_ELEMENT_MUST_BE_SPECIFIED=A root element name must be specified. +_UI_WARNING_SYSTEM_ID_MUST_BE_SPECIFIED=A system ID must be specified. + +_UI_INVALID_NAME=Invalid name + +# String used for editing namespaces (org.eclipse.wst.xml.ui.nsedit) +_UI_ENTER_REQ_PREFIX_AND_NAMESPACE=Enter the required prefix and namespace URI for the namespace declaration. +_UI_SELECT_REGISTERED_NAMESPACES=Select From Registered Namespaces +_UI_SPECIFY_NEW_NAMESPACE=Specify New Namespace +_UI_SELECT_NAMESPACE_TO_ADD=Select the namespace declarations to add. +_UI_ADD_NAMESPACE_DECLARATIONS=Add Namespace Declarations +_UI_NAMESPACE_DECLARATIONS=Namespace Declarations +_UI_TARGET_NAMESPACE=Target Namespace + + +#====================================================================================== +# +# Here is the list of Error string that have message IDs - make sure they are unique +# Range for XMLBuilder messageIDs: IWAX1601E - IWAX1800E +# Since we'll be combing these plugins at some later point we'll use the same range +# and be carefull not to clobber those defined in xmlbuilder's plugin.properties +#====================================================================================== +_ERROR_XML_ATTRIBUTE_ALREADY_EXISTS=IWAK0110E The element already has an attribute with this name. + +# +error_message_goes_here=error message goes here +SurroundWithNewElementQuickAssistProposal.0=Surround with new element +SurroundWithNewElementQuickAssistProposal.1=Surround with new element +RenameInFileQuickAssistProposal.0=Link all references for a rename in file (does not change references in other files) +RenameInFileQuickAssistProposal.1=Rename in file +InsertRequiredAttrsQuickAssistProposal.0=Insert required attributes +InsertRequiredAttrsQuickAssistProposal.1=Insert required attributes +EncodingSettings.0=IANA: +EncodingSettings.1=Encoding: +TemplateContextTypeXMLTag.0=XML Tags +TemplateContextTypeXMLAttributeValue.0=XML Attribute Values +TemplateContextTypeXMLAttribute.0=XML Attributes +TemplateContextTypeXML.0=All XML +DragNodeCommand.0=Move +CommonEditNamespacesDialog.0=Add... +JFaceNodeAdapter.1=Refresh Property Sheet +QuickFixProcessorXML.0=Remove empty tag +QuickFixProcessorXML.1=Change to empty-element tag +QuickFixProcessorXML.2=Remove this tag +QuickFixProcessorXML.3=Insert end tag before first child element +QuickFixProcessorXML.4=Insert end tag at end of element +QuickFixProcessorXML.5=Remove attributes in end tag +QuickFixProcessorXML.6=Insert default attribute value +QuickFixProcessorXML.7=Remove this attribute +QuickFixProcessorXML.8=Remove spaces before tag name +QuickFixProcessorXML.9=Remove spaces before processing instruction +QuickFixProcessorXML.10=Remove namespace in processing instruction +QuickFixProcessorXML.11=Remove this element +QuickFixProcessorXML.12=Remove this attribute value +QuickFixProcessorXML.13=Insert required attribute +QuickFixProcessorXML.14=Quote attribute value +QuickFixProcessorXML.15=Insert closing bracket +QuickFixProcessorXML.16=Remove this attribute and its value +XMLPropertySourceAdapter.0=Attributes + +WorkbenchDefaultEncodingSettings.0=Use workbench encoding diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/DOMObserver.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/DOMObserver.java new file mode 100644 index 0000000000..e94585515d --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/DOMObserver.java @@ -0,0 +1,190 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui; + + +import java.util.Timer; +import java.util.TimerTask; + +import org.eclipse.wst.common.contentmodel.modelquery.CMDocumentManager; +import org.eclipse.wst.common.contentmodel.modelquery.ModelQuery; +import org.eclipse.wst.common.contentmodel.modelqueryimpl.CMDocumentLoader; +import org.eclipse.wst.common.contentmodel.modelqueryimpl.InferredGrammarBuildingCMDocumentLoader; +import org.eclipse.wst.sse.core.INodeAdapter; +import org.eclipse.wst.sse.core.INodeNotifier; +import org.eclipse.wst.sse.core.IStructuredModel; +import org.eclipse.wst.xml.core.document.XMLModel; +import org.eclipse.wst.xml.core.modelquery.ModelQueryUtil; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + + +/** + * This class is used to observe changes in the DOM and perform + * occasional'scans' to deduce information. We use a delay timer mechanism to + * ensure scans are made every couple of seconds to avoid performance + * problems. Currently this class is used to keep track of referenced grammar + * uri's within the document ensure that they are loaded by the + * CMDocumentManager. We might want to generalize this class to perform other + * suplimental information gathering that is suitable for 'time delayed' + * computation (error hints etc.). + */ +// TODO: Where should this class go? +public class DOMObserver { + + + // An abstract adapter that ensures that the children of a new Node are + // also adapted + // + abstract class DocumentAdapter implements INodeAdapter { + public DocumentAdapter(Document document) { + ((INodeNotifier) document).addAdapter(this); + adapt(document.getDocumentElement()); + } + + public void adapt(Element element) { + if (element != null) { + if (((INodeNotifier) element).getExistingAdapter(this) == null) { + ((INodeNotifier) element).addAdapter(this); + + for (Node child = element.getFirstChild(); child != null; child = child.getNextSibling()) { + if (child.getNodeType() == Node.ELEMENT_NODE) { + adapt((Element) child); + } + } + } + } + } + + public boolean isAdapterForType(Object type) { + return type == this; + } + + abstract public void notifyChanged(INodeNotifier notifier, int eventType, Object feature, Object oldValue, Object newValue, int index); + } + + /** + * This class listens to the changes in the CMDocument and triggers a + * CMDocument load + */ + class MyDocumentAdapter extends DocumentAdapter { + MyDocumentAdapter(Document document) { + super(document); + } + + public void notifyChanged(INodeNotifier notifier, int eventType, Object feature, Object oldValue, Object newValue, int index) { + switch (eventType) { + case INodeNotifier.ADD : { + if (newValue instanceof Element) { + //System.out.println("ADD (to " + + // ((Node)notifier).getNodeName() + ") " + + // ((Element)newValue).getNodeName() + " old " + + // oldValue); + adapt((Element) newValue); + } + break; + } + //case INodeNotifier.REMOVE: + case INodeNotifier.CHANGE : + case INodeNotifier.STRUCTURE_CHANGED : + case INodeNotifier.CONTENT_CHANGED : { + Node node = (Node) notifier; + if (node.getNodeType() == Node.ELEMENT_NODE) { + Element element = (Element) node; + switch (eventType) { + case INodeNotifier.CHANGE : { + invokeDelayedCMDocumentLoad(); + break; + } + case INodeNotifier.STRUCTURE_CHANGED : { + // structure change + invokeDelayedCMDocumentLoad(); + break; + } + case INodeNotifier.CONTENT_CHANGED : { + // some content changed + break; + } + } + } else if (node.getNodeType() == Node.DOCUMENT_NODE) { + invokeDelayedCMDocumentLoad(); + } + break; + } + } + } + } + + // + // + protected class MyTimerTask extends TimerTask { + public MyTimerTask() { + super(); + timerTaskCount++; + } + + public void run() { + timerTaskCount--; + if (timerTaskCount == 0) { + invokeCMDocumentLoad(); + } + } + } + + protected static Timer timer = new Timer(true); + protected Document document; + protected boolean isGrammarInferenceEnabled; + protected IStructuredModel model; + protected int timerTaskCount = 0; + + public DOMObserver(IStructuredModel model) { + this.document = (model instanceof XMLModel) ? ((XMLModel) model).getDocument() : null; + + if (document != null) { + ModelQuery modelQuery = ModelQueryUtil.getModelQuery(document); + if (modelQuery != null && modelQuery.getCMDocumentManager() != null) { + CMDocumentManager cmDocumentManager = modelQuery.getCMDocumentManager(); + cmDocumentManager.setPropertyEnabled(CMDocumentManager.PROPERTY_AUTO_LOAD, false); + } + + MyDocumentAdapter myDocumentAdapter = new MyDocumentAdapter(document); + } + } + + public void init() { + // CS: we seem to expose an XSD initialization problem when we do this + // immediately + // very nasty... I need to revist this problem with Ed Merks + // + //invokeCMDocumentLoad(); + invokeDelayedCMDocumentLoad(); + } + + public void invokeCMDocumentLoad() { + ModelQuery modelQuery = ModelQueryUtil.getModelQuery(document); + if (modelQuery != null && modelQuery.getCMDocumentManager() != null) { + CMDocumentLoader loader = isGrammarInferenceEnabled ? new InferredGrammarBuildingCMDocumentLoader(document, modelQuery) : new CMDocumentLoader(document, modelQuery); + loader.loadCMDocuments(); + } + } + + public void invokeDelayedCMDocumentLoad() { + //Display.getCurrent().timerExec(2000, new MyTimerTask()); + timer.schedule(new MyTimerTask(), 2000); + } + + public void setGrammarInferenceEnabled(boolean isEnabled) { + isGrammarInferenceEnabled = isEnabled; + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/JobStatusLineHelper.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/JobStatusLineHelper.java new file mode 100644 index 0000000000..b0803039ad --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/JobStatusLineHelper.java @@ -0,0 +1,103 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui; + +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.jobs.IJobChangeEvent; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.core.runtime.jobs.JobChangeAdapter; +import org.eclipse.jface.action.IStatusLineManager; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.IActionBars; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.wst.common.contentmodel.modelquery.CMDocumentManager; + + +/** + * Updates the status line when an appropriate Job is about to be run. + */ +public class JobStatusLineHelper extends JobChangeAdapter { + private static JobStatusLineHelper instance; + + public static void init() { + if (instance == null) { + instance = new JobStatusLineHelper(); + } + } + + private int running = 0; + + private JobStatusLineHelper() { + Platform.getJobManager().addJobChangeListener(this); + } + + public void aboutToRun(IJobChangeEvent event) { + Job job = event.getJob(); + if (job.belongsTo(CMDocumentManager.class)) { + running++; + setStatusLine(event.getJob().getName()); + } + } + + public void done(IJobChangeEvent event) { + Job job = event.getJob(); + if (job.belongsTo(CMDocumentManager.class)) { + running--; + if (running == 0) { + setStatusLine(""); //$NON-NLS-1$ + } + } + } + + private Display getDisplay() { + return PlatformUI.getWorkbench().getDisplay(); + } + + private void setStatusLine(final String message) { + String msgString = message; + if (message == null) { + msgString = ""; //$NON-NLS-1$ + } + final String finalMessageForThread = msgString; + if (getDisplay() != null) { + Runnable runnable = new Runnable() { + public void run() { + IWorkbench workbench = PlatformUI.getWorkbench(); + if (workbench != null) { + IWorkbenchWindow workbenchWindow = workbench.getActiveWorkbenchWindow(); + if (workbenchWindow != null) { + IEditorPart part = workbenchWindow.getActivePage().getActiveEditor(); + // part is sometimes null by the time this runs + // ... must be better way to get actionBars + // and/or statLineManager? + if (part != null) { + IActionBars actionBars = part.getEditorSite().getActionBars(); + if (actionBars != null) { + IStatusLineManager statusLineManager = actionBars.getStatusLineManager(); + if (statusLineManager != null) { + statusLineManager.setMessage(finalMessageForThread); + } + } + } + } + } + } + }; + Display workbenchDefault = PlatformUI.getWorkbench().getDisplay(); + workbenchDefault.asyncExec(runnable); + } + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/Logger.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/Logger.java new file mode 100644 index 0000000000..8d94fe57ec --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/Logger.java @@ -0,0 +1,155 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui; + + + +import java.util.StringTokenizer; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Plugin; +import org.eclipse.core.runtime.Status; + +/** + * Small convenience class to log messages to plugin's log file and also, if + * desired, the console. This class should only be used by classes in this + * plugin. Other plugins should make their own copy, with appropriate ID. + */ +public class Logger { + public static final int ERROR = IStatus.ERROR; // 4 + public static final int ERROR_DEBUG = 200 + ERROR; + private static Plugin fPlugin = XMLEditorPlugin.getDefault(); + private static final String fPluginId = fPlugin.getDescriptor().getUniqueIdentifier(); + public static final int INFO = IStatus.INFO; // 1 + public static final int INFO_DEBUG = 200 + INFO; + + public static final int OK = IStatus.OK; // 0 + + public static final int OK_DEBUG = 200 + OK; + + private static final String TRACEFILTER_LOCATION = "/debug/tracefilter"; //$NON-NLS-1$ + public static final int WARNING = IStatus.WARNING; // 2 + public static final int WARNING_DEBUG = 200 + WARNING; + + /** + * Adds message to log. + * + * @param level + * severity level of the message (OK, INFO, WARNING, ERROR, + * OK_DEBUG, INFO_DEBUG, WARNING_DEBUG, ERROR_DEBUG) + * @param message + * text to add to the log + * @param exception + * exception thrown + */ + protected static void _log(int level, String message, Throwable exception) { + if (level == OK_DEBUG || level == INFO_DEBUG || level == WARNING_DEBUG || level == ERROR_DEBUG) { + if (!isDebugging()) + return; + } + + int severity = IStatus.OK; + switch (level) { + case INFO_DEBUG : + case INFO : + severity = IStatus.INFO; + break; + case WARNING_DEBUG : + case WARNING : + severity = IStatus.WARNING; + break; + case ERROR_DEBUG : + case ERROR : + severity = IStatus.ERROR; + } + message = (message != null) ? message : "null"; //$NON-NLS-1$ + Status statusObj = new Status(severity, fPluginId, severity, message, exception); + fPlugin.getLog().log(statusObj); + } + + /** + * Prints message to log if category matches /debug/tracefilter option. + * + * @param message + * text to print + * @param category + * category of the message, to be compared with + * /debug/tracefilter + */ + protected static void _trace(String category, String message, Throwable exception) { + if (isTracing(category)) { + message = (message != null) ? message : "null"; //$NON-NLS-1$ + Status statusObj = new Status(IStatus.OK, fPluginId, IStatus.OK, message, exception); + fPlugin.getLog().log(statusObj); + } + } + + /** + * @return true if the plugin for this logger is debugging + */ + public static boolean isDebugging() { + return fPlugin.isDebugging(); + } + + /** + * Determines if currently tracing a category + * + * @param category + * @return true if tracing category, false otherwise + */ + public static boolean isTracing(String category) { + if (!isDebugging()) + return false; + + String traceFilter = Platform.getDebugOption(fPluginId + TRACEFILTER_LOCATION); + if (traceFilter != null) { + StringTokenizer tokenizer = new StringTokenizer(traceFilter, ","); //$NON-NLS-1$ + while (tokenizer.hasMoreTokens()) { + String cat = tokenizer.nextToken().trim(); + if (category.equals(cat)) { + return true; + } + } + } + return false; + } + + public static void log(int level, String message) { + _log(level, message, null); + } + + public static void log(int level, String message, Throwable exception) { + _log(level, message, exception); + } + + public static void logException(String message, Throwable exception) { + _log(ERROR, message, exception); + } + + public static void logException(Throwable exception) { + _log(ERROR, exception.getMessage(), exception); + } + + public static void trace(String category, String message) { + _trace(category, message, null); + } + + public static void traceException(String category, String message, Throwable exception) { + _trace(category, message, exception); + } + + public static void traceException(String category, Throwable exception) { + _trace(category, exception.getMessage(), exception); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/StructuredTextEditorXML.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/StructuredTextEditorXML.java new file mode 100644 index 0000000000..76836f9152 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/StructuredTextEditorXML.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui; + +import java.util.ResourceBundle; + +import org.eclipse.jface.action.Action; +import org.eclipse.wst.sse.ui.StructuredTextEditor; +import org.eclipse.wst.sse.ui.edit.util.ActionDefinitionIds; +import org.eclipse.wst.sse.ui.edit.util.StructuredTextEditorActionConstants; +import org.eclipse.wst.sse.ui.internal.search.FindOccurrencesActionProvider; +import org.eclipse.wst.sse.ui.nls.ResourceHandler; +import org.eclipse.wst.xml.ui.actions.AddBlockCommentActionXML; +import org.eclipse.wst.xml.ui.actions.CleanupActionXML; +import org.eclipse.wst.xml.ui.actions.RemoveBlockCommentActionXML; +import org.eclipse.wst.xml.ui.actions.ToggleCommentActionXML; +import org.eclipse.wst.xml.ui.internal.editor.IHelpContextIds; +import org.eclipse.wst.xml.ui.internal.search.XMLFindOccurrencesAction; + + +public class StructuredTextEditorXML extends StructuredTextEditor { + protected void createActions() { + super.createActions(); + + ResourceBundle resourceBundle = ResourceHandler.getResourceBundle(); + + Action action = new CleanupActionXML(resourceBundle, StructuredTextEditorActionConstants.ACTION_NAME_CLEANUP_DOCUMENT + DOT, this); + action.setActionDefinitionId(ActionDefinitionIds.CLEANUP_DOCUMENT); + setAction(StructuredTextEditorActionConstants.ACTION_NAME_CLEANUP_DOCUMENT, action); + + /* + * action = new CommentActionXML(resourceBundle, + * StructuredTextEditorActionConstants.ACTION_NAME_COMMENT + DOT, + * this); action.setActionDefinitionId(ActionDefinitionIds.COMMENT); + * setAction(StructuredTextEditorActionConstants.ACTION_NAME_COMMENT, + * action); + * + * action = new UncommentActionXML(resourceBundle, + * StructuredTextEditorActionConstants.ACTION_NAME_UNCOMMENT + DOT, + * this); action.setActionDefinitionId(ActionDefinitionIds.UNCOMMENT); + * setAction(StructuredTextEditorActionConstants.ACTION_NAME_UNCOMMENT, + * action); + */ + + action = new ToggleCommentActionXML(resourceBundle, StructuredTextEditorActionConstants.ACTION_NAME_TOGGLE_COMMENT + DOT, this); + action.setActionDefinitionId(ActionDefinitionIds.TOGGLE_COMMENT); + setAction(StructuredTextEditorActionConstants.ACTION_NAME_TOGGLE_COMMENT, action); + + action = new AddBlockCommentActionXML(resourceBundle, StructuredTextEditorActionConstants.ACTION_NAME_ADD_BLOCK_COMMENT + DOT, this); + action.setActionDefinitionId(ActionDefinitionIds.ADD_BLOCK_COMMENT); + setAction(StructuredTextEditorActionConstants.ACTION_NAME_ADD_BLOCK_COMMENT, action); + + action = new RemoveBlockCommentActionXML(resourceBundle, StructuredTextEditorActionConstants.ACTION_NAME_REMOVE_BLOCK_COMMENT + DOT, this); + action.setActionDefinitionId(ActionDefinitionIds.REMOVE_BLOCK_COMMENT); + setAction(StructuredTextEditorActionConstants.ACTION_NAME_REMOVE_BLOCK_COMMENT, action); + + FindOccurrencesActionProvider foAction = new FindOccurrencesActionProvider(resourceBundle, StructuredTextEditorActionConstants.ACTION_NAME_FIND_OCCURRENCES + DOT, this); + foAction.addAction(new XMLFindOccurrencesAction(resourceBundle, "", this)); //$NON-NLS-1$ + foAction.setActionDefinitionId(ActionDefinitionIds.FIND_OCCURRENCES); + setAction(StructuredTextEditorActionConstants.ACTION_NAME_FIND_OCCURRENCES, foAction); + markAsSelectionDependentAction(StructuredTextEditorActionConstants.ACTION_NAME_FIND_OCCURRENCES, true); + } + + protected void initializeEditor() { + super.initializeEditor(); + setHelpContextId(IHelpContextIds.XML_SOURCEVIEW_HELPID); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/StructuredTextViewerConfigurationXML.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/StructuredTextViewerConfigurationXML.java new file mode 100644 index 0000000000..d9843d5602 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/StructuredTextViewerConfigurationXML.java @@ -0,0 +1,295 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.runtime.Platform; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.text.ITextDoubleClickStrategy; +import org.eclipse.jface.text.ITextHover; +import org.eclipse.jface.text.contentassist.ContentAssistant; +import org.eclipse.jface.text.contentassist.IContentAssistProcessor; +import org.eclipse.jface.text.contentassist.IContentAssistant; +import org.eclipse.jface.text.formatter.IContentFormatter; +import org.eclipse.jface.text.formatter.MultiPassContentFormatter; +import org.eclipse.jface.text.information.IInformationPresenter; +import org.eclipse.jface.text.information.IInformationProvider; +import org.eclipse.jface.text.information.InformationPresenter; +import org.eclipse.jface.text.reconciler.IReconciler; +import org.eclipse.jface.text.reconciler.IReconcilingStrategy; +import org.eclipse.jface.text.source.ISourceViewer; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.eclipse.ui.texteditor.ITextEditor; +import org.eclipse.wst.dtd.ui.style.LineStyleProviderForDTDSubSet; +import org.eclipse.wst.sse.core.IModelManager; +import org.eclipse.wst.sse.core.IModelManagerPlugin; +import org.eclipse.wst.sse.core.IStructuredModel; +import org.eclipse.wst.sse.core.format.StructuredFormattingStrategy; +import org.eclipse.wst.sse.core.text.rules.StructuredTextPartitioner; +import org.eclipse.wst.sse.ui.EditorPlugin; +import org.eclipse.wst.sse.ui.StructuredTextReconciler; +import org.eclipse.wst.sse.ui.StructuredTextViewer; +import org.eclipse.wst.sse.ui.StructuredTextViewerConfiguration; +import org.eclipse.wst.sse.ui.preferences.CommonEditorPreferenceNames; +import org.eclipse.wst.sse.ui.preferences.PreferenceKeyGenerator; +import org.eclipse.wst.sse.ui.style.IHighlighter; +import org.eclipse.wst.sse.ui.style.LineStyleProvider; +import org.eclipse.wst.sse.ui.taginfo.AnnotationHoverProcessor; +import org.eclipse.wst.sse.ui.taginfo.ProblemAnnotationHoverProcessor; +import org.eclipse.wst.sse.ui.taginfo.TextHoverManager; +import org.eclipse.wst.sse.ui.util.EditorUtility; +import org.eclipse.wst.xml.core.format.FormatProcessorXML; +import org.eclipse.wst.xml.core.text.rules.StructuredTextPartitionerForXML; +import org.eclipse.wst.xml.ui.contentassist.NoRegionContentAssistProcessor; +import org.eclipse.wst.xml.ui.contentassist.XMLContentAssistProcessor; +import org.eclipse.wst.xml.ui.doubleclick.XMLDoubleClickStrategy; +import org.eclipse.wst.xml.ui.internal.autoedit.StructuredAutoEditStrategyXML; +import org.eclipse.wst.xml.ui.internal.correction.CorrectionProcessorXML; +import org.eclipse.wst.xml.ui.reconcile.StructuredTextReconcilingStrategyForContentModel; +import org.eclipse.wst.xml.ui.reconcile.StructuredTextReconcilingStrategyForMarkup; +import org.eclipse.wst.xml.ui.style.LineStyleProviderForXML; +import org.eclipse.wst.xml.ui.taginfo.XMLBestMatchHoverProcessor; +import org.eclipse.wst.xml.ui.taginfo.XMLInformationProvider; +import org.eclipse.wst.xml.ui.taginfo.XMLTagInfoHoverProcessor; + + +public class StructuredTextViewerConfigurationXML extends StructuredTextViewerConfiguration { + InformationPresenter fInformationPresenter = null; + private boolean reconcilerStrategiesAreSet; + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.ui.StructuredTextViewerConfiguration#getAutoEditStrategies(org.eclipse.jface.text.source.ISourceViewer) + */ + public Map getAutoEditStrategies(ISourceViewer sourceViewer) { + Map result = super.getAutoEditStrategies(sourceViewer); + + if (result.get(StructuredTextPartitionerForXML.ST_DEFAULT_XML) == null) + result.put(StructuredTextPartitionerForXML.ST_DEFAULT_XML, new ArrayList(1)); + List strategies = (List) result.get(StructuredTextPartitionerForXML.ST_DEFAULT_XML); + strategies.add(new StructuredAutoEditStrategyXML()); + return result; + } + + public String[] getConfiguredContentTypes(ISourceViewer sourceViewer) { + + if (configuredContentTypes == null) { + String[] xmlTypes = StructuredTextPartitionerForXML.getConfiguredContentTypes(); + configuredContentTypes = new String[xmlTypes.length + 2]; + configuredContentTypes[0] = StructuredTextPartitioner.ST_DEFAULT_PARTITION; + configuredContentTypes[1] = StructuredTextPartitioner.ST_UNKNOWN_PARTITION; + int index = 0; + System.arraycopy(xmlTypes, 0, configuredContentTypes, index += 2, xmlTypes.length); + } + return configuredContentTypes; + } + + public IContentAssistant getContentAssistant(ISourceViewer sourceViewer) { + + IContentAssistant ca = super.getContentAssistant(sourceViewer); + if (ca != null && ca instanceof ContentAssistant) { + ContentAssistant contentAssistant = (ContentAssistant) ca; + IContentAssistProcessor xmlContentAssistProcessor = new XMLContentAssistProcessor(); + IContentAssistProcessor noRegionProcessor = new NoRegionContentAssistProcessor(); + addContentAssistProcessor(contentAssistant, xmlContentAssistProcessor, StructuredTextPartitioner.ST_DEFAULT_PARTITION); + addContentAssistProcessor(contentAssistant, xmlContentAssistProcessor, StructuredTextPartitionerForXML.ST_DEFAULT_XML); + addContentAssistProcessor(contentAssistant, noRegionProcessor, StructuredTextPartitioner.ST_UNKNOWN_PARTITION); + //contentAssistant.setContentAssistProcessor(xmlContentAssistProcessor, + // StructuredTextPartitioner.ST_DEFAULT_PARTITION); + //contentAssistant.setContentAssistProcessor(xmlContentAssistProcessor, + // StructuredTextPartitionerForXML.ST_DEFAULT_XML); + //contentAssistant.setContentAssistProcessor(noRegionProcessor, + // StructuredTextPartitioner.ST_UNKNOWN_PARTITION); + } + return ca; + } + + public IContentFormatter getContentFormatter(ISourceViewer sourceViewer) { + final MultiPassContentFormatter formatter = new MultiPassContentFormatter(getConfiguredDocumentPartitioning(sourceViewer), StructuredTextPartitionerForXML.ST_DEFAULT_XML); + + formatter.setMasterStrategy(new StructuredFormattingStrategy(new FormatProcessorXML())); + + return formatter; + } + + public IContentAssistant getCorrectionAssistant(ISourceViewer sourceViewer) { + IContentAssistant ca = super.getCorrectionAssistant(sourceViewer); + + if (ca != null && ca instanceof ContentAssistant) { + ContentAssistant correctionAssistant = (ContentAssistant) ca; + ITextEditor editor = getTextEditor(); + if (editor != null) { + IContentAssistProcessor correctionProcessor = new CorrectionProcessorXML(editor); + correctionAssistant.setContentAssistProcessor(correctionProcessor, StructuredTextPartitionerForXML.ST_DEFAULT_XML); + correctionAssistant.setContentAssistProcessor(correctionProcessor, StructuredTextPartitionerForXML.ST_XML_CDATA); + correctionAssistant.setContentAssistProcessor(correctionProcessor, StructuredTextPartitionerForXML.ST_XML_COMMENT); + correctionAssistant.setContentAssistProcessor(correctionProcessor, StructuredTextPartitionerForXML.ST_XML_DECLARATION); + correctionAssistant.setContentAssistProcessor(correctionProcessor, StructuredTextPartitionerForXML.ST_XML_PI); + correctionAssistant.setContentAssistProcessor(correctionProcessor, StructuredTextPartitionerForXML.ST_DTD_SUBSET); + } + } + return ca; + } + + public ITextDoubleClickStrategy getDoubleClickStrategy(ISourceViewer sourceViewer, String contentType) { + + if (contentType.compareTo(StructuredTextPartitionerForXML.ST_DEFAULT_XML) == 0) + return new XMLDoubleClickStrategy(); + else + return super.getDoubleClickStrategy(sourceViewer, contentType); + } + + public IHighlighter getHighlighter(ISourceViewer sourceViewer) { + + IHighlighter highlighter = super.getHighlighter(sourceViewer); + if (highlighter != null) { + LineStyleProvider xmlProvider = new LineStyleProviderForXML(); + highlighter.addProvider(StructuredTextPartitionerForXML.ST_DEFAULT_XML, xmlProvider); + highlighter.addProvider(StructuredTextPartitionerForXML.ST_XML_CDATA, xmlProvider); + highlighter.addProvider(StructuredTextPartitionerForXML.ST_XML_COMMENT, xmlProvider); + highlighter.addProvider(StructuredTextPartitionerForXML.ST_XML_DECLARATION, xmlProvider); + highlighter.addProvider(StructuredTextPartitionerForXML.ST_XML_PI, xmlProvider); + highlighter.addProvider(StructuredTextPartitionerForXML.ST_DTD_SUBSET, new LineStyleProviderForDTDSubSet()); + } + return highlighter; + } + + public IInformationPresenter getInformationPresenter(ISourceViewer sourceViewer) { + + if (fInformationPresenter == null) { + fInformationPresenter = new InformationPresenter(getInformationPresenterControlCreator(sourceViewer)); + IInformationProvider xmlInformationProvider = new XMLInformationProvider(); + fInformationPresenter.setInformationProvider(xmlInformationProvider, StructuredTextPartitioner.ST_DEFAULT_PARTITION); + fInformationPresenter.setInformationProvider(xmlInformationProvider, StructuredTextPartitionerForXML.ST_DEFAULT_XML); + fInformationPresenter.setSizeConstraints(60, 10, true, true); + } + return fInformationPresenter; + } + + private IModelManager getModelManager() { + + IModelManagerPlugin plugin = (IModelManagerPlugin) Platform.getPlugin(IModelManagerPlugin.ID); + return plugin.getModelManager(); + } + + public IReconciler getReconciler(ISourceViewer sourceViewer) { + + if (fReconciler != null) { + // a reconciler should always be installed or disposed of + if (!fReconciler.isInstalled()) { + fReconciler = null; + reconcilerStrategiesAreSet = false; + } + } + + // the first time running through, there's no model (so no pref store) + // but the reconciler still needs to be created so that its document + // gets set + if (fReconciler == null) { + // create one + fReconciler = new StructuredTextReconciler(); + // a null editorPart is valid + //fReconciler.setEditor(editorPart); + } + + IPreferenceStore store = ((AbstractUIPlugin) Platform.getPlugin(SSE_EDITOR_ID)).getPreferenceStore(); + boolean reconcilingEnabled = store.getBoolean(CommonEditorPreferenceNames.EVALUATE_TEMPORARY_PROBLEMS); + + // the second time through, the strategies are set + if (fReconciler != null && !reconcilerStrategiesAreSet && reconcilingEnabled) { + StructuredTextViewer viewer = null; + if (sourceViewer instanceof StructuredTextViewer) { + viewer = ((StructuredTextViewer) sourceViewer); + } + IStructuredModel sModel = getModelManager().getExistingModelForRead(viewer.getDocument()); + try { + + + if (sModel != null) { + // check language (ContentTypeID).... + String contentTypeId = sModel.getModelHandler().getAssociatedContentTypeId(); + String generatedKey = PreferenceKeyGenerator.generateKey(CommonEditorPreferenceNames.EDITOR_VALIDATION_METHOD, contentTypeId); + String validationMethodPref = EditorPlugin.getInstance().getPreferenceStore().getString(generatedKey); + IReconcilingStrategy defaultStrategy = null; + + // pref set to no validation, so return + if (validationMethodPref.equals(CommonEditorPreferenceNames.EDITOR_VALIDATION_NONE)) + return fReconciler; + + // content model is the default for xml.. + // "Content Model" strategies (requires propagating + // adapter + // from AdapterFactoryProviderFor*) + + IReconcilingStrategy markupStrategy = new StructuredTextReconcilingStrategyForMarkup((ITextEditor) editorPart); + IReconcilingStrategy xmlStrategy = new StructuredTextReconcilingStrategyForContentModel((ITextEditor) editorPart); + defaultStrategy = xmlStrategy; + fReconciler.setReconcilingStrategy(markupStrategy, StructuredTextPartitioner.ST_DEFAULT_PARTITION); + fReconciler.setReconcilingStrategy(xmlStrategy, StructuredTextPartitionerForXML.ST_DEFAULT_XML); + fReconciler.setDefaultStrategy(defaultStrategy); + + reconcilerStrategiesAreSet = true; + } + } finally { + if (sModel != null) + sModel.releaseFromRead(); + } + } + return fReconciler; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.source.SourceViewerConfiguration#getTextHover(org.eclipse.jface.text.source.ISourceViewer, + * java.lang.String, int) + */ + public ITextHover getTextHover(ISourceViewer sourceViewer, String contentType, int stateMask) { + // look for appropriate text hover processor to return based on + // content type and state mask + if ((contentType == StructuredTextPartitioner.ST_DEFAULT_PARTITION) || (contentType == StructuredTextPartitionerForXML.ST_DEFAULT_XML)) { + // check which of xml's text hover is handling stateMask + TextHoverManager.TextHoverDescriptor[] hoverDescs = EditorPlugin.getDefault().getTextHoverManager().getTextHovers(); + int i = 0; + while (i < hoverDescs.length) { + if (hoverDescs[i].isEnabled() && EditorUtility.computeStateMask(hoverDescs[i].getModifierString()) == stateMask) { + String hoverType = hoverDescs[i].getId(); + if (TextHoverManager.COMBINATION_HOVER.equalsIgnoreCase(hoverType)) + return new XMLBestMatchHoverProcessor(); + else if (TextHoverManager.PROBLEM_HOVER.equalsIgnoreCase(hoverType)) + return new ProblemAnnotationHoverProcessor(); + else if (TextHoverManager.ANNOTATION_HOVER.equalsIgnoreCase(hoverType)) + return new AnnotationHoverProcessor(); + else if (TextHoverManager.DOCUMENTATION_HOVER.equalsIgnoreCase(hoverType)) + return new XMLTagInfoHoverProcessor(); + } + i++; + } + } + return super.getTextHover(sourceViewer, contentType, stateMask); + } + + public void unConfigure(ISourceViewer viewer) { + + super.unConfigure(viewer); + + // InformationPresenters + if (fInformationPresenter != null) { + fInformationPresenter.uninstall(); + } + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/XMLEditorPlugin.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/XMLEditorPlugin.java new file mode 100644 index 0000000000..df497af771 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/XMLEditorPlugin.java @@ -0,0 +1,236 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui; + +import java.io.IOException; + +import org.eclipse.core.runtime.IPluginDescriptor; +import org.eclipse.core.runtime.Platform; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.text.templates.ContextTypeRegistry; +import org.eclipse.jface.text.templates.persistence.TemplateStore; +import org.eclipse.ui.editors.text.templates.ContributionContextTypeRegistry; +import org.eclipse.ui.editors.text.templates.ContributionTemplateStore; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.eclipse.wst.common.encoding.content.IContentTypeIdentifier; +import org.eclipse.wst.sse.ui.EditorPlugin; +import org.eclipse.wst.sse.ui.preferences.CommonEditorPreferenceNames; +import org.eclipse.wst.sse.ui.preferences.PreferenceKeyGenerator; +import org.eclipse.wst.sse.ui.preferences.ui.ColorHelper; +import org.eclipse.wst.sse.ui.registry.AdapterFactoryRegistry; +import org.eclipse.wst.sse.ui.registry.AdapterFactoryRegistryImpl; +import org.eclipse.wst.sse.ui.registry.embedded.EmbeddedAdapterFactoryRegistryImpl; +import org.eclipse.wst.xml.ui.style.IStyleConstantsXML; +import org.eclipse.wst.xml.ui.templates.TemplateContextTypeXML; +import org.eclipse.wst.xml.ui.templates.TemplateContextTypeXMLAttribute; +import org.eclipse.wst.xml.ui.templates.TemplateContextTypeXMLAttributeValue; +import org.eclipse.wst.xml.ui.templates.TemplateContextTypeXMLTag; + + +/** + * The main plugin class to be used in the desktop. + */ +public class XMLEditorPlugin extends AbstractUIPlugin { + public final static String ID = "org.eclipse.wst.xml.ui"; //$NON-NLS-1$ + protected static XMLEditorPlugin instance = null; + + public static XMLEditorPlugin getDefault() { + return instance; + } + + public synchronized static XMLEditorPlugin getInstance() { + return instance; + } + + /** + * The template context type registry for the xml editor. + * + * @since 3.0 + */ + private ContextTypeRegistry fContextTypeRegistry; + + /** + * The template store for the xml editor. + * + * @since 3.0 + */ + private TemplateStore fTemplateStore; + + /** + * true if editor preference store has been initialized with default + * values false otherwise + */ + private boolean preferencesInitd = false; + + public XMLEditorPlugin(IPluginDescriptor descriptor) { + super(descriptor); + instance = this; + + // reference the preference store so + // initializeDefaultPreferences(IPreferenceStore preferenceStore) is + // called + IPreferenceStore store = getPreferenceStore(); + // for some reason initializeDefaultPreferences is not always called, + // so + // just add an extra check to see if not initialized, then call init + if (!preferencesInitd) { + initializeDefaultPreferences(store); + } + JobStatusLineHelper.init(); + } + + public AdapterFactoryRegistry getAdapterFactoryRegistry() { + return AdapterFactoryRegistryImpl.getInstance(); + + } + + public AdapterFactoryRegistry getEmbeddedAdapterFactoryRegistry() { + return EmbeddedAdapterFactoryRegistryImpl.getInstance(); + + } + + /** + * Returns the template context type registry for the xml plugin. + * + * @return the template context type registry for the xml plugin + */ + public ContextTypeRegistry getTemplateContextRegistry() { + if (fContextTypeRegistry == null) { + fContextTypeRegistry = new ContributionContextTypeRegistry(); + + fContextTypeRegistry.addContextType(new TemplateContextTypeXML()); + fContextTypeRegistry.addContextType(new TemplateContextTypeXMLTag()); + fContextTypeRegistry.addContextType(new TemplateContextTypeXMLAttribute()); + fContextTypeRegistry.addContextType(new TemplateContextTypeXMLAttributeValue()); + } + + return fContextTypeRegistry; + } + + /** + * Returns the template store for the xml editor templates. + * + * @return the template store for the xml editor templates + */ + public TemplateStore getTemplateStore() { + if (fTemplateStore == null) { + fTemplateStore = new ContributionTemplateStore(getTemplateContextRegistry(), getPreferenceStore(), CommonEditorPreferenceNames.TEMPLATES_KEY); + + try { + fTemplateStore.load(); + } catch (IOException e) { + Logger.logException(e); + } + } + return fTemplateStore; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ui.plugin.AbstractUIPlugin#initializeDefaultPluginPreferences() + */ + protected void initializeDefaultPreferences(IPreferenceStore store) { + + // ignore this preference store + // use EditorPlugin preference store + IPreferenceStore editorStore = ((AbstractUIPlugin) Platform.getPlugin(EditorPlugin.ID)).getPreferenceStore(); + EditorPlugin.initializeDefaultEditorPreferences(editorStore); + initializeDefaultXMLPreferences(editorStore); + preferencesInitd = true; + } + + protected void initializeDefaultXMLPreferences(IPreferenceStore store) { + + String ctId = IContentTypeIdentifier.ContentTypeID_SSEXML; + + store.setDefault(PreferenceKeyGenerator.generateKey(CommonEditorPreferenceNames.CONTENT_ASSIST_SUPPORTED, ctId), true); + store.setDefault(PreferenceKeyGenerator.generateKey(CommonEditorPreferenceNames.AUTO_PROPOSE, ctId), true); + store.setDefault(PreferenceKeyGenerator.generateKey(CommonEditorPreferenceNames.AUTO_PROPOSE_CODE, ctId), CommonEditorPreferenceNames.LT); + + store.setDefault(CommonEditorPreferenceNames.EDITOR_VALIDATION_METHOD, CommonEditorPreferenceNames.EDITOR_VALIDATION_CONTENT_MODEL); //$NON-NLS-1$ + + store.setDefault(PreferenceKeyGenerator.generateKey(CommonEditorPreferenceNames.EDITOR_VALIDATION_METHOD, ctId), CommonEditorPreferenceNames.EDITOR_VALIDATION_CONTENT_MODEL); //$NON-NLS-1$ + store.setDefault(PreferenceKeyGenerator.generateKey(CommonEditorPreferenceNames.EDITOR_USE_INFERRED_GRAMMAR, ctId), true); + + // XML Style Preferences + String NOBACKGROUNDBOLD = " | null | false"; //$NON-NLS-1$ + String styleValue = ColorHelper.getColorString(127, 0, 127) + NOBACKGROUNDBOLD; + store.setDefault(PreferenceKeyGenerator.generateKey(IStyleConstantsXML.TAG_ATTRIBUTE_NAME, ctId), styleValue); + + styleValue = ColorHelper.getColorString(42, 0, 255) + NOBACKGROUNDBOLD; + store.setDefault(PreferenceKeyGenerator.generateKey(IStyleConstantsXML.TAG_ATTRIBUTE_VALUE, ctId), styleValue); + + styleValue = "null" + NOBACKGROUNDBOLD; //$NON-NLS-1$ + store.setDefault(PreferenceKeyGenerator.generateKey(IStyleConstantsXML.TAG_ATTRIBUTE_EQUALS, ctId), styleValue); // specified + // value + // is + // black; + // leaving + // as + // widget + // default + + styleValue = ColorHelper.getColorString(63, 95, 191) + NOBACKGROUNDBOLD; + store.setDefault(PreferenceKeyGenerator.generateKey(IStyleConstantsXML.COMMENT_BORDER, ctId), styleValue); + store.setDefault(PreferenceKeyGenerator.generateKey(IStyleConstantsXML.COMMENT_TEXT, ctId), styleValue); + + styleValue = ColorHelper.getColorString(0, 128, 128) + NOBACKGROUNDBOLD; + store.setDefault(PreferenceKeyGenerator.generateKey(IStyleConstantsXML.DECL_BORDER, ctId), styleValue); + + styleValue = ColorHelper.getColorString(0, 0, 128) + NOBACKGROUNDBOLD; + store.setDefault(PreferenceKeyGenerator.generateKey(IStyleConstantsXML.DOCTYPE_NAME, ctId), styleValue); + store.setDefault(PreferenceKeyGenerator.generateKey(IStyleConstantsXML.DOCTYPE_EXTERNAL_ID_PUBREF, ctId), styleValue); + + styleValue = ColorHelper.getColorString(128, 128, 128) + NOBACKGROUNDBOLD; + store.setDefault(PreferenceKeyGenerator.generateKey(IStyleConstantsXML.DOCTYPE_EXTERNAL_ID, ctId), styleValue); + + styleValue = ColorHelper.getColorString(63, 127, 95) + NOBACKGROUNDBOLD; + store.setDefault(PreferenceKeyGenerator.generateKey(IStyleConstantsXML.DOCTYPE_EXTERNAL_ID_SYSREF, ctId), styleValue); + + styleValue = "null" + NOBACKGROUNDBOLD; //$NON-NLS-1$ + store.setDefault(PreferenceKeyGenerator.generateKey(IStyleConstantsXML.XML_CONTENT, ctId), styleValue); // specified + // value + // is + // black; + // leaving + // as + // widget + // default + + styleValue = ColorHelper.getColorString(0, 128, 128) + NOBACKGROUNDBOLD; + store.setDefault(PreferenceKeyGenerator.generateKey(IStyleConstantsXML.TAG_BORDER, ctId), styleValue); + + styleValue = ColorHelper.getColorString(63, 127, 127) + NOBACKGROUNDBOLD; + store.setDefault(PreferenceKeyGenerator.generateKey(IStyleConstantsXML.TAG_NAME, ctId), styleValue); + + styleValue = ColorHelper.getColorString(0, 128, 128) + NOBACKGROUNDBOLD; + store.setDefault(PreferenceKeyGenerator.generateKey(IStyleConstantsXML.PI_BORDER, ctId), styleValue); + + styleValue = "null" + NOBACKGROUNDBOLD; //$NON-NLS-1$ + store.setDefault(PreferenceKeyGenerator.generateKey(IStyleConstantsXML.PI_CONTENT, ctId), styleValue); // specified + // value + // is + // black; + // leaving + // as + // widget + // default + + styleValue = ColorHelper.getColorString(0, 128, 128) + NOBACKGROUNDBOLD; + store.setDefault(PreferenceKeyGenerator.generateKey(IStyleConstantsXML.CDATA_BORDER, ctId), styleValue); + + styleValue = ColorHelper.getColorString(0, 0, 0) + NOBACKGROUNDBOLD; + store.setDefault(PreferenceKeyGenerator.generateKey(IStyleConstantsXML.CDATA_TEXT, ctId), styleValue); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/XMLSpellCheckTarget.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/XMLSpellCheckTarget.java new file mode 100644 index 0000000000..150549ce70 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/XMLSpellCheckTarget.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui; + +import org.eclipse.wst.sse.ui.SpellCheckTargetImpl; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; + + +public class XMLSpellCheckTarget extends SpellCheckTargetImpl { + + /** + * @param editor + */ + public XMLSpellCheckTarget() { + super(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.ui.SpellCheckTargetImpl#isValidType(java.lang.String) + */ + protected boolean isValidType(String type) { + boolean valid = false; + if (XMLRegionContext.XML_COMMENT_TEXT.equals(type) || XMLRegionContext.XML_CONTENT.equals(type)) { + valid = true; + } + return valid || super.isValidType(type); + } + +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/AbstractNodeActionManager.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/AbstractNodeActionManager.java new file mode 100644 index 0000000000..493b4b3437 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/AbstractNodeActionManager.java @@ -0,0 +1,657 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ + + +package org.eclipse.wst.xml.ui.actions; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Vector; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.wst.common.contentmodel.CMAttributeDeclaration; +import org.eclipse.wst.common.contentmodel.CMDataType; +import org.eclipse.wst.common.contentmodel.CMElementDeclaration; +import org.eclipse.wst.common.contentmodel.CMNode; +import org.eclipse.wst.common.contentmodel.modelquery.ModelQuery; +import org.eclipse.wst.common.contentmodel.util.CMDescriptionBuilder; +import org.eclipse.wst.common.contentmodel.util.DOMContentBuilder; +import org.eclipse.wst.common.contentmodel.util.DOMContentBuilderImpl; +import org.eclipse.wst.common.contentmodel.util.DOMNamespaceHelper; +import org.eclipse.wst.sse.core.IStructuredModel; +import org.eclipse.wst.xml.ui.internal.editor.XMLEditorPluginImageHelper; +import org.eclipse.wst.xml.ui.internal.editor.XMLEditorPluginImages; +import org.eclipse.wst.xml.ui.util.XMLCommonResources; +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.ProcessingInstruction; + + + +public abstract class AbstractNodeActionManager extends BaseNodeActionManager { + + + /** + * AddNodeAction + */ + public class AddNodeAction extends NodeAction { + protected CMNode cmnode; + protected String description; + protected int index; + protected int nodeType; + protected Node parent; + protected String undoDescription; + + + public AddNodeAction(CMNode cmnode, Node parent, int index) { + this.cmnode = cmnode; + this.parent = parent; + this.index = index; + + String text = getLabel(parent, cmnode); + setText(text); + description = text; + undoDescription = XMLCommonResources.getInstance().getString("_UI_MENU_ADD") + " " + text; //$NON-NLS-1$ //$NON-NLS-2$ + setImageDescriptor(imageDescriptorCache.getImageDescriptor(cmnode)); + } + + + public AddNodeAction(int nodeType, Node parent, int index) { + this.nodeType = nodeType; + this.index = index; + this.parent = parent; + + switch (nodeType) { + case Node.COMMENT_NODE : { + description = XMLCommonResources.getInstance().getString("_UI_MENU_COMMENT"); //$NON-NLS-1$ + undoDescription = XMLCommonResources.getInstance().getString("_UI_MENU_ADD_COMMENT"); //$NON-NLS-1$ + break; + } + case Node.PROCESSING_INSTRUCTION_NODE : { + description = XMLCommonResources.getInstance().getString("_UI_MENU_PROCESSING_INSTRUCTION"); //$NON-NLS-1$ + undoDescription = XMLCommonResources.getInstance().getString("_UI_MENU_ADD_PROCESSING_INSTRUCTION"); //$NON-NLS-1$ + break; + } + case Node.CDATA_SECTION_NODE : { + description = XMLCommonResources.getInstance().getString("_UI_MENU_CDATA_SECTION"); //$NON-NLS-1$ + undoDescription = XMLCommonResources.getInstance().getString("_UI_MENU_ADD_CDATA_SECTION"); //$NON-NLS-1$ + break; + } + case Node.TEXT_NODE : { + description = XMLCommonResources.getInstance().getString("_UI_MENU_PCDATA"); //$NON-NLS-1$ + undoDescription = XMLCommonResources.getInstance().getString("_UI_MENU_ADD_PCDATA"); //$NON-NLS-1$ + break; + } + } + setText(description); + setImageDescriptor(imageDescriptorCache.getImageDescriptor(new Integer(nodeType))); + } + + + protected void addNodeForCMNode() { + if (parent != null) { + insert(parent, cmnode, index); + } + } + + + protected void addNodeForNodeType() { + Document document = parent.getNodeType() == Node.DOCUMENT_NODE ? (Document) parent : parent.getOwnerDocument(); + Node newChildNode = null; + boolean format = true; + switch (nodeType) { + case Node.COMMENT_NODE : { + newChildNode = document.createComment(XMLCommonResources.getInstance().getString("_UI_COMMENT_VALUE")); //$NON-NLS-1$ + break; + } + case Node.PROCESSING_INSTRUCTION_NODE : { + newChildNode = document.createProcessingInstruction(XMLCommonResources.getInstance().getString("_UI_PI_TARGET_VALUE"), XMLCommonResources.getInstance().getString("_UI_PI_DATA_VALUE")); //$NON-NLS-1$ //$NON-NLS-2$ + break; + } + case Node.CDATA_SECTION_NODE : { + newChildNode = document.createCDATASection(""); //$NON-NLS-1$ + break; + } + case Node.TEXT_NODE : { + format = false; + newChildNode = document.createTextNode(parent.getNodeName()); + break; + } + } + + if (newChildNode != null) { + List list = new Vector(1); + list.add(newChildNode); + insertNodesAtIndex(parent, list, index, format); + } + } + + + public String getUndoDescription() { + return undoDescription; + } + + + public void run() { + beginNodeAction(this); + if (cmnode != null) { + addNodeForCMNode(); + } else { + addNodeForNodeType(); + } + endNodeAction(this); + } + } + + + /** + * DeleteAction + */ + public class DeleteAction extends NodeAction { + protected List list; + + public DeleteAction(List list) { + setText(XMLCommonResources.getInstance().getString("_UI_MENU_REMOVE")); //$NON-NLS-1$ + this.list = list; + } + + public DeleteAction(Node node) { + setText(XMLCommonResources.getInstance().getString("_UI_MENU_REMOVE")); //$NON-NLS-1$ + list = new Vector(); + list.add(node); + } + + public String getUndoDescription() { + return XMLCommonResources.getInstance().getString("DELETE"); //$NON-NLS-1$ + } + + public void run() { + beginNodeAction(this); + + for (Iterator i = list.iterator(); i.hasNext();) { + Node node = (Node) i.next(); + if (node.getNodeType() == Node.ATTRIBUTE_NODE) { + Attr attr = (Attr) node; + attr.getOwnerElement().removeAttributeNode(attr); + } else { + Node parent = node.getParentNode(); + if (parent != null) { + Node previousSibling = node.getPreviousSibling(); + if (previousSibling != null && isWhitespaceTextNode(previousSibling)) { + parent.removeChild(previousSibling); + } + parent.removeChild(node); + } + } + } + + endNodeAction(this); + } + } + + + class ImageDescriptorCache { + protected ImageDescriptor attributeImage = XMLEditorPluginImageHelper.getInstance().getImageDescriptor(XMLEditorPluginImages.IMG_OBJ_ATTRIBUTE); + protected ImageDescriptor cdataSectionImage = XMLEditorPluginImageHelper.getInstance().getImageDescriptor(XMLEditorPluginImages.IMG_OBJ_CDATASECTION); + protected ImageDescriptor commentImage = XMLEditorPluginImageHelper.getInstance().getImageDescriptor(XMLEditorPluginImages.IMG_OBJ_COMMENT); + protected ImageDescriptor elementImage = XMLEditorPluginImageHelper.getInstance().getImageDescriptor(XMLEditorPluginImages.IMG_OBJ_ELEMENT); + protected ImageDescriptor piImage = XMLEditorPluginImageHelper.getInstance().getImageDescriptor(XMLEditorPluginImages.IMG_OBJ_PROCESSINGINSTRUCTION); + protected ImageDescriptor textImage = XMLEditorPluginImageHelper.getInstance().getImageDescriptor(XMLEditorPluginImages.IMG_OBJ_TXTEXT); + + public ImageDescriptor getImageDescriptor(Object object) { + ImageDescriptor result = null; + if (object instanceof CMNode) { + CMNode cmnode = (CMNode) object; + switch (cmnode.getNodeType()) { + case CMNode.ATTRIBUTE_DECLARATION : { + result = attributeImage; + break; + } + case CMNode.DATA_TYPE : { + result = textImage; + break; + } + case CMNode.ELEMENT_DECLARATION : { + result = elementImage; + break; + } + case CMNode.GROUP : { + result = elementImage; + break; + } + } + } else if (object instanceof Integer) { + Integer integer = (Integer) object; + switch (integer.intValue()) { + case Node.COMMENT_NODE : { + result = commentImage; + break; + } + case Node.PROCESSING_INSTRUCTION_NODE : { + result = piImage; + break; + } + case Node.CDATA_SECTION_NODE : { + result = cdataSectionImage; + break; + } + case Node.TEXT_NODE : { + result = textImage; + break; + } + } + } + return result; + } + } + + // TODO... remove this class. I'm pretty sure it is no longer used by + // anyone. + /** + * @depracated + */ + public class InsertAction extends NodeAction { + protected String description; + protected int index; + protected int nodeType; + protected Node parent; + + public InsertAction(int nodeType, Node parent, int index) { + this.nodeType = nodeType; + this.index = index; + this.parent = parent; + switch (nodeType) { + case Node.COMMENT_NODE : { + description = XMLCommonResources.getInstance().getString("_UI_MENU_COMMENT"); //$NON-NLS-1$ + break; + } + case Node.PROCESSING_INSTRUCTION_NODE : { + description = XMLCommonResources.getInstance().getString("_UI_MENU_PROCESSING_INSTRUCTION"); //$NON-NLS-1$ + break; + } + case Node.CDATA_SECTION_NODE : { + description = XMLCommonResources.getInstance().getString("_UI_MENU_CDATA_SECTION"); //$NON-NLS-1$ + break; + } + case Node.TEXT_NODE : { + description = XMLCommonResources.getInstance().getString("_UI_MENU_PCDATA"); //$NON-NLS-1$ + break; + } + } + setText(description); + setImageDescriptor(imageDescriptorCache.getImageDescriptor(new Integer(nodeType))); + } + + public InsertAction(int nodeType, Node parent, int index, String title) { + this.nodeType = nodeType; + this.index = index; + this.parent = parent; + description = title; + setText(description); + setImageDescriptor(imageDescriptorCache.getImageDescriptor(new Integer(nodeType))); + } + + public String getUndoDescription() { + return XMLCommonResources.getInstance().getString("_UI_MENU_ADD") + " " + description; //$NON-NLS-1$ //$NON-NLS-2$ + } + + public void run() { + beginNodeAction(this); + + Document document = parent.getNodeType() == Node.DOCUMENT_NODE ? (Document) parent : parent.getOwnerDocument(); + Node newChildNode = null; + boolean format = true; + switch (nodeType) { + case Node.COMMENT_NODE : { + newChildNode = document.createComment(XMLCommonResources.getInstance().getString("_UI_COMMENT_VALUE")); //$NON-NLS-1$ + break; + } + case Node.PROCESSING_INSTRUCTION_NODE : { + newChildNode = document.createProcessingInstruction(XMLCommonResources.getInstance().getString("_UI_PI_TARGET_VALUE"), XMLCommonResources.getInstance().getString("_UI_PI_DATA_VALUE")); //$NON-NLS-1$ //$NON-NLS-2$ + break; + } + case Node.CDATA_SECTION_NODE : { + newChildNode = document.createCDATASection(""); //$NON-NLS-1$ + break; + } + case Node.TEXT_NODE : { + format = false; + newChildNode = document.createTextNode(parent.getNodeName()); + break; + } + } + + if (newChildNode != null) { + List list = new Vector(1); + list.add(newChildNode); + insertNodesAtIndex(parent, list, index, format); + } + + endNodeAction(this); + } + } + + + /** + * ReplaceNodeAction + */ + public class ReplaceNodeAction extends NodeAction { + protected CMNode cmnode; + protected String description; + protected int endIndex; + protected Node parent; + protected int startIndex; + + + public ReplaceNodeAction(Node parent, CMNode cmnode, int startIndex, int endIndex) { + this.parent = parent; + this.cmnode = cmnode; + this.startIndex = startIndex; + this.endIndex = endIndex; + + setText(getLabel(parent, cmnode)); + setImageDescriptor(imageDescriptorCache.getImageDescriptor(cmnode)); + } + + public String getUndoDescription() { + String result = XMLCommonResources.getInstance().getString("_UI_LABEL_UNDO_REPLACE_DESCRIPTION"); //$NON-NLS-1$ + result += " " + getLabel(parent, cmnode); //$NON-NLS-1$ + return result; + } + + public void run() { + beginNodeAction(this); + + if (parent != null && cmnode != null) { + remove(parent, startIndex, endIndex); + insert(parent, cmnode, startIndex); + } + endNodeAction(this); + } + } + + protected ImageDescriptorCache imageDescriptorCache = new ImageDescriptorCache(); + protected Viewer viewer; + + public AbstractNodeActionManager(IStructuredModel model, ModelQuery modelQuery, Viewer viewer) { + super(model, modelQuery); + this.viewer = viewer; + } + + + public void beginNodeAction(NodeAction action) { + model.beginRecording(action, action.getUndoDescription()); + } + + + protected Action createAddAttributeAction(Element parent, CMAttributeDeclaration ad) { + Action action = null; + if (ad == null) { + action = new EditAttributeAction(this, parent, null, XMLCommonResources.getInstance().getString("_UI_MENU_NEW_ATTRIBUTE"), XMLCommonResources.getInstance().getString("_UI_MENU_NEW_ATTRIBUTE_TITLE")); //$NON-NLS-1$ //$NON-NLS-2$ + } else { + action = new AddNodeAction(ad, parent, -1); + } + return action; + } + + + protected Action createAddCDataSectionAction(Node parent, int index) { + return new AddNodeAction(Node.CDATA_SECTION_NODE, parent, index); + } + + + protected Action createAddCommentAction(Node parent, int index) { + return new AddNodeAction(Node.COMMENT_NODE, parent, index); + } + + + protected Action createAddDoctypeAction(Document document, int index) { + return new EditDoctypeAction(model, document, model.getBaseLocation(), XMLCommonResources.getInstance().getString("_UI_MENU_ADD_DTD_INFORMATION")); //$NON-NLS-1$ + } + + + protected Action createAddElementAction(Node parent, CMElementDeclaration ed, int index) { + Action action = null; + if (ed == null) { + action = new EditElementAction(this, parent, index, XMLCommonResources.getInstance().getString("_UI_MENU_NEW_ELEMENT"), XMLCommonResources.getInstance().getString("_UI_MENU_NEW_ELEMENT_TITLE")); //$NON-NLS-1$ //$NON-NLS-2$ + } else { + action = new AddNodeAction(ed, parent, index); + } + return action; + } + + + protected Action createAddPCDataAction(Node parent, CMDataType dataType, int index) { + Action action = null; + if (dataType == null) { + action = new AddNodeAction(Node.TEXT_NODE, parent, index); + } else { + action = new AddNodeAction(dataType, parent, index); + } + return action; + } + + + protected Action createAddProcessingInstructionAction(Node parent, int index) { + Node refChild = getRefChildNodeAtIndex(parent, index); + Action action = new EditProcessingInstructionAction(this, parent, refChild, XMLCommonResources.getInstance().getString("_UI_MENU_ADD_PROCESSING_INSTRUCTION"), XMLCommonResources.getInstance().getString("ADD_PROCESSING_INSTRUCTION")); //$NON-NLS-1$ //$NON-NLS-2$ + action.setImageDescriptor(imageDescriptorCache.getImageDescriptor(new Integer(Node.PROCESSING_INSTRUCTION_NODE))); + return action; + } + + + protected Action createAddSchemaInfoAction(Element element) { + return new EditSchemaInfoAction(this, element.getOwnerDocument(), model.getBaseLocation(), XMLCommonResources.getInstance().getString("_UI_MENU_ADD_SCHEMA_INFORMATION")); //$NON-NLS-1$ + } + + + protected Action createDeleteAction(List selection) { + DeleteAction deleteAction = new DeleteAction(selection); + deleteAction.setEnabled(selection.size() > 0); + return deleteAction; + } + + + public DOMContentBuilder createDOMContentBuilder(Document document) { + DOMContentBuilderImpl builder = new DOMContentBuilderImpl(document); + return builder; + } + + + protected Action createEditAttributeAction(Attr attr, CMAttributeDeclaration ad) { + return new EditAttributeAction(this, attr.getOwnerElement(), attr, XMLCommonResources.getInstance().getString("_UI_MENU_EDIT_ATTRIBUTE"), XMLCommonResources.getInstance().getString("_UI_MENU_EDIT_ATTRIBUTE_TITLE")); //$NON-NLS-1$ //$NON-NLS-2$ + } + + + protected Action createEditDoctypeAction(DocumentType doctype) { + return new EditDoctypeAction(model, doctype, model.getBaseLocation(), XMLCommonResources.getInstance().getString("_UI_MENU_EDIT_DOCTYPE")); //$NON-NLS-1$ + } + + + protected Action createEditProcessingInstructionAction(ProcessingInstruction pi) { + return new EditProcessingInstructionAction(this, pi, XMLCommonResources.getInstance().getString("_UI_MENU_EDIT_PROCESSING_INSTRUCTION"), XMLCommonResources.getInstance().getString("_UI_MENU_EDIT_PROCESSING_INSTRUCTION_TITLE")); //$NON-NLS-1$ //$NON-NLS-2$ + } + + + protected Action createEditSchemaInfoAction(Element element) { + return new EditSchemaInfoAction(this, element.getOwnerDocument(), model.getBaseLocation(), XMLCommonResources.getInstance().getString("_UI_MENU_EDIT_NAMESPACES")); //$NON-NLS-1$ + } + + + protected Action createRenameAction(Node node) { + Action result = null; + if (node instanceof Element) { + result = new EditElementAction(this, (Element) node, XMLCommonResources.getInstance().getString("_UI_MENU_RENAME"), XMLCommonResources.getInstance().getString("_UI_MENU_RENAME_TITLE")); //$NON-NLS-1$ //$NON-NLS-2$ + } + return result; + } + + + protected Action createReplaceAction(Node parent, CMNode cmnode, int startIndex, int endIndex) { + return new ReplaceNodeAction(parent, cmnode, startIndex, endIndex); + } + + public void endNodeAction(NodeAction action) { + model.endRecording(action); + } + + + + public void fillContextMenu(IMenuManager menuManager, ISelection selection) { + try { + List selectionList = new ArrayList(); + if (selection instanceof IStructuredSelection) { + IStructuredSelection es = (IStructuredSelection) selection; + for (Iterator i = es.iterator(); i.hasNext();) { + selectionList.add(i.next()); + } + } + + contributeActions(menuManager, selectionList); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * + */ + public String getLabel(Node parent, CMNode cmnode) { + String result = "?" + cmnode + "?"; //$NON-NLS-1$ //$NON-NLS-2$ + if (cmnode != null) { + result = (String) cmnode.getProperty("description"); //$NON-NLS-1$ + if (result == null) { + if (cmnode.getNodeType() == CMNode.GROUP) { + CMDescriptionBuilder descriptionBuilder = new CMDescriptionBuilder(); + result = descriptionBuilder.buildDescription(cmnode); + } else { + result = DOMNamespaceHelper.computeName(cmnode, parent, null); + } + } + } + return result; + } + + + public IStructuredModel getModel() { + return model; + } + + + public Shell getWorkbenchWindowShell() { + return XMLCommonResources.getInstance().getWorkbench().getActiveWorkbenchWindow().getShell(); + } + + + public void insert(Node parent, CMNode cmnode, int index) { + Document document = parent.getNodeType() == Node.DOCUMENT_NODE ? (Document) parent : parent.getOwnerDocument(); + DOMContentBuilder builder = createDOMContentBuilder(document); + builder.setBuildPolicy(DOMContentBuilder.BUILD_ONLY_REQUIRED_CONTENT); + builder.build(parent, cmnode); + insertNodesAtIndex(parent, builder.getResult(), index); + } + + + public void insertNodesAtIndex(Node parent, List list, int index) { + insertNodesAtIndex(parent, list, index, true); + } + + + public void insertNodesAtIndex(Node parent, List list, int index, boolean format) { + NodeList nodeList = parent.getChildNodes(); + if (index == -1) { + index = nodeList.getLength(); + } + Node refChild = (index < nodeList.getLength()) ? nodeList.item(index) : null; + + // here we consider the case where the previous node is a 'white + // space' Text node + // we should really do the insert before this node + // + int prevIndex = index - 1; + Node prevChild = (prevIndex < nodeList.getLength()) ? nodeList.item(prevIndex) : null; + if (isWhitespaceTextNode(prevChild)) { + refChild = prevChild; + } + + for (Iterator i = list.iterator(); i.hasNext();) { + Node newNode = (Node) i.next(); + + if (newNode.getNodeType() == Node.ATTRIBUTE_NODE) { + Element parentElement = (Element) parent; + parentElement.setAttributeNode((Attr) newNode); + } else { + parent.insertBefore(newNode, refChild); + } + } + + boolean formatDeep = false; + for (Iterator i = list.iterator(); i.hasNext();) { + Node newNode = (Node) i.next(); + if (newNode.getNodeType() == Node.ELEMENT_NODE) { + formatDeep = true; + } + + if (format) { + reformat(newNode, formatDeep); + } + } + + setViewerSelection(list); + } + + + /** + * This method is abstract since currently, the sed editor is required to + * perform formating and we don't want to create a dependency on the sed + * editor. + */ + public abstract void reformat(Node parent, boolean deep); + + + public void remove(Node parent, int startIndex, int endIndex) { + NodeList nodeList = parent.getChildNodes(); + for (int i = endIndex; i >= startIndex; i--) { + Node node = nodeList.item(i); + if (node != null) { + parent.removeChild(node); + } + } + } + + + public void setViewerSelection(List list) { + if (viewer != null) { + viewer.setSelection(new StructuredSelection(list), true); + } + } + + + public void setViewerSelection(Node node) { + if (viewer != null) { + viewer.setSelection(new StructuredSelection(node), true); + } + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/ActionContributorXML.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/ActionContributorXML.java new file mode 100644 index 0000000000..ec8d89d533 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/ActionContributorXML.java @@ -0,0 +1,205 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.actions; + +import java.util.ResourceBundle; + +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.IStatusLineManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.ui.IActionBars; +import org.eclipse.ui.IEditorActionBarContributor; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IWorkbenchActionConstants; +import org.eclipse.ui.texteditor.ITextEditor; +import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds; +import org.eclipse.ui.texteditor.RetargetTextEditorAction; +import org.eclipse.wst.sse.ui.edit.util.ActionContributor; +import org.eclipse.wst.sse.ui.edit.util.ActionDefinitionIds; +import org.eclipse.wst.sse.ui.edit.util.StructuredTextEditorActionConstants; +import org.eclipse.wst.sse.ui.nls.ResourceHandler; + + +/** + * XMLEditorActionContributor + * + * This class should not be used inside multi page editor's + * ActionBarContributor, since cascaded init() call from the + * ActionBarContributor will causes exception and it leads to lose whole + * toolbars. + * + * Instead, use SourcePageActionContributor for source page contributor of + * multi page editor. + * + * Note that this class is still valid for single page editor. + */ +public class ActionContributorXML extends ActionContributor { + private static final String[] EDITOR_IDS = {"org.eclipse.wst.xml.ui.StructuredTextEditorXML", "org.eclipse.wst.sse.ui.StructuredTextEditor", "org.eclipse.wst.xml.ui.StructuredTextEditorXML2"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + protected RetargetTextEditorAction fCleanupDocument = null; + protected RetargetTextEditorAction fComment = null; + // tooltip + // action + protected RetargetTextEditorAction fContentAssist = null; + // action + protected RetargetTextEditorAction fFindOccurrences = null; + protected RetargetTextEditorAction fFormatActiveElements = null; + protected RetargetTextEditorAction fFormatDocument = null; + protected MenuManager fFormatMenu = null; + protected RetargetTextEditorAction fOpenFileAction = null; // open file + protected RetargetTextEditorAction fQuickFix = null; + + protected RetargetTextEditorAction fShowTooltipAction = null; // show + protected RetargetTextEditorAction fUncomment = null; + + public ActionContributorXML() { + super(); + + ResourceBundle resourceBundle = ResourceHandler.getResourceBundle(); + + // edit commands + fShowTooltipAction = new RetargetTextEditorAction(resourceBundle, StructuredTextEditorActionConstants.ACTION_NAME_INFORMATION + StructuredTextEditorActionConstants.DOT); + fShowTooltipAction.setActionDefinitionId(ActionDefinitionIds.INFORMATION); + + fContentAssist = new RetargetTextEditorAction(resourceBundle, StructuredTextEditorActionConstants.ACTION_NAME_CONTENTASSIST_PROPOSALS + StructuredTextEditorActionConstants.DOT); + fContentAssist.setActionDefinitionId(ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS); + + fQuickFix = new RetargetTextEditorAction(resourceBundle, StructuredTextEditorActionConstants.ACTION_NAME_QUICK_FIX + StructuredTextEditorActionConstants.DOT); + fQuickFix.setActionDefinitionId(ActionDefinitionIds.QUICK_FIX); + + // source commands + fCleanupDocument = new RetargetTextEditorAction(resourceBundle, StructuredTextEditorActionConstants.ACTION_NAME_CLEANUP_DOCUMENT + StructuredTextEditorActionConstants.DOT); + fCleanupDocument.setActionDefinitionId(ActionDefinitionIds.CLEANUP_DOCUMENT); + + fFormatDocument = new RetargetTextEditorAction(resourceBundle, StructuredTextEditorActionConstants.ACTION_NAME_FORMAT_DOCUMENT + StructuredTextEditorActionConstants.DOT); + fFormatDocument.setActionDefinitionId(ActionDefinitionIds.FORMAT_DOCUMENT); + + fFormatActiveElements = new RetargetTextEditorAction(resourceBundle, StructuredTextEditorActionConstants.ACTION_NAME_FORMAT_ACTIVE_ELEMENTS + StructuredTextEditorActionConstants.DOT); + fFormatActiveElements.setActionDefinitionId(ActionDefinitionIds.FORMAT_ACTIVE_ELEMENTS); + + fFormatMenu = new MenuManager(ResourceHandler.getString("FormatMenu.label")); //$NON-NLS-1$ + fFormatMenu.add(fFormatDocument); + fFormatMenu.add(fFormatActiveElements); + + // navigate commands + fOpenFileAction = new RetargetTextEditorAction(resourceBundle, StructuredTextEditorActionConstants.ACTION_NAME_OPEN_FILE + StructuredTextEditorActionConstants.DOT); + fOpenFileAction.setActionDefinitionId(ActionDefinitionIds.OPEN_FILE); + + fFindOccurrences = new RetargetTextEditorAction(resourceBundle, StructuredTextEditorActionConstants.ACTION_NAME_FIND_OCCURRENCES + StructuredTextEditorActionConstants.DOT); + fFindOccurrences.setActionDefinitionId(ActionDefinitionIds.FIND_OCCURRENCES); + } + + protected void addToMenu(IMenuManager menu) { + // edit commands + IMenuManager editMenu = menu.findMenuUsingPath(IWorkbenchActionConstants.M_EDIT); + if (editMenu != null) { + editMenu.add(fCommandsSeparator); + editMenu.add(fToggleInsertModeAction); + editMenu.add(fCommandsSeparator); + editMenu.add(fExpandSelectionToMenu); + editMenu.add(fCommandsSeparator); + editMenu.add(fShowTooltipAction); + editMenu.add(fContentAssist); + editMenu.add(fQuickFix); + editMenu.add(fMenuAdditionsGroupMarker); + } + + // source commands + String sourceMenuLabel = ResourceHandler.getString("SourceMenu.label"); //$NON-NLS-1$ + String sourceMenuId = "sourceMenuId"; // This is just a menu id. No + // need to translate. + // //$NON-NLS-1$ + IMenuManager sourceMenu = new MenuManager(sourceMenuLabel, sourceMenuId); + menu.insertAfter(IWorkbenchActionConstants.M_EDIT, sourceMenu); + if (sourceMenu != null) { + sourceMenu.add(fCommandsSeparator); + sourceMenu.add(fToggleComment); + sourceMenu.add(fAddBlockComment); + sourceMenu.add(fRemoveBlockComment); + sourceMenu.add(fShiftRight); + sourceMenu.add(fShiftLeft); + sourceMenu.add(fCleanupDocument); + sourceMenu.add(fFormatMenu); + sourceMenu.add(fCommandsSeparator); + sourceMenu.add(fFindOccurrences); + } + + // navigate commands + IMenuManager navigateMenu = menu.findMenuUsingPath(IWorkbenchActionConstants.M_NAVIGATE); + if (navigateMenu != null) { + navigateMenu.appendToGroup(IWorkbenchActionConstants.OPEN_EXT, fCommandsSeparator); + navigateMenu.appendToGroup(IWorkbenchActionConstants.OPEN_EXT, fOpenFileAction); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.ui.edit.util.ActionContributor#getExtensionIDs() + */ + protected String[] getExtensionIDs() { + return EDITOR_IDS; + } + + /** + * @see IEditorActionBarContributor#setActiveEditor(IEditorPart) + */ + public void setActiveEditor(IEditorPart activeEditor) { + if (getActiveEditorPart() == activeEditor) + return; + super.setActiveEditor(activeEditor); + + IActionBars actionBars = getActionBars(); + if (actionBars != null) { + IStatusLineManager statusLineManager = actionBars.getStatusLineManager(); + if (statusLineManager != null) { + statusLineManager.setMessage(null); + statusLineManager.setErrorMessage(null); + } + } + + ITextEditor textEditor = getTextEditor(activeEditor); + + fShowTooltipAction.setAction(getAction(textEditor, StructuredTextEditorActionConstants.ACTION_NAME_INFORMATION)); + fContentAssist.setAction(getAction(textEditor, StructuredTextEditorActionConstants.ACTION_NAME_CONTENTASSIST_PROPOSALS)); + fQuickFix.setAction(getAction(textEditor, StructuredTextEditorActionConstants.ACTION_NAME_QUICK_FIX)); + + fCleanupDocument.setAction(getAction(textEditor, StructuredTextEditorActionConstants.ACTION_NAME_CLEANUP_DOCUMENT)); + fFormatDocument.setAction(getAction(textEditor, StructuredTextEditorActionConstants.ACTION_NAME_FORMAT_DOCUMENT)); + fFormatActiveElements.setAction(getAction(textEditor, StructuredTextEditorActionConstants.ACTION_NAME_FORMAT_ACTIVE_ELEMENTS)); + + fOpenFileAction.setAction(getAction(textEditor, StructuredTextEditorActionConstants.ACTION_NAME_OPEN_FILE)); + + fFindOccurrences.setAction(getAction(textEditor, StructuredTextEditorActionConstants.ACTION_NAME_FIND_OCCURRENCES)); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.ui.ISourceViewerActionBarContributor#setViewerSpecificContributionsEnabled(boolean) + */ + public void setViewerSpecificContributionsEnabled(boolean enabled) { + super.setViewerSpecificContributionsEnabled(enabled); + + fShowTooltipAction.setEnabled(enabled); + fContentAssist.setEnabled(enabled); + fQuickFix.setEnabled(enabled); + // cleanup and format document actions do not rely on source viewer + // being enabled + // fCleanupDocument.setEnabled(enabled); + // fFormatDocument.setEnabled(enabled); + + fFormatActiveElements.setEnabled(enabled); + fOpenFileAction.setEnabled(enabled); + fFindOccurrences.setEnabled(enabled); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/AddBlockCommentActionXML.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/AddBlockCommentActionXML.java new file mode 100644 index 0000000000..5b30e11881 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/AddBlockCommentActionXML.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.actions; + +import java.util.ResourceBundle; + +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.ui.texteditor.ITextEditor; +import org.eclipse.wst.sse.core.IndexedRegion; +import org.eclipse.wst.sse.core.exceptions.SourceEditingRuntimeException; +import org.eclipse.wst.sse.ui.edit.util.StructuredTextEditorActionConstants; +import org.eclipse.wst.sse.ui.nls.ResourceHandler; +import org.eclipse.wst.xml.core.internal.document.CommentImpl; + + +public class AddBlockCommentActionXML extends CommentActionXML { + protected int fCloseCommentOffset; + protected int fOpenCommentOffset; + protected IndexedRegion fSelectionEndIndexedRegion; + protected IndexedRegion fSelectionStartIndexedRegion; + + public AddBlockCommentActionXML(ResourceBundle bundle, String prefix, ITextEditor editor) { + super(bundle, prefix, editor); + } + + protected void init() { + super.init(); + + fSelectionStartIndexedRegion = fModel.getIndexedRegion(fSelectionStartOffset); + fSelectionEndIndexedRegion = fModel.getIndexedRegion(fSelectionEndOffset); + + if (fSelectionStartIndexedRegion == null || fSelectionEndIndexedRegion == null) + return; + + fOpenCommentOffset = fSelectionStartIndexedRegion.getStartOffset(); + fCloseCommentOffset = fSelectionEndIndexedRegion.getEndOffset() + OPEN_COMMENT.length(); + } + + protected void processAction() { + if (fSelection.getLength() == 0 && fSelectionStartIndexedRegion instanceof CommentImpl) + return; + + fModel.beginRecording(this, ResourceHandler.getString(StructuredTextEditorActionConstants.ACTION_NAME_ADD_BLOCK_COMMENT + ".tooltip")); //$NON-NLS-1$ + fModel.aboutToChangeModel(); + + try { + fDocument.replace(fOpenCommentOffset, 0, OPEN_COMMENT); + fDocument.replace(fCloseCommentOffset, 0, CLOSE_COMMENT); + removeOpenCloseComments(fOpenCommentOffset + OPEN_COMMENT.length(), fCloseCommentOffset - fOpenCommentOffset - CLOSE_COMMENT.length()); + } catch (BadLocationException e) { + throw new SourceEditingRuntimeException(); + } + + fModel.changedModel(); + fModel.endRecording(this); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/BaseNodeActionManager.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/BaseNodeActionManager.java new file mode 100644 index 0000000000..fc587b374e --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/BaseNodeActionManager.java @@ -0,0 +1,518 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ + + +package org.eclipse.wst.xml.ui.actions; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Vector; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.wst.common.contentmodel.CMAttributeDeclaration; +import org.eclipse.wst.common.contentmodel.CMDataType; +import org.eclipse.wst.common.contentmodel.CMDocument; +import org.eclipse.wst.common.contentmodel.CMElementDeclaration; +import org.eclipse.wst.common.contentmodel.CMNode; +import org.eclipse.wst.common.contentmodel.modelquery.ModelQuery; +import org.eclipse.wst.common.contentmodel.modelquery.ModelQueryAction; +import org.eclipse.wst.sse.core.IStructuredModel; +import org.eclipse.wst.xml.core.document.XMLModel; +import org.eclipse.wst.xml.ui.util.XMLCommonResources; +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.ProcessingInstruction; + + + +public abstract class BaseNodeActionManager { + + + /** + * MyMenuManager + */ + public static class MyMenuManager extends MenuManager { + protected String title; + + public MyMenuManager(String s) { + super(s); + title = s; + } + + public boolean isEnabled() { + return !isEmpty(); + } + + public String toString() { + return title; + } + } + + public static DocumentType getDoctype(Node node) { + Document document = (node.getNodeType() == Node.DOCUMENT_NODE) ? (Document) node : node.getOwnerDocument(); + return document.getDoctype(); + } + + protected MenuBuilder menuBuilder = new MenuBuilder(); + protected IStructuredModel model; + protected ModelQuery modelQuery; + + protected BaseNodeActionManager(IStructuredModel model, ModelQuery modelQuery) { + this.model = model; + this.modelQuery = modelQuery; + } + + + protected void addActionHelper(IMenuManager menu, List modelQueryActionList) { + List actionList = new Vector(); + for (Iterator i = modelQueryActionList.iterator(); i.hasNext();) { + ModelQueryAction action = (ModelQueryAction) i.next(); + if (action.getCMNode() != null) { + int cmNodeType = action.getCMNode().getNodeType(); + if (action.getKind() == ModelQueryAction.INSERT) { + switch (cmNodeType) { + case CMNode.ATTRIBUTE_DECLARATION : { + actionList.add(createAddAttributeAction((Element) action.getParent(), (CMAttributeDeclaration) action.getCMNode())); + break; + } + case CMNode.ELEMENT_DECLARATION : { + actionList.add(createAddElementAction(action.getParent(), (CMElementDeclaration) action.getCMNode(), action.getStartIndex())); + break; + } + } + } else if (action.getKind() == ModelQueryAction.REPLACE) { + if (action.getParent() != null && action.getCMNode() != null) { + actionList.add(createReplaceAction(action.getParent(), action.getCMNode(), action.getStartIndex(), action.getEndIndex())); + } + } + } + } + menuBuilder.populateMenu(menu, actionList, false); + } + + protected void contributeAction(IMenuManager menu, Action action) { + if (action != null) { + menu.add(action); + } + } + + + public void contributeActions(IMenuManager menu, List selection) { + int editMode = modelQuery.getEditMode(); + int ic = (editMode == ModelQuery.EDIT_MODE_CONSTRAINED_STRICT) ? ModelQuery.INCLUDE_CHILD_NODES | ModelQuery.INCLUDE_SEQUENCE_GROUPS : ModelQuery.INCLUDE_CHILD_NODES; + int vc = (editMode == ModelQuery.EDIT_MODE_CONSTRAINED_STRICT) ? ModelQuery.VALIDITY_STRICT : ModelQuery.VALIDITY_NONE; + + List implicitlySelectedNodeList = null; + + if (selection.size() > 0) { + implicitlySelectedNodeList = getSelectedNodes(selection, true); + + // contribute delete actions + contributeDeleteActions(menu, implicitlySelectedNodeList, ic, vc); + } + + if (selection.size() == 1) { + Node node = (Node) selection.get(0); + + // contribute edit actions + contributeEditActions(menu, node); + + // contribute add child actions + contributeAddChildActions(menu, node, ic, vc); + + // contribute add before actions + contributeAddSiblingActions(menu, node, ic, vc); + } + + if (selection.size() > 0) { + // contribute replace actions + contributeReplaceActions(menu, implicitlySelectedNodeList, ic, vc); + } + + if (selection.size() == 0) { + Document document = ((XMLModel) model).getDocument(); + contributeAddDocumentChildActions(menu, document, ic, vc); + contributeEditGrammarInformationActions(menu, document); + } + } + + + protected void contributeAddChildActions(IMenuManager menu, Node node, int ic, int vc) { + int nodeType = node.getNodeType(); + + if (nodeType == Node.ELEMENT_NODE) { + // 'Add Child...' and 'Add Attribute...' actions + // + Element element = (Element) node; + + IMenuManager addAttributeMenu = new MyMenuManager(XMLCommonResources.getInstance().getString("_UI_MENU_ADD_ATTRIBUTE")); //$NON-NLS-1$ + IMenuManager addChildMenu = new MyMenuManager(XMLCommonResources.getInstance().getString("_UI_MENU_ADD_CHILD")); //$NON-NLS-1$ + menu.add(addAttributeMenu); + menu.add(addChildMenu); + + CMElementDeclaration ed = modelQuery.getCMElementDeclaration(element); + if (ed != null) { + // add insert attribute actions + // + List modelQueryActionList = new ArrayList(); + modelQuery.getInsertActions(element, ed, -1, ModelQuery.INCLUDE_ATTRIBUTES, vc, modelQueryActionList); + addActionHelper(addAttributeMenu, modelQueryActionList); + + // add insert child node actions + // + modelQueryActionList = new ArrayList(); + modelQuery.getInsertActions(element, ed, -1, ic, vc, modelQueryActionList); + addActionHelper(addChildMenu, modelQueryActionList); + } + + // add PI and COMMENT + contributePIAndCommentActions(addChildMenu, element, ed, -1); + + // add PCDATA, CDATA_SECTION + contributeTextNodeActions(addChildMenu, element, ed, -1); + + // add NEW ELEMENT + contributeUnconstrainedAddElementAction(addChildMenu, element, ed, -1); + + // add ATTRIBUTE + contributeUnconstrainedAttributeActions(addAttributeMenu, element, ed); + } + } + + + protected void contributeAddDocumentChildActions(IMenuManager menu, Document document, int ic, int vc) { + IMenuManager addChildMenu = new MyMenuManager(XMLCommonResources.getInstance().getString("_UI_MENU_ADD_CHILD")); //$NON-NLS-1$ + menu.add(addChildMenu); + + // add PI and COMMENT + contributePIAndCommentActions(addChildMenu, document, -1); + + // add NEW ELEMENT + contributeUnconstrainedAddElementAction(addChildMenu, document, -1); + } + + + protected void contributeAddSiblingActions(IMenuManager menu, Node node, int ic, int vc) { + IMenuManager addBeforeMenu = new MyMenuManager(XMLCommonResources.getInstance().getString("_UI_MENU_ADD_BEFORE")); //$NON-NLS-1$ + IMenuManager addAfterMenu = new MyMenuManager(XMLCommonResources.getInstance().getString("_UI_MENU_ADD_AFTER")); //$NON-NLS-1$ + menu.add(addBeforeMenu); + menu.add(addAfterMenu); + + Node parentNode = node.getParentNode(); + if (parentNode != null) { + int index = getIndex(parentNode, node); + if (parentNode.getNodeType() == Node.ELEMENT_NODE) { + Element parentElement = (Element) parentNode; + CMElementDeclaration parentED = modelQuery.getCMElementDeclaration(parentElement); + if (parentED != null) { + // 'Add Before...' and 'Add After...' actions + // + List modelQueryActionList = new ArrayList(); + modelQuery.getInsertActions(parentElement, parentED, index, ic, vc, modelQueryActionList); + addActionHelper(addBeforeMenu, modelQueryActionList); + + modelQueryActionList = new ArrayList(); + modelQuery.getInsertActions(parentElement, parentED, index + 1, ic, vc, modelQueryActionList); + addActionHelper(addAfterMenu, modelQueryActionList); + } + + // add COMMENT and PI before and after + contributePIAndCommentActions(addBeforeMenu, parentElement, parentED, index); + contributePIAndCommentActions(addAfterMenu, parentElement, parentED, index + 1); + + // add PCDATA, CDATA_SECTION before and after + contributeTextNodeActions(addBeforeMenu, parentElement, parentED, index); + contributeTextNodeActions(addAfterMenu, parentElement, parentED, index + 1); + + // add NEW ELEMENT before and after + contributeUnconstrainedAddElementAction(addBeforeMenu, parentElement, parentED, index); + contributeUnconstrainedAddElementAction(addAfterMenu, parentElement, parentED, index + 1); + } else if (parentNode.getNodeType() == Node.DOCUMENT_NODE) { + Document document = (Document) parentNode; + CMDocument cmDocument = modelQuery.getCorrespondingCMDocument(parentNode); + if (cmDocument != null) { + // add possible root element insertions + // + List modelQueryActionList = new ArrayList(); + modelQuery.getInsertActions(document, cmDocument, index, ic, vc, modelQueryActionList); + addActionHelper(addAfterMenu, modelQueryActionList); + + modelQueryActionList = new ArrayList(); + modelQuery.getInsertActions(document, cmDocument, index + 1, ic, vc, modelQueryActionList); + addActionHelper(addAfterMenu, modelQueryActionList); + } + + // add COMMENT and PI before and after + contributePIAndCommentActions(addBeforeMenu, document, index); + contributePIAndCommentActions(addAfterMenu, document, index + 1); + + // add ELEMENT before and after + contributeUnconstrainedAddElementAction(addBeforeMenu, document, index); + contributeUnconstrainedAddElementAction(addAfterMenu, document, index + 1); + } + } + } + + protected void contributeDeleteActions(IMenuManager menu, List list, int ic, int vc) { + boolean canRemove = modelQuery.canRemove(list, vc); + + + // a delete action with an empty list will produce a disabled menu + // item + // + List resultList = canRemove ? list : Collections.EMPTY_LIST; + contributeAction(menu, createDeleteAction(resultList)); + } + + + protected void contributeEditActions(IMenuManager menu, Node node) { + contributeEditGrammarInformationActions(menu, node); + + if (node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) { + contributeAction(menu, createEditProcessingInstructionAction((ProcessingInstruction) node)); + } else if (node.getNodeType() == Node.ATTRIBUTE_NODE) { + contributeAction(menu, createEditAttributeAction((Attr) node, null)); + } + } + + + protected void contributeEditGrammarInformationActions(IMenuManager menu, Node node) { + Document document = node.getNodeType() == Node.DOCUMENT_NODE ? (Document) node : node.getOwnerDocument(); + + DocumentType doctype = getDoctype(node); + if (doctype == null) { + contributeAction(menu, createAddDoctypeAction(document, -1)); + } + + if (node.getNodeType() == Node.DOCUMENT_TYPE_NODE) { + contributeAction(menu, createEditDoctypeAction((DocumentType) node)); + } + + if (doctype == null && getRootElement(document) != null) { + contributeAction(menu, createEditSchemaInfoAction(getRootElement(document))); + } + } + + protected void contributePIAndCommentActions(IMenuManager menu, Document document, int index) { + // test to make sure that the index isn't before the XML declaration + // + contributeAction(menu, createAddCommentAction(document, index)); + contributeAction(menu, createAddProcessingInstructionAction(document, index)); + } + + + protected void contributePIAndCommentActions(IMenuManager menu, Element parentElement, CMElementDeclaration parentEd, int index) { + if (parentEd == null || isCommentAllowed(parentEd)) { + contributeAction(menu, createAddCommentAction(parentElement, index)); + contributeAction(menu, createAddProcessingInstructionAction(parentElement, index)); + } + } + + + protected void contributeReplaceActions(IMenuManager menu, List selectedNodeList, int ic, int vc) { + // 'Replace With...' actions + // + IMenuManager replaceWithMenu = new MyMenuManager(XMLCommonResources.getInstance().getString("_UI_MENU_REPLACE_WITH")); //$NON-NLS-1$ + menu.add(replaceWithMenu); + + if (modelQuery.getEditMode() == ModelQuery.EDIT_MODE_CONSTRAINED_STRICT && selectedNodeList.size() > 0) { + Node node = (Node) selectedNodeList.get(0); + Node parentNode = node.getParentNode(); + if (parentNode != null && parentNode.getNodeType() == Node.ELEMENT_NODE) { + Element parentElement = (Element) parentNode; + CMElementDeclaration parentED = modelQuery.getCMElementDeclaration(parentElement); + if (parentED != null) { + List replaceActionList = new Vector(); + modelQuery.getReplaceActions(parentElement, parentED, selectedNodeList, ic, vc, replaceActionList); + addActionHelper(replaceWithMenu, replaceActionList); + } + } + } + } + + protected void contributeTextNodeActions(IMenuManager menu, Element parentElement, CMElementDeclaration parentEd, int index) { + if (parentEd == null || isTextAllowed(parentEd)) { + CMDataType dataType = parentEd != null ? parentEd.getDataType() : null; + contributeAction(menu, createAddPCDataAction(parentElement, dataType, index)); + contributeAction(menu, createAddCDataSectionAction(parentElement, index)); + } + } + + + protected void contributeUnconstrainedAddElementAction(IMenuManager menu, Document document, int index) { + if (isUnconstrainedActionAllowed()) { + if (getRootElement(document) == null) { + int xmlDeclarationIndex = -1; + int doctypeIndex = -1; + NodeList nodeList = document.getChildNodes(); + int nodeListLength = nodeList.getLength(); + for (int i = 0; i < nodeListLength; i++) { + Node node = nodeList.item(i); + int nodeType = node.getNodeType(); + if (nodeType == Node.DOCUMENT_TYPE_NODE) { + doctypeIndex = i; + break; + } else if (nodeType == Node.PROCESSING_INSTRUCTION_NODE) { + ProcessingInstruction pi = (ProcessingInstruction) node; + if (pi.getTarget().equalsIgnoreCase("xml") && xmlDeclarationIndex == -1) { //$NON-NLS-1$ + xmlDeclarationIndex = i; + } + } + } + + if ((xmlDeclarationIndex == -1 || index > xmlDeclarationIndex) && (doctypeIndex == -1 || index > doctypeIndex)) { + contributeAction(menu, createAddElementAction(document, null, index)); + } + } + } + } + + + protected void contributeUnconstrainedAddElementAction(IMenuManager menu, Element parentElement, CMElementDeclaration parentEd, int index) { + if (isUnconstrainedActionAllowed()) { + if (parentEd == null || parentEd.getProperty("isInferred") == Boolean.TRUE || (modelQuery.getEditMode() != ModelQuery.EDIT_MODE_CONSTRAINED_STRICT && isElementAllowed(parentEd))) { //$NON-NLS-1$ + contributeAction(menu, createAddElementAction(parentElement, null, index)); + } + } + } + + + protected void contributeUnconstrainedAttributeActions(IMenuManager menu, Element parentElement, CMElementDeclaration parentEd) { + if (isUnconstrainedActionAllowed()) { + if (parentEd == null || parentEd.getProperty("isInferred") == Boolean.TRUE || modelQuery.getEditMode() != ModelQuery.EDIT_MODE_CONSTRAINED_STRICT) { //$NON-NLS-1$ + contributeAction(menu, createAddAttributeAction(parentElement, null)); + } + } + } + + abstract protected Action createAddAttributeAction(Element parent, CMAttributeDeclaration ad); + + abstract protected Action createAddCDataSectionAction(Node parent, int index); + + abstract protected Action createAddCommentAction(Node parent, int index); + + abstract protected Action createAddDoctypeAction(Document parent, int index); + + abstract protected Action createAddElementAction(Node parent, CMElementDeclaration ed, int index); + + abstract protected Action createAddPCDataAction(Node parent, CMDataType dataType, int index); + + abstract protected Action createAddProcessingInstructionAction(Node parent, int index); + + abstract protected Action createAddSchemaInfoAction(Element element); + + abstract protected Action createDeleteAction(List selection); + + abstract protected Action createEditAttributeAction(Attr attribute, CMAttributeDeclaration ad); + + abstract protected Action createEditDoctypeAction(DocumentType doctype); + + abstract protected Action createEditProcessingInstructionAction(ProcessingInstruction pi); + + abstract protected Action createEditSchemaInfoAction(Element element); + + abstract protected Action createRenameAction(Node node); + + abstract protected Action createReplaceAction(Node parent, CMNode cmnode, int startIndex, int endIndex); + + + public int getIndex(Node parentNode, Node child) { + NodeList nodeList = parentNode.getChildNodes(); + int index = -1; + int size = nodeList.getLength(); + for (int i = 0; i < size; i++) { + if (nodeList.item(i) == child) { + index = i; + break; + } + } + return index; + } + + + public Node getRefChildNodeAtIndex(Node parent, int index) { + NodeList nodeList = parent.getChildNodes(); + Node refChild = (index >= 0 && index < nodeList.getLength()) ? nodeList.item(index) : null; + return refChild; + } + + + protected Element getRootElement(Document document) { + Element result = null; + NodeList nodeList = document.getChildNodes(); + int nodeListLength = nodeList.getLength(); + for (int i = 0; i < nodeListLength; i++) { + Node node = nodeList.item(i); + if (node.getNodeType() == Node.ELEMENT_NODE) { + result = (Element) node; + break; + } + } + return result; + } + + + protected List getSelectedNodes(List list, boolean includeTextNodes) { + List result = new ArrayList(0); + for (Iterator i = list.iterator(); i.hasNext();) { + Object object = i.next(); + if (object instanceof Node) { + Node node = (Node) object; + if (node.getNodeType() == Node.TEXT_NODE) { + if (includeTextNodes) { + result.add(object); + } + } else { + result.add(node); + } + } + } + return result; + } + + + protected boolean isCommentAllowed(CMElementDeclaration parentEd) { + int contentType = parentEd.getContentType(); + return contentType == CMElementDeclaration.ELEMENT || contentType == CMElementDeclaration.MIXED || contentType == CMElementDeclaration.PCDATA || contentType == CMElementDeclaration.ANY; + } + + + protected boolean isElementAllowed(CMElementDeclaration parentEd) { + int contentType = parentEd.getContentType(); + return contentType == CMElementDeclaration.ELEMENT || contentType == CMElementDeclaration.MIXED || contentType == CMElementDeclaration.ANY; + } + + + protected boolean isTextAllowed(CMElementDeclaration parentEd) { + int contentType = parentEd.getContentType(); + return contentType == CMElementDeclaration.MIXED || contentType == CMElementDeclaration.PCDATA || contentType == CMElementDeclaration.ANY; + } + + + protected boolean isUnconstrainedActionAllowed() { + return true; + } + + + protected boolean isWhitespaceTextNode(Node node) { + return (node != null) && (node.getNodeType() == Node.TEXT_NODE) && (node.getNodeValue().trim().length() == 0); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/CleanupActionXML.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/CleanupActionXML.java new file mode 100644 index 0000000000..e5a3a13cce --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/CleanupActionXML.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.actions; + +import java.util.ResourceBundle; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.texteditor.ITextEditor; +import org.eclipse.wst.sse.core.cleanup.IStructuredCleanupProcessor; +import org.eclipse.wst.sse.ui.edit.util.CleanupAction; +import org.eclipse.wst.xml.core.cleanup.CleanupProcessorXML; + + +public class CleanupActionXML extends CleanupAction { + protected IStructuredCleanupProcessor fCleanupProcessor; + + public CleanupActionXML(ResourceBundle bundle, String prefix, ITextEditor editor) { + super(bundle, prefix, editor); + } + + protected Dialog getCleanupDialog(Shell shell) { + if (fCleanupDialog == null) + fCleanupDialog = new CleanupDialogXML(shell); + + return fCleanupDialog; + } + + protected IStructuredCleanupProcessor getCleanupProcessor() { + if (fCleanupProcessor == null) + fCleanupProcessor = new CleanupProcessorXML(); + + return fCleanupProcessor; + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/CleanupDialogXML.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/CleanupDialogXML.java new file mode 100644 index 0000000000..4e059c8592 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/CleanupDialogXML.java @@ -0,0 +1,198 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.actions; + +import org.eclipse.core.runtime.Preferences; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.help.WorkbenchHelp; +import org.eclipse.wst.common.encoding.CommonEncodingPreferenceNames; +import org.eclipse.wst.sse.core.IStructuredModel; +import org.eclipse.wst.sse.core.preferences.CommonModelPreferenceNames; +import org.eclipse.wst.sse.ui.nls.ResourceHandler; +import org.eclipse.wst.xml.core.XMLModelPlugin; +import org.eclipse.wst.xml.ui.internal.editor.IHelpContextIds; + + +public class CleanupDialogXML extends Dialog implements SelectionListener { + protected Button fCheckBoxCompressEmptyElementTags; + protected Button fCheckBoxConvertEOLCodes; + protected Button fCheckBoxFormatSource; + protected Button fCheckBoxInsertMissingTags; + protected Button fCheckBoxInsertRequiredAttrs; + protected Button fCheckBoxQuoteAttrValues; + protected IStructuredModel fModel = null; + protected Preferences fPreferences = null; + protected Button fRadioButtonAttrNameCaseAsis; + protected Button fRadioButtonAttrNameCaseLower; + protected Button fRadioButtonAttrNameCaseUpper; + protected Button fRadioButtonConvertEOLMac; + protected Button fRadioButtonConvertEOLUnix; + protected Button fRadioButtonConvertEOLWindows; + + protected Button fRadioButtonTagNameCaseAsis; + protected Button fRadioButtonTagNameCaseLower; + protected Button fRadioButtonTagNameCaseUpper; + + public CleanupDialogXML(Shell shell) { + + super(shell); + } + + public Control createDialogArea(Composite parent) { + + getShell().setText(ResourceHandler.getString("Cleanup_UI_")); //$NON-NLS-1$ = "Cleanup" + Composite composite = new Composite(parent, SWT.NULL); + createDialogAreaInComposite(composite); + initializeOptions(); + return composite; + } + + protected void createDialogAreaInComposite(Composite composite) { + + WorkbenchHelp.setHelp(composite, IHelpContextIds.CLEANUP_XML_HELPID); // use + // XML + // specific + // help + + GridLayout layout = new GridLayout(); + layout.numColumns = 1; + layout.makeColumnsEqualWidth = true; + composite.setLayout(layout); + + // Compress empty element tags + fCheckBoxCompressEmptyElementTags = new Button(composite, SWT.CHECK); + fCheckBoxCompressEmptyElementTags.setText(ResourceHandler.getString("Compress_empty_element_tags_UI_")); //$NON-NLS-1$ + fCheckBoxCompressEmptyElementTags.addSelectionListener(this); + + // Insert missing required attrs + fCheckBoxInsertRequiredAttrs = new Button(composite, SWT.CHECK); + fCheckBoxInsertRequiredAttrs.setText(ResourceHandler.getString("Insert_required_attributes_UI_")); //$NON-NLS-1$ + fCheckBoxInsertRequiredAttrs.addSelectionListener(this); + + // Insert missing begin/end tags + fCheckBoxInsertMissingTags = new Button(composite, SWT.CHECK); + fCheckBoxInsertMissingTags.setText(ResourceHandler.getString("Insert_missing_tags_UI_")); //$NON-NLS-1$ = "Insert missing tags" + fCheckBoxInsertMissingTags.addSelectionListener(this); + + // Quote attribute values + fCheckBoxQuoteAttrValues = new Button(composite, SWT.CHECK); + fCheckBoxQuoteAttrValues.setText(ResourceHandler.getString("Quote_attribute_values_UI_")); //$NON-NLS-1$ = "Quote attribute values" + fCheckBoxQuoteAttrValues.addSelectionListener(this); + + // Format source + fCheckBoxFormatSource = new Button(composite, SWT.CHECK); + fCheckBoxFormatSource.setText(ResourceHandler.getString("Format_source_UI_")); //$NON-NLS-1$ = "Format source" + fCheckBoxFormatSource.addSelectionListener(this); + + // Convert EOL code + fCheckBoxConvertEOLCodes = new Button(composite, SWT.CHECK); + fCheckBoxConvertEOLCodes.setText(ResourceHandler.getString("Convert_EOL_codes_UI_")); //$NON-NLS-1$ = "Convert end-of-line codes" + fCheckBoxConvertEOLCodes.addSelectionListener(this); + Composite EOLCodes = new Composite(composite, SWT.NULL); + GridLayout hLayout = new GridLayout(); + hLayout.numColumns = 3; + EOLCodes.setLayout(hLayout); + fRadioButtonConvertEOLWindows = new Button(EOLCodes, SWT.RADIO); + fRadioButtonConvertEOLWindows.setText(ResourceHandler.getString("EOL_Windows_UI")); //$NON-NLS-1$ = "Windows" + fRadioButtonConvertEOLWindows.addSelectionListener(this); + fRadioButtonConvertEOLUnix = new Button(EOLCodes, SWT.RADIO); + fRadioButtonConvertEOLUnix.setText(ResourceHandler.getString("EOL_Unix_UI")); //$NON-NLS-1$ = "Unix" + fRadioButtonConvertEOLUnix.addSelectionListener(this); + fRadioButtonConvertEOLMac = new Button(EOLCodes, SWT.RADIO); + fRadioButtonConvertEOLMac.setText(ResourceHandler.getString("EOL_Mac_UI")); //$NON-NLS-1$ = "Mac" + fRadioButtonConvertEOLMac.addSelectionListener(this); + } + + protected void enableEOLCodeRadios(boolean enable) { + + if ((fRadioButtonConvertEOLWindows != null) && (fRadioButtonConvertEOLUnix != null) && (fRadioButtonConvertEOLMac != null)) { + fRadioButtonConvertEOLWindows.setEnabled(enable); + fRadioButtonConvertEOLUnix.setEnabled(enable); + fRadioButtonConvertEOLMac.setEnabled(enable); + if (!fRadioButtonConvertEOLWindows.getSelection() && !fRadioButtonConvertEOLUnix.getSelection() && !fRadioButtonConvertEOLMac.getSelection()) + fRadioButtonConvertEOLWindows.setSelection(true); + } + } + + protected Preferences getModelPreferences() { + return XMLModelPlugin.getDefault().getPluginPreferences(); + } + + protected void initializeOptions() { + + fCheckBoxCompressEmptyElementTags.setSelection(getModelPreferences().getBoolean(CommonModelPreferenceNames.COMPRESS_EMPTY_ELEMENT_TAGS)); + fCheckBoxInsertRequiredAttrs.setSelection(getModelPreferences().getBoolean(CommonModelPreferenceNames.INSERT_REQUIRED_ATTRS)); + fCheckBoxInsertMissingTags.setSelection(getModelPreferences().getBoolean(CommonModelPreferenceNames.INSERT_MISSING_TAGS)); + fCheckBoxQuoteAttrValues.setSelection(getModelPreferences().getBoolean(CommonModelPreferenceNames.QUOTE_ATTR_VALUES)); + fCheckBoxFormatSource.setSelection(getModelPreferences().getBoolean(CommonModelPreferenceNames.FORMAT_SOURCE)); + fCheckBoxConvertEOLCodes.setSelection(getModelPreferences().getBoolean(CommonModelPreferenceNames.CONVERT_EOL_CODES)); + String EOLCode = getModelPreferences().getString(CommonModelPreferenceNames.CLEANUP_EOL_CODE); + if (EOLCode.compareTo(CommonEncodingPreferenceNames.LF) == 0) + fRadioButtonConvertEOLUnix.setSelection(true); + else if (EOLCode.compareTo(CommonEncodingPreferenceNames.CR) == 0) + fRadioButtonConvertEOLMac.setSelection(true); + else + fRadioButtonConvertEOLWindows.setSelection(true); + enableEOLCodeRadios(fCheckBoxConvertEOLCodes.getSelection()); + } + + protected void okPressed() { + + storeOptions(); + super.okPressed(); + } + + public void setModel(IStructuredModel model) { + + fModel = model; + } + + protected void storeOptions() { + + getModelPreferences().setValue(CommonModelPreferenceNames.COMPRESS_EMPTY_ELEMENT_TAGS, fCheckBoxCompressEmptyElementTags.getSelection()); + getModelPreferences().setValue(CommonModelPreferenceNames.INSERT_REQUIRED_ATTRS, fCheckBoxInsertRequiredAttrs.getSelection()); + getModelPreferences().setValue(CommonModelPreferenceNames.INSERT_MISSING_TAGS, fCheckBoxInsertMissingTags.getSelection()); + getModelPreferences().setValue(CommonModelPreferenceNames.QUOTE_ATTR_VALUES, fCheckBoxQuoteAttrValues.getSelection()); + getModelPreferences().setValue(CommonModelPreferenceNames.FORMAT_SOURCE, fCheckBoxFormatSource.getSelection()); + getModelPreferences().setValue(CommonModelPreferenceNames.CONVERT_EOL_CODES, fCheckBoxConvertEOLCodes.getSelection()); + if (fRadioButtonConvertEOLUnix.getSelection()) { + getModelPreferences().setValue(CommonModelPreferenceNames.CLEANUP_EOL_CODE, CommonEncodingPreferenceNames.LF); + } else if (fRadioButtonConvertEOLMac.getSelection()) { + getModelPreferences().setValue(CommonModelPreferenceNames.CLEANUP_EOL_CODE, CommonEncodingPreferenceNames.CR); + } else { + getModelPreferences().setValue(CommonModelPreferenceNames.CLEANUP_EOL_CODE, CommonEncodingPreferenceNames.CRLF); + } + // explicitly save plugin preferences so values are stored + XMLModelPlugin.getDefault().savePluginPreferences(); + } + + public void widgetDefaultSelected(SelectionEvent e) { + + widgetSelected(e); + } + + public void widgetSelected(SelectionEvent e) { + + getButton(OK).setEnabled((fRadioButtonTagNameCaseLower != null && (fRadioButtonTagNameCaseLower.getSelection() || fRadioButtonTagNameCaseUpper.getSelection())) || (fRadioButtonAttrNameCaseLower != null && (fRadioButtonAttrNameCaseLower.getSelection() || fRadioButtonAttrNameCaseUpper.getSelection())) || fCheckBoxInsertMissingTags.getSelection() || fCheckBoxQuoteAttrValues.getSelection() || fCheckBoxFormatSource.getSelection() || fCheckBoxConvertEOLCodes.getSelection() || (fRadioButtonConvertEOLUnix != null && (fRadioButtonConvertEOLUnix.getSelection() || fRadioButtonConvertEOLMac.getSelection() || fRadioButtonConvertEOLWindows.getSelection()))); + if (e.widget == fCheckBoxConvertEOLCodes) + enableEOLCodeRadios(fCheckBoxConvertEOLCodes.getSelection()); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/CommentActionXML.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/CommentActionXML.java new file mode 100644 index 0000000000..f2b8c13f71 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/CommentActionXML.java @@ -0,0 +1,207 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.actions; + +import java.util.ResourceBundle; + +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextSelection; +import org.eclipse.jface.text.Position; +import org.eclipse.jface.text.TextSelection; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.texteditor.IDocumentProvider; +import org.eclipse.ui.texteditor.ITextEditor; +import org.eclipse.ui.texteditor.TextEditorAction; +import org.eclipse.wst.sse.core.IStructuredModel; +import org.eclipse.wst.sse.core.exceptions.SourceEditingRuntimeException; +import org.eclipse.wst.sse.ui.IModelProvider; +import org.eclipse.wst.sse.ui.edit.util.StructuredTextEditorActionConstants; +import org.eclipse.wst.sse.ui.nls.ResourceHandler; + + +public class CommentActionXML extends TextEditorAction { + protected static final String CLOSE_COMMENT = "-->"; //$NON-NLS-1$ + protected static final String OPEN_COMMENT = "<!--"; //$NON-NLS-1$ + protected IDocument fDocument; + protected IStructuredModel fModel; + protected ITextSelection fSelection; + protected int fSelectionEndLine; + protected int fSelectionEndLineOffset; + protected int fSelectionEndOffset; + protected Position fSelectionPosition; + protected int fSelectionStartLine; + protected int fSelectionStartLineOffset; + protected int fSelectionStartOffset; + protected boolean fUpdateSelection; + + public CommentActionXML(ResourceBundle bundle, String prefix, ITextEditor editor) { + super(bundle, prefix, editor); + } + + protected void comment(int openCommentOffset, int closeCommentOffset) { + try { + fDocument.replace(openCommentOffset, 0, OPEN_COMMENT); + fDocument.replace(closeCommentOffset, 0, CLOSE_COMMENT); + removeOpenCloseComments(openCommentOffset + OPEN_COMMENT.length(), closeCommentOffset - openCommentOffset - CLOSE_COMMENT.length()); + } catch (BadLocationException e) { + throw new SourceEditingRuntimeException(); + } + } + + protected ITextSelection getCurrentSelection() { + ITextEditor editor = getTextEditor(); + if (editor != null) { + ISelectionProvider provider = editor.getSelectionProvider(); + if (provider != null) { + ISelection selection = provider.getSelection(); + if (selection instanceof ITextSelection) + return (ITextSelection) selection; + } + } + return null; + } + + protected void init() { + ITextEditor editor = getTextEditor(); + if (editor == null) + return; + + IDocumentProvider docProvider = editor.getDocumentProvider(); + if (docProvider == null || !(docProvider instanceof IModelProvider)) + return; + + IModelProvider modelProvider = (IModelProvider) docProvider; + + IEditorInput input = editor.getEditorInput(); + if (input == null) + return; + + fDocument = modelProvider.getDocument(input); + fModel = modelProvider.getModel(input); + if (fDocument == null || fModel == null) + return; + + fSelection = getCurrentSelection(); + fSelectionStartOffset = fSelection.getOffset(); + fSelectionEndOffset = fSelectionStartOffset + fSelection.getLength(); + + // add selection position to document + fSelectionPosition = new Position(fSelection.getOffset(), fSelection.getLength()); + try { + fDocument.addPosition(fSelectionPosition); + } catch (BadLocationException e) { + throw new SourceEditingRuntimeException(); + } + + try { + fSelectionStartLine = fDocument.getLineOfOffset(fSelectionStartOffset); + fSelectionEndLine = fDocument.getLineOfOffset(fSelectionEndOffset); + fSelectionStartLineOffset = fDocument.getLineOffset(fSelectionStartLine); + fSelectionEndLineOffset = fDocument.getLineOffset(fSelectionEndLine); + } catch (BadLocationException e) { + throw new SourceEditingRuntimeException(); + } + + // adjust selection end line + if (fSelectionEndLine > fSelectionStartLine && fSelectionEndLineOffset == fSelectionEndOffset) + fSelectionEndLine--; + } + + protected boolean isCommentLine(int line) { + try { + IRegion region = fDocument.getLineInformation(line); + String string = fDocument.get(region.getOffset(), region.getLength()).trim(); + return string.length() >= OPEN_COMMENT.length() + CLOSE_COMMENT.length() && string.startsWith(OPEN_COMMENT) && string.endsWith(CLOSE_COMMENT); + } catch (BadLocationException e) { + throw new SourceEditingRuntimeException(); + } + } + + protected void prepareSelection() { + fUpdateSelection = fSelection.getLength() > 0 && fSelectionStartLineOffset == fSelectionStartOffset && !isCommentLine(fSelectionStartLine); + } + + protected void processAction() { + fModel.beginRecording(this, ResourceHandler.getString(StructuredTextEditorActionConstants.ACTION_NAME_COMMENT + ".tooltip")); //$NON-NLS-1$ + fModel.aboutToChangeModel(); + + for (int i = fSelectionStartLine; i <= fSelectionEndLine; i++) { + try { + if (fDocument.getLineLength(i) > 0 && !isCommentLine(i)) { + int openCommentOffset = fDocument.getLineOffset(i); + int lineDelimiterLength = fDocument.getLineDelimiter(i) == null ? 0 : fDocument.getLineDelimiter(i).length(); + int closeCommentOffset = openCommentOffset + fDocument.getLineLength(i) - lineDelimiterLength + OPEN_COMMENT.length(); + comment(openCommentOffset, closeCommentOffset); + } + } catch (BadLocationException e) { + throw new SourceEditingRuntimeException(); + } + } + + fModel.changedModel(); + fModel.endRecording(this); + } + + protected void removeOpenCloseComments(int offset, int length) { + try { + int adjusted_length = length; + + // remove open comments + String string = fDocument.get(offset, length); + int index = string.lastIndexOf(OPEN_COMMENT); + while (index != -1) { + fDocument.replace(offset + index, OPEN_COMMENT.length(), ""); //$NON-NLS-1$ + index = string.lastIndexOf(OPEN_COMMENT, index - 1); + adjusted_length -= OPEN_COMMENT.length(); + } + + // remove close comments + string = fDocument.get(offset, adjusted_length); + index = string.lastIndexOf(CLOSE_COMMENT); + while (index != -1) { + fDocument.replace(offset + index, CLOSE_COMMENT.length(), ""); //$NON-NLS-1$ + index = string.lastIndexOf(CLOSE_COMMENT, index - 1); + } + } catch (BadLocationException e) { + throw new SourceEditingRuntimeException(); + } + } + + public void run() { + init(); + prepareSelection(); + processAction(); + updateSelection(); + } + + protected void setCurrentSelection(ITextSelection selection) { + ITextEditor editor = getTextEditor(); + if (editor != null) { + ISelectionProvider provider = editor.getSelectionProvider(); + if (provider != null) { + provider.setSelection(selection); + } + } + } + + protected void updateSelection() { + if (fUpdateSelection) { + ITextSelection selection = new TextSelection(fDocument, fSelectionPosition.getOffset() - OPEN_COMMENT.length(), fSelectionPosition.getLength() + OPEN_COMMENT.length()); + setCurrentSelection(selection); + } + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/EditAttributeAction.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/EditAttributeAction.java new file mode 100644 index 0000000000..63ab5c228b --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/EditAttributeAction.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ + + +package org.eclipse.wst.xml.ui.actions; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.window.Window; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.wst.xml.ui.dialogs.EditAttributeDialog; +import org.eclipse.wst.xml.ui.internal.editor.XMLEditorPluginImageHelper; +import org.eclipse.wst.xml.ui.internal.editor.XMLEditorPluginImages; +import org.eclipse.wst.xml.ui.util.XMLCommonResources; +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + + + +public class EditAttributeAction extends NodeAction { + protected static ImageDescriptor imageDescriptor; + + public static ImageDescriptor createImageDescriptor() { + if (imageDescriptor == null) { + imageDescriptor = XMLEditorPluginImageHelper.getInstance().getImageDescriptor(XMLEditorPluginImages.IMG_OBJ_ATTRIBUTE); + } + return imageDescriptor; + } + + protected Attr attr; + protected AbstractNodeActionManager manager; + protected Element ownerElement; + protected String title; + + public EditAttributeAction(AbstractNodeActionManager manager, Element ownerElement, Attr attr, String actionLabel, String title) { + this.manager = manager; + this.ownerElement = ownerElement; + this.attr = attr; + this.title = title; + setText(actionLabel); + // assume if attr is null then this is an 'Add' that requires action + // an icons... otherwise this is an edit + if (attr == null) { + setImageDescriptor(createImageDescriptor()); + } + } + + public String getUndoDescription() { + return title; + } + + public void run() { + manager.beginNodeAction(this); + Shell shell = XMLCommonResources.getInstance().getWorkbench().getActiveWorkbenchWindow().getShell(); + EditAttributeDialog dialog = new EditAttributeDialog(shell, ownerElement, attr); + dialog.create(); + dialog.getShell().setText(title); + dialog.setBlockOnOpen(true); + dialog.open(); + + if (dialog.getReturnCode() == Window.OK) { + if (attr != null) { + ownerElement.removeAttributeNode(attr); + } + Document document = ownerElement.getOwnerDocument(); + Attr newAttribute = document.createAttribute(dialog.getAttributeName()); + newAttribute.setValue(dialog.getAttributeValue()); + ownerElement.setAttributeNode(newAttribute); + manager.setViewerSelection(newAttribute); + } + manager.endNodeAction(this); + } +} + diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/EditDoctypeAction.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/EditDoctypeAction.java new file mode 100644 index 0000000000..dabe610434 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/EditDoctypeAction.java @@ -0,0 +1,191 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ + + +package org.eclipse.wst.xml.ui.actions; + +import org.eclipse.core.runtime.Path; +import org.eclipse.jface.action.Action; +import org.eclipse.jface.window.Window; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.PlatformUI; +import org.eclipse.wst.sse.core.IStructuredModel; +import org.eclipse.wst.xml.core.document.XMLDocument; +import org.eclipse.wst.xml.core.document.XMLDocumentType; +import org.eclipse.wst.xml.core.internal.document.DocumentImpl; +import org.eclipse.wst.xml.ui.dialogs.EditDoctypeDialog; +import org.eclipse.wst.xml.ui.util.XMLCommonResources; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + + + +/** + * EditDoctypeAction + */ +public class EditDoctypeAction extends Action { + protected DocumentType doctype; + protected Document document; + protected IStructuredModel model; + protected String resourceLocation; + protected String title; + + /** + * This constructor is used to create a new doctype. + */ + public EditDoctypeAction(IStructuredModel model, Document document, String resourceLocation, String title) { + setText(title); + this.model = model; + this.document = document; + this.resourceLocation = resourceLocation; + this.title = title; + } + + /** + * This constructor is used to edit an exisitng doctype. + */ + public EditDoctypeAction(IStructuredModel model, DocumentType doctype, String resourceLocation, String title) { + setText(title); + this.model = model; + this.doctype = doctype; + this.resourceLocation = resourceLocation; + this.title = title; + } + + + protected DocumentType createDoctype(EditDoctypeDialog dialog, Document document) { + DocumentType result = null; + if (document instanceof DocumentImpl) { + XMLDocument documentImpl = (XMLDocument) document; + XMLDocumentType doctypeImpl = (XMLDocumentType) documentImpl.createDoctype(dialog.getName()); + doctypeImpl.setPublicId(dialog.getPublicId()); + doctypeImpl.setSystemId(dialog.getSystemId()); + result = doctypeImpl; + } + return result; + } + + private Display getDisplay() { + + return PlatformUI.getWorkbench().getDisplay(); + } + + + protected String getRootElementName(Document document) { + Element rootElement = null; + NodeList nodeList = document.getChildNodes(); + int nodeListLength = nodeList.getLength(); + for (int i = 0; i < nodeListLength; i++) { + Node childNode = nodeList.item(i); + if (childNode.getNodeType() == Node.ELEMENT_NODE) { + rootElement = (Element) childNode; + break; + } + } + return rootElement != null ? rootElement.getNodeName() : XMLCommonResources.getInstance().getString("_UI_LABEL_ROOT_ELEMENT_VALUE"); //$NON-NLS-1$ + } + + public String getUndoDescription() { + return title; + } + + + protected void insertDoctype(DocumentType doctype, Document document) { + Node refChild = null; + NodeList nodeList = document.getChildNodes(); + int nodeListLength = nodeList.getLength(); + for (int i = 0; i < nodeListLength; i++) { + Node childNode = nodeList.item(i); + if (childNode.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE || childNode.getNodeType() == Node.COMMENT_NODE) { + // continue on to the nextNode + } else { + refChild = childNode; + break; + } + } + + document.insertBefore(doctype, refChild); + //manager.reformat(doctype, false); + } + + public void run() { + model.beginRecording(this, getUndoDescription()); + //Shell shell = + // XMLCommonUIPlugin.getInstance().getWorkbench().getActiveWorkbenchWindow().getShell(); + Shell shell = getDisplay().getActiveShell(); + EditDoctypeDialog dialog = showEditDoctypeDialog(shell); + + if (dialog.getReturnCode() == Window.OK) { + if (doctype != null) { + updateDoctype(dialog, doctype); + } else if (document != null) { + DocumentType doctype = createDoctype(dialog, document); + if (doctype != null) { + insertDoctype(doctype, document); + } + } + } + model.endRecording(this); + } + + protected EditDoctypeDialog showEditDoctypeDialog(Shell shell) { + EditDoctypeDialog dialog = null; + + if (doctype != null) { + dialog = new EditDoctypeDialog(shell, doctype); + if (title == null) { + title = XMLCommonResources.getInstance().getString("_UI_LABEL_EDIT_DOCTYPE"); //$NON-NLS-1$ + } + } else if (document != null) { + String rootElementName = getRootElementName(document); + dialog = new EditDoctypeDialog(shell, rootElementName, "", rootElementName + ".dtd"); //$NON-NLS-1$ //$NON-NLS-2$ + if (title == null) { + title = XMLCommonResources.getInstance().getString("_UI_MENU_ADD_DTD_INFORMATION_TITLE"); //$NON-NLS-1$ + } + } + + dialog.setComputeSystemId(doctype == null || doctype.getSystemId() == null || doctype.getSystemId().trim().length() == 0); + + dialog.setErrorChecking(false);//!model.getType().equals(IStructuredModel.HTML)); + dialog.create(); + dialog.getShell().setText(title); + dialog.setBlockOnOpen(true); + dialog.setResourceLocation(new Path(resourceLocation)); + dialog.open(); + + return dialog; + } + + + protected void updateDoctype(EditDoctypeDialog dialog, DocumentType doctype) { + if (doctype instanceof XMLDocumentType) { + XMLDocumentType doctypeImpl = (XMLDocumentType) doctype; + if (doctypeImpl.getName().equals(dialog.getName())) { + doctypeImpl.setPublicId(dialog.getPublicId()); + doctypeImpl.setSystemId(dialog.getSystemId()); + } else { + // we need to create a new one and remove the old + // + Document document = doctype.getOwnerDocument(); + DocumentType newDoctype = createDoctype(dialog, document); + document.insertBefore(newDoctype, doctype); + document.removeChild(doctype); + //manager.reformat(newDoctype, false); + } + } + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/EditElementAction.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/EditElementAction.java new file mode 100644 index 0000000000..081be78958 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/EditElementAction.java @@ -0,0 +1,119 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.actions; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.window.Window; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.xml.core.document.XMLElement; +import org.eclipse.wst.xml.core.document.XMLModel; +import org.eclipse.wst.xml.ui.dialogs.EditElementDialog; +import org.eclipse.wst.xml.ui.internal.editor.XMLEditorPluginImageHelper; +import org.eclipse.wst.xml.ui.internal.editor.XMLEditorPluginImages; +import org.eclipse.wst.xml.ui.util.XMLCommonResources; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + + + +public class EditElementAction extends NodeAction { + + protected static ImageDescriptor imageDescriptor; + + public static ImageDescriptor createImageDescriptor() { + if (imageDescriptor == null) { + imageDescriptor = XMLEditorPluginImageHelper.getInstance().getImageDescriptor(XMLEditorPluginImages.IMG_OBJ_ELEMENT); + } + return imageDescriptor; + } + + protected Element element; + protected int insertionIndex = -1; + protected AbstractNodeActionManager manager; + protected Node parent; + protected String title; + + public EditElementAction(AbstractNodeActionManager manager, Element element, String actionLabel, String dialogTitle) { + this(manager, element.getParentNode(), -1, element, actionLabel, dialogTitle); + } + + protected EditElementAction(AbstractNodeActionManager manager, Node parent, int index, Element element, String actionLabel, String title) { + this.manager = manager; + this.parent = parent; + this.insertionIndex = index; + this.element = element; + this.title = title; + setText(actionLabel); + if (element == null) { + setImageDescriptor(createImageDescriptor()); + } + } + + public EditElementAction(AbstractNodeActionManager manager, Node parent, int index, String actionLabel, String title) { + this(manager, parent, index, null, actionLabel, title); + } + + public String getUndoDescription() { + return title; + } + + public void run() { + manager.beginNodeAction(this); + Shell shell = XMLCommonResources.getInstance().getWorkbench().getActiveWorkbenchWindow().getShell(); + EditElementDialog dialog = new EditElementDialog(shell, element); + dialog.create(); + dialog.getShell().setText(title); + dialog.setBlockOnOpen(true); + dialog.open(); + + if (dialog.getReturnCode() == Window.OK) { + Document document = parent.getNodeType() == Node.DOCUMENT_NODE ? (Document) parent : parent.getOwnerDocument(); + if (element != null) { + // here we need to do a rename... which seems to be quite hard + // to do :-( + if (element instanceof XMLElement) { + XMLElement elementImpl = (XMLElement) element; + XMLModel model = elementImpl.getModel(); + String oldName = elementImpl.getNodeName(); + String newName = dialog.getElementName(); + setStructuredDocumentRegionElementName(model, elementImpl.getStartStructuredDocumentRegion(), oldName, newName); + setStructuredDocumentRegionElementName(model, elementImpl.getEndStructuredDocumentRegion(), oldName, newName); + } + } else { + Element newElement = document.createElement(dialog.getElementName()); + NodeList nodeList = parent.getChildNodes(); + int nodeListLength = nodeList.getLength(); + Node refChild = insertionIndex < nodeListLength && insertionIndex >= 0 ? nodeList.item(insertionIndex) : null; + parent.insertBefore(newElement, refChild); + manager.reformat(newElement, false); + manager.setViewerSelection(newElement); + } + } + manager.endNodeAction(this); + } + + protected void setStructuredDocumentRegionElementName(XMLModel model, IStructuredDocumentRegion flatNode, String oldName, String newName) { + if (flatNode != null) { + String string = flatNode.getText(); + int index = string.indexOf(oldName); + if (index != -1) { + index += flatNode.getStart(); + model.getStructuredDocument().replaceText(this, index, oldName.length(), newName); + } + } + } +} + diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/EditProcessingInstructionAction.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/EditProcessingInstructionAction.java new file mode 100644 index 0000000000..f4b8f46bac --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/EditProcessingInstructionAction.java @@ -0,0 +1,95 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.actions; + +import org.eclipse.jface.window.Window; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.wst.xml.ui.dialogs.EditProcessingInstructionDialog; +import org.eclipse.wst.xml.ui.util.XMLCommonResources; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.ProcessingInstruction; + + + +/** + * EditProcessingInstructionAction + */ +public class EditProcessingInstructionAction extends NodeAction { + protected Node childRef; + protected AbstractNodeActionManager manager; + protected Node parent; + protected ProcessingInstruction pi; + protected String title; + + /** + * This constructor is used to add a new ProcessingInstruction + */ + public EditProcessingInstructionAction(AbstractNodeActionManager manager, Node parent, Node childRef, String actionLabel, String title) { + setText(actionLabel); + this.manager = manager; + this.parent = parent; + this.childRef = childRef; + this.title = title; + } + + /** + * This constructor is used to edit a ProcessingInstruction + */ + public EditProcessingInstructionAction(AbstractNodeActionManager manager, ProcessingInstruction pi, String actionLabel, String title) { + setText(actionLabel); + this.manager = manager; + this.pi = pi; + this.parent = pi.getParentNode(); + this.title = title; + } + + public String getUndoDescription() { + return title; + } + + public void run() { + manager.beginNodeAction(this); + Shell shell = XMLCommonResources.getInstance().getWorkbench().getActiveWorkbenchWindow().getShell(); + + EditProcessingInstructionDialog dialog = null; + if (pi != null) { + dialog = new EditProcessingInstructionDialog(shell, pi); + } else { + dialog = new EditProcessingInstructionDialog(shell, XMLCommonResources.getInstance().getString("_UI_PI_TARGET_VALUE"), XMLCommonResources.getInstance().getString("_UI_PI_DATA_VALUE")); //$NON-NLS-1$ //$NON-NLS-2$ + } + + dialog.create(); + dialog.getShell().setText(title); + dialog.setBlockOnOpen(true); + dialog.open(); + + if (dialog.getReturnCode() == Window.OK) { + if (pi != null) { + childRef = pi; + } + + Document document = parent.getNodeType() == Node.DOCUMENT_NODE ? (Document) parent : parent.getOwnerDocument(); + Node newNode = document.createProcessingInstruction(dialog.getTarget(), dialog.getData()); + parent.insertBefore(newNode, childRef); + + if (pi != null) { + parent.removeChild(pi); + } + + manager.reformat(newNode, false); + manager.setViewerSelection(newNode); + } + manager.endNodeAction(this); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/EditSchemaInfoAction.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/EditSchemaInfoAction.java new file mode 100644 index 0000000000..5b2c3e2a7b --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/EditSchemaInfoAction.java @@ -0,0 +1,167 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.actions; + +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.runtime.Path; +import org.eclipse.jface.window.Window; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.wst.common.contentmodel.util.DOMNamespaceInfoManager; +import org.eclipse.wst.common.contentmodel.util.NamespaceInfo; +import org.eclipse.wst.xml.ui.dialogs.EditSchemaInfoDialog; +import org.eclipse.wst.xml.ui.util.XMLCommonResources; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + + +//import com.ibm.etools.xml.common.ui.dialogs.EditSchemaInfoDialog; + + +/** + * EditDoctypeAction + */ +public class EditSchemaInfoAction extends NodeAction { + protected AbstractNodeActionManager manager; + protected DOMNamespaceInfoManager namespaceInfoManager = new DOMNamespaceInfoManager(); + protected Node node; + protected String resourceLocation; + protected String title; + + public EditSchemaInfoAction(AbstractNodeActionManager manager, Node node, String resourceLocation, String title) { + this.manager = manager; + this.node = node; + setText(title); + this.resourceLocation = resourceLocation; + this.title = title; + } + + protected Map createPrefixMapping(List oldList, List newList) { + Map map = new Hashtable(); + + Hashtable oldURIToPrefixTable = new Hashtable(); + for (Iterator i = oldList.iterator(); i.hasNext();) { + NamespaceInfo oldInfo = (NamespaceInfo) i.next(); + oldURIToPrefixTable.put(oldInfo.uri, oldInfo); + } + + for (Iterator i = newList.iterator(); i.hasNext();) { + NamespaceInfo newInfo = (NamespaceInfo) i.next(); + NamespaceInfo oldInfo = (NamespaceInfo) oldURIToPrefixTable.get(newInfo.uri != null ? newInfo.uri : ""); //$NON-NLS-1$ + + + // if oldInfo is non null ... there's a matching URI in the old + // set + // we can use its prefix to detemine out mapping + // + // if oldInfo is null ... we use the 'oldCopy' we stashed away + // assuming that the user changed the URI and the prefix + if (oldInfo == null) { + oldInfo = (NamespaceInfo) newInfo.getProperty("oldCopy"); //$NON-NLS-1$ + } + + if (oldInfo != null) { + String newPrefix = newInfo.prefix != null ? newInfo.prefix : ""; //$NON-NLS-1$ + String oldPrefix = oldInfo.prefix != null ? oldInfo.prefix : ""; //$NON-NLS-1$ + if (!oldPrefix.equals(newPrefix)) { + map.put(oldPrefix, newPrefix); + } + } + } + return map; + } + + public Element getElement(Node node) { + Element result = null; + if (node.getNodeType() == Node.ELEMENT_NODE) { + result = (Element) node; + } else if (node.getNodeType() == Node.DOCUMENT_NODE) { + result = getRootElement((Document) node); + } + return result; + } + + + public Element getRootElement(Document document) { + Element rootElement = null; + NodeList nodeList = document.getChildNodes(); + int nodeListLength = nodeList.getLength(); + for (int i = 0; i < nodeListLength; i++) { + Node childNode = nodeList.item(i); + if (childNode.getNodeType() == Node.ELEMENT_NODE) { + rootElement = (Element) childNode; + break; + } + } + return rootElement; + } + + public String getUndoDescription() { + return title; + } + + public void run() { + manager.beginNodeAction(this); + + // todo... change constructor to take an element + Element element = getElement(node); + if (element != null) { + Shell shell = XMLCommonResources.getInstance().getWorkbench().getActiveWorkbenchWindow().getShell(); + EditSchemaInfoDialog dialog = new EditSchemaInfoDialog(shell, new Path(resourceLocation)); + + List namespaceInfoList = namespaceInfoManager.getNamespaceInfoList(element); + List oldNamespaceInfoList = NamespaceInfo.cloneNamespaceInfoList(namespaceInfoList); + + // here we store a copy of the old info for each NamespaceInfo + // this info will be used in createPrefixMapping() to figure out + // how to update the document + // in response to these changes + for (Iterator i = namespaceInfoList.iterator(); i.hasNext();) { + NamespaceInfo info = (NamespaceInfo) i.next(); + NamespaceInfo oldCopy = new NamespaceInfo(info); + info.setProperty("oldCopy", oldCopy); //$NON-NLS-1$ + } + + dialog.setNamespaceInfoList(namespaceInfoList); + dialog.create(); + //dialog.getShell().setSize(500, 300); + dialog.getShell().setText(XMLCommonResources.getInstance().getString("_UI_MENU_EDIT_SCHEMA_INFORMATION_TITLE")); //$NON-NLS-1$ + dialog.setBlockOnOpen(true); + dialog.open(); + + if (dialog.getReturnCode() == Window.OK) { + List newInfoList = dialog.getNamespaceInfoList(); + namespaceInfoManager.removeNamespaceInfo(element); + namespaceInfoManager.addNamespaceInfo(element, newInfoList, true); + + // see if we need to rename any prefixes + Map prefixMapping = createPrefixMapping(oldNamespaceInfoList, namespaceInfoList); + if (prefixMapping.size() > 0) { + try { + manager.getModel().aboutToChangeModel(); + ReplacePrefixAction replacePrefixAction = new ReplacePrefixAction(manager, element, prefixMapping); + replacePrefixAction.run(); + } finally { + manager.getModel().changedModel(); + } + } + } + } + manager.endNodeAction(this); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/MenuBuilder.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/MenuBuilder.java new file mode 100644 index 0000000000..0403f88d34 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/MenuBuilder.java @@ -0,0 +1,145 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ + + +package org.eclipse.wst.xml.ui.actions; + +import java.text.Collator; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.MenuManager; + + +public class MenuBuilder { + + + protected Comparator comparator = new Comparator() { + + public int compare(Object o1, Object o2) { + return Collator.getInstance().compare(getSortKey(o1), getSortKey(o2)); + } + + protected String getSortKey(Object o) { + String result = ""; //$NON-NLS-1$ + if (o instanceof IAction) { + IAction action = (IAction) o; + result = action.getText(); + } + //else if (o instanceof MenuData) + //{ + // result = "z" + ((MenuData)o).name; + //} + return result; + } + }; + + + protected void createAlphebeticalGrouping(IMenuManager menu, List actionList) { + Object[] array = actionList.toArray(); + if (array.length > 0) { + Arrays.sort(array, comparator); + } + + int groupSize = 15; + int minGroupSize = 5; + int numberOfGroups = (array.length / groupSize) + ((array.length % groupSize > minGroupSize) ? 1 : 0); + + for (int i = 0; i < numberOfGroups; i++) { + boolean isLastGroup = (i == (numberOfGroups - 1)); + int firstIndex = i * groupSize; + int lastIndex = isLastGroup ? array.length - 1 : i * groupSize + groupSize - 1; + Action firstAction = (Action) array[firstIndex]; + Action lastAction = (Action) array[lastIndex]; + MenuManager submenu = new MenuManager(firstAction.getText() + " - " + lastAction.getText()); //$NON-NLS-1$ + menu.add(submenu); + for (int j = firstIndex; j <= lastIndex; j++) { + submenu.add((Action) array[j]); + } + } + } + + + public void populateMenu(IMenuManager menu, List actionList, boolean createTiered) { + // sort the actions + if (actionList.size() < 25) { + Object[] array = actionList.toArray(); + if (array.length > 0) { + Arrays.sort(array, comparator); + } + for (int i = 0; i < array.length; i++) { + menu.add((Action) array[i]); + } + } else { + createAlphebeticalGrouping(menu, actionList); + } + } + + /* + * protected void createPropertyGrouping(IMenuManager menu, List + * actionList) { MenuDataTable menuDataTable = new MenuDataTable(); + * + * for (Iterator i = actionList.iterator(); i.hasNext(); ) { String + * groupName = null; Action action = (Action)i.next(); if (action + * instanceof NodeAction) { groupName = + * ((NodeAction)action).getGroupName(); } if (groupName == null) { + * groupName = ""; } MenuData menuData = + * menuDataTable.lookupOrCreate(groupName, ""); + * menuData.childList.add(action); } populateMenu(menu, + * menuDataTable.getRoot()); } + * + * + * protected void populateMenu(MenuManager menuManager, MenuData menuData) { + * for (Iterator i = menuData.childList.iterator(); i.hasNext(); ) { + * Object o = i.next(); if (o instanceof Action) { + * menuManager.add((Action)o); } else if (o instanceof MenuData) { + * MenuData childMenuData = (MenuData)o; MenuManager childMenuManager = + * new MenuManager(childMenuData.name); menuManager.add(childMenuManager); + * populateMenu(childMenuManager, childMenuData); } } } + * + * + * public MenuDataTable { protected Hashtable table = new Hashtable(); + * protected MenuData root; + * + * public MenuDataTable() { root = lookupOrCreateMenuData(null, null); } + * + * protected MenuData lookupMenuData(String name) { String key = name != + * null ? name : ""; return (MenuData)menuDataTable.get(key); } + * + * protected MenuData lookupOrCreateMenuData(String name, String + * parentName) { String key = name != null ? name : ""; MenuData menuData = + * (MenuData)menuDataTable.get(key); if (menuData == null) { menuData = + * new MenuData(name, parentName); menuDataTable.put(key, menuData); } + * return menuData; } + * + * public MenuData getRoot() { return root; } } + * + * + * protected class MenuData { public String name; public String + * parentName; public List childList = new Vector(); + * + * MenuData(String name, String parentName) { this.name = name; + * this.parentName = parentName; } + * + * protected void sort() { Object[] array = childList.toArray(); if + * (array.length > 0 ) { Arrays.sort(array, comparator); } childList = + * Arrays.asList(array); + * + * for (Iterator i = childList.iterator(); i.hasNext(); ) { Object o = + * i.next(); if (o instanceof MenuData) { ((MenuData)o).sort(); } } } } + */ +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/NodeAction.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/NodeAction.java new file mode 100644 index 0000000000..ff91cdd068 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/NodeAction.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ + + +package org.eclipse.wst.xml.ui.actions; + +import org.eclipse.jface.action.Action; + +public abstract class NodeAction extends Action { + + public String getSortKey() { + return null; + } + + public abstract String getUndoDescription(); +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/RemoveBlockCommentActionXML.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/RemoveBlockCommentActionXML.java new file mode 100644 index 0000000000..a5a5acb981 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/RemoveBlockCommentActionXML.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.actions; + +import java.util.ResourceBundle; + +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.ui.texteditor.ITextEditor; +import org.eclipse.wst.sse.core.exceptions.SourceEditingRuntimeException; +import org.eclipse.wst.sse.ui.edit.util.StructuredTextEditorActionConstants; +import org.eclipse.wst.sse.ui.nls.ResourceHandler; +import org.eclipse.wst.xml.core.internal.document.CommentImpl; + + +public class RemoveBlockCommentActionXML extends AddBlockCommentActionXML { + public RemoveBlockCommentActionXML(ResourceBundle bundle, String prefix, ITextEditor editor) { + super(bundle, prefix, editor); + } + + protected void init() { + super.init(); + + fCloseCommentOffset = fSelectionEndIndexedRegion.getEndOffset() - OPEN_COMMENT.length() - CLOSE_COMMENT.length(); + } + + protected void processAction() { + fModel.beginRecording(this, ResourceHandler.getString(StructuredTextEditorActionConstants.ACTION_NAME_REMOVE_BLOCK_COMMENT + ".tooltip")); //$NON-NLS-1$ + fModel.aboutToChangeModel(); + + if (fSelection.getLength() == 0) { + if (fSelectionStartIndexedRegion instanceof CommentImpl) { + try { + fDocument.replace(fOpenCommentOffset, OPEN_COMMENT.length(), ""); //$NON-NLS-1$ + fDocument.replace(fCloseCommentOffset, CLOSE_COMMENT.length(), ""); //$NON-NLS-1$ + } catch (BadLocationException e) { + throw new SourceEditingRuntimeException(); + } + } + } else { + if (fSelectionStartIndexedRegion instanceof CommentImpl) { + try { + fDocument.replace(fOpenCommentOffset, OPEN_COMMENT.length(), ""); //$NON-NLS-1$ + } catch (BadLocationException e) { + throw new SourceEditingRuntimeException(); + } + } + + if (fSelectionEndIndexedRegion instanceof CommentImpl) { + try { + fDocument.replace(fCloseCommentOffset, CLOSE_COMMENT.length(), ""); //$NON-NLS-1$ + } catch (BadLocationException e) { + throw new SourceEditingRuntimeException(); + } + } + } + removeOpenCloseComments(fOpenCommentOffset + OPEN_COMMENT.length(), fCloseCommentOffset - fOpenCommentOffset - CLOSE_COMMENT.length()); + + fModel.changedModel(); + fModel.endRecording(this); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/ReplacePrefixAction.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/ReplacePrefixAction.java new file mode 100644 index 0000000000..c94df41219 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/ReplacePrefixAction.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.actions; + +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Vector; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.wst.common.contentmodel.util.DOMVisitor; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + + + +public class ReplacePrefixAction extends NodeAction { + + class NodeCollectingDOMVisitor extends DOMVisitor { + public List list = new Vector(); + + protected boolean isPrefixChangedNeeded(Node node) { + String key = node.getPrefix() != null ? node.getPrefix() : ""; //$NON-NLS-1$ + return prefixMapping.get(key) != null; + } + + public void visitAttr(Attr attr) { + /* + * if (isPrefixChangedNeeded(element)) { list.add(attr); } + */ + } + + protected void visitElement(Element element) { + super.visitElement(element); + if (isPrefixChangedNeeded(element)) { + list.add(element); + } + } + } + + protected static ImageDescriptor imageDescriptor; + protected Element element; + protected AbstractNodeActionManager manager; + protected Map prefixMapping; + + public ReplacePrefixAction(AbstractNodeActionManager manager, Element element, Map prefixMapping) { + this.manager = manager; + this.element = element; + this.prefixMapping = prefixMapping; + } + + public String getUndoDescription() { + return ""; //$NON-NLS-1$ + } + + public void run() { + NodeCollectingDOMVisitor visitor = new NodeCollectingDOMVisitor(); + visitor.visitNode(element); + for (Iterator i = visitor.list.iterator(); i.hasNext();) { + Node node = (Node) i.next(); + String key = node.getPrefix() != null ? node.getPrefix() : ""; //$NON-NLS-1$ + String newPrefix = (String) prefixMapping.get(key); + if (newPrefix != null) { + node.setPrefix(newPrefix); + } + } + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/ToggleCommentActionXML.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/ToggleCommentActionXML.java new file mode 100644 index 0000000000..02b7d66268 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/ToggleCommentActionXML.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.actions; + +import java.util.ResourceBundle; + +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IRegion; +import org.eclipse.ui.texteditor.ITextEditor; +import org.eclipse.wst.sse.core.exceptions.SourceEditingRuntimeException; +import org.eclipse.wst.sse.ui.edit.util.StructuredTextEditorActionConstants; +import org.eclipse.wst.sse.ui.nls.ResourceHandler; + + +public class ToggleCommentActionXML extends UncommentActionXML { + public ToggleCommentActionXML(ResourceBundle bundle, String prefix, ITextEditor editor) { + super(bundle, prefix, editor); + } + + protected void processAction() { + fModel.beginRecording(this, ResourceHandler.getString(StructuredTextEditorActionConstants.ACTION_NAME_COMMENT + ".tooltip")); //$NON-NLS-1$ + fModel.aboutToChangeModel(); + + for (int i = fSelectionStartLine; i <= fSelectionEndLine; i++) { + try { + if (fDocument.getLineLength(i) > 0) { + if (isCommentLine(i)) { + int lineOffset = fDocument.getLineOffset(i); + IRegion region = fDocument.getLineInformation(i); + String string = fDocument.get(region.getOffset(), region.getLength()); + int openCommentOffset = lineOffset + string.indexOf(OPEN_COMMENT); + int closeCommentOffset = lineOffset + string.indexOf(CLOSE_COMMENT) - OPEN_COMMENT.length(); + uncomment(openCommentOffset, closeCommentOffset); + } else { + int openCommentOffset = fDocument.getLineOffset(i); + int lineDelimiterLength = fDocument.getLineDelimiter(i) == null ? 0 : fDocument.getLineDelimiter(i).length(); + int closeCommentOffset = openCommentOffset + fDocument.getLineLength(i) - lineDelimiterLength + OPEN_COMMENT.length(); + comment(openCommentOffset, closeCommentOffset); + } + } + } catch (BadLocationException e) { + throw new SourceEditingRuntimeException(); + } + } + + fModel.changedModel(); + fModel.endRecording(this); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/UncommentActionXML.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/UncommentActionXML.java new file mode 100644 index 0000000000..2dac342048 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/actions/UncommentActionXML.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.actions; + +import java.util.ResourceBundle; + +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IRegion; +import org.eclipse.ui.texteditor.ITextEditor; +import org.eclipse.wst.sse.core.exceptions.SourceEditingRuntimeException; +import org.eclipse.wst.sse.ui.edit.util.StructuredTextEditorActionConstants; +import org.eclipse.wst.sse.ui.nls.ResourceHandler; + + +public class UncommentActionXML extends CommentActionXML { + public UncommentActionXML(ResourceBundle bundle, String prefix, ITextEditor editor) { + super(bundle, prefix, editor); + } + + protected void processAction() { + fModel.beginRecording(this, ResourceHandler.getString(StructuredTextEditorActionConstants.ACTION_NAME_COMMENT + ".tooltip")); //$NON-NLS-1$ + fModel.aboutToChangeModel(); + + for (int i = fSelectionStartLine; i <= fSelectionEndLine; i++) { + try { + if (fDocument.getLineLength(i) > 0 && isCommentLine(i)) { + int lineOffset = fDocument.getLineOffset(i); + IRegion region = fDocument.getLineInformation(i); + String string = fDocument.get(region.getOffset(), region.getLength()); + int openCommentOffset = lineOffset + string.indexOf(OPEN_COMMENT); + int closeCommentOffset = lineOffset + string.indexOf(CLOSE_COMMENT) - OPEN_COMMENT.length(); + uncomment(openCommentOffset, closeCommentOffset); + } + } catch (BadLocationException e) { + throw new SourceEditingRuntimeException(); + } + } + + fModel.changedModel(); + fModel.endRecording(this); + } + + protected void uncomment(int openCommentOffset, int closeCommentOffset) { + try { + fDocument.replace(openCommentOffset, OPEN_COMMENT.length(), ""); //$NON-NLS-1$ + fDocument.replace(closeCommentOffset, CLOSE_COMMENT.length(), ""); //$NON-NLS-1$ + } catch (BadLocationException e) { + throw new SourceEditingRuntimeException(); + } + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/AbstractContentAssistProcessor.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/AbstractContentAssistProcessor.java new file mode 100644 index 0000000000..375da3a347 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/AbstractContentAssistProcessor.java @@ -0,0 +1,2209 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.contentassist; + +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; +import java.util.Properties; +import java.util.Vector; + +import org.eclipse.core.runtime.Platform; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.contentassist.ICompletionProposal; +import org.eclipse.jface.text.contentassist.IContentAssistProcessor; +import org.eclipse.jface.text.contentassist.IContextInformation; +import org.eclipse.jface.text.contentassist.IContextInformationValidator; +import org.eclipse.swt.graphics.Image; +import org.eclipse.wst.common.contentmodel.CMAttributeDeclaration; +import org.eclipse.wst.common.contentmodel.CMContent; +import org.eclipse.wst.common.contentmodel.CMDataType; +import org.eclipse.wst.common.contentmodel.CMDocument; +import org.eclipse.wst.common.contentmodel.CMElementDeclaration; +import org.eclipse.wst.common.contentmodel.CMEntityDeclaration; +import org.eclipse.wst.common.contentmodel.CMGroup; +import org.eclipse.wst.common.contentmodel.CMNamedNodeMap; +import org.eclipse.wst.common.contentmodel.CMNode; +import org.eclipse.wst.common.contentmodel.CMNodeList; +import org.eclipse.wst.common.contentmodel.modelquery.ModelQuery; +import org.eclipse.wst.common.contentmodel.modelquery.ModelQueryAction; +import org.eclipse.wst.common.contentmodel.util.DOMNamespaceHelper; +import org.eclipse.wst.common.encoding.ContentTypeEncodingPreferences; +import org.eclipse.wst.common.encoding.content.IContentTypeIdentifier; +import org.eclipse.wst.sse.core.IModelManagerPlugin; +import org.eclipse.wst.sse.core.IStructuredModel; +import org.eclipse.wst.sse.core.IndexedRegion; +import org.eclipse.wst.sse.core.text.IStructuredDocument; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.core.text.ITextRegionContainer; +import org.eclipse.wst.sse.core.text.ITextRegionList; +import org.eclipse.wst.sse.core.util.Debug; +import org.eclipse.wst.sse.ui.IReleasable; +import org.eclipse.wst.sse.ui.Logger; +import org.eclipse.wst.sse.ui.StructuredTextViewer; +import org.eclipse.wst.sse.ui.internal.contentassist.ContentAssistUtils; +import org.eclipse.wst.sse.ui.internal.contentassist.CustomCompletionProposal; +import org.eclipse.wst.sse.ui.nls.ResourceHandler; +import org.eclipse.wst.xml.core.document.XMLDocument; +import org.eclipse.wst.xml.core.document.XMLElement; +import org.eclipse.wst.xml.core.document.XMLModel; +import org.eclipse.wst.xml.core.document.XMLNode; +import org.eclipse.wst.xml.core.internal.document.AttrImpl; +import org.eclipse.wst.xml.core.jsp.model.parser.temp.XMLJSPRegionContexts; +import org.eclipse.wst.xml.core.modelquery.ModelQueryUtil; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; +import org.eclipse.wst.xml.ui.internal.editor.XMLEditorPluginImageHelper; +import org.eclipse.wst.xml.ui.internal.editor.XMLEditorPluginImages; +import org.eclipse.wst.xml.ui.taginfo.MarkupTagInfoProvider; +import org.eclipse.wst.xml.ui.templates.TemplateContextTypeIds; +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + + +abstract public class AbstractContentAssistProcessor implements IContentAssistProcessor, IReleasable { + protected static final String INTERNALERROR = ResourceHandler.getString("SEVERE_internal_error_occu_UI_"); //$NON-NLS-1$ = "SEVERE internal error occurred " + protected static final String UNKNOWN_ATTR = ResourceHandler.getString("No_known_attribute__UI_"); //$NON-NLS-1$ = "No known attribute " + protected static final String UNKNOWN_CONTEXT = ResourceHandler.getString("Content_Assist_not_availab_UI_"); //$NON-NLS-1$ = "Content Assist not available at the current location " + protected char completionProposalAutoActivationCharacters[] = null; + protected char contextInformationAutoActivationCharacters[] = null; + private AttributeContextInformationProvider fAttributeInfoProvider = null; + private AttributeContextInformationPresenter fContextInformationPresenter = null; + + protected String fErrorMessage = null; + protected XMLContentModelGenerator fGenerator; + //protected IResource resource = null; + protected MarkupTagInfoProvider fInfoProvider = null; + protected ITextViewer fTextViewer = null; + + protected List macroContexts = new ArrayList(); + + private final boolean showValues = true; + + public AbstractContentAssistProcessor() { + super(); + init(); + } + + protected void addAttributeNameProposals(ContentAssistRequest contentAssistRequest) { + XMLNode node = (XMLNode) contentAssistRequest.getNode(); + IStructuredDocumentRegion sdRegion = contentAssistRequest.getDocumentRegion(); + // retrieve the list of attributes + CMElementDeclaration elementDecl = getCMElementDeclaration(node); + if (elementDecl != null) { + CMNamedNodeMap attributes = elementDecl.getAttributes(); + String matchString = contentAssistRequest.getMatchString(); + + //check whether an attribute really exists for the replacement + // offsets AND if it possesses a value + boolean attrAtLocationHasValue = false; + NamedNodeMap attrs = node.getAttributes(); + for (int i = 0; i < attrs.getLength(); i++) { + AttrImpl existingAttr = (AttrImpl) attrs.item(i); + ITextRegion name = existingAttr.getNameRegion(); + + if (sdRegion.getStartOffset(name) <= contentAssistRequest.getReplacementBeginPosition() && sdRegion.getStartOffset(name) + name.getLength() >= contentAssistRequest.getReplacementBeginPosition() + contentAssistRequest.getReplacementLength() && existingAttr.getValueRegion() != null) { + attrAtLocationHasValue = true; + break; + } + } + + // only add proposals for the attributes whose names begin with + // the matchstring + if (attributes != null) { + // CMVC 246618 + int isRequired = 0; + Image attrImage = null; + for (int i = 0; i < attributes.getLength(); i++) { + CMAttributeDeclaration attrDecl = (CMAttributeDeclaration) attributes.item(i); + if (attrDecl.getUsage() == CMAttributeDeclaration.REQUIRED) { + isRequired = XMLRelevanceConstants.R_REQUIRED; + attrImage = XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_ATT_REQ_OBJ); + } else { + isRequired = 0; + attrImage = XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_ATTRIBUTE); + } + + + boolean showAttribute = true; + showAttribute = showAttribute && beginsWith(getRequiredName(node, attrDecl), matchString.trim()); + AttrImpl attr = (AttrImpl) node.getAttributes().getNamedItem(getRequiredName(node, attrDecl)); + ITextRegion nameRegion = attr != null ? attr.getNameRegion() : null; + // nameRegion.getEndOffset() + 1 is required to allow for + // matches against the full name of an existing Attr + showAttribute = showAttribute && ((attr == null) || (nameRegion != null && sdRegion.getStartOffset(nameRegion) <= contentAssistRequest.getReplacementBeginPosition() && sdRegion.getStartOffset(nameRegion) + nameRegion.getLength() >= contentAssistRequest.getReplacementBeginPosition() + contentAssistRequest.getReplacementLength())); + if (showAttribute) { + String proposedText = null; + String proposedInfo = getAdditionalInfo(elementDecl, attrDecl); + CustomCompletionProposal proposal = null; + // attribute is at this location and already exists + if (attrAtLocationHasValue) { + // only propose the name + proposedText = getRequiredName(node, attrDecl); + proposal = new CustomCompletionProposal(proposedText, contentAssistRequest.getReplacementBeginPosition(), contentAssistRequest.getReplacementLength(), proposedText.length(), attrImage, proposedText, null, proposedInfo, XMLRelevanceConstants.R_XML_ATTRIBUTE_NAME + isRequired, true); //CMVC + // 269884 + } + // no attribute exists or is elsewhere, generate + // minimally + else { + Attr existingAttrNode = (Attr) node.getAttributes().getNamedItem(getRequiredName(node, attrDecl)); + String value = null; + if (existingAttrNode != null) + value = existingAttrNode.getNodeValue(); + if (value != null && value.length() > 0) + proposedText = getRequiredName(node, attrDecl); + else { + proposedText = getRequiredText(node, attrDecl); + } + proposal = new CustomCompletionProposal(proposedText, contentAssistRequest.getReplacementBeginPosition(), contentAssistRequest.getReplacementLength(), attrDecl.getNodeName().length() + 2, attrImage, + // if the value isn't empty (no empty set of + // quotes), show it + (showValues && proposedText.indexOf("\"\"") < 0) ? proposedText : getRequiredName(node, attrDecl), //$NON-NLS-1$ + null, proposedInfo, XMLRelevanceConstants.R_XML_ATTRIBUTE_NAME + isRequired); + } + contentAssistRequest.addProposal(proposal); + } + } + } + } else { + setErrorMessage(ResourceHandler.getString("25concat", (new Object[]{node.getNodeName()}))); //+ + // node.getNodeName() + // + "> + // is + // unknown"); + // //$NON-NLS-1$ + // = + // "Element + // <{0}> + // is + // unknown." + } + addTemplates(contentAssistRequest, TemplateContextTypeIds.ATTRIBUTE); + } + + protected void addAttributeValueProposals(ContentAssistRequest contentAssistRequest) { + XMLNode node = (XMLNode) contentAssistRequest.getNode(); + + // Find the attribute region and name for which this position should + // have a value proposed + IStructuredDocumentRegion open = node.getFirstStructuredDocumentRegion(); + ITextRegionList openRegions = open.getRegions(); + int i = openRegions.indexOf(contentAssistRequest.getRegion()); + if (i < 0) + return; + ITextRegion nameRegion = null; + while (i >= 0) { + nameRegion = openRegions.get(i--); + if (nameRegion.getType() == XMLRegionContext.XML_TAG_ATTRIBUTE_NAME) + break; + } + + // the name region is REQUIRED to do anything useful + if (nameRegion != null) { + // Retrieve the declaration + CMElementDeclaration elementDecl = getCMElementDeclaration(node); + + //String attributeName = nameRegion.getText(); + String attributeName = open.getText(nameRegion); + + CMAttributeDeclaration attrDecl = null; + + // No CMElementDeclaration means no attribute metadata, but + // retrieve the + // declaration for the attribute otherwise + if (elementDecl != null) { + CMNamedNodeMap attributes = elementDecl.getAttributes(); + String noprefixName = DOMNamespaceHelper.getUnprefixedName(attributeName); + if (attributes != null) { + attrDecl = (CMAttributeDeclaration) attributes.getNamedItem(noprefixName); + if (attrDecl == null) { + attrDecl = (CMAttributeDeclaration) attributes.getNamedItem(attributeName); + } + } + if (attrDecl == null) { + setErrorMessage(UNKNOWN_ATTR, attributeName); + } + } + + String currentValue = node.getAttributes().getNamedItem(attributeName).getNodeValue(); + String proposedInfo = null; + if (attrDecl != null && attrDecl.getAttrType() != null) { + // attribute is known, prompt with values from the declaration + proposedInfo = getAdditionalInfo(elementDecl, attrDecl); + List possibleValues = getPossibleDataTypeValues(node, attrDecl); + if (possibleValues.size() > 0) { + // ENUMERATED VALUES + String matchString = contentAssistRequest.getMatchString(); + if (matchString == null) + matchString = ""; //$NON-NLS-1$ + if (matchString.length() > 0 && (matchString.startsWith("\"") || matchString.startsWith("'"))) //$NON-NLS-2$//$NON-NLS-1$ + matchString = matchString.substring(1); + boolean currentValid = false; + + // d210858, if the region's a container, don't suggest the + // enumerated values as they probably won't help + boolean existingComplicatedValue = contentAssistRequest.getRegion() != null && contentAssistRequest.getRegion() instanceof ITextRegionContainer; + if (!existingComplicatedValue) { + for (Iterator j = possibleValues.iterator(); j.hasNext();) { + String possibleValue = (String) j.next(); + currentValid = currentValid || possibleValue.equals(currentValue); + if (matchString.length() == 0 || possibleValue.startsWith(matchString)) { + CustomCompletionProposal proposal = new CustomCompletionProposal("\"" + possibleValue + "\"", //$NON-NLS-2$//$NON-NLS-1$ + contentAssistRequest.getReplacementBeginPosition(), contentAssistRequest.getReplacementLength(), possibleValue.length() + 1, XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_ATTRIBUTE), possibleValue, null, proposedInfo, XMLRelevanceConstants.R_XML_ATTRIBUTE_VALUE); + contentAssistRequest.addProposal(proposal); + } + } + } + } else if ((attrDecl.getUsage() == CMAttributeDeclaration.FIXED || attrDecl.getAttrType().getImpliedValueKind() == CMDataType.IMPLIED_VALUE_FIXED) && attrDecl.getAttrType().getImpliedValue() != null) { + // FIXED values + String value = attrDecl.getAttrType().getImpliedValue(); + if (value != null && value.length() > 0) { + CustomCompletionProposal proposal = new CustomCompletionProposal("\"" + value + "\"", //$NON-NLS-2$//$NON-NLS-1$ + contentAssistRequest.getReplacementBeginPosition(), contentAssistRequest.getReplacementLength(), value.length() + 1, XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_ATTRIBUTE), value, null, proposedInfo, XMLRelevanceConstants.R_XML_ATTRIBUTE_VALUE); + contentAssistRequest.addProposal(proposal); + if (currentValue.length() > 0 && !value.equals(currentValue)) { + proposal = new CustomCompletionProposal("\"" + currentValue + "\"", //$NON-NLS-2$//$NON-NLS-1$ + contentAssistRequest.getReplacementBeginPosition(), contentAssistRequest.getReplacementLength(), currentValue.length() + 1, XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_ATTRIBUTE), currentValue, null, proposedInfo, XMLRelevanceConstants.R_XML_ATTRIBUTE_VALUE); + contentAssistRequest.addProposal(proposal); + } + } + } + } else { + // unknown attribute, so supply nice empty values + proposedInfo = getAdditionalInfo(null, elementDecl); + CustomCompletionProposal proposal = null; + if (currentValue != null && currentValue.length() > 0) { + proposal = new CustomCompletionProposal("\"" + currentValue + "\"", //$NON-NLS-2$//$NON-NLS-1$ + contentAssistRequest.getReplacementBeginPosition(), contentAssistRequest.getReplacementLength(), 1, XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_ATTRIBUTE), "\"" + currentValue + "\"", //$NON-NLS-2$//$NON-NLS-1$ + null, proposedInfo, XMLRelevanceConstants.R_XML_ATTRIBUTE_VALUE); + contentAssistRequest.addProposal(proposal); + } + } + } else + setErrorMessage(UNKNOWN_CONTEXT); + + addTemplates(contentAssistRequest, TemplateContextTypeIds.ATTRIBUTEVALUE); + } + + protected void addCommentProposal(ContentAssistRequest contentAssistRequest) { + contentAssistRequest.addProposal(new CustomCompletionProposal("<!-- -->", //$NON-NLS-1$ + contentAssistRequest.getReplacementBeginPosition(), contentAssistRequest.getReplacementLength(), 5, XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_COMMENT), ResourceHandler.getString("6concat", (new Object[]{" <!-- -->"})), //$NON-NLS-1$ = "comment {0}"//$NON-NLS-2$ + null, null, XMLRelevanceConstants.R_COMMENT)); + } + + /** + * Add all of the element declarations int the CMContent object into one + * big list. + */ + protected void addContent(List contentList, CMContent content) { + if (content == null) + return; + if (content instanceof CMGroup) { + CMNodeList children = ((CMGroup) content).getChildNodes(); + if (children == null) + return; + for (int i = 0; i < children.getLength(); i++) { + CMNode child = children.item(i); + if (child.getNodeType() == CMNode.ELEMENT_DECLARATION) { + contentList.add(child); + } else { + if (child.getNodeType() == CMNode.GROUP) { + addContent(contentList, (CMContent) child); + } else { + throw new IllegalArgumentException("Unknown content child: " + child); //$NON-NLS-1$ + } + } + } + } else { + contentList.add(content); + } + } + + protected void addDocTypeProposal(ContentAssistRequest contentAssistRequest) { + // if a DocumentElement exists, use that for the root Element name + String rootname = "unspecified"; //$NON-NLS-1$ + if (contentAssistRequest.getNode().getOwnerDocument().getDocumentElement() != null) + rootname = contentAssistRequest.getNode().getOwnerDocument().getDocumentElement().getNodeName(); + + String proposedText = "<!DOCTYPE " + rootname + " PUBLIC \"//UNKNOWN/\" \"unknown.dtd\">"; //$NON-NLS-1$ //$NON-NLS-2$ + ICompletionProposal proposal = new CustomCompletionProposal(proposedText, contentAssistRequest.getReplacementBeginPosition(), contentAssistRequest.getReplacementLength(), 10, XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_DOCTYPE), "<!DOCTYPE ... >", //$NON-NLS-1$ + null, null, XMLRelevanceConstants.R_DOCTYPE); // TODO + // provide + // special + // documentation + // on doc + // type + contentAssistRequest.addProposal(proposal); + } + + /** + * Add the proposals for a completely empty document + */ + protected void addEmptyDocumentProposals(ContentAssistRequest contentAssistRequest) { + addXMLProposal(contentAssistRequest); + addTemplates(contentAssistRequest, TemplateContextTypeIds.TAG); + } + + /** + * Add the proposals for the name in an end tag + */ + protected void addEndTagNameProposals(ContentAssistRequest contentAssistRequest) { + + if (contentAssistRequest.getStartOffset() + contentAssistRequest.getRegion().getTextLength() < contentAssistRequest.getReplacementBeginPosition()) { + CustomCompletionProposal proposal = new CustomCompletionProposal(">", //$NON-NLS-1$ + contentAssistRequest.getReplacementBeginPosition(), contentAssistRequest.getReplacementLength(), 1, XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_TAG_GENERIC), ResourceHandler.getString("9concat", (new Object[]{" '>'"})), //$NON-NLS-1$ = "Close with {0}"//$NON-NLS-2$ + null, null, XMLRelevanceConstants.R_END_TAG_NAME); + contentAssistRequest.addProposal(proposal); + } else { + XMLNode node = (XMLNode) contentAssistRequest.getNode(); + ModelQuery modelQuery = ModelQueryUtil.getModelQuery(node.getOwnerDocument()); + Node aNode = contentAssistRequest.getNode(); + String matchString = contentAssistRequest.getMatchString(); + if (matchString.startsWith("</")) //$NON-NLS-1$ + matchString = matchString.substring(2); + while (aNode != null) { + if (aNode.getNodeType() == Node.ELEMENT_NODE) { + if (aNode.getNodeName().startsWith(matchString)) { + XMLNode aXMLNode = (XMLNode) aNode; + CMElementDeclaration ed = modelQuery.getCMElementDeclaration((Element) aNode); + if ((aXMLNode.getEndStructuredDocumentRegion() == null) && (ed == null || (ed.getContentType() != CMElementDeclaration.EMPTY))) { + String proposedText = aNode.getNodeName(); + String proposedInfo = (ed != null) ? getAdditionalInfo(null, ed) : null; + if (node.getNodeType() == Node.TEXT_NODE && !contentAssistRequest.getDocumentRegion().isEnded()) + proposedText += ">"; //$NON-NLS-1$ + CustomCompletionProposal proposal = null; + // double check to see if the region acted upon is + // a tag name; replace it if so + if (contentAssistRequest.getRegion().getType() == XMLRegionContext.XML_TAG_NAME) { + proposal = new CustomCompletionProposal(proposedText, contentAssistRequest.getStartOffset(), contentAssistRequest.getRegion().getTextLength(), proposedText.length(), XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_TAG_GENERIC), proposedText, null, proposedInfo, XMLRelevanceConstants.R_END_TAG_NAME); + } else { + proposal = new CustomCompletionProposal(proposedText, contentAssistRequest.getReplacementBeginPosition(), contentAssistRequest.getReplacementLength(), proposedText.length(), XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_TAG_GENERIC), ResourceHandler.getString("9concat", (new Object[]{"'" + proposedText + "'"})), //$NON-NLS-1$ = "Close with {0}"//$NON-NLS-2$ //$NON-NLS-3$ + null, proposedInfo, XMLRelevanceConstants.R_END_TAG_NAME); + } + contentAssistRequest.addProposal(proposal); + } + } + } + aNode = aNode.getParentNode(); + } + } + } + + /** + * Prompt for end tags to a non-empty Node that hasn't ended Handles these + * cases: <br> + * <tagOpen>| <br> + * <tagOpen>< |<br> + * <tagOpen></ | + * + * @param contentAssistRequest + */ + protected void addEndTagProposals(ContentAssistRequest contentAssistRequest) { + XMLNode node = (XMLNode) contentAssistRequest.getParent(); + + // CMVC 241090 for special meta-info comment tags + if (isCommentNode(node)) { + // loop and find non comment node parent + while (node != null && isCommentNode(node)) { + node = (XMLNode) node.getParentNode(); + } + } + + // data to create a CustomCompletionProposal + String replaceText = node.getNodeName() + ">"; //$NON-NLS-1$ + int replaceBegin = contentAssistRequest.getReplacementBeginPosition(); + int replaceLength = contentAssistRequest.getReplacementLength(); + int cursorOffset = node.getNodeName().length() + 1; + String displayString = ""; //$NON-NLS-1$ + String proposedInfo = ""; //$NON-NLS-1$ + Image image = XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_TAG_GENERIC); + + setErrorMessage(null); + boolean addProposal = false; + + if (node.getNodeType() == Node.ELEMENT_NODE) { + // fix for CMVC 261790 + // //////////////////////////////////////////////////////////////////////////////////// + IStructuredDocument sDoc = (IStructuredDocument) fTextViewer.getDocument(); + IStructuredDocumentRegion xmlEndTagOpen = sDoc.getRegionAtCharacterOffset(contentAssistRequest.getReplacementBeginPosition()); + // skip backward to "<", "</", or the (unclosed) start tag, null + // if not found + String type = ""; //$NON-NLS-1$ + while (xmlEndTagOpen != null && (type = xmlEndTagOpen.getType()) != XMLRegionContext.XML_END_TAG_OPEN && type != XMLRegionContext.XML_TAG_CLOSE && !needsEndTag(xmlEndTagOpen) && type != XMLRegionContext.XML_TAG_OPEN) { + xmlEndTagOpen = xmlEndTagOpen.getPrevious(); + } + + if (xmlEndTagOpen == null) + return; + + node = (XMLNode) node.getModel().getIndexedRegion(xmlEndTagOpen.getStartOffset()); + node = (XMLNode) node.getParentNode(); + + if (isStartTag(xmlEndTagOpen)) { + // this is the case for a start tag w/out end tag + // eg: + // <p> + // <% String test = "test"; %> + // | + if (needsEndTag(xmlEndTagOpen)) { + String tagName = getTagName(xmlEndTagOpen); + xmlEndTagOpen.getTextEndOffset(); + replaceLength = 0; + replaceText = "</" + tagName + ">"; //$NON-NLS-1$ //$NON-NLS-2$ $NON-NLS-2$ + //replaceText = "</" + node.getNodeName() + ">"; + // //$NON-NLS-1$ $NON-NLS-2$ + cursorOffset = tagName.length() + 3; + displayString = ResourceHandler.getString("17concat", (new Object[]{tagName})); //$NON-NLS-1$ + addProposal = true; + } + } else if (type == XMLRegionContext.XML_END_TAG_OPEN) { + // this is the case for: <tag> </ | + // possibly <tag> </ |<anotherTag> + // should only be replacing white space... + replaceLength = (replaceBegin > xmlEndTagOpen.getTextEndOffset()) ? replaceBegin - xmlEndTagOpen.getTextEndOffset() : 0; + replaceText = node.getNodeName() + ">"; //$NON-NLS-1$ + cursorOffset = replaceText.length(); + replaceBegin = xmlEndTagOpen.getTextEndOffset(); + displayString = ResourceHandler.getString("15concat", (new Object[]{node.getNodeName()})); //$NON-NLS-1$ + addProposal = true; + } else if (type == XMLRegionContext.XML_TAG_OPEN) { + // this is the case for: <tag> < | + replaceText = "/" + node.getNodeName() + ">"; //$NON-NLS-1$ //$NON-NLS-2$ $NON-NLS-2$ + cursorOffset = replaceText.length(); + //replaceText = "/" + node.getNodeName() + ">"; //$NON-NLS-1$ + // $NON-NLS-2$ + // should only be replacing white space... + replaceLength = (replaceBegin > xmlEndTagOpen.getTextEndOffset()) ? replaceBegin - xmlEndTagOpen.getTextEndOffset() : 0; + replaceBegin = xmlEndTagOpen.getTextEndOffset(); + displayString = ResourceHandler.getString("15concat", (new Object[]{"/" + node.getNodeName()})); //$NON-NLS-1$ //$NON-NLS-2$ + addProposal = true; + } + } + // fix for CMVC 261790 + // //////////////////////////////////////////////////////////////////////////////////// + // fix for CMVC 263163, sometimes the node is not null, but + // getNodeValue() is null, put in a null check + else if (node.getNodeValue() != null && node.getNodeValue().indexOf("</") != -1) { //$NON-NLS-1$ + // the case where "</" is started, but the nodes comes in as a + // text node (instead of element) + // like this: <tag> </| + Node parent = node.getParentNode(); + if (parent != null && parent.getNodeType() != Node.DOCUMENT_NODE) { + replaceText = parent.getNodeName() + ">"; //$NON-NLS-1$ + cursorOffset = replaceText.length(); + displayString = ResourceHandler.getString("17concat", (new Object[]{parent.getNodeName()})); //$NON-NLS-1$ + setErrorMessage(null); + addProposal = true; + } + } + // end fix for CMVC 261790 + // //////////////////////////////////////////////////////////////////////////////////// + else if (node.getNodeType() == Node.DOCUMENT_NODE) { + setErrorMessage(UNKNOWN_CONTEXT); + } + if (addProposal == true) { + CustomCompletionProposal proposal = new CustomCompletionProposal(replaceText, replaceBegin, replaceLength, cursorOffset, image, displayString, null, proposedInfo, XMLRelevanceConstants.R_END_TAG); + contentAssistRequest.addProposal(proposal); + } + } + + protected void addEntityProposals(ContentAssistRequest contentAssistRequest, int documentPosition, ITextRegion completionRegion, XMLNode treeNode) { + ICompletionProposal[] eps = computeEntityReferenceProposals(documentPosition, completionRegion, treeNode); + for (int i = 0; eps != null && i < eps.length; i++) + contentAssistRequest.addProposal(eps[i]); + } + + protected void addEntityProposals(Vector proposals, Properties map, String key, int nodeOffset, IStructuredDocumentRegion sdRegion, ITextRegion completionRegion) { + if (map == null) + return; + String entityName = ""; //$NON-NLS-1$ + String entityValue = ""; //$NON-NLS-1$ + Image entityIcon = XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_ENTITY_REFERENCE); + String replacementText = ""; //$NON-NLS-1$ + String displayString = ""; //$NON-NLS-1$ + Enumeration keys = map.keys(); + + while (keys != null && keys.hasMoreElements()) { + entityName = (String) keys.nextElement(); + entityValue = map.getProperty(entityName); + // filter based on partial entity string... + if (entityName.toLowerCase().startsWith(key.toLowerCase()) || key.trim().equals("")) //$NON-NLS-1$ + { + // figure out selection...if text is selected, add it to + // selection length + int selectionLength = nodeOffset; + if (fTextViewer != null) { + selectionLength += fTextViewer.getSelectedRange().y; + } + // create a new proposal for entity string... + replacementText = "&" + entityName + ";"; //$NON-NLS-1$ //$NON-NLS-2$ + displayString = "&" + entityName + "; (" + entityValue + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + ICompletionProposal cp = new CustomCompletionProposal(replacementText, sdRegion.getStartOffset(completionRegion), selectionLength, replacementText.length(), entityIcon, displayString, null, null, XMLRelevanceConstants.R_ENTITY); + if (cp != null) { + proposals.add(cp); + } + } + } + } + + protected void addPCDATAProposal(String nodeName, ContentAssistRequest contentAssistRequest) { + CustomCompletionProposal proposal = new CustomCompletionProposal("<![CDATA[]]>", //$NON-NLS-1$ + contentAssistRequest.getReplacementBeginPosition(), contentAssistRequest.getReplacementLength(), 9, XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_CDATASECTION), "CDATA Section", //$NON-NLS-1$ + null, null, XMLRelevanceConstants.R_CDATA); + contentAssistRequest.addProposal(proposal); + + proposal = new CustomCompletionProposal(nodeName, contentAssistRequest.getReplacementBeginPosition(), contentAssistRequest.getReplacementLength(), nodeName.length(), XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_TXTEXT), "#PCDATA", //$NON-NLS-1$ + null, null, XMLRelevanceConstants.R_CDATA); + contentAssistRequest.addProposal(proposal); + } + + protected void addStartDocumentProposals(ContentAssistRequest contentAssistRequest) { + Node aNode = contentAssistRequest.getNode(); + boolean xmlpiFound = false; + Document owningDocument = aNode.getOwnerDocument(); + // ==> // int xmlpiNodePosition = -1; + + // make sure xmlpi is root element + // don't want doctype proposal if XMLPI isn't first element... + // CMVC 242943 + // CMVC 245532 + Node first = owningDocument.getFirstChild(); + boolean xmlpiIsFirstElement = (first != null && first.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE); + boolean insertDoctype = xmlpiIsFirstElement; + + for (Node child = owningDocument.getFirstChild(); child != null; child = child.getNextSibling()) { + boolean xmlpi = (child.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE && child.getNodeName().equals("xml")); //$NON-NLS-1$ + xmlpiFound = xmlpiFound || xmlpi; + if (xmlpiFound) { + if (child instanceof XMLNode) { + // ==> // int xmlpiNodePosition = + // ((XMLNode)child).getEndOffset(); + } + // skip white space and text + while ((child = child.getNextSibling()) != null && (child.getNodeType() == Node.TEXT_NODE)) { + } + // check if theres a node inbetween XMLPI and cursor position + if (child != null && child instanceof XMLNode) { + // CMVC 257486 + if (contentAssistRequest.getReplacementBeginPosition() >= ((XMLNode) child).getEndOffset() || !xmlpiIsFirstElement) { + insertDoctype = false; + } + } + break; + } + } + + if (!xmlpiFound) { + addXMLProposal(contentAssistRequest); + } else if (owningDocument.getDoctype() == null && isCursorAfterXMLPI(contentAssistRequest) && insertDoctype) { + addDocTypeProposal(contentAssistRequest); + } + } + + /** + * Close an unclosed start tag + */ + protected void addTagCloseProposals(ContentAssistRequest contentAssistRequest) { + XMLNode node = (XMLNode) contentAssistRequest.getParent(); + if (node.getNodeType() == Node.ELEMENT_NODE) { + + CMElementDeclaration elementDecl = getCMElementDeclaration(node); + String proposedInfo = (elementDecl != null) ? getAdditionalInfo(null, elementDecl) : null; + int contentType = (elementDecl != null) ? elementDecl.getContentType() : CMElementDeclaration.ANY; + // if it's XML and content doesn't HAVE to be element, add "/>" + // proposal. + boolean endWithSlashBracket = (getXML(node) && contentType != CMElementDeclaration.ELEMENT); + + // is the start tag ended properly? + if (contentAssistRequest.getDocumentRegion() == node.getFirstStructuredDocumentRegion() && !(node.getFirstStructuredDocumentRegion()).isEnded()) { + setErrorMessage(null); + // Is this supposed to be an empty tag? Note that if we can't + // tell, we assume it's not. + if (elementDecl != null && elementDecl.getContentType() == CMElementDeclaration.EMPTY) { + // prompt with a self-closing end character if needed + CustomCompletionProposal proposal = new CustomCompletionProposal(getContentGenerator().getStartTagClose(node, elementDecl), contentAssistRequest.getReplacementBeginPosition(), + // this is one of the few times to ignore the length -- + // always insert + // contentAssistRequest.getReplacementLength(), + 0, getContentGenerator().getStartTagClose(node, elementDecl).length(), XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_TAG_GENERIC), ResourceHandler.getString("3concat", (new Object[]{getContentGenerator().getStartTagClose(node, elementDecl)})), //$NON-NLS-1$ = "Close with '{0}'" + null, proposedInfo, XMLRelevanceConstants.R_CLOSE_TAG); + contentAssistRequest.addProposal(proposal); + } else { + // prompt with a close for the start tag + CustomCompletionProposal proposal = new CustomCompletionProposal(">", //$NON-NLS-1$ + contentAssistRequest.getReplacementBeginPosition(), + // this is one of the few times to ignore the + // length -- always insert + // contentAssistRequest.getReplacementLength(), + 0, 1, XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_TAG_GENERIC), ResourceHandler.getString("9concat", (new Object[]{" '>'"})), //$NON-NLS-1$ = "Close with {0}"//$NON-NLS-2$ + null, proposedInfo, XMLRelevanceConstants.R_CLOSE_TAG); + contentAssistRequest.addProposal(proposal); + + // prompt with the closer for the start tag and an end tag + // if one is not present + if (node.getEndStructuredDocumentRegion() == null) { + // FIX FOR CMVC 247482 + // make sure tag name is actually what it thinks it + // is...(eg. <%@ vs. <jsp:directive) + IStructuredDocumentRegion sdr = contentAssistRequest.getDocumentRegion(); + String openingTagText = (sdr != null) ? sdr.getFullText() : ""; //$NON-NLS-1$ + if (openingTagText != null && openingTagText.indexOf(node.getNodeName()) != -1) { + proposal = new CustomCompletionProposal("></" + node.getNodeName() + ">", //$NON-NLS-2$//$NON-NLS-1$ + contentAssistRequest.getReplacementBeginPosition(), + // this is one of the few times to + // ignore the length -- always insert + // contentAssistRequest.getReplacementLength(), + 0, 1, XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_TAG_GENERIC), ResourceHandler.getString("5concat", (new Object[]{node.getNodeName()})), //$NON-NLS-1$ = "Close with '></{0}>'" + null, proposedInfo, XMLRelevanceConstants.R_CLOSE_TAG); + contentAssistRequest.addProposal(proposal); + } + } + // prompt with slash bracket "/>" incase if it's a self + // ending tag + if (endWithSlashBracket) { + proposal = new CustomCompletionProposal("/>", //$NON-NLS-1$ + contentAssistRequest.getReplacementBeginPosition(), + // this is one of the few times to ignore + // the length -- always insert + // contentAssistRequest.getReplacementLength(), + 0, 2, XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_TAG_GENERIC), ResourceHandler.getString("9concat", (new Object[]{" \"/>\""})), //$NON-NLS-1$ = "Close with {0}"//$NON-NLS-2$ + null, proposedInfo, XMLRelevanceConstants.R_CLOSE_TAG + 1); // +1 + // to + // bring + // to + // top + // of + // list + contentAssistRequest.addProposal(proposal); + } + } + } else if (contentAssistRequest.getDocumentRegion() == node.getLastStructuredDocumentRegion() && !node.getLastStructuredDocumentRegion().isEnded()) { + setErrorMessage(null); + // prompt with a closing end character for the end tag + CustomCompletionProposal proposal = new CustomCompletionProposal(">", //$NON-NLS-1$ + contentAssistRequest.getReplacementBeginPosition(), + // this is one of the few times to ignore the + // length -- always insert + // contentAssistRequest.getReplacementLength(), + 0, 1, XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_TAG_GENERIC), ResourceHandler.getString("9concat", (new Object[]{" '>'"})), //$NON-NLS-1$ = "Close with {0}"//$NON-NLS-2$ + null, proposedInfo, XMLRelevanceConstants.R_CLOSE_TAG); + contentAssistRequest.addProposal(proposal); + } + } else if (node.getNodeType() == Node.DOCUMENT_NODE) { + setErrorMessage(UNKNOWN_CONTEXT); + } + } + + protected void addTagInsertionProposals(ContentAssistRequest contentAssistRequest, int childPosition) { + List cmnodes = null; + Node parent = contentAssistRequest.getParent(); + List validActions = null; + String error = null; + + // CMVC #242943 shouldn't have proposals before XMLPI + // (nsd) This is only valid at the document element level + // only valid if it's XML (check added 2/17/2004) + if (parent != null && parent.getNodeType() == Node.DOCUMENT_NODE && ((XMLDocument) parent).isXMLType() && !isCursorAfterXMLPI(contentAssistRequest)) { + // but we should always have macros + // need to be careful these are only added one time + addTemplates(contentAssistRequest, TemplateContextTypeIds.TAG); + return; + } + // only want proposals if cursor is after doctype... + if (!isCursorAfterDoctype(contentAssistRequest)) + return; + + // CMVC 248081 + // fix for meta-info comment nodes.. they currently "hide" other + // proposals because the don't + // have a content model (so can't propose any children..) + if (parent != null && parent instanceof XMLNode && isCommentNode((XMLNode) parent)) { + // loop and find non comment node? + while (parent != null && isCommentNode((XMLNode) parent)) { + parent = (XMLNode) parent.getParentNode(); + } + } + + if (parent.getNodeType() == Node.ELEMENT_NODE) { + CMElementDeclaration parentDecl = getCMElementDeclaration(parent); + if (parentDecl != null) { + // XSD-specific ability - no filtering + CMDataType childType = parentDecl.getDataType(); + if (childType != null) { + String[] childStrings = childType.getEnumeratedValues(); + if (childStrings != null) { + // the content string is the sole valid child...so + // replace the rest + int begin = contentAssistRequest.getReplacementBeginPosition(); + int length = contentAssistRequest.getReplacementLength(); + if (parent instanceof XMLNode) { + if (((XMLNode) parent).getLastStructuredDocumentRegion() != ((XMLNode) parent).getFirstStructuredDocumentRegion()) { + begin = ((XMLNode) parent).getFirstStructuredDocumentRegion().getEndOffset(); + length = ((XMLNode) parent).getLastStructuredDocumentRegion().getStartOffset() - begin; + } + } + String proposedInfo = getAdditionalInfo(parentDecl, childType); + for (int i = 0; i < childStrings.length; i++) { + CustomCompletionProposal textProposal = new CustomCompletionProposal(childStrings[i], begin, length, childStrings[i].length(), XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_ENUM), childStrings[i], null, proposedInfo, XMLRelevanceConstants.R_TAG_INSERTION); + contentAssistRequest.addProposal(textProposal); + } + } + } + } + if (parentDecl != null && parentDecl.getContentType() == CMElementDeclaration.PCDATA) { + addPCDATAProposal(parentDecl.getNodeName(), contentAssistRequest); + } else { + // retrieve the list of children + validActions = getAvailableChildrenAtIndex((Element) parent, childPosition); + cmnodes = getValidCMNodes(childPosition, ModelQueryAction.INSERT, validActions); + Iterator nodeIterator = cmnodes.iterator(); + if (!nodeIterator.hasNext()) { + if (getCMElementDeclaration(parent) != null) + error = ResourceHandler.getString("1concat", (new Object[]{parent.getNodeName()})); //$NON-NLS-1$ = "{0} has no available child tags." + else + error = ResourceHandler.getString("31concat", (new Object[]{parent.getNodeName()})); //$NON-NLS-1$ + } + String matchString = contentAssistRequest.getMatchString(); + // chop off any leading <'s and whitespace from the + // matchstring + while ((matchString.length() > 0) && (Character.isWhitespace(matchString.charAt(0)) || beginsWith(matchString, "<"))) //$NON-NLS-1$ + //$NON-NLS-1$ + matchString = matchString.substring(1); + while (nodeIterator.hasNext()) { + Object o = nodeIterator.next(); + if (o instanceof CMElementDeclaration) { + CMElementDeclaration elementDecl = (CMElementDeclaration) o; + // only add proposals for the child element's that + // begin with the matchstring + String tagname = getRequiredName(parent, elementDecl); + // Account for the < and >. If attributes were + // added, the cursor will be placed + // at the offset before of the first character of the + // first attribute name. + int markupAdjustment = getContentGenerator().getMinimalStartTagLength(parent, elementDecl); + if (beginsWith(tagname, matchString)) { + String proposedText = getRequiredText(parent, elementDecl); + String proposedInfo = getAdditionalInfo(parentDecl, elementDecl); + CustomCompletionProposal proposal = new CustomCompletionProposal(proposedText, contentAssistRequest.getReplacementBeginPosition(), contentAssistRequest.getReplacementLength(), markupAdjustment, XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_TAG_GENERIC), tagname, null, proposedInfo, XMLRelevanceConstants.R_TAG_INSERTION); + contentAssistRequest.addProposal(proposal); + } + } + } + if (contentAssistRequest.getProposals().size() == 0) { + if (error != null) + setErrorMessage(error); + else if (contentAssistRequest.getMatchString() != null && contentAssistRequest.getMatchString().length() > 0) + setErrorMessage(ResourceHandler.getString("11concat", (new Object[]{parent.getNodeName(), contentAssistRequest.getMatchString()}))); //$NON-NLS-1$ + //$NON-NLS-1$ = "No known child tag names of <{0}> begin with \"{1}\"." + else + setErrorMessage(ResourceHandler.getString("14concat", (new Object[]{parent.getNodeName()}))); //$NON-NLS-1$ + } + } + } else if (parent.getNodeType() == Node.DOCUMENT_NODE) { + // Can only prompt with elements if the cursor position is past + // the XML processing + // instruction and DOCTYPE declaration + boolean xmlpiFound = false; + boolean doctypeFound = false; + int minimumOffset = -1; + + for (Node child = parent.getFirstChild(); child != null; child = child.getNextSibling()) { + + boolean xmlpi = (child.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE && child.getNodeName().equals("xml")); //$NON-NLS-1$ + boolean doctype = child.getNodeType() == Node.DOCUMENT_TYPE_NODE; + if (xmlpi || doctype && minimumOffset < 0) + minimumOffset = ((XMLNode) child).getFirstStructuredDocumentRegion().getStartOffset() + ((XMLNode) child).getFirstStructuredDocumentRegion().getTextLength(); + xmlpiFound = xmlpiFound || xmlpi; + doctypeFound = doctypeFound || doctype; + } + if (!xmlpiFound && contentAssistRequest.getReplacementBeginPosition() < minimumOffset) { + addXMLProposal(contentAssistRequest); + } + + if (contentAssistRequest.getReplacementBeginPosition() >= minimumOffset) { + List childDecls = getAvailableRootChildren((Document) parent, childPosition); + for (int i = 0; i < childDecls.size(); i++) { + CMElementDeclaration ed = (CMElementDeclaration) childDecls.get(i); + if (ed != null) { + String proposedText = getRequiredText(parent, ed); + String tagname = getRequiredName(parent, ed); + // account for the < and > + int markupAdjustment = getContentGenerator().getMinimalStartTagLength(parent, ed); + String proposedInfo = getAdditionalInfo(null, ed); + CustomCompletionProposal proposal = new CustomCompletionProposal(proposedText, contentAssistRequest.getReplacementBeginPosition(), contentAssistRequest.getReplacementLength(), markupAdjustment, XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_TAG_GENERIC), tagname, null, proposedInfo, XMLRelevanceConstants.R_TAG_INSERTION); + contentAssistRequest.addProposal(proposal); + } + } + } + } + addTemplates(contentAssistRequest, TemplateContextTypeIds.TAG); + } + + protected void addTagNameProposals(ContentAssistRequest contentAssistRequest, int childPosition) { + List cmnodes = null; + Node parent = contentAssistRequest.getParent(); + XMLNode node = (XMLNode) contentAssistRequest.getNode(); + List validActions = null; + String error = null; + String matchString = contentAssistRequest.getMatchString(); + if (parent.getNodeType() == Node.ELEMENT_NODE) { + // retrieve the list of children + validActions = getAvailableChildrenAtIndex((Element) parent, childPosition); + cmnodes = getValidCMNodes(childPosition, ModelQueryAction.INSERT, validActions); + Iterator nodeIterator = cmnodes.iterator(); + // chop off any leading <'s and whitespace from the matchstring + while ((matchString.length() > 0) && (Character.isWhitespace(matchString.charAt(0)) || beginsWith(matchString, "<"))) //$NON-NLS-1$ + //$NON-NLS-1$ + matchString = matchString.substring(1); + if (!nodeIterator.hasNext()) + error = ResourceHandler.getString("8concat", (new Object[]{parent.getNodeName()})); //$NON-NLS-1$ + while (nodeIterator.hasNext()) { + CMNode elementDecl = (CMNode) nodeIterator.next(); + if (elementDecl != null) { + // only add proposals for the child element's that begin + // with the matchstring + String proposedText = null; + int cursorAdjustment = 0; + + // do a check to see if partial attributes of partial tag + // names are in list + if ((node != null && node.getAttributes() != null && node.getAttributes().getLength() > 0 && attributeInList(node, parent, elementDecl)) || ((node.getNodeType() != Node.TEXT_NODE) && node.getFirstStructuredDocumentRegion().isEnded())) { + + proposedText = getRequiredName(parent, elementDecl); + cursorAdjustment = proposedText.length(); + } else { + proposedText = getRequiredName(parent, elementDecl); + cursorAdjustment = proposedText.length(); + if (elementDecl instanceof CMElementDeclaration) { + CMElementDeclaration ed = (CMElementDeclaration) elementDecl; + if (ed.getContentType() == CMElementDeclaration.EMPTY) { + proposedText += getContentGenerator().getStartTagClose(parent, ed); + cursorAdjustment = proposedText.length(); + } else { + cursorAdjustment = proposedText.length() + 1; + proposedText += "></" + getRequiredName(parent, elementDecl) + ">"; //$NON-NLS-2$//$NON-NLS-1$ + } + } + } + if (beginsWith(proposedText, matchString)) { + String proposedInfo = getAdditionalInfo(getCMElementDeclaration(parent), elementDecl); + CustomCompletionProposal proposal = new CustomCompletionProposal(proposedText, contentAssistRequest.getReplacementBeginPosition(), contentAssistRequest.getReplacementLength(), cursorAdjustment, XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_TAG_GENERIC), getRequiredName(parent, elementDecl), null, proposedInfo, XMLRelevanceConstants.R_TAG_NAME); + contentAssistRequest.addProposal(proposal); + } + } + } + if (contentAssistRequest.getProposals().size() == 0) { + if (error != null) + setErrorMessage(error); + else if (contentAssistRequest.getMatchString() != null && contentAssistRequest.getMatchString().length() > 0) + setErrorMessage(ResourceHandler.getString("27concat", (new Object[]{parent.getNodeName(), contentAssistRequest.getMatchString()}))); //$NON-NLS-1$ + //$NON-NLS-1$ = "No known child tag names of <{0}> begin with \"{1}\"" + else + setErrorMessage(ResourceHandler.getString("28concat", (new Object[]{parent.getNodeName()}))); //$NON-NLS-1$ + } + } else if (parent.getNodeType() == Node.DOCUMENT_NODE) { + List childElements = getAvailableRootChildren((Document) parent, childPosition); + for (int i = 0; i < childElements.size(); i++) { + CMNode ed = (CMNode) childElements.get(i); + if (ed == null) + continue; + String proposedText = null; + int cursorAdjustment = 0; + proposedText = getRequiredName(parent, ed); + if (!beginsWith(proposedText, matchString)) + continue; + if ((node != null && node.getAttributes() != null && node.getAttributes().getLength() > 0) || ((node.getNodeType() != Node.TEXT_NODE) && node.getFirstStructuredDocumentRegion().isEnded())) { + cursorAdjustment = proposedText.length(); + } else { + cursorAdjustment = proposedText.length(); + if (ed instanceof CMElementDeclaration) { + CMElementDeclaration elementDecl = (CMElementDeclaration) ed; + if (elementDecl.getContentType() == CMElementDeclaration.EMPTY) { + proposedText += getContentGenerator().getStartTagClose(parent, elementDecl); + cursorAdjustment = proposedText.length(); + } else { + cursorAdjustment = proposedText.length() + 1; + proposedText += "></" + getRequiredName(parent, elementDecl) + ">"; //$NON-NLS-2$//$NON-NLS-1$ + } + } + } + String proposedInfo = getAdditionalInfo(null, ed); + CustomCompletionProposal proposal = new CustomCompletionProposal(proposedText, contentAssistRequest.getReplacementBeginPosition(), contentAssistRequest.getReplacementLength(), cursorAdjustment, XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_TAG_GENERIC), getRequiredName(parent, ed), null, proposedInfo, XMLRelevanceConstants.R_TAG_NAME); + contentAssistRequest.addProposal(proposal); + } + } + } + + /** + * Adds templates to the list of proposals + * + * @param contentAssistRequest + * @param context + */ + protected void addTemplates(ContentAssistRequest contentAssistRequest, String context) { + if (macroContexts.contains(context)) + return; + if (contentAssistRequest == null) + return; + macroContexts.add(context); + + boolean useProposalList = !contentAssistRequest.shouldSeparate(); + + if (getTemplateCompletionProcessor() != null) { + getTemplateCompletionProcessor().setContextType(context); + ICompletionProposal[] proposals = getTemplateCompletionProcessor().computeCompletionProposals(fTextViewer, contentAssistRequest.getReplacementBeginPosition()); + for (int i = 0; i < proposals.length; ++i) { + if (useProposalList) + contentAssistRequest.addProposal(proposals[i]); + else + contentAssistRequest.addMacro(proposals[i]); + } + } + } + + protected void addXMLProposal(ContentAssistRequest contentAssistRequest) { + String proposedText = "<?xml version=\"1.0\" encoding=\"" + ContentTypeEncodingPreferences.getUserPreferredCharsetName(IContentTypeIdentifier.ContentTypeID_SSEXML) + "\"?>"; //$NON-NLS-2$//$NON-NLS-1$ + ICompletionProposal proposal = new CustomCompletionProposal(proposedText, contentAssistRequest.getReplacementBeginPosition(), contentAssistRequest.getReplacementLength(), proposedText.length(), XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_PROCESSINGINSTRUCTION), proposedText, null, null, XMLRelevanceConstants.R_XML_DECLARATION); // TODO + // add + // special + // XML + // proposal + // info + contentAssistRequest.addProposal(proposal); + } + + /** + * This method determines if any of the attributes in the proposed XMLNode + * node, are possible values of attributes from possible Elements at this + * point in the document according to the Content Model. + * + * @param node + * the element with attributes that you would like to test if + * are possible for possible Elements at this point + * @param cmnode + * possible element at this point in the document (depending on + * what 'node' is) + * @return true if any attributes of 'node' match any possible attributes + * from 'cmnodes' list. + */ + protected boolean attributeInList(XMLNode node, Node parent, CMNode cmnode) { + if (node == null || parent == null || cmnode == null) + return false; + String elementMatchString = node.getNodeName(); + String cmnodeName = getRequiredName(parent, cmnode);//cmnode.getNodeName(); + if (node instanceof Element) { + NamedNodeMap map = ((Element) node).getAttributes(); + String attrMatchString = ""; //$NON-NLS-1$ + CMNamedNodeMap cmattrMap = null; + // iterate attribute possibilities for partially started node + for (int i = 0; map != null && i < map.getLength(); i++) { + attrMatchString = map.item(i).getNodeName(); + // filter on whatever user typed for element name already + if (beginsWith(cmnodeName, elementMatchString)) { + if (cmnode.getNodeType() == CMNode.ELEMENT_DECLARATION) { + cmattrMap = ((CMElementDeclaration) cmnode).getAttributes(); + // iterate possible attributes from a cmnode in + // proposal list + for (int k = 0; cmattrMap != null && k < cmattrMap.getLength(); k++) { + // check if name matches + if (cmattrMap.item(k).getNodeName().equals(attrMatchString)) { + return true; + } + } + } + } + } + } + return false; + } + + protected boolean beginsWith(String aString, String prefix) { + if (aString == null || prefix == null) + return true; + // (pa) 221190 matching independent of case to be consistant with Java + // editor CA + return aString.toLowerCase().startsWith(prefix.toLowerCase()); + } + + protected ContentAssistRequest computeAttributeProposals(int documentPosition, String matchString, ITextRegion completionRegion, XMLNode nodeAtOffset, XMLNode node) { + ContentAssistRequest contentAssistRequest = null; + IStructuredDocumentRegion sdRegion = getStructuredDocumentRegion(documentPosition); + if (documentPosition < sdRegion.getStartOffset(completionRegion)) { + // setup to insert new attributes + contentAssistRequest = newContentAssistRequest(nodeAtOffset, node, sdRegion, completionRegion, documentPosition, 0, matchString); + } else { + // Setup to replace an existing attribute name + contentAssistRequest = newContentAssistRequest(nodeAtOffset, node, sdRegion, completionRegion, sdRegion.getStartOffset(completionRegion), completionRegion.getTextLength(), matchString); + } + addAttributeNameProposals(contentAssistRequest); + contentAssistRequest.setReplacementBeginPosition(documentPosition); + contentAssistRequest.setReplacementLength(0); + if (node.getFirstStructuredDocumentRegion() != null && (!node.getFirstStructuredDocumentRegion().isEnded())) { + addTagCloseProposals(contentAssistRequest); + } + return contentAssistRequest; + } + + protected ContentAssistRequest computeAttributeValueProposals(int documentPosition, String matchString, ITextRegion completionRegion, XMLNode nodeAtOffset, XMLNode node) { + ContentAssistRequest contentAssistRequest = null; + IStructuredDocumentRegion sdRegion = getStructuredDocumentRegion(documentPosition); + if (documentPosition > sdRegion.getStartOffset(completionRegion) + completionRegion.getTextLength() && sdRegion.getStartOffset(completionRegion) + completionRegion.getTextLength() != sdRegion.getStartOffset(completionRegion) + completionRegion.getLength()) { + // setup to add a new attribute at the documentPosition + XMLNode actualNode = (XMLNode) node.getModel().getIndexedRegion(sdRegion.getStartOffset(completionRegion)); + contentAssistRequest = newContentAssistRequest(actualNode, actualNode, sdRegion, completionRegion, documentPosition, 0, matchString); + addAttributeNameProposals(contentAssistRequest); + if (actualNode.getFirstStructuredDocumentRegion() != null && !actualNode.getFirstStructuredDocumentRegion().isEnded()) { + addTagCloseProposals(contentAssistRequest); + } + } else { + // setup to replace the existing value + if (!nodeAtOffset.getFirstStructuredDocumentRegion().isEnded() && documentPosition < sdRegion.getStartOffset(completionRegion)) { + // if the IStructuredDocumentRegion isn't closed and the + // cursor is in front of the value, add + contentAssistRequest = newContentAssistRequest(nodeAtOffset, node, sdRegion, completionRegion, documentPosition, 0, matchString); + addAttributeNameProposals(contentAssistRequest); + } else { + contentAssistRequest = newContentAssistRequest(nodeAtOffset, node, sdRegion, completionRegion, sdRegion.getStartOffset(completionRegion), completionRegion.getTextLength(), matchString); + addAttributeValueProposals(contentAssistRequest); + } + } + return contentAssistRequest; + } + + protected ContentAssistRequest computeCompletionProposals(int documentPosition, String matchString, ITextRegion completionRegion, XMLNode treeNode, XMLNode xmlnode) { + ContentAssistRequest contentAssistRequest = null; + String regionType = completionRegion.getType(); + IStructuredDocumentRegion sdRegion = getStructuredDocumentRegion(documentPosition); + + // Handle the most common and best supported cases + if (xmlnode.getNodeType() == Node.ELEMENT_NODE || xmlnode.getNodeType() == Node.DOCUMENT_NODE) { + if (regionType == XMLRegionContext.XML_TAG_OPEN) { + contentAssistRequest = computeTagOpenProposals(documentPosition, matchString, completionRegion, treeNode, xmlnode); + } else if (regionType == XMLRegionContext.XML_TAG_NAME) { + contentAssistRequest = computeTagNameProposals(documentPosition, matchString, completionRegion, treeNode, xmlnode); + } else if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_NAME) { + contentAssistRequest = computeAttributeProposals(documentPosition, matchString, completionRegion, treeNode, xmlnode); + } else if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_EQUALS) { + contentAssistRequest = computeEqualsProposals(documentPosition, matchString, completionRegion, treeNode, xmlnode); + } else if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE && documentPosition == sdRegion.getTextEndOffset() && (sdRegion.getText(completionRegion).endsWith("\"") || sdRegion.getText(completionRegion).endsWith("\'"))) //$NON-NLS-1$ //$NON-NLS-2$ + { + // this is for when the cursor is at the end of the closing + // quote for an attribute.. + XMLNode actualNode = (XMLNode) xmlnode.getModel().getIndexedRegion(sdRegion.getStartOffset(completionRegion)); + contentAssistRequest = newContentAssistRequest(actualNode, actualNode, sdRegion, completionRegion, documentPosition, 0, matchString); + addTagCloseProposals(contentAssistRequest); + } else if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE) { + contentAssistRequest = computeAttributeValueProposals(documentPosition, matchString, completionRegion, treeNode, xmlnode); + } else if ((regionType == XMLRegionContext.XML_TAG_CLOSE) || (regionType == XMLRegionContext.XML_EMPTY_TAG_CLOSE) || (regionType == XMLJSPRegionContexts.JSP_DIRECTIVE_CLOSE)) { + contentAssistRequest = computeTagCloseProposals(documentPosition, matchString, completionRegion, treeNode, xmlnode); + } else if (regionType == XMLRegionContext.XML_END_TAG_OPEN) { + contentAssistRequest = computeEndTagOpenProposals(documentPosition, matchString, completionRegion, treeNode, xmlnode); + } else if (regionType == XMLRegionContext.XML_CONTENT || regionType == XMLRegionContext.XML_CHAR_REFERENCE || regionType == XMLRegionContext.XML_ENTITY_REFERENCE || regionType == XMLRegionContext.XML_PE_REFERENCE) { + contentAssistRequest = computeContentProposals(documentPosition, matchString, completionRegion, treeNode, xmlnode); + } + + // These ITextRegion types begin DOM Elements as well and although + // internally harder to assist, + // text insertions directly before them can be made + else if (documentPosition == sdRegion.getStartOffset(completionRegion) && (regionType == XMLJSPRegionContexts.JSP_COMMENT_OPEN || regionType == XMLJSPRegionContexts.JSP_DECLARATION_OPEN || regionType == XMLJSPRegionContexts.JSP_DIRECTIVE_OPEN || regionType == XMLJSPRegionContexts.JSP_EXPRESSION_OPEN || regionType == XMLJSPRegionContexts.JSP_SCRIPTLET_OPEN || regionType == XMLRegionContext.XML_DECLARATION_OPEN || regionType == XMLRegionContext.XML_PI_OPEN || regionType == XMLRegionContext.XML_COMMENT_OPEN || regionType == XMLRegionContext.XML_CDATA_OPEN)) { + contentAssistRequest = newContentAssistRequest(treeNode, xmlnode.getParentNode(), sdRegion, completionRegion, documentPosition, 0, matchString); + addTagInsertionProposals(contentAssistRequest, getElementPositionForModelQuery(treeNode)); + addStartDocumentProposals(contentAssistRequest); + } + } + // Not a Document or Element? (odd cases go here for now) + else if (isCloseRegion(completionRegion)) { + contentAssistRequest = newContentAssistRequest(treeNode, xmlnode.getParentNode(), sdRegion, completionRegion, sdRegion.getStartOffset(completionRegion) + completionRegion.getLength(), 0, matchString); + addStartDocumentProposals(contentAssistRequest); + if (documentPosition >= sdRegion.getTextEndOffset(completionRegion)) + addTagInsertionProposals(contentAssistRequest, getElementPositionForModelQuery(treeNode) + 1); + } else if (documentPosition == sdRegion.getStartOffset(completionRegion) && (regionType == XMLJSPRegionContexts.JSP_COMMENT_OPEN || regionType == XMLJSPRegionContexts.JSP_DECLARATION_OPEN || regionType == XMLJSPRegionContexts.JSP_DIRECTIVE_OPEN || regionType == XMLJSPRegionContexts.JSP_EXPRESSION_OPEN || regionType == XMLJSPRegionContexts.JSP_SCRIPTLET_OPEN || regionType == XMLRegionContext.XML_DECLARATION_OPEN || regionType == XMLRegionContext.XML_PI_OPEN || regionType == XMLRegionContext.XML_COMMENT_OPEN || regionType == XMLRegionContext.XML_CDATA_OPEN)) { + contentAssistRequest = newContentAssistRequest(treeNode, xmlnode.getParentNode(), sdRegion, completionRegion, documentPosition, 0, matchString); + addTagInsertionProposals(contentAssistRequest, getElementPositionForModelQuery(treeNode)); + addStartDocumentProposals(contentAssistRequest); + } + return contentAssistRequest; + } + + /** + * CONTENT ASSIST STARTS HERE + * + * Return a list of proposed code completions based on the specified + * location within the document that corresponds to the current cursor + * position within the text-editor control. + * + * @param textViewer + * @param documentPosition - + * the cursor location within the document + * @param treeNode - + * the Node at the documentPosition + * + * @return an array of ICompletionProposals + */ + public ICompletionProposal[] computeCompletionProposals(ITextViewer textViewer, int documentPosition) { + + setErrorMessage(null); + macroContexts.clear(); + + fTextViewer = textViewer; + + IndexedRegion treeNode = ContentAssistUtils.getNodeAt((StructuredTextViewer) textViewer, documentPosition); + + Node node = (Node) treeNode; + while (node != null && node.getNodeType() == Node.TEXT_NODE && node.getParentNode() != null) + node = node.getParentNode(); + XMLNode xmlnode = (XMLNode) node; + + ContentAssistRequest contentAssistRequest = null; + + IStructuredDocumentRegion sdRegion = getStructuredDocumentRegion(documentPosition); + ITextRegion completionRegion = getCompletionRegion(documentPosition, node); + + String matchString = getMatchString(sdRegion, completionRegion, documentPosition); + + // Handle empty Documents + if (completionRegion == null) { + if (((treeNode == null) || ((Node) treeNode).getNodeType() == Node.DOCUMENT_NODE) && completionRegion == null && (xmlnode == null || xmlnode.getChildNodes() == null || xmlnode.getChildNodes().getLength() == 0)) { + IStructuredModel sModel = ((IModelManagerPlugin) Platform.getPlugin(IModelManagerPlugin.ID)).getModelManager().getExistingModelForRead(textViewer.getDocument()); + try { + if (sModel != null) { + XMLDocument docNode = ((XMLModel) sModel).getDocument(); + contentAssistRequest = newContentAssistRequest(docNode, docNode, sdRegion, completionRegion, documentPosition, 0, null); + addEmptyDocumentProposals(contentAssistRequest); + addTemplates(contentAssistRequest, TemplateContextTypeIds.ALL); + addTemplates(contentAssistRequest, TemplateContextTypeIds.TAG); + } + } finally { + if (sModel != null) + sModel.releaseFromRead(); + } + return contentAssistRequest.getCompletionProposals(); + } + // MASSIVE ERROR CONDITION + Logger.logException(new IllegalStateException("completion region was null")); //$NON-NLS-1$ + setErrorMessage(INTERNALERROR); + contentAssistRequest = newContentAssistRequest((Node) treeNode, node.getParentNode(), sdRegion, completionRegion, documentPosition, 0, ""); //$NON-NLS-1$ + addTemplates(contentAssistRequest, TemplateContextTypeIds.ALL); + return contentAssistRequest.getCompletionProposals(); + } + + + // catch documents where no region can be determined + if (xmlnode.getNodeType() == Node.DOCUMENT_NODE && (completionRegion == null || xmlnode.getChildNodes() == null || xmlnode.getChildNodes().getLength() == 0)) { + contentAssistRequest = computeStartDocumentProposals(documentPosition, matchString, completionRegion, (XMLNode) treeNode, xmlnode); + return contentAssistRequest.getCompletionProposals(); + } + + // compute normal proposals + contentAssistRequest = computeCompletionProposals(documentPosition, matchString, completionRegion, (XMLNode) treeNode, xmlnode); + if (contentAssistRequest == null) { + contentAssistRequest = newContentAssistRequest((Node) treeNode, node.getParentNode(), sdRegion, completionRegion, documentPosition, 0, ""); //$NON-NLS-1$ + if (Debug.displayWarnings) + System.out.println(UNKNOWN_CONTEXT + " " + completionRegion.getType() + "@" + documentPosition); //$NON-NLS-2$//$NON-NLS-1$ + setErrorMessage(UNKNOWN_CONTEXT); + } + // #180541 + addTemplates(contentAssistRequest, TemplateContextTypeIds.ALL); + + if (contentAssistRequest.getProposals().size() == 0) + setErrorMessage(UNKNOWN_CONTEXT); + + return contentAssistRequest.getCompletionProposals(); + } + + protected ContentAssistRequest computeContentProposals(int documentPosition, String matchString, ITextRegion completionRegion, XMLNode nodeAtOffset, XMLNode node) { + ContentAssistRequest contentAssistRequest = null; + + // setup to add children at the content node's position + contentAssistRequest = newContentAssistRequest(nodeAtOffset, node, getStructuredDocumentRegion(documentPosition), completionRegion, documentPosition, 0, matchString); + if (node != null && node.getNodeType() == Node.DOCUMENT_NODE && ((Document) node).getDoctype() == null) + addStartDocumentProposals(contentAssistRequest); + addTagInsertionProposals(contentAssistRequest, getElementPositionForModelQuery(nodeAtOffset)); + if (node.getNodeType() != Node.DOCUMENT_NODE) { + addEndTagProposals(contentAssistRequest); + } + // entities? + addEntityProposals(contentAssistRequest, documentPosition, completionRegion, node); + //addEntityProposals(contentAssistRequest); + return contentAssistRequest; + } + + /** + * Returns information about possible contexts based on the specified + * location within the document that corresponds to the current cursor + * position within the text viewer. + * + * @param viewer + * the viewer whose document is used to compute the possible + * contexts + * @param documentPosition + * an offset within the document for which context information + * should be computed + * @return an array of context information objects or <code>null</code> + * if no context could be found + */ + public IContextInformation[] computeContextInformation(ITextViewer viewer, int documentOffset) { + if (fAttributeInfoProvider == null) + fAttributeInfoProvider = new AttributeContextInformationProvider((IStructuredDocument) viewer.getDocument(), (AttributeContextInformationPresenter) getContextInformationValidator()); + return fAttributeInfoProvider.getAttributeInformation(documentOffset); + } + + protected ContentAssistRequest computeEndTagOpenProposals(int documentPosition, String matchString, ITextRegion completionRegion, XMLNode nodeAtOffset, XMLNode node) { + ContentAssistRequest contentAssistRequest = null; + IStructuredDocumentRegion sdRegion = getStructuredDocumentRegion(documentPosition); + int completionRegionStart = sdRegion.getStartOffset(completionRegion); + int completionRegionLength = completionRegion.getLength(); + IStructuredDocumentRegion sdRegionAtCompletionOffset = node.getStructuredDocument().getRegionAtCharacterOffset(completionRegionStart + completionRegionLength); + ITextRegion regionAtEndOfCompletion = sdRegionAtCompletionOffset.getRegionAtCharacterOffset(completionRegionStart + completionRegionLength); + + if (documentPosition != completionRegionStart && regionAtEndOfCompletion != null && regionAtEndOfCompletion.getType() == XMLRegionContext.XML_TAG_NAME) { + ITextRegion nameRegion = regionAtEndOfCompletion; + contentAssistRequest = newContentAssistRequest(nodeAtOffset, nodeAtOffset.getParentNode(), sdRegion, completionRegion, sdRegion.getStartOffset(nameRegion), nameRegion.getTextLength(), matchString); + } else { + if (nodeAtOffset.getFirstStructuredDocumentRegion() == sdRegion) { + // abnormal case, this unmatched end tag will be a sibling + contentAssistRequest = newContentAssistRequest(nodeAtOffset, nodeAtOffset.getParentNode(), sdRegion, completionRegion, documentPosition, 0, matchString); + } else { + // normal case, this end tag is the parent + contentAssistRequest = newContentAssistRequest(nodeAtOffset, nodeAtOffset, sdRegion, completionRegion, documentPosition, 0, matchString); + } + } + //if (documentPosition >= sdRegion.getStartOffset(completionRegion) + + // completionRegion.getTextLength()) + addEndTagProposals(contentAssistRequest); + //else + if (completionRegionStart == documentPosition) { + // positioned at start of end tag + addTagInsertionProposals(contentAssistRequest, node.getChildNodes().getLength()); + } + return contentAssistRequest; + } + + /** + * return all possible EntityReferenceProposals (according to current + * position in doc) + */ + protected ICompletionProposal[] computeEntityReferenceProposals(int documentPosition, ITextRegion completionRegion, XMLNode treeNode) { + // only handle XML content for now + Vector proposals = new Vector(); // ICompletionProposals + IStructuredDocumentRegion sdRegion = getStructuredDocumentRegion(documentPosition); + if (completionRegion != null && completionRegion.getType() == XMLRegionContext.XML_CONTENT) { + int nodeOffset = documentPosition - sdRegion.getStartOffset(completionRegion); + String regionText = sdRegion.getFullText(completionRegion); + + //if directly to the right of a &, region will be null, need to + // move to + // the previous region...there might be a better way to do this + if (regionText != null && regionText.trim().equals("") && documentPosition > 0) { //$NON-NLS-1$ + IStructuredDocumentRegion prev = treeNode.getStructuredDocument().getRegionAtCharacterOffset(documentPosition - 1); + if (prev != null && prev.getFullText().trim().equals("&")) { //$NON-NLS-1$ + completionRegion = prev; + regionText = prev.getFullText(); + nodeOffset = 1; + } + } + + // string must start w/ & + if (regionText != null && regionText.startsWith("&")) { //$NON-NLS-1$ + String key = (nodeOffset > 0) ? regionText.substring(1, nodeOffset) : ""; //$NON-NLS-1$ + + // get entity proposals, passing in the appropriate start + // string + ModelQuery mq = ModelQueryUtil.getModelQuery(((Node) treeNode).getOwnerDocument()); + if (mq != null) { + CMDocument xmlDoc = mq.getCorrespondingCMDocument(treeNode); + CMNamedNodeMap cmmap = null; + Properties entities = null; + if (xmlDoc != null) { + cmmap = xmlDoc.getEntities(); + } + if (cmmap != null) { + entities = mapToProperties(cmmap); + } else // 224787 in absence of content model, just use + // minimal 5 entities + { + entities = new Properties(); + entities.put("quot", "\""); //$NON-NLS-1$ //$NON-NLS-2$ + entities.put("apos", "'"); //$NON-NLS-1$ //$NON-NLS-2$ + entities.put("amp", "&"); //$NON-NLS-1$ //$NON-NLS-2$ + entities.put("lt", "<"); //$NON-NLS-1$ //$NON-NLS-2$ + entities.put("gt", ">"); //$NON-NLS-1$ //$NON-NLS-2$ + entities.put("nbsp", " "); //$NON-NLS-1$ //$NON-NLS-2$ + } + addEntityProposals(proposals, entities, key, nodeOffset, sdRegion, completionRegion); //$NON-NLS-1$ + } + } + } + return (ICompletionProposal[]) ((proposals.size() > 0) ? proposals.toArray(new ICompletionProposal[proposals.size()]) : null); + } + + protected ContentAssistRequest computeEqualsProposals(int documentPosition, String matchString, ITextRegion completionRegion, XMLNode nodeAtOffset, XMLNode node) { + ContentAssistRequest contentAssistRequest = null; + IStructuredDocumentRegion sdRegion = getStructuredDocumentRegion(documentPosition); + ITextRegion valueRegion = node.getStartStructuredDocumentRegion().getRegionAtCharacterOffset(sdRegion.getStartOffset(completionRegion) + completionRegion.getLength()); + if (valueRegion != null && valueRegion.getType() == XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE && sdRegion.getStartOffset(valueRegion) <= documentPosition) { + // replace the adjacent attribute value + contentAssistRequest = newContentAssistRequest(nodeAtOffset, node, sdRegion, valueRegion, sdRegion.getStartOffset(valueRegion), valueRegion.getTextLength(), matchString); + } else { + // append an attribute value after the '=' + contentAssistRequest = newContentAssistRequest(nodeAtOffset, node, sdRegion, completionRegion, documentPosition, 0, matchString); + } + addAttributeValueProposals(contentAssistRequest); + return contentAssistRequest; + } + + protected ContentAssistRequest computeStartDocumentProposals(int documentPosition, String matchString, ITextRegion completionRegion, XMLNode nodeAtOffset, XMLNode node) { + // setup for a non-empty document, but one that hasn't been formally + // started + ContentAssistRequest contentAssistRequest = null; + contentAssistRequest = newContentAssistRequest(nodeAtOffset, node, getStructuredDocumentRegion(documentPosition), completionRegion, documentPosition, 0, matchString); + addStartDocumentProposals(contentAssistRequest); + addTemplates(contentAssistRequest, TemplateContextTypeIds.TAG); + addTemplates(contentAssistRequest, TemplateContextTypeIds.ALL); + return contentAssistRequest; + } + + protected ContentAssistRequest computeTagCloseProposals(int documentPosition, String matchString, ITextRegion completionRegion, XMLNode nodeAtOffset, XMLNode node) { + ContentAssistRequest contentAssistRequest = null; + IStructuredDocumentRegion sdRegion = getStructuredDocumentRegion(documentPosition); + + if ((node.getNodeType() == Node.DOCUMENT_NODE) || (documentPosition >= sdRegion.getEndOffset())) { + // this is a content request as the documentPosition is AFTER the + // end of the closing region + if (node == nodeAtOffset && node.getParentNode() != null) + node = (XMLNode) node.getParentNode(); + contentAssistRequest = newContentAssistRequest(nodeAtOffset, node, sdRegion, completionRegion, documentPosition, 0, matchString); + addTagInsertionProposals(contentAssistRequest, getElementPositionForModelQuery(nodeAtOffset)); + if (node.getNodeType() != Node.DOCUMENT_NODE && node.getEndStructuredDocumentRegion() == null) { + addEndTagProposals(contentAssistRequest); + } + } else { + // at the start of the tag's close or within it + ITextRegion closeRegion = sdRegion.getLastRegion(); + boolean insideTag = !sdRegion.isEnded() || documentPosition <= sdRegion.getStartOffset(closeRegion); + if (insideTag) { + // this is a request for completions within a tag + contentAssistRequest = newContentAssistRequest(nodeAtOffset, node, sdRegion, completionRegion, documentPosition, 0, matchString); + if (node.getNodeType() != Node.DOCUMENT_NODE && node.getEndStructuredDocumentRegion() != null) { + addTagCloseProposals(contentAssistRequest); + } + if (sdRegion == nodeAtOffset.getFirstStructuredDocumentRegion()) { + contentAssistRequest.setReplacementBeginPosition(documentPosition); + contentAssistRequest.setReplacementLength(0); + addAttributeNameProposals(contentAssistRequest); + } + } + } + return contentAssistRequest; + } + + protected ContentAssistRequest computeTagNameProposals(int documentPosition, String matchString, ITextRegion completionRegion, XMLNode nodeAtOffset, XMLNode node) { + ContentAssistRequest contentAssistRequest = null; + IStructuredDocumentRegion sdRegion = getStructuredDocumentRegion(documentPosition); + + if (sdRegion != nodeAtOffset.getFirstStructuredDocumentRegion()) { + //completing the *first* tag in "<tagname1 |<tagname2" + XMLNode actualNode = (XMLNode) node.getModel().getIndexedRegion(sdRegion.getStartOffset(completionRegion)); + if (actualNode != null) { + if (actualNode.getFirstStructuredDocumentRegion() == sdRegion) { + // start tag + if (documentPosition > sdRegion.getStartOffset(completionRegion) + completionRegion.getLength()) { + // it's attributes + contentAssistRequest = newContentAssistRequest(actualNode, actualNode, sdRegion, completionRegion, documentPosition - matchString.length(), matchString.length(), matchString); + if (node.getStructuredDocument().getRegionAtCharacterOffset(sdRegion.getStartOffset(completionRegion) - 1).getRegionAtCharacterOffset(sdRegion.getStartOffset(completionRegion) - 1).getType() == XMLRegionContext.XML_TAG_OPEN) + addAttributeNameProposals(contentAssistRequest); + addTagCloseProposals(contentAssistRequest); + } else { + // it's name + contentAssistRequest = newContentAssistRequest(actualNode, actualNode.getParentNode(), sdRegion, completionRegion, documentPosition - matchString.length(), matchString.length(), matchString); + addTagNameProposals(contentAssistRequest, getElementPositionForModelQuery(actualNode)); + } + } else { + if (documentPosition >= sdRegion.getStartOffset(completionRegion) + completionRegion.getLength()) { + // insert name + contentAssistRequest = newContentAssistRequest(actualNode, actualNode.getParentNode(), sdRegion, completionRegion, documentPosition, 0, matchString); + } else { + //replace name + contentAssistRequest = newContentAssistRequest(actualNode, actualNode.getParentNode(), sdRegion, completionRegion, sdRegion.getStartOffset(completionRegion), completionRegion.getTextLength(), matchString); + } + addEndTagNameProposals(contentAssistRequest); + } + } + } else { + if (documentPosition > sdRegion.getStartOffset(completionRegion) + completionRegion.getTextLength()) { + // unclosed tag with only a name; should prompt for attributes + // and a close instead + contentAssistRequest = newContentAssistRequest(nodeAtOffset, node, sdRegion, completionRegion, documentPosition - matchString.length(), matchString.length(), matchString); + addAttributeNameProposals(contentAssistRequest); + addTagCloseProposals(contentAssistRequest); + } else { + if (sdRegion.getRegions().get(0).getType() != XMLRegionContext.XML_END_TAG_OPEN) { + contentAssistRequest = newContentAssistRequest(node, node.getParentNode(), sdRegion, completionRegion, sdRegion.getStartOffset(completionRegion), completionRegion.getTextLength(), matchString); + addTagNameProposals(contentAssistRequest, getElementPositionForModelQuery(nodeAtOffset)); + } else { + XMLNode actualNode = (XMLNode) node.getModel().getIndexedRegion(documentPosition); + if (actualNode != null) { + if (documentPosition >= sdRegion.getStartOffset(completionRegion) + completionRegion.getTextLength()) { + contentAssistRequest = newContentAssistRequest(actualNode, actualNode.getParentNode(), sdRegion, completionRegion, documentPosition, 0, matchString); + } else { + contentAssistRequest = newContentAssistRequest(actualNode, actualNode.getParentNode(), sdRegion, completionRegion, sdRegion.getStartOffset(completionRegion), completionRegion.getTextLength(), matchString); + } + addEndTagNameProposals(contentAssistRequest); + } + } + } + } + return contentAssistRequest; + } + + protected ContentAssistRequest computeTagOpenProposals(int documentPosition, String matchString, ITextRegion completionRegion, XMLNode nodeAtOffset, XMLNode node) { + ContentAssistRequest contentAssistRequest = null; + IStructuredDocumentRegion sdRegion = getStructuredDocumentRegion(documentPosition); + if (sdRegion != nodeAtOffset.getFirstStructuredDocumentRegion()) { + //completing the *first* XML_TAG_OPEN in "<<tagname" + XMLNode actualNode = (XMLNode) node.getModel().getIndexedRegion(sdRegion.getStartOffset(completionRegion)); + if (actualNode != null) { + contentAssistRequest = newContentAssistRequest(actualNode, actualNode.getParentNode(), sdRegion, completionRegion, documentPosition, 0, matchString); + addTagNameProposals(contentAssistRequest, getElementPositionForModelQuery(actualNode)); + addEndTagProposals(contentAssistRequest); // (pa) 220850 + } + } else { + if (documentPosition == sdRegion.getStartOffset(completionRegion)) { + if (node.getNodeType() == Node.ELEMENT_NODE) { + // at the start of an existing tag, right before the '<' + contentAssistRequest = newContentAssistRequest(nodeAtOffset, node.getParentNode(), sdRegion, completionRegion, documentPosition, 0, matchString); + addTagInsertionProposals(contentAssistRequest, getElementPositionForModelQuery(nodeAtOffset)); + addEndTagProposals(contentAssistRequest); + } else if (node.getNodeType() == Node.DOCUMENT_NODE) { + // at the opening of the VERY first tag with a '<' + contentAssistRequest = newContentAssistRequest(nodeAtOffset, node.getParentNode(), sdRegion, completionRegion, sdRegion.getStartOffset(completionRegion), completionRegion.getTextLength(), matchString); + addStartDocumentProposals(contentAssistRequest); + } + } else { + // within the white space + ITextRegion name = getNameRegion(node.getStartStructuredDocumentRegion()); + // (pa) ITextRegion refactor + //if (name != null && name.containsOffset(documentPosition)) + // { + if (name != null && (sdRegion.getStartOffset(name) <= documentPosition && sdRegion.getEndOffset(name) >= documentPosition)) { + // replace the existing name + contentAssistRequest = newContentAssistRequest(node, node.getParentNode(), sdRegion, completionRegion, sdRegion.getStartOffset(name), name.getTextLength(), matchString); + } else { + // insert a valid new name, or possibly an end tag + contentAssistRequest = newContentAssistRequest(nodeAtOffset, ((Node) nodeAtOffset).getParentNode(), sdRegion, completionRegion, documentPosition, 0, matchString); + addEndTagProposals(contentAssistRequest); + contentAssistRequest.setReplacementBeginPosition(documentPosition); + contentAssistRequest.setReplacementLength(0); + } + addTagNameProposals(contentAssistRequest, getElementPositionForModelQuery(nodeAtOffset)); + } + } + return contentAssistRequest; + } + + /** + * Retreives cmnode's documentation to display in the completion + * proposal's additional info. If no documentation exists for cmnode, try + * displaying parentOrOwner's documentation + * + * @return String any documentation information to display for cmnode. + * <code>null</code> if there is nothing to display. + */ + protected String getAdditionalInfo(CMNode parentOrOwner, CMNode cmnode) { + String addlInfo = null; + + if (cmnode == null) { + if (Debug.displayWarnings) { + new IllegalArgumentException("Null declaration!").printStackTrace(); //$NON-NLS-1$ + } + return null; + } + + addlInfo = getInfoProvider().getInfo(cmnode); + if (addlInfo == null && parentOrOwner != null) + addlInfo = getInfoProvider().getInfo(parentOrOwner); + return addlInfo; + } + + // returns a list of ModelQueryActions + protected List getAvailableChildrenAtIndex(Element parent, int index) { + List list = new ArrayList(); + CMElementDeclaration parentDecl = getCMElementDeclaration(parent); + if (parentDecl != null) { + ModelQuery modelQuery = ModelQueryUtil.getModelQuery(parent.getOwnerDocument()); + // taken from ActionManagers + // int editMode = modelQuery.getEditMode(); + int editMode = ModelQuery.EDIT_MODE_UNCONSTRAINED; + int ic = (editMode == ModelQuery.EDIT_MODE_CONSTRAINED_STRICT) ? ModelQuery.INCLUDE_CHILD_NODES | ModelQuery.INCLUDE_SEQUENCE_GROUPS : ModelQuery.INCLUDE_CHILD_NODES; + int vc = (editMode == ModelQuery.EDIT_MODE_CONSTRAINED_STRICT) ? ModelQuery.VALIDITY_STRICT : ModelQuery.VALIDITY_NONE; + modelQuery.getInsertActions(parent, parentDecl, index, ic, vc, list); + } + return list; + } + + // returns a list of CMElementDeclarations + protected List getAvailableRootChildren(Document document, int childIndex) { + List list = null; + + // extract the valid 'root' node name from the DocumentType Node + DocumentType docType = document.getDoctype(); + String rootName = null; + if (docType != null) { + rootName = docType.getNodeName(); + } + if (rootName == null) + return new ArrayList(0); + + for (Node child = document.getFirstChild(); child != null; child = child.getNextSibling()) { + //make sure the "root" Element isn't already present + // is it required to be an Element? + if (child.getNodeType() == Node.ELEMENT_NODE && stringsEqual(child.getNodeName(), rootName)) { + // if the node is missing either the start or end tag, don't + // count it as present + if (child instanceof XMLNode && (((XMLNode) child).getStartStructuredDocumentRegion() == null || ((XMLNode) child).getEndStructuredDocumentRegion() == null)) + continue; + if (Debug.displayInfo) + System.out.println(rootName + " already present!"); //$NON-NLS-1$ + setErrorMessage(ResourceHandler.getString("18concat", (new Object[]{rootName}))); //$NON-NLS-1$ = "The document element <{0}> is already present." + return new ArrayList(0); + } + } + + list = new ArrayList(1); + ModelQuery modelQuery = ModelQueryUtil.getModelQuery(document); + if (modelQuery != null) { + CMDocument cmdoc = modelQuery.getCorrespondingCMDocument(document); + if (cmdoc != null) { + if (rootName != null) { + CMElementDeclaration rootDecl = (CMElementDeclaration) cmdoc.getElements().getNamedItem(rootName); + if (rootDecl != null) { + list.add(rootDecl); + } else { + // supply the given document name anyway, even if it + // is an error + list.add(new SimpleCMElementDeclaration(rootName)); + if (Debug.displayInfo || Debug.displayWarnings) + System.out.println("No definition found for " + rootName + " in " + docType.getPublicId() + "/" + docType.getSystemId()); //$NON-NLS-3$//$NON-NLS-2$//$NON-NLS-1$ + String location = "" + (docType.getPublicId() != null ? docType.getPublicId() + "/" : "") + (docType.getSystemId() != null ? docType.getSystemId() : ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + //$NON-NLS-4$//$NON-NLS-3$//$NON-NLS-2$//$NON-NLS-1$ + //$NON-NLS-4$//$NON-NLS-3$//$NON-NLS-2$//$NON-NLS-1$ + if (location.length() > 0) + setErrorMessage(ResourceHandler.getString("29concat", (new Object[]{rootName, location}))); //$NON-NLS-1$ = "No definition was found for element <{0}> in {1}" + else + setErrorMessage(ResourceHandler.getString("20concat", (new Object[]{rootName}))); //$NON-NLS-1$ = "No definition was found for element <{0}>" + } + } + } else { + if (Debug.displayInfo || Debug.displayWarnings) + System.out.println("No content model found."); //$NON-NLS-1$ + //$NON-NLS-1$ + //$NON-NLS-1$ + String location = "" + (docType.getPublicId() != null ? docType.getPublicId() + "/" : "") + (docType.getSystemId() != null ? docType.getSystemId() : ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + //$NON-NLS-4$//$NON-NLS-3$//$NON-NLS-2$//$NON-NLS-1$ + //$NON-NLS-4$//$NON-NLS-3$//$NON-NLS-2$//$NON-NLS-1$ + if (location.length() > 0) + setErrorMessage(ResourceHandler.getString("24concat", (new Object[]{location}))); //$NON-NLS-1$ = "No content model found for {0}." + else + setErrorMessage(ResourceHandler.getString("No_content_model_found_UI_")); //$NON-NLS-1$ = "No content model found" + } + } + + return list; + } + + protected CMElementDeclaration getCMElementDeclaration(Node node) { + CMElementDeclaration result = null; + if (node.getNodeType() == Node.ELEMENT_NODE) { + ModelQuery modelQuery = ModelQueryUtil.getModelQuery(node.getOwnerDocument()); + if (modelQuery != null) + result = modelQuery.getCMElementDeclaration((Element) node); + } + return result; + } + + /** + * Returns the characters which when entered by the user should + * automatically trigger the presentation of possible completions. + * + * @return the auto activation characters for completion proposal or + * <code>null</code> if no auto activation is desired + */ + public char[] getCompletionProposalAutoActivationCharacters() { + return completionProposalAutoActivationCharacters; + } + + protected ITextRegion getCompletionRegion(int offset, IStructuredDocumentRegion sdRegion) { + ITextRegion region = sdRegion.getRegionAtCharacterOffset(offset); + if (region == null) + return null; + + if (sdRegion.getStartOffset(region) == offset) { + // The offset is at the beginning of the region + if ((sdRegion.getStartOffset(region) == sdRegion.getStartOffset()) && (sdRegion.getPrevious() != null) && (!sdRegion.getPrevious().isEnded())) { + // Is the region also the start of the node? If so, the + // previous IStructuredDocumentRegion is + // where to look for a useful region. + region = sdRegion.getPrevious().getRegionAtCharacterOffset(offset - 1); + } else { + // Is there no separating whitespace from the previous region? + // If not, + // then that region is the important one + ITextRegion previousRegion = sdRegion.getRegionAtCharacterOffset(offset - 1); + if ((previousRegion != null) && (previousRegion != region) && (previousRegion.getTextLength() == previousRegion.getLength())) { + region = previousRegion; + } + } + } else { + // The offset is NOT at the beginning of the region + if (offset > sdRegion.getStartOffset(region) + region.getTextLength()) { + // Is the offset within the whitespace after the text in this + // region? + // If so, use the next region + ITextRegion nextRegion = sdRegion.getRegionAtCharacterOffset(sdRegion.getStartOffset(region) + region.getLength()); + if (nextRegion != null) + region = nextRegion; + } else { + // Is the offset within the important text for this region? + // If so, then we've already got the right one. + } + } + + // valid WHITE_SPACE region handler (#179924) + if (region != null && region.getType() == XMLRegionContext.WHITE_SPACE) { + ITextRegion previousRegion = sdRegion.getRegionAtCharacterOffset(sdRegion.getStartOffset(region) - 1); + if (previousRegion != null) + region = previousRegion; + } + + return region; + } + + /** + * Return the region whose content's require completion. This is something + * of a misnomer as sometimes the user wants to be prompted for contents + * of a non-existant ITextRegion, such as for enumerated attribute values + * following an '=' sign. + */ + protected ITextRegion getCompletionRegion(int documentPosition, Node domnode) { + if (domnode == null) + return null; + + ITextRegion region = null; + int offset = documentPosition; + IStructuredDocumentRegion flatNode = null; + XMLNode node = (XMLNode) domnode; + + if (node.getNodeType() == Node.DOCUMENT_NODE) { + if (node.getStructuredDocument().getLength() == 0) + return null; + ITextRegion result = node.getStructuredDocument().getRegionAtCharacterOffset(offset).getRegionAtCharacterOffset(offset); + while (result == null) { + offset--; + result = node.getStructuredDocument().getRegionAtCharacterOffset(offset).getRegionAtCharacterOffset(offset); + } + return result; + } + + IStructuredDocumentRegion startTag = node.getStartStructuredDocumentRegion(); + IStructuredDocumentRegion endTag = node.getEndStructuredDocumentRegion(); + + // Determine if the offset is within the start + // IStructuredDocumentRegion, end IStructuredDocumentRegion, or + // somewhere within the Node's XML content. + if ((startTag != null) && (startTag.getStartOffset() <= offset) && (offset < startTag.getStartOffset() + startTag.getLength())) + flatNode = startTag; + else if ((endTag != null) && (endTag.getStartOffset() <= offset) && (offset < endTag.getStartOffset() + endTag.getLength())) + flatNode = endTag; + + if (flatNode != null) { + // the offset is definitely within the start or end tag, continue + // on and find the region + region = getCompletionRegion(offset, flatNode); + } else { + // the docPosition is neither within the start nor the end, so it + // must be content + flatNode = node.getStructuredDocument().getRegionAtCharacterOffset(offset); + // (pa) ITextRegion refactor + //if (flatNode.contains(documentPosition)) { + if (flatNode.getStartOffset() <= documentPosition && flatNode.getEndOffset() >= documentPosition) { + // we're interesting in completing/extending the previous + // IStructuredDocumentRegion if the current + // IStructuredDocumentRegion isn't plain content or if it's + // preceded by an orphan '<' + if ((offset == flatNode.getStartOffset()) && (flatNode.getPrevious() != null) && (flatNode.getRegionAtCharacterOffset(documentPosition) != null && flatNode.getRegionAtCharacterOffset(documentPosition).getType() != XMLRegionContext.XML_CONTENT || flatNode.getPrevious().getLastRegion().getType() == XMLRegionContext.XML_TAG_OPEN || flatNode.getPrevious().getLastRegion().getType() == XMLRegionContext.XML_END_TAG_OPEN)) { + // Is the region also the start of the node? If so, the + // previous IStructuredDocumentRegion is + // where to look for a useful region. + region = flatNode.getPrevious().getLastRegion(); + } else if (flatNode.getEndOffset() == documentPosition) { + region = flatNode.getLastRegion(); + } else + region = flatNode.getFirstRegion(); + } else { + // catch end of document positions where the docPosition isn't + // in a IStructuredDocumentRegion + region = flatNode.getLastRegion(); + } + } + + return region; + } + + /** + * Provided by default. Subclasses may override with their own + * implementations. + * + * @see AbstractContentAssistProcessor#getContentGenerator() + */ + public XMLContentModelGenerator getContentGenerator() { + if (fGenerator == null) + fGenerator = new XMLContentModelGenerator(); + return fGenerator; + } + + /** + * Returns the characters which when entered by the user should + * automatically trigger the presentation of context information. + * + * @return the auto activation characters for presenting context + * information or <code>null</code> if no auto activation is + * desired + */ + public char[] getContextInformationAutoActivationCharacters() { + return contextInformationAutoActivationCharacters; + } + + /** + * Returns a validator used to determine when displayed context + * information should be dismissed. May only return <code>null</code> if + * the processor is incapable of computing context information. + * + * @return a context information validator, or <code>null</code> if the + * processor is incapable of computing context information + */ + public IContextInformationValidator getContextInformationValidator() { + if (fContextInformationPresenter == null) + fContextInformationPresenter = new AttributeContextInformationPresenter(); + return fContextInformationPresenter; + } + + protected int getElementPosition(Node child) { + Node parent = child.getParentNode(); + if (parent == null) + return 0; + + NodeList children = parent.getChildNodes(); + if (children == null) + return 0; + int count = 0; + + for (int i = 0; i < children.getLength(); i++) { + if (children.item(i) == child) + return count; + else + // if (children.item(i).getNodeType() == Node.ELEMENT_NODE) + count++; + } + return 0; + } + + private int getElementPositionForModelQuery(Node child) { + return getElementPosition(child); + // return -1; + } + + /** + * Return the reason why computeProposals was not able to find any + * completions. + * + * @return an error message or null if no error occurred + */ + public String getErrorMessage() { + return fErrorMessage; + } + + /** + * @param iResource + */ + // public void initialize(IResource iResource) { + // this.resource = iResource; + // } + /** + * Gets the infoProvider. + * + * @return fInfoProvider and if fInfoProvider was <code>null</code> + * create a new instance + */ + public MarkupTagInfoProvider getInfoProvider() { + if (fInfoProvider == null) { + fInfoProvider = new MarkupTagInfoProvider(); + } + return fInfoProvider; + } + + protected String getMatchString(IStructuredDocumentRegion parent, ITextRegion aRegion, int offset) { + if (aRegion == null || isCloseRegion(aRegion)) + return ""; //$NON-NLS-1$ + String matchString = null; + String regionType = aRegion.getType(); + if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_EQUALS || regionType == XMLRegionContext.XML_TAG_OPEN || (offset > parent.getStartOffset(aRegion) + aRegion.getTextLength())) { + matchString = ""; //$NON-NLS-1$ + } else if (regionType == XMLRegionContext.XML_CONTENT) { + matchString = ""; //$NON-NLS-1$ + } else { + if (parent.getText(aRegion).length() > 0 && parent.getStartOffset(aRegion) < offset) + matchString = parent.getText(aRegion).substring(0, offset - parent.getStartOffset(aRegion)); + else + matchString = ""; //$NON-NLS-1$ + } + return matchString; + } + + protected ITextRegion getNameRegion(IStructuredDocumentRegion flatNode) { + if (flatNode == null) + return null; + Iterator regionList = flatNode.getRegions().iterator(); + while (regionList.hasNext()) { + ITextRegion region = (ITextRegion) regionList.next(); + if (isNameRegion(region)) + return region; + } + return null; + } + + /** + * Retrieves all of the possible valid values for this attribute + * declaration + */ + protected List getPossibleDataTypeValues(Node node, CMAttributeDeclaration ad) { + List list = null; + if (node.getNodeType() == Node.ELEMENT_NODE) { + Element element = (Element) node; + String[] dataTypeValues = null; + // The ModelQuery may not be available if the corresponding + // adapter + // is absent + ModelQuery modelQuery = ModelQueryUtil.getModelQuery(element.getOwnerDocument()); + if (modelQuery != null) { + dataTypeValues = modelQuery.getPossibleDataTypeValues(element, ad); + } else { + if (ad.getAttrType() != null) + dataTypeValues = ad.getAttrType().getEnumeratedValues(); + } + if (dataTypeValues != null) { + list = new ArrayList(dataTypeValues.length); + for (int i = 0; i < dataTypeValues.length; i++) { + list.add(dataTypeValues[i]); + } + } + } + if (list == null) { + list = new ArrayList(0); + } + return list; + } + + protected String getRequiredName(Node parentOrOwner, CMNode cmnode) { + if (cmnode == null || parentOrOwner == null) { + if (Debug.displayWarnings) { + new IllegalArgumentException("Null declaration!").printStackTrace(); //$NON-NLS-1$ + } + return ""; //$NON-NLS-1$ + } + return getContentGenerator().getRequiredName(parentOrOwner, cmnode); + } + + protected String getRequiredText(Node parentOrOwner, CMAttributeDeclaration attrDecl) { + if (attrDecl == null) { + if (Debug.displayWarnings) { + new IllegalArgumentException("Null attribute declaration!").printStackTrace(); //$NON-NLS-1$ + } + return ""; //$NON-NLS-1$ + } + StringBuffer buff = new StringBuffer(); + getContentGenerator().generateRequiredAttribute(parentOrOwner, attrDecl, buff); + return buff.toString(); + } + + protected String getRequiredText(Node parentOrOwner, CMElementDeclaration elementDecl) { + if (elementDecl == null) { + if (Debug.displayWarnings) { + new IllegalArgumentException("Null attribute declaration!").printStackTrace(); //$NON-NLS-1$ + } + return ""; //$NON-NLS-1$ + } + StringBuffer buff = new StringBuffer(); + getContentGenerator().generateTag(parentOrOwner, elementDecl, buff); + return buff.toString(); + } + + /** + * StructuredTextViewer must be set before using this. + */ + public IStructuredDocumentRegion getStructuredDocumentRegion(int pos) { + // (pa) ITextRegion refactor defect 245190 + //return + // (IStructuredDocumentRegion)ContentAssistUtils.getNodeAt((StructuredTextViewer)fTextViewer, + // pos); + return ContentAssistUtils.getStructuredDocumentRegion((StructuredTextViewer) fTextViewer, pos); + } + + /** + * @param xmlEndTagOpen + * @return + */ + private String getTagName(IStructuredDocumentRegion sdRegion) { + ITextRegionList regions = sdRegion.getRegions(); + ITextRegion region = null; + String name = ""; //$NON-NLS-1$ + for (int i = 0; i < regions.size(); i++) { + region = regions.get(i); + if (region.getType() == XMLRegionContext.XML_TAG_NAME) { + name = sdRegion.getText(region); + break; + } + } + return name; + } + + /** + * Return the template completion processor to be used + * + * @return AbstractTemplateCompletionProcessor + */ + protected AbstractTemplateCompletionProcessor getTemplateCompletionProcessor() { + return null; + } + + protected List getValidCMNodes(int childPosition, int kindOfAction, List modelQueryActions) { + Iterator iterator = modelQueryActions.iterator(); + List cmnodes = new Vector(); + while (iterator.hasNext()) { + ModelQueryAction action = (ModelQueryAction) iterator.next(); + if (childPosition < 0 || (action.getStartIndex() <= childPosition && childPosition <= action.getEndIndex()) && action.getKind() == kindOfAction) { + CMNode actionCMNode = action.getCMNode(); + if (actionCMNode != null && !cmnodes.contains(actionCMNode)) + cmnodes.add(actionCMNode); + } + } + return cmnodes; + } + + /** + * Similar to the call in HTMLContentAssistProcessor. Pass in a node, it + * tells you if the document is XML type. + * + * @param node + * @return + */ + protected boolean getXML(Node node) { + if (node == null) + return false; + + Document doc = null; + doc = (node.getNodeType() != Node.DOCUMENT_NODE) ? node.getOwnerDocument() : ((Document) node); + + return (doc instanceof XMLDocument) && ((XMLDocument) doc).isXMLType(); + } + + // Initialize local settings + protected void init() { + // implement in subclasses + } + + protected boolean isCloseRegion(ITextRegion region) { + String type = region.getType(); + return ((type == XMLRegionContext.XML_PI_CLOSE) || (type == XMLRegionContext.XML_TAG_CLOSE) || (type == XMLRegionContext.XML_EMPTY_TAG_CLOSE) || (type == XMLRegionContext.XML_CDATA_CLOSE) || (type == XMLRegionContext.XML_COMMENT_CLOSE) || (type == XMLRegionContext.XML_ATTLIST_DECL_CLOSE) || (type == XMLRegionContext.XML_ELEMENT_DECL_CLOSE) || (type == XMLRegionContext.XML_DOCTYPE_DECLARATION_CLOSE) || (type == XMLJSPRegionContexts.JSP_CLOSE) || (type == XMLJSPRegionContexts.JSP_COMMENT_CLOSE) || (type == XMLJSPRegionContexts.JSP_DIRECTIVE_CLOSE) || (type == XMLRegionContext.XML_DECLARATION_CLOSE)); + } + + /* + * This is to determine if a tag is a special meta-info comment tag that + * shows up as an ELEMENT + */ + private boolean isCommentNode(XMLNode node) { + return (node != null && node instanceof XMLElement && ((XMLElement) node).isCommentTag()); + } + + /** + * Checks if cursor position is after doctype tag... + * + * @param car + * @return + */ + protected boolean isCursorAfterDoctype(ContentAssistRequest car) { + Node aNode = car.getNode(); + Document parent = aNode.getOwnerDocument(); + int xmldoctypeNodePosition = -1; + boolean isAfterDoctype = true; + + if (parent == null) + return true; // blank document case + + for (Node child = parent.getFirstChild(); child != null; child = child.getNextSibling()) { + if (child instanceof XMLNode) { + if (child.getNodeType() == Node.DOCUMENT_TYPE_NODE) { + xmldoctypeNodePosition = ((XMLNode) child).getEndOffset(); + isAfterDoctype = (car.getReplacementBeginPosition() >= xmldoctypeNodePosition); + break; + } + } + } + return isAfterDoctype; + } + + /** + * This method can check if the cursor is after the XMLPI + * + * @param car + * @return + */ + protected boolean isCursorAfterXMLPI(ContentAssistRequest car) { + Node aNode = car.getNode(); + boolean xmlpiFound = false; + Document parent = aNode.getOwnerDocument(); + int xmlpiNodePosition = -1; + boolean isAfterXMLPI = false; + + if (parent == null) + return true; // blank document case + + for (Node child = parent.getFirstChild(); child != null; child = child.getNextSibling()) { + boolean xmlpi = (child.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE && child.getNodeName().equals("xml")); //$NON-NLS-1$ + xmlpiFound = xmlpiFound || xmlpi; + if (xmlpiFound) { + if (child instanceof XMLNode) { + xmlpiNodePosition = ((XMLNode) child).getEndOffset(); + isAfterXMLPI = (car.getReplacementBeginPosition() >= xmlpiNodePosition); + } + break; + } + } + return isAfterXMLPI; + } + + protected boolean isNameRegion(ITextRegion region) { + String type = region.getType(); + return ((type == XMLRegionContext.XML_TAG_NAME) || (type == XMLJSPRegionContexts.JSP_DIRECTIVE_NAME) || (type == XMLRegionContext.XML_ELEMENT_DECL_NAME) || (type == XMLRegionContext.XML_DOCTYPE_NAME) || (type == XMLRegionContext.XML_ATTLIST_DECL_NAME) || (type == XMLJSPRegionContexts.JSP_ROOT_TAG_NAME) || type == XMLJSPRegionContexts.JSP_DIRECTIVE_NAME); + } + + protected boolean isQuote(String string) { + String trimmed = string.trim(); + if (trimmed.length() > 0) { + return trimmed.charAt(0) == '\'' || trimmed.charAt(0) == '"'; + } + return false; + } + + /** + * @param xmlEndTagOpen + * @return + */ + private boolean isSelfClosed(IStructuredDocumentRegion startTag) { + ITextRegionList regions = startTag.getRegions(); + return regions.get(regions.size() - 1).getType() == XMLRegionContext.XML_EMPTY_TAG_CLOSE; + } + + /** + * @param xmlEndTagOpen + * @return + */ + private boolean isStartTag(IStructuredDocumentRegion sdRegion) { + boolean result = false; + if (sdRegion.getRegions().size() > 0) { + ITextRegion r = sdRegion.getRegions().get(0); + result = r.getType() == XMLRegionContext.XML_TAG_OPEN && sdRegion.isEnded(); + } + return result; + } + + protected Properties mapToProperties(CMNamedNodeMap map) { + Properties p = new Properties(); + for (int i = 0; i < map.getLength(); i++) { + CMEntityDeclaration decl = (CMEntityDeclaration) map.item(i); + p.put(decl.getName(), decl.getValue()); + } + return p; + } + + /** + * Gets the corresponding XMLNode, and checks if it's closed. + * + * @param startTag + * @return + */ + private boolean needsEndTag(IStructuredDocumentRegion startTag) { + boolean result = false; + IStructuredModel sModel = ((IModelManagerPlugin) Platform.getPlugin(IModelManagerPlugin.ID)).getModelManager().getExistingModelForRead(fTextViewer.getDocument()); + try { + if (sModel != null) { + XMLNode xmlNode = (XMLNode) sModel.getIndexedRegion(startTag.getStart()); + if (!isStartTag(startTag)) + result = false; + else if (isSelfClosed(startTag)) + result = false; + else if (!xmlNode.isContainer()) + result = false; + else + result = xmlNode.getEndStructuredDocumentRegion() == null; + } + } finally { + if (sModel != null) + sModel.releaseFromRead(); + } + return result; + } + + protected ContentAssistRequest newContentAssistRequest(Node node, Node possibleParent, IStructuredDocumentRegion documentRegion, ITextRegion completionRegion, int begin, int length, String filter) { + return new ContentAssistRequest(node, possibleParent, documentRegion, completionRegion, begin, length, filter, null); + } + + public void release() { + fGenerator = null; + } + + /** + * Set the reason why computeProposals was not able to find any + * completions. + */ + public void setErrorMessage(String errorMessage) { + fErrorMessage = errorMessage; + } + + /** + * Set the reason why computeProposals was not able to find any + * completions. + */ + protected void setErrorMessage(String errorMessage, String append) { + setErrorMessage(errorMessage + append); + } + + /** + * Set the reason why computeProposals was not able to find any + * completions. + */ + protected void setErrorMessage(String errorMessage, String prepend, String append) { + setErrorMessage(prepend + errorMessage + append); + } + + protected boolean stringsEqual(String a, String b) { + // (pa) 221190 matching independent of case to be consistant with Java + // editor CA + return a.equalsIgnoreCase(b); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/AbstractContentModelGenerator.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/AbstractContentModelGenerator.java new file mode 100644 index 0000000000..27b0d7267b --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/AbstractContentModelGenerator.java @@ -0,0 +1,86 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.contentassist; + +import org.eclipse.wst.common.contentmodel.CMAttributeDeclaration; +import org.eclipse.wst.common.contentmodel.CMElementDeclaration; +import org.eclipse.wst.common.contentmodel.CMNamedNodeMap; +import org.eclipse.wst.common.contentmodel.CMNode; +import org.eclipse.wst.common.contentmodel.util.DOMNamespaceHelper; +import org.w3c.dom.Node; + + +public abstract class AbstractContentModelGenerator { + + public static boolean generateChildren = false; + + public AbstractContentModelGenerator() { + super(); + } + + public abstract void generateAttribute(CMAttributeDeclaration attrDecl, StringBuffer buffer); + + protected void generateAttributes(CMElementDeclaration elementDecl, StringBuffer buffer) { + CMNamedNodeMap attributes = elementDecl.getAttributes(); + if (attributes == null) + return; + for (int i = 0; i < attributes.getLength(); i++) { + generateAttribute((CMAttributeDeclaration) attributes.item(i), buffer); + } + return; + } + + protected abstract void generateEndTag(String tagName, Node parentNode, CMElementDeclaration elementDecl, StringBuffer buffer); + + public void generateRequiredChildren(Node parentNode, CMElementDeclaration elementDecl, StringBuffer buffer) { + if (generateChildren) { + } + return; + } + + protected abstract void generateStartTag(String tagName, Node parentNode, CMElementDeclaration elementDecl, StringBuffer buffer); + + public void generateTag(Node parent, CMElementDeclaration elementDecl, StringBuffer buffer) { + if (elementDecl == null || buffer == null) + return; + + String tagName = getRequiredName(parent, elementDecl); + + generateStartTag(tagName, parent, elementDecl, buffer); + generateRequiredChildren(parent, elementDecl, buffer); + generateEndTag(tagName, parent, elementDecl, buffer); + return; + } + + public abstract int getMinimalStartTagLength(Node node, CMElementDeclaration elementDecl); + + public String getRequiredName(Node ownerNode, CMNode cmnode) { + if (ownerNode != null) { + return DOMNamespaceHelper.computeName(cmnode, ownerNode, null); + } + return cmnode.getNodeName(); + } + + public abstract String getStartTagClose(Node parentNode, CMElementDeclaration elementDecl); + + protected boolean requiresAttributes(CMElementDeclaration ed) { + CMNamedNodeMap attributes = ed.getAttributes(); + if (attributes == null) + return false; + for (int i = 0; i < attributes.getLength(); i++) { + if (((CMAttributeDeclaration) attributes.item(i)).getUsage() == CMAttributeDeclaration.REQUIRED) + return true; + } + return false; + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/AbstractTemplateCompletionProcessor.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/AbstractTemplateCompletionProcessor.java new file mode 100644 index 0000000000..542a7e6397 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/AbstractTemplateCompletionProcessor.java @@ -0,0 +1,118 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.contentassist; + +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.Region; +import org.eclipse.jface.text.contentassist.ICompletionProposal; +import org.eclipse.jface.text.templates.ContextTypeRegistry; +import org.eclipse.jface.text.templates.Template; +import org.eclipse.jface.text.templates.TemplateCompletionProcessor; +import org.eclipse.jface.text.templates.TemplateContext; +import org.eclipse.jface.text.templates.TemplateContextType; +import org.eclipse.jface.text.templates.persistence.TemplateStore; +import org.eclipse.swt.graphics.Image; +import org.eclipse.wst.xml.ui.internal.editor.XMLEditorPluginImageHelper; +import org.eclipse.wst.xml.ui.internal.editor.XMLEditorPluginImages; + + +/** + * A completion processor that computes template proposals and works with + * AbstractContentAssistProcessor + */ +abstract public class AbstractTemplateCompletionProcessor extends TemplateCompletionProcessor { + private String fContextTypeId = null; + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.templates.TemplateCompletionProcessor#createProposal(org.eclipse.jface.text.templates.Template, + * org.eclipse.jface.text.templates.TemplateContext, + * org.eclipse.jface.text.Region, int) + */ + protected ICompletionProposal createProposal(Template template, TemplateContext context, Region region, int relevance) { + // CustomTemplateProposal turns the additional information to content + // fit for HTML + return new CustomTemplateProposal(template, context, region, getImage(template), relevance); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.templates.TemplateCompletionProcessor#getContextType(org.eclipse.jface.text.ITextViewer, + * org.eclipse.jface.text.IRegion) + */ + protected TemplateContextType getContextType(ITextViewer viewer, IRegion region) { + // another completion processor should have already set the current + // context type id, so just use that value instead of trying to + // determine + // the context type again + if (getTemplateContextRegistry() != null) { + return getTemplateContextRegistry().getContextType(getContextTypeId()); + } + return null; + } + + protected String getContextTypeId() { + return fContextTypeId; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.templates.TemplateCompletionProcessor#getImage(org.eclipse.jface.text.templates.Template) + */ + protected Image getImage(Template template) { + // just return the same image for now + return XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_TAG_MACRO); + } + + /** + * Return the template context registry to use with this completion + * processor + * + * @return ContextTypeRegistry + */ + abstract protected ContextTypeRegistry getTemplateContextRegistry(); + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.templates.TemplateCompletionProcessor#getTemplates(java.lang.String) + */ + protected Template[] getTemplates(String contextTypeId) { + if (getTemplateStore() != null) { + return getTemplateStore().getTemplates(contextTypeId); + } + return null; + } + + /** + * Return the template store to use with this template completion + * processor + * + * @return TemplateStore + */ + abstract protected TemplateStore getTemplateStore(); + + /** + * Set the current context type to use when determining completion + * proposals. + * + * @param contextTypeId + */ + public void setContextType(String contextTypeId) { + fContextTypeId = contextTypeId; + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/AttributeContextInformation.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/AttributeContextInformation.java new file mode 100644 index 0000000000..79048fba87 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/AttributeContextInformation.java @@ -0,0 +1,114 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.contentassist; + +import java.util.HashMap; + +import org.eclipse.jface.text.contentassist.IContextInformation; +import org.eclipse.jface.text.contentassist.IContextInformationExtension; +import org.eclipse.swt.graphics.Image; +import org.eclipse.wst.sse.ui.util.Assert; + + +/** + * Implementation of IContextInformation. Adds knowledge about the information + * display string such as required attributes for this context. + * + * @author pavery + */ +public class AttributeContextInformation implements IContextInformation { + private HashMap fAttr2RangeMap; + /** The name of the context */ + private String fContextDisplayString; + /** The image to be displayed */ + private Image fImage; + /** The information to be displayed */ + private String fInformationDisplayString; + private int fPosition; + + /** + * Creates a new context information with an image. + * + * @param image + * the image to display when presenting the context information + * @param contextDisplayString + * the string to be used when presenting the context + * @param informationDisplayString + * the string to be displayed when presenting the context + * information, may not be <code>null</code> + */ + public AttributeContextInformation(Image image, String contextDisplayString, String informationDisplayString, HashMap attr2RangeMap) { + Assert.isNotNull(informationDisplayString); + + fImage = image; + fContextDisplayString = contextDisplayString; + fInformationDisplayString = informationDisplayString; + fAttr2RangeMap = attr2RangeMap; + } + + /** + * Creates a new context information without an image. + * + * @param contextDisplayString + * the string to be used when presenting the context + * @param informationDisplayString + * the string to be displayed when presenting the context + * information + */ + public AttributeContextInformation(String contextDisplayString, String informationDisplayString, HashMap attr2RangeMap) { + this(null, contextDisplayString, informationDisplayString, attr2RangeMap); + } + + /** + * Maps (String -> Position). The attribute name to the Text position. + * + * @return + */ + public HashMap getAttr2RangeMap() { + return fAttr2RangeMap; + } + + /** + * @see org.eclipse.jface.text.contentassist.IContextInformation#getContextDisplayString() + */ + public String getContextDisplayString() { + if (fContextDisplayString != null) + return fContextDisplayString; + return fInformationDisplayString; + } + + /** + * @see IContextInformationExtension#getContextInformationPosition() + */ + public int getContextInformationPosition() { + return fPosition; + } + + /** + * @see org.eclipse.jface.text.contentassist.IContextInformation#getImage() + */ + public Image getImage() { + return fImage; + } + + /** + * @see org.eclipse.jface.text.contentassist.IContextInformation#getInformationDisplayString() + */ + public String getInformationDisplayString() { + return fInformationDisplayString; + } + + public void setContextInformationPosition(int position) { + fPosition = position; + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/AttributeContextInformationPresenter.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/AttributeContextInformationPresenter.java new file mode 100644 index 0000000000..ab19b30c7e --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/AttributeContextInformationPresenter.java @@ -0,0 +1,112 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.contentassist; + +import java.util.HashMap; + +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.Position; +import org.eclipse.jface.text.TextPresentation; +import org.eclipse.jface.text.contentassist.IContextInformation; +import org.eclipse.jface.text.contentassist.IContextInformationPresenter; +import org.eclipse.jface.text.contentassist.IContextInformationValidator; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.StyleRange; +import org.eclipse.wst.sse.core.text.IStructuredDocument; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.core.text.ITextRegionList; +import org.eclipse.wst.xml.core.document.XMLNode; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; + + +/** + * Responsible for the presentation of the context info popup. This includes + * text style, and when the window should close. + * + * @author pavery + */ +public class AttributeContextInformationPresenter implements IContextInformationPresenter, IContextInformationValidator { + private int fDocumentPosition = -1; + + private IContextInformation fInfo = null; + private ContextInfoModelUtil fModelUtil = null; + private ITextViewer fViewer = null; + + /** + * @see org.eclipse.jface.text.contentassist.IContextInformationValidator#install(org.eclipse.jface.text.contentassist.IContextInformation, + * org.eclipse.jface.text.ITextViewer, int) + */ + public void install(IContextInformation info, ITextViewer viewer, int documentPosition) { + fInfo = info; + fViewer = viewer; + fDocumentPosition = documentPosition; + fModelUtil = new ContextInfoModelUtil((IStructuredDocument) fViewer.getDocument()); + } + + /** + * @see org.eclipse.jface.text.contentassist.IContextInformationValidator#isContextInformationValid(int) + */ + public boolean isContextInformationValid(int documentPosition) { + // determine whether or not this context info should still be + // showing... + // if cursor still within the element it's valid... + IStructuredDocumentRegion startRegion = fModelUtil.getXMLNode(fDocumentPosition).getStartStructuredDocumentRegion(); + int start = startRegion.getStartOffset(); + int end = startRegion.getEndOffset(); + return documentPosition < end && documentPosition > start + 1; + } + + /** + * @see org.eclipse.jface.text.contentassist.IContextInformationPresenter#updatePresentation(int, + * org.eclipse.jface.text.TextPresentation) + */ + public boolean updatePresentation(int documentPosition, TextPresentation presentation) { + presentation.clear(); + + if (!(fInfo instanceof AttributeContextInformation)) + return false; + + // iterate existing attributes from current node + XMLNode xmlNode = fModelUtil.getXMLNode(documentPosition); + IStructuredDocumentRegion sdRegion = xmlNode.getFirstStructuredDocumentRegion(); + ITextRegionList regions = sdRegion.getRegions(); + ITextRegion r = null; + String attrName = ""; //$NON-NLS-1$ + Object temp = null; + Position p = null; + HashMap map = ((AttributeContextInformation) fInfo).getAttr2RangeMap(); + + // so we can add ranges in order + StyleRange[] sorted = new StyleRange[fInfo.getInformationDisplayString().length()]; + for (int i = 0; i < regions.size(); i++) { + r = regions.get(i); + if (r.getType() == XMLRegionContext.XML_TAG_ATTRIBUTE_NAME) { + attrName = sdRegion.getText(r); + temp = map.get(attrName); + if (temp != null) { + p = (Position) temp; + sorted[p.offset] = new StyleRange(p.offset, p.length, null, null, SWT.BOLD); + } + } + } + // style ranges need to be added in order + StyleRange sr = null; + for (int i = 0; i < sorted.length; i++) { + sr = sorted[i]; + if (sr != null) + presentation.addStyleRange(sr); + } + return true; + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/AttributeContextInformationProvider.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/AttributeContextInformationProvider.java new file mode 100644 index 0000000000..fd5b96d255 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/AttributeContextInformationProvider.java @@ -0,0 +1,208 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.contentassist; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; + +import org.eclipse.jface.text.Position; +import org.eclipse.jface.text.contentassist.ContextInformation; +import org.eclipse.jface.text.contentassist.IContextInformation; +import org.eclipse.wst.common.contentmodel.CMAttributeDeclaration; +import org.eclipse.wst.common.contentmodel.CMContent; +import org.eclipse.wst.common.contentmodel.CMElementDeclaration; +import org.eclipse.wst.common.contentmodel.CMGroup; +import org.eclipse.wst.common.contentmodel.CMNamedNodeMap; +import org.eclipse.wst.common.contentmodel.CMNode; +import org.eclipse.wst.common.contentmodel.CMNodeList; +import org.eclipse.wst.sse.core.text.IStructuredDocument; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegionList; +import org.eclipse.wst.xml.core.document.XMLNode; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + + +/** + * Calculates attribute context information based on a StructuedDocument and + * document position. + * + * @author pavery + */ +class AttributeContextInformationProvider { + private final IContextInformation[] EMPTY_CONTEXT_INFO = new IContextInformation[0]; + private Comparator fComparator; + + private IStructuredDocument fDocument = null; + private ContextInfoModelUtil fModelUtil = null; + + public AttributeContextInformationProvider(IStructuredDocument doc, AttributeContextInformationPresenter presenter) { + fDocument = doc; + fModelUtil = new ContextInfoModelUtil(fDocument); + } + + /** + * @param sdRegion + * @return + */ + private boolean canProposeInfo(IStructuredDocumentRegion sdRegion) { + if (sdRegion != null && isEndTag(sdRegion)) + return false; + else + return true; + } + + public IContextInformation[] getAttributeInformation(int offset) { + /* + * need to take care of special cases w/ ambiguous regions <tag>| + * </tag> also end tags.. + */ + IContextInformation[] results = EMPTY_CONTEXT_INFO; + + IStructuredDocumentRegion sdRegion = fModelUtil.getDocument().getRegionAtCharacterOffset(offset); + if (!canProposeInfo(sdRegion)) + return EMPTY_CONTEXT_INFO; + + XMLNode node = fModelUtil.getXMLNode(offset); + if (node != null) { + switch (node.getNodeType()) { + case Node.ELEMENT_NODE : + results = getInfoForElement(node); + break; + // future... + // case Node.TEXT_NODE : + // results = getInfoForText(node); + // break; + } + } + return results; + } + + /** + * Returns a comparator that compares CMAttributeDeclaration names. + * + * @return the comparator + */ + private Comparator getCMAttributeComparator() { + if (fComparator == null) + fComparator = new Comparator() { + public int compare(Object o1, Object o2) { + return ((CMAttributeDeclaration) o1).getAttrName().compareTo(((CMAttributeDeclaration) o2).getAttrName()); + } + }; + return fComparator; + } + + /** + * @param node + * @return + */ + private IContextInformation[] getInfoForElement(XMLNode node) { + IContextInformation[] results = EMPTY_CONTEXT_INFO; + CMElementDeclaration decl = fModelUtil.getModelQuery().getCMElementDeclaration((Element) node); + if (decl != null) { + CMNamedNodeMap attributes = decl.getAttributes(); + + String attrContextString = node.getNodeName(); + StringBuffer attrInfo = new StringBuffer(" "); //$NON-NLS-1$ + String name = ""; //$NON-NLS-1$ + HashMap attrPosMap = new HashMap(); + int pos = 0; + int length = 0; + int numPerLine = 8; + + CMAttributeDeclaration[] sortedAttrs = getSortedAttributes(attributes); + + for (int i = 0; i < sortedAttrs.length; i++) { + name = sortedAttrs[i].getAttrName(); + length = name.length(); + pos = attrInfo.length(); + + attrInfo.append(name); + + if (sortedAttrs[i].getUsage() == CMAttributeDeclaration.REQUIRED) { + attrInfo.append("*"); //$NON-NLS-1$ + length++; + } + if (i < attributes.getLength() - 1) { + attrInfo.append(" "); //$NON-NLS-1$ + if (i != 0 && i % numPerLine == 0) + attrInfo.append("\n "); //$NON-NLS-1$ + } + attrPosMap.put(name, new Position(pos, length)); + } + if (!attrInfo.toString().trim().equals("")) //$NON-NLS-1$ + return new IContextInformation[]{new AttributeContextInformation(attrContextString, attrInfo.toString(), attrPosMap)}; + } + return results; + } + + /** + * @param node + * @return + */ + IContextInformation[] getInfoForText(XMLNode node) { + Node parent = node.getParentNode(); + String contextString = node.getNodeName(); + StringBuffer info = new StringBuffer(" "); //$NON-NLS-1$ + if (parent != null && parent.getNodeType() == Node.ELEMENT_NODE) { + CMElementDeclaration decl = fModelUtil.getModelQuery().getCMElementDeclaration((Element) parent); + CMContent content = decl.getContent(); + if (content instanceof CMGroup) { + CMGroup cmGroup = (CMGroup) content; + CMNodeList children = cmGroup.getChildNodes(); + CMNode cmNode = null; + for (int i = 0; i < children.getLength(); i++) { + cmNode = children.item(i); + contextString = cmNode.getNodeName(); + if (contextString != null) { + info.append("<" + cmNode.getNodeName() + ">"); //$NON-NLS-1$ //$NON-NLS-2$ + if (i < children.getLength() - 1) + info.append(" "); //$NON-NLS-1$ + } + } + } + } + if (!info.toString().trim().equals("")) //$NON-NLS-1$ + return new IContextInformation[]{new ContextInformation(contextString, info.toString())}; + else + return EMPTY_CONTEXT_INFO; + } + + /** + * Returns sorted array of CMAttributeDeclarations. + * + * @param attributes + * @return + */ + private CMAttributeDeclaration[] getSortedAttributes(CMNamedNodeMap attributes) { + List sorted = new ArrayList(); + for (int i = 0; i < attributes.getLength(); i++) + sorted.add(attributes.item(i)); + Collections.sort(sorted, getCMAttributeComparator()); + return (CMAttributeDeclaration[]) sorted.toArray(new CMAttributeDeclaration[sorted.size()]); + } + + /** + * @param sdRegion + * @return + */ + private boolean isEndTag(IStructuredDocumentRegion sdRegion) { + ITextRegionList regions = sdRegion.getRegions(); + return regions.get(0).getType() == XMLRegionContext.XML_END_TAG_OPEN; + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/ContentAssistRequest.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/ContentAssistRequest.java new file mode 100644 index 0000000000..083829e210 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/ContentAssistRequest.java @@ -0,0 +1,277 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.contentassist; + + + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.eclipse.jface.text.contentassist.ICompletionProposal; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.core.text.ITextRegionCollection; +import org.eclipse.wst.sse.core.util.StringUtils; +import org.eclipse.wst.sse.ui.preferences.PreferenceManager; +import org.w3c.dom.Node; + + +public class ContentAssistRequest { + protected IStructuredDocumentRegion documentRegion = null; + + + protected PreferenceManager fPreferenceManager = null; + protected List macros = new ArrayList(); + protected String matchString; + protected Node node = null; + protected Node parent = null; + protected List proposals = new ArrayList(); + protected ITextRegion region = null; + protected int replacementBeginPosition; + protected int replacementLength; + + // private Boolean separate = null; // (pa) not used + // private Boolean sort = null; // (pa) not used + /** + * XMLContentAssistRequest constructor comment. + */ + public ContentAssistRequest(Node node, Node parent, IStructuredDocumentRegion documentRegion, ITextRegion completionRegion, int begin, int length, String filter, PreferenceManager preferencesManager) { + super(); + setNode(node); + setParent(parent); + setDocumentRegion(documentRegion); + setRegion(completionRegion); + setMatchString(filter); + setReplacementBeginPosition(begin); + setReplacementLength(length); + fPreferenceManager = preferencesManager; + } + + public void addMacro(ICompletionProposal newProposal) { + macros.add(newProposal); + } + + public void addProposal(ICompletionProposal newProposal) { + proposals.add(newProposal); + } + + public ICompletionProposal[] getCompletionProposals() { + ICompletionProposal results[] = null; + if (getProposals().size() > 0 || getMacros().size() > 0) { + List allProposals = new ArrayList(); + if (!shouldSeparate()) { + allProposals.addAll(getProposals()); + // should be empty, as all macros should have gone into the + // proposal list + allProposals.addAll(getMacros()); + allProposals = sortProposals(allProposals); + } else { + allProposals.addAll(sortProposals(getProposals())); + allProposals.addAll(sortProposals(getMacros())); + } + + results = new ICompletionProposal[allProposals.size()]; + for (int i = 0; i < allProposals.size(); i++) { + results[i] = (ICompletionProposal) allProposals.get(i); + } + } + return results; + } + + /** + * + * @return com.ibm.sed.structuredDocument.core.IStructuredDocumentRegion + */ + public IStructuredDocumentRegion getDocumentRegion() { + return documentRegion; + } + + /** + * + * @return java.util.List + */ + public java.util.List getMacros() { + return macros; + } + + /** + * + * @return java.lang.String + */ + public java.lang.String getMatchString() { + return matchString; + } + + /** + * + * @return org.w3c.dom.Node + */ + public org.w3c.dom.Node getNode() { + return node; + } + + /** + * + * @return org.w3c.dom.Node + */ + public org.w3c.dom.Node getParent() { + return parent; + } + + public PreferenceManager getPreferenceManager() { + return fPreferenceManager; + } + + /** + * + * @return java.util.List + */ + public java.util.List getProposals() { + return proposals; + } + + /** + * + * @return com.ibm.sed.structuredDocument.core.ITextRegion + */ + public ITextRegion getRegion() { + return region; + } + + /** + * + * @return int + */ + public int getReplacementBeginPosition() { + return replacementBeginPosition; + } + + /** + * @return int + */ + public int getReplacementLength() { + return replacementLength; + } + + public int getStartOffset() { + if (getDocumentRegion() != null && getRegion() != null) + return ((ITextRegionCollection) getDocumentRegion()).getStartOffset(getRegion()); + return -1; + } + + public String getText() { + if (getDocumentRegion() != null && getRegion() != null) + return ((ITextRegionCollection) getDocumentRegion()).getText(getRegion()); + return ""; //$NON-NLS-1$ + } + + public int getTextEndOffset() { + if (getDocumentRegion() != null && getRegion() != null) + return ((ITextRegionCollection) getDocumentRegion()).getTextEndOffset(getRegion()); + return -1; + } + + /** + * @param region + */ + public void setDocumentRegion(IStructuredDocumentRegion region) { + documentRegion = region; + } + + /** + * + * @param newMatchString + * java.lang.String + */ + public void setMatchString(java.lang.String newMatchString) { + matchString = newMatchString; + } + + /** + * + * @param newNode + * org.w3c.dom.Node + */ + public void setNode(org.w3c.dom.Node newNode) { + node = newNode; + } + + /** + * + * @param newParent + * org.w3c.dom.Node + */ + public void setParent(org.w3c.dom.Node newParent) { + parent = newParent; + } + + /** + * + * @param newRegion + * com.ibm.sed.structuredDocument.ITextRegion + */ + public void setRegion(ITextRegion newRegion) { + region = newRegion; + } + + /** + * + * @param newReplacementBeginPosition + * int + */ + public void setReplacementBeginPosition(int newReplacementBeginPosition) { + replacementBeginPosition = newReplacementBeginPosition; + } + + /** + * + * @param newReplacementEndPosition + * int + */ + public void setReplacementLength(int newReplacementLength) { + replacementLength = newReplacementLength; + } + + public boolean shouldSeparate() { + /* + * if (separate == null) { PreferenceManager manager = + * getPreferenceManager(); if(manager == null) { separate = + * Boolean.FALSE; } else { Element caSettings = + * manager.getElement(PreferenceNames.CONTENT_ASSIST); separate = new + * Boolean(caSettings.getAttribute(PreferenceNames.SEPARATE).equals(PreferenceNames.TRUE)); } } + * return separate.booleanValue(); + */ + return false; + } + + protected List sortProposals(List proposalsIn) { + Collections.sort(proposalsIn, new ProposalComparator()); + return proposalsIn; + + } + + /** + * + * @return java.lang.String + */ + public java.lang.String toString() { + return "Node: " + getNode() //$NON-NLS-1$ + + "\nParent: " + getParent() //$NON-NLS-1$ + + "\nStructuredDocumentRegion: " + StringUtils.escape(getDocumentRegion().toString()) //$NON-NLS-1$ + + "\nRegion: " + getRegion() //$NON-NLS-1$ + + "\nMatch string: '" + StringUtils.escape(getMatchString()) + "'" //$NON-NLS-2$//$NON-NLS-1$ + + "\nOffsets: [" + getReplacementBeginPosition() + "-" + (getReplacementBeginPosition() + getReplacementLength()) + "]\n"; //$NON-NLS-3$//$NON-NLS-2$//$NON-NLS-1$ + } + +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/ContextInfoModelUtil.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/ContextInfoModelUtil.java new file mode 100644 index 0000000000..7810b073c8 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/ContextInfoModelUtil.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.contentassist; + +import org.eclipse.core.runtime.Platform; +import org.eclipse.wst.common.contentmodel.modelquery.ModelQuery; +import org.eclipse.wst.sse.core.IModelManager; +import org.eclipse.wst.sse.core.IModelManagerPlugin; +import org.eclipse.wst.sse.core.text.IStructuredDocument; +import org.eclipse.wst.xml.core.document.XMLModel; +import org.eclipse.wst.xml.core.document.XMLNode; +import org.eclipse.wst.xml.core.modelquery.ModelQueryUtil; + + +/** + * @author pavery + */ +public class ContextInfoModelUtil { + IStructuredDocument fDocument = null; + private final String SSE_MODEL_ID = "org.eclipse.wst.sse.core"; //$NON-NLS-1$ + + ContextInfoModelUtil(IStructuredDocument doc) { + fDocument = doc; + } + + public IStructuredDocument getDocument() { + return fDocument; + } + + public IModelManager getModelManager() { + return ((IModelManagerPlugin) Platform.getPlugin(SSE_MODEL_ID)).getModelManager(); + } + + public ModelQuery getModelQuery() { + ModelQuery mq = null; + + XMLModel xmlModel = (XMLModel) getModelManager().getExistingModelForRead(getDocument()); + mq = ModelQueryUtil.getModelQuery(xmlModel.getDocument()); + xmlModel.releaseFromRead(); + + return mq; + } + + public XMLNode getXMLNode(int offset) { + XMLModel xmlModel = (XMLModel) getModelManager().getExistingModelForRead(getDocument()); + XMLNode xmlNode = (XMLNode) xmlModel.getIndexedRegion(offset); + xmlModel.releaseFromRead(); + return xmlNode; + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/CustomTemplateProposal.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/CustomTemplateProposal.java new file mode 100644 index 0000000000..27b24fe59a --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/CustomTemplateProposal.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.contentassist; + +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.templates.Template; +import org.eclipse.jface.text.templates.TemplateContext; +import org.eclipse.jface.text.templates.TemplateProposal; +import org.eclipse.swt.graphics.Image; +import org.eclipse.wst.sse.core.util.StringUtils; +import org.eclipse.wst.sse.ui.contentassist.IRelevanceCompletionProposal; + + +/** + * Purpose of this class is to make the additional proposal info into content + * fit for an HTML viewer (by escaping characters) + */ +public class CustomTemplateProposal extends TemplateProposal implements IRelevanceCompletionProposal { + + /** + * @param template + * @param context + * @param region + * @param image + */ + public CustomTemplateProposal(Template template, TemplateContext context, IRegion region, Image image) { + super(template, context, region, image); + } + + /** + * @param template + * @param context + * @param region + * @param image + * @param relevance + */ + public CustomTemplateProposal(Template template, TemplateContext context, IRegion region, Image image, int relevance) { + super(template, context, region, image, relevance); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getAdditionalProposalInfo() + */ + public String getAdditionalProposalInfo() { + String additionalInfo = super.getAdditionalProposalInfo(); + return StringUtils.convertToHTMLContent(additionalInfo); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/NoRegionContentAssistProcessor.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/NoRegionContentAssistProcessor.java new file mode 100644 index 0000000000..727b1ed635 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/NoRegionContentAssistProcessor.java @@ -0,0 +1,264 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.contentassist; + + + +import java.util.HashMap; +import java.util.Iterator; + +import org.eclipse.core.resources.IResource; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.ITypedRegion; +import org.eclipse.jface.text.contentassist.ICompletionProposal; +import org.eclipse.jface.text.contentassist.IContentAssistProcessor; +import org.eclipse.jface.text.contentassist.IContextInformation; +import org.eclipse.jface.text.contentassist.IContextInformationValidator; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.ui.IReleasable; +import org.eclipse.wst.sse.ui.StructuredTextViewer; +import org.eclipse.wst.sse.ui.contentassist.IResourceDependentProcessor; +import org.eclipse.wst.sse.ui.internal.contentassist.ContentAssistUtils; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; +import org.eclipse.wst.xml.core.text.rules.StructuredTextPartitionerForXML; + + +/** + * ContentAssistProcessor to handle special cases in content assist where the + * partitioner cannot determine a partition type at the current cursor + * position (usually at EOF). + * + * @author pavery + */ +public class NoRegionContentAssistProcessor implements IContentAssistProcessor, IResourceDependentProcessor, IReleasable { + + protected char completionProposalAutoActivationCharacters[] = null; + protected char contextInformationAutoActivationCharacters[] = null; + + private final ICompletionProposal[] EMPTY_PROPOSAL_SET = new ICompletionProposal[0]; + protected String fErrorMessage = null; + protected HashMap fNameToProcessorMap = null; + protected HashMap fPartitionToProcessorMap = null; + protected IResource fResource = null; + + public NoRegionContentAssistProcessor() { + super(); + fPartitionToProcessorMap = new HashMap(); + fNameToProcessorMap = new HashMap(); + initNameToProcessorMap(); + initPartitionToProcessorMap(); + + } + + /** + * Figures out what the correct ICompletionProposalProcessor is and + * computesCompletionProposals on that. + * + * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#computeCompletionProposals(org.eclipse.jface.text.ITextViewer, + * int) + */ + public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int documentOffset) { + IContentAssistProcessor p = null; + ICompletionProposal[] results = EMPTY_PROPOSAL_SET; + + p = guessContentAssistProcessor(viewer, documentOffset); + if (p != null) + results = p.computeCompletionProposals(viewer, documentOffset); + + return (results != null) ? results : EMPTY_PROPOSAL_SET; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#computeContextInformation(org.eclipse.jface.text.ITextViewer, + * int) + */ + public IContextInformation[] computeContextInformation(ITextViewer viewer, int documentOffset) { + // get context info from processor that we end up using... + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getCompletionProposalAutoActivationCharacters() + */ + public char[] getCompletionProposalAutoActivationCharacters() { + return completionProposalAutoActivationCharacters; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getContextInformationAutoActivationCharacters() + */ + public char[] getContextInformationAutoActivationCharacters() { + return contextInformationAutoActivationCharacters; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getContextInformationValidator() + */ + public IContextInformationValidator getContextInformationValidator() { + // return the validator for the content assist processor that we + // used... + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getErrorMessage() + */ + public String getErrorMessage() { + return fErrorMessage; + } + + /** + * Gives you the document partition type (String) for the given + * StructuredTextViewer and documentPosition. + * + * @param viewer + * @param documentPosition + * @return String + */ + protected String getPartitionType(StructuredTextViewer viewer, int documentPosition) { + IDocument document = viewer.getDocument(); + String partitionType = null; + ITypedRegion partition = null; + try { + partition = document.getPartition(documentPosition); + partitionType = partition.getType(); + } catch (BadLocationException e) { + partitionType = null; + } + return partitionType; + } + + /** + * Guesses a ContentAssistProcessor based on the TextViewer and + * documentOffset. + * + * @param viewer + * @param documentOffset + * @return + */ + protected IContentAssistProcessor guessContentAssistProcessor(ITextViewer viewer, int documentOffset) { + // mapping logic here... + // look @ previous region + // look @ previous doc partition type + // look @ page language + IContentAssistProcessor p = null; + IStructuredDocumentRegion sdRegion = ContentAssistUtils.getStructuredDocumentRegion((StructuredTextViewer) viewer, documentOffset); + if (sdRegion != null) { + String currentRegionType = sdRegion.getType(); + //System.out.println("current region type is >> " + + // currentRegionType); + if (currentRegionType == XMLRegionContext.UNDEFINED) { + IStructuredDocumentRegion sdPrev = sdRegion.getPrevious(); + if (sdPrev != null) { + String prevRegionType = sdPrev.getType(); + //System.out.println("previous region type is >> " + + // prevRegionType); + } + } + } + // working w/ viewer & document partition + if (p == null && viewer.getDocument().getLength() > 0) { + String prevPartitionType = getPartitionType((StructuredTextViewer) viewer, documentOffset - 1); + //System.out.println("previous partition type is > " + + // prevPartitionType); + p = (IContentAssistProcessor) fPartitionToProcessorMap.get(prevPartitionType); + } + return p; + } + + /** + * Necessary for certain content assist processors (such as + * JSPJavaContentAssistProcessor). This gets set in + * StructuredTextViewerConfiguration. + * + */ + public void initialize(IResource resource) { + fResource = resource; + setResourceOnProcessors(resource); + } + + /** + * Inits map for extra ContentAssistProcessors (useBean, get/setProperty) + */ + protected void initNameToProcessorMap() { + } + + /** + * Adds all relevent ContentAssistProcessors to the partition to processor + * map (just XML here) + */ + protected void initPartitionToProcessorMap() { + XMLContentAssistProcessor xmlProcessor = new XMLContentAssistProcessor(); + fPartitionToProcessorMap.put(StructuredTextPartitionerForXML.ST_DEFAULT_XML, xmlProcessor); + } + + public void release() { + releasePartitionToProcessorMap(); + releaseNameToProcessorMap(); + } + + protected void releaseMap(HashMap map) { + if (map != null && !map.isEmpty()) { + Iterator it = map.keySet().iterator(); + Object key = null; + while (it.hasNext()) { + key = it.next(); + if (map.get(key) instanceof IReleasable) + ((IReleasable) map.get(key)).release(); + } + map.clear(); + map = null; + } + } + + protected void releaseNameToProcessorMap() { + releaseMap(fNameToProcessorMap); + } + + protected void releasePartitionToProcessorMap() { + releaseMap(fPartitionToProcessorMap); + } + + private void setResourceOnMap(IResource resource, HashMap map) { + if (!map.isEmpty()) { + Iterator keys = map.keySet().iterator(); + Object o = null; + while (keys.hasNext()) { + o = fPartitionToProcessorMap.get(keys.next()); + if (o instanceof IResourceDependentProcessor) + ((IResourceDependentProcessor) o).initialize(resource); + } + } + } + + /** + * @param resource + */ + private void setResourceOnProcessors(IResource resource) { + setResourceOnMap(resource, fPartitionToProcessorMap); + setResourceOnMap(resource, fNameToProcessorMap); + } + +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/NonValidatingModelQueryAction.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/NonValidatingModelQueryAction.java new file mode 100644 index 0000000000..1bdfb81983 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/NonValidatingModelQueryAction.java @@ -0,0 +1,159 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.contentassist; + + + +import org.eclipse.wst.common.contentmodel.CMNode; + +public class NonValidatingModelQueryAction implements org.eclipse.wst.common.contentmodel.modelquery.ModelQueryAction { + + protected CMNode cmnode = null; + protected int endIndex = 0; + protected int kind = INSERT; + protected int startIndex = 0; + protected Object userData = null; + + /** + * NonValidatingModelQueryAction constructor comment. + */ + protected NonValidatingModelQueryAction() { + super(); + } + + /** + * NonValidatingModelQueryAction constructor comment. + */ + public NonValidatingModelQueryAction(CMNode newChild, int newKind, int newStart, int newEnd, Object newUserData) { + super(); + cmnode = newChild; + kind = newKind; + startIndex = newStart; + endIndex = newEnd; + userData = newUserData; + } + + /** + * getCMNode method comment. + */ + public org.eclipse.wst.common.contentmodel.CMNode getCMNode() { + return cmnode; + } + + /** + * + * @return int + */ + public int getEndIndex() { + return endIndex; + } + + /** + * + * @return int + */ + public int getKind() { + return kind; + } + + /** + * getParent method comment. + */ + public org.w3c.dom.Node getParent() { + return null; + } + + /** + * + * @return int + */ + public int getStartIndex() { + return startIndex; + } + + /** + * getUserData method comment. + */ + public Object getUserData() { + return null; + } + + /** + * performAction method comment. + */ + public void performAction() { + } + + /** + * setCMNode method comment. + */ + protected void setCMNode(org.eclipse.wst.common.contentmodel.CMNode newNode) { + cmnode = newNode; + } + + /** + * + * @param newEndIndex + * int + */ + protected void setEndIndex(int newEndIndex) { + endIndex = newEndIndex; + } + + /** + * + * @param newKind + * int + */ + protected void setKind(int newKind) { + kind = newKind; + } + + /** + * + * @param newStartIndex + * int + */ + protected void setStartIndex(int newStartIndex) { + startIndex = newStartIndex; + } + + /** + * setUserData method comment. + */ + public void setUserData(Object object) { + } + + /** + * + * @return java.lang.String + */ + public String toString() { + String actionName = null; + switch (kind) { + case INSERT : + actionName = "INSERT";//$NON-NLS-1$ + break; + case REMOVE : + actionName = "REMOVE";//$NON-NLS-1$ + break; + case REPLACE : + actionName = "REPLACE";//$NON-NLS-1$ + break; + default : + actionName = "UNKNOWN ACTION ";//$NON-NLS-1$ + } + String nodeName = (cmnode != null) ? getCMNode().getNodeName() : "(unknown)";//$NON-NLS-1$ + return actionName + "=" + nodeName + "(" + startIndex + "..." + endIndex + ")";//$NON-NLS-4$//$NON-NLS-3$//$NON-NLS-2$//$NON-NLS-1$ + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/ProposalComparator.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/ProposalComparator.java new file mode 100644 index 0000000000..3a4bf4d69a --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/ProposalComparator.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.contentassist; + + + +import java.util.Comparator; + +import org.eclipse.jface.text.contentassist.ICompletionProposal; +import org.eclipse.wst.sse.ui.contentassist.IRelevanceCompletionProposal; + + +public class ProposalComparator implements Comparator { + + + public int compare(Object o1, Object o2) { + int relevance = 0; + if (o1 instanceof IRelevanceCompletionProposal && o2 instanceof IRelevanceCompletionProposal) { + // sort based on relevance + IRelevanceCompletionProposal cp1 = (IRelevanceCompletionProposal) o1; + IRelevanceCompletionProposal cp2 = (IRelevanceCompletionProposal) o2; + + relevance = cp2.getRelevance() - cp1.getRelevance(); + + // if same relevance, secondary sort (lexigraphically) + if (relevance == 0 && o1 instanceof ICompletionProposal && o2 instanceof ICompletionProposal) { + String displayString1 = ((ICompletionProposal) o1).getDisplayString(); + String displayString2 = ((ICompletionProposal) o2).getDisplayString(); + if (displayString1 != null && displayString2 != null) + //relevance = displayString1.compareTo(displayString2); + // // this didn't mix caps w/ lowercase + relevance = java.text.Collator.getInstance().compare(displayString1, displayString2); + } + } + // otherwise if it's not ISEDRelevanceCompletionProposal, don't sort + return relevance; + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/SimpleCMElementDeclaration.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/SimpleCMElementDeclaration.java new file mode 100644 index 0000000000..42dce88174 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/SimpleCMElementDeclaration.java @@ -0,0 +1,170 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.contentassist; + + + +public class SimpleCMElementDeclaration implements org.eclipse.wst.common.contentmodel.CMElementDeclaration { + + String fNodeName; + + /** + * SimpleCMELementDeclaration constructor comment. + */ + public SimpleCMElementDeclaration() { + super(); + } + + public SimpleCMElementDeclaration(String nodeName) { + super(); + setNodeName(nodeName); + } + + /** + * getAttributes method + * + * @return CMNamedNodeMap + * + * Returns CMNamedNodeMap of AttributeDeclaration + */ + public org.eclipse.wst.common.contentmodel.CMNamedNodeMap getAttributes() { + return null; + } + + /** + * getCMContent method + * + * @return CMContent + * + * Returns the root node of this element's content model. This can be an + * CMElementDeclaration or a CMGroup + */ + public org.eclipse.wst.common.contentmodel.CMContent getContent() { + return null; + } + + /** + * getContentType method + * + * @return int + * + * Returns one of : ANY, EMPTY, ELEMENT, MIXED, PCDATA, CDATA. + */ + public int getContentType() { + return 0; + } + + /** + * getDataType method + * + * @return java.lang.String + */ + public org.eclipse.wst.common.contentmodel.CMDataType getDataType() { + return null; + } + + /** + * getElementName method + * + * @return java.lang.String + */ + public String getElementName() { + return null; + } + + /** + * getLocalElements method + * + * @return CMNamedNodeMap + * + * Returns a list of locally defined elements. + */ + public org.eclipse.wst.common.contentmodel.CMNamedNodeMap getLocalElements() { + return null; + } + + /** + * getMaxOccur method + * + * @return int + * + * If -1, it's UNBOUNDED. + */ + public int getMaxOccur() { + return 0; + } + + /** + * getMinOccur method + * + * @return int + * + * If 0, it's OPTIONAL. If 1, it's REQUIRED. + */ + public int getMinOccur() { + return 0; + } + + /** + * + * @return java.lang.String + */ + public java.lang.String getNodeName() { + return fNodeName; + } + + /** + * getNodeType method + * + * @return int + * + * Returns one of : + * + */ + public int getNodeType() { + return 0; + } + + /** + * getProperty method + * + * @return java.lang.Object + * + * Returns the object property desciped by the propertyName + * + */ + public Object getProperty(String propertyName) { + return null; + } + + /** + * + * @param newNodeName + * java.lang.String + */ + public void setNodeName(java.lang.String newNodeName) { + fNodeName = newNodeName; + } + + /** + * supports method + * + * @return boolean + * + * Returns true if the CMNode supports a specified property + * + */ + public boolean supports(String propertyName) { + return false; + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/SourceEditorImageHelper.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/SourceEditorImageHelper.java new file mode 100644 index 0000000000..637a785cc8 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/SourceEditorImageHelper.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.contentassist; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.swt.graphics.Image; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.eclipse.wst.xml.ui.XMLEditorPlugin; + + +/** + * @deprecated use internal XMLEditorPluginImageHelper or external + * SharedXMLEditorPluginImageHelper instead + */ +public class SourceEditorImageHelper { + + public SourceEditorImageHelper() { + super(); + } + + public Image createImage(String resource) { + ImageDescriptor desc = AbstractUIPlugin.imageDescriptorFromPlugin(XMLEditorPlugin.ID, resource); + Image image = desc.createImage(); + JFaceResources.getImageRegistry().put(resource, image); + return image; + } + + public Image getImage(String resource) { + Image image = JFaceResources.getImageRegistry().get(resource); + if (image == null) { + image = createImage(resource); + } + return image; + } + + +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/XMLContentAssistProcessor.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/XMLContentAssistProcessor.java new file mode 100644 index 0000000000..0a4b8dc155 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/XMLContentAssistProcessor.java @@ -0,0 +1,86 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.contentassist; + + + +import org.eclipse.core.resources.IResource; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.util.PropertyChangeEvent; +import org.eclipse.wst.common.encoding.content.IContentTypeIdentifier; +import org.eclipse.wst.sse.ui.EditorPlugin; +import org.eclipse.wst.sse.ui.preferences.CommonEditorPreferenceNames; +import org.eclipse.wst.sse.ui.preferences.PreferenceKeyGenerator; + + +public class XMLContentAssistProcessor extends AbstractContentAssistProcessor implements IPropertyChangeListener { + + protected IPreferenceStore fPreferenceStore = null; + protected IResource fResource = null; + protected AbstractTemplateCompletionProcessor fTemplateProcessor = null; + + public XMLContentAssistProcessor() { + super(); + } + + protected IPreferenceStore getPreferenceStore() { + if (fPreferenceStore == null) + fPreferenceStore = EditorPlugin.getDefault().getPreferenceStore(); + //fPreferenceStore = + // CommonPreferencesPlugin.getDefault().getPreferenceStore(ContentType.ContentTypeID_XML); + + return fPreferenceStore; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.xml.ui.contentassist.AbstractContentAssistProcessor#getTemplateCompletionProcessor() + */ + protected AbstractTemplateCompletionProcessor getTemplateCompletionProcessor() { + if (fTemplateProcessor == null) { + fTemplateProcessor = new XMLTemplateCompletionProcessor(); + } + return fTemplateProcessor; + } + + protected void init() { + getPreferenceStore().addPropertyChangeListener(this); + reinit(); + } + + public void propertyChange(PropertyChangeEvent event) { + String property = event.getProperty(); + + if (property.compareTo(CommonEditorPreferenceNames.AUTO_PROPOSE) == 0 || property.compareTo(CommonEditorPreferenceNames.AUTO_PROPOSE_CODE) == 0) { + reinit(); + } + } + + protected void reinit() { + String key = PreferenceKeyGenerator.generateKey(CommonEditorPreferenceNames.AUTO_PROPOSE, IContentTypeIdentifier.ContentTypeID_SSEXML); + boolean doAuto = getPreferenceStore().getBoolean(key); + if (doAuto) { + key = PreferenceKeyGenerator.generateKey(CommonEditorPreferenceNames.AUTO_PROPOSE_CODE, IContentTypeIdentifier.ContentTypeID_SSEXML); + completionProposalAutoActivationCharacters = getPreferenceStore().getString(key).toCharArray(); + } else { + completionProposalAutoActivationCharacters = null; + } + } + + public void release() { + super.release(); + getPreferenceStore().removePropertyChangeListener(this); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/XMLContentAssistUtilities.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/XMLContentAssistUtilities.java new file mode 100644 index 0000000000..ad52a23c68 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/XMLContentAssistUtilities.java @@ -0,0 +1,473 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.contentassist; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.contentassist.ICompletionProposal; +import org.eclipse.wst.sse.core.IndexedRegion; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.core.text.ITextRegionContainer; +import org.eclipse.wst.sse.core.util.ScriptLanguageKeys; +import org.eclipse.wst.sse.ui.internal.contentassist.ContentAssistUtils; +import org.eclipse.wst.sse.ui.internal.contentassist.CustomCompletionProposal; +import org.eclipse.wst.sse.ui.nls.ResourceHandler; +import org.eclipse.wst.xml.core.document.XMLElement; +import org.eclipse.wst.xml.core.document.XMLNode; +import org.eclipse.wst.xml.core.jsp.model.parser.temp.XMLJSPRegionContexts; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; +import org.eclipse.wst.xml.ui.internal.editor.XMLEditorPluginImageHelper; +import org.w3c.dom.Document; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + + +/** + * @author pavery + */ +public class XMLContentAssistUtilities extends ContentAssistUtils { + public static final String CONTENT = "Content"; //$NON-NLS-1$ + public static final String CONTENT_SCRIPT_TYPE = "Content-Script-Type"; //$NON-NLS-1$ + public static final String HEAD = "HEAD"; //$NON-NLS-1$ + public static final String HTML = "HTML"; //$NON-NLS-1$ + public static final String HTTP_EQUIV = "HTTP-EQUIV"; //$NON-NLS-1$ + public static final String META = "META"; //$NON-NLS-1$ + + /** + * A convenience method for getting the closing proposal given the + * contents (IndexedRegion) of a tag that is started, but possibly not + * ended + * + * @param viewer + * the text viewer + * @param documentPosition + * the cursor position in the viewer + * @param indexedNode + * the contents of the tag that is started but possibly not + * ended + * @param parentTagName + * the tag on which you are checkin for an ending tag + * @param imagePath + * content assist image path in realation to com.ibm.sed. + * structured. contentassist. xmlSourceEditorImageHelper + * @return ICompletionProposal + */ + public static ICompletionProposal computeJSPEndTagProposal(ITextViewer viewer, int documentPosition, IndexedRegion indexedNode, String parentTagName, String imagePath) { + ICompletionProposal p = null; + + // check if tag is closed + boolean hasEndTag = true; + boolean isJSPTag = false; + XMLNode xnode = null; + String tagName = ""; //$NON-NLS-1$ + if (indexedNode instanceof XMLNode) { + xnode = ((XMLNode) indexedNode); + // it's ended already... + if (xnode.getEndStructuredDocumentRegion() != null) + return null; + XMLNode openNode = null; + if (!xnode.getNodeName().equalsIgnoreCase(parentTagName)) + openNode = (XMLNode) xnode.getParentNode(); + if (openNode != null) { + if (openNode instanceof XMLElement) { + isJSPTag = ((XMLElement) openNode).isJSPTag(); + } + tagName = openNode.getNodeName(); + hasEndTag = (openNode.getEndStructuredDocumentRegion() != null); + } + } + + // it's closed, don't add close tag proposal + if (!hasEndTag && !isJSPTag) { + + // create appropriate close tag text + String proposedText = proposedText = "</" + tagName; // ResourceHandler + // wants text + // w/out + // ending '>' + // //$NON-NLS-1$ + String viewerText = viewer.getTextWidget().getText(); + if (viewerText.length() >= documentPosition && viewerText.length() >= 2 && documentPosition >= 2) { + String last2chars = viewerText.substring(documentPosition - 2, documentPosition); + if (last2chars.endsWith("</")) //$NON-NLS-1$ + proposedText = tagName; + else if (last2chars.endsWith("<")) //$NON-NLS-1$ + proposedText = "/" + tagName; //$NON-NLS-1$ + } + + // create proposal + p = new CustomCompletionProposal(proposedText + ">", //$NON-NLS-1$ + documentPosition, 0, proposedText.length() + 1, XMLEditorPluginImageHelper.getInstance().getImage(imagePath), //$NON-NLS-1$ + ResourceHandler.getString("15concat", (new Object[]{proposedText})), //$NON-NLS-1$ = "End with '{0}>'" + null, null, XMLRelevanceConstants.R_END_TAG); + } else if (!hasEndTag && isJSPTag) { + + // create appropriate close tag text + String proposedText = proposedText = "%"; // ResourceHandler wants + // text w/out ending '>' + // //$NON-NLS-1$ + String viewerText = viewer.getTextWidget().getText(); + + // TODO (pa) make it smarter to add "%>" or just ">" if % is + // already there... + if (viewerText.length() >= documentPosition && viewerText.length() >= 2) { + String last2chars = viewerText.substring(documentPosition - 2, documentPosition); + String lastchar = viewerText.substring(documentPosition - 1, documentPosition); + if (lastchar.equals("%")) //$NON-NLS-1$ + { + if (last2chars.endsWith("<%")) //$NON-NLS-1$ + proposedText = "%"; //$NON-NLS-1$ + else + proposedText = ""; //$NON-NLS-1$ + } + } + + // create proposal + p = new CustomCompletionProposal(proposedText + ">", //$NON-NLS-1$ + documentPosition, 0, proposedText.length() + 1, XMLEditorPluginImageHelper.getInstance().getImage(imagePath), //$NON-NLS-1$ + ResourceHandler.getString("15concat", (new Object[]{proposedText})), //$NON-NLS-1$ = "End with '{0}>'" + null, null, XMLRelevanceConstants.R_END_TAG); + } + + return p; + } + + + /** + * A convenience method for getting the closing proposal given the + * contents (IndexedRegion) of a tag that is started, but possibly not + * ended + * + * @param viewer + * the text viewer + * @param documentPosition + * the cursor position in the viewer + * @param indexedNode + * the contents of the tag that is started but possibly not + * ended + * @param parentTagName + * the tag on which you are checkin for an ending tag + * @param imagePath + * content assist image path in realation to com.ibm.sed. + * structured. contentassist. xmlSourceEditorImageHelper + * @return ICompletionProposal + */ + public static ICompletionProposal computeXMLEndTagProposal(ITextViewer viewer, int documentPosition, IndexedRegion indexedNode, String parentTagName, String imagePath) { + ICompletionProposal p = null; + + // check if tag is closed + boolean hasEndTag = true; + XMLNode xnode = null; + String tagName = ""; //$NON-NLS-1$ + if (indexedNode instanceof XMLNode) { + xnode = ((XMLNode) indexedNode); + // it's ended already... + if (xnode.getEndStructuredDocumentRegion() != null) + return null; + XMLNode styleNode = null; + if (!xnode.getNodeName().equalsIgnoreCase(parentTagName)) + styleNode = (XMLNode) xnode.getParentNode(); + if (styleNode != null) { + tagName = styleNode.getNodeName(); + hasEndTag = (styleNode.getEndStructuredDocumentRegion() != null); + } + } + + // it's closed, don't add close tag proposal + if (!hasEndTag) { + + // create appropriate close tag text + String proposedText = proposedText = "</" + tagName; // ResourceHandler + // wants text + // w/out + // ending '>' + // //$NON-NLS-1$ + String viewerText = viewer.getTextWidget().getText(); + if (viewerText.length() >= documentPosition && viewerText.length() >= 2 && documentPosition >= 2) { + String last2chars = viewerText.substring(documentPosition - 2, documentPosition); + if (last2chars.endsWith("</")) //$NON-NLS-1$ + proposedText = tagName; + else if (last2chars.endsWith("<")) //$NON-NLS-1$ + proposedText = "/" + tagName; //$NON-NLS-1$ + } + + // create proposal + p = new CustomCompletionProposal(proposedText + ">", //$NON-NLS-1$ + documentPosition, 0, proposedText.length() + 1, XMLEditorPluginImageHelper.getInstance().getImage(imagePath), //$NON-NLS-1$ + ResourceHandler.getString("15concat", (new Object[]{proposedText})), //$NON-NLS-1$ = "End with '{0}>'" + null, null, XMLRelevanceConstants.R_END_TAG); + } + return p; + } + + private static String getMetaScriptType(Document doc) { + // Can not just do a Document.getElementsByTagName(String) as this + // needs + // to be relatively fast. + List metas = new ArrayList(); + // check for META tags under the Document + Node html = null; + Node head = null; + Node child = null; + //---------------------------------------------------------------------- + // (pa) 20021217 + // cmvc defect 235554 + // performance enhancement: using child.getNextSibling() rather than + // nodeList(item) for O(n) vs. O(n*n) + //---------------------------------------------------------------------- + + for (child = doc.getFirstChild(); child != null; child = child.getNextSibling()) { + if (child.getNodeType() != Node.ELEMENT_NODE) + continue; + if (child.getNodeName().equalsIgnoreCase(META)) + metas.add(child); + else if (child.getNodeName().equalsIgnoreCase(HTML)) + html = child; + } + // NodeList children = doc.getChildNodes(); + // for(int i = 0; i < children.getLength(); i++) { + // child = children.item(i); + // if(child.getNodeType() != Node.ELEMENT_NODE) + // continue; + // if(child.getNodeName().equalsIgnoreCase(META)) + // metas.add(child); + // else if(child.getNodeName().equalsIgnoreCase(HTML)) + // html = child; + // } + + // check for META tags under HEAD + if (html != null) { + for (child = html.getFirstChild(); child != null && head == null; child = child.getNextSibling()) { + if (child.getNodeType() != Node.ELEMENT_NODE) + continue; + if (child.getNodeName().equalsIgnoreCase(HEAD)) + head = child; + } + // children = html.getChildNodes(); + // for(int i = 0; i < children.getLength() && head == null; i++) { + // child = children.item(i); + // if(child.getNodeType() != Node.ELEMENT_NODE) + // continue; + // if(child.getNodeName().equalsIgnoreCase(HEAD)) + // head = child; + // } + } + + if (head != null) { + for (head.getFirstChild(); child != null; child = child.getNextSibling()) { + if (child.getNodeType() != Node.ELEMENT_NODE) + continue; + if (child.getNodeName().equalsIgnoreCase(META)) + metas.add(child); + } + // children = head.getChildNodes(); + // for(int i = 0 ; i < children.getLength(); i++) { + // child = children.item(i); + // if(child.getNodeType() != Node.ELEMENT_NODE) + // continue; + // if(child.getNodeName().equalsIgnoreCase(META)) + // metas.add(child); + // } + } + + return getMetaScriptType(metas); + } + + private static String getMetaScriptType(List metaNodeList) { + Node meta = null; + NamedNodeMap attributes = null; + boolean httpEquiv = false; + String contentScriptType = null; + + for (int i = metaNodeList.size() - 1; i >= 0; i--) { + meta = (Node) metaNodeList.get(i); + attributes = meta.getAttributes(); + httpEquiv = false; + contentScriptType = null; + for (int j = 0; j < attributes.getLength(); j++) { + if (attributes.item(j).getNodeName().equalsIgnoreCase(HTTP_EQUIV)) { + httpEquiv = attributes.item(j).getNodeValue().equalsIgnoreCase(CONTENT_SCRIPT_TYPE); + } else if (attributes.item(j).getNodeName().equalsIgnoreCase(CONTENT)) { + contentScriptType = attributes.item(j).getNodeValue(); + } + } + if (httpEquiv && contentScriptType != null) + return contentScriptType; + } + return null; + } + + /** + * Returns the scripting language the scriptNode is in Currently returns + * javascript unless some unknown type or language is specified. Then the + * unknown type/language is returned + * + * @param scriptNode + * @return + */ + public static String getScriptLanguage(Node scriptNode) { + Node attr = null; + + boolean specified = false; + // try to find a scripting adapter for 'type' + if ((scriptNode == null) || (scriptNode.getAttributes() == null)) + return null; + + attr = scriptNode.getAttributes().getNamedItem("type");//$NON-NLS-1$ + if (attr != null) { + specified = true; + String type = attr.getNodeValue(); + return lookupScriptType(type); + } + // now try to find a scripting adapter for 'language' (deprecated by + // HTML specifications) + attr = scriptNode.getAttributes().getNamedItem("language");//$NON-NLS-1$ + if (attr != null) { + specified = true; + String language = attr.getNodeValue(); + return lookupScriptLanguage(language); + } + // check if one is specified by a META tag at the root level or inside + // of HEAD + String type = null; + if (!specified) + type = getMetaScriptType(scriptNode.getOwnerDocument()); + if (type != null) { + specified = true; + return lookupScriptType(type); + } + // return default + if (!specified) + return ScriptLanguageKeys.JAVASCRIPT; + return null; + } + + /** + * Tells you if the flatnode is the %> delimiter + * + * @param fn + * @return boolean + */ + public static boolean isJSPCloseDelimiter(IStructuredDocumentRegion fn) { + if (fn == null) + return false; + return isJSPCloseDelimiter(fn.getType()); + } + + public static boolean isJSPCloseDelimiter(String type) { + if (type == null) + return false; + return (type == XMLJSPRegionContexts.JSP_CLOSE || type == XMLRegionContext.XML_TAG_CLOSE); + } + + /** + * Tells you if the flatnode is the JSP region <%%>, <%=%>, <%!%> + * + * @param fn + * @return boolean + */ + public static boolean isJSPDelimiter(IStructuredDocumentRegion fn) { + boolean isDelimiter = false; + String type = fn.getType(); + if (type != null) { + isDelimiter = isJSPDelimiter(type); + } + return isDelimiter; + } + + public static boolean isJSPDelimiter(String type) { + if (type == null) + return false; + return (isJSPOpenDelimiter(type) || isJSPCloseDelimiter(type)); + } + + /** + * Tells you if the flatnode is <%, <%=, or <%! + * + * @param fn + * @return boolean + */ + public static boolean isJSPOpenDelimiter(IStructuredDocumentRegion fn) { + if (fn == null) + return false; + return isJSPOpenDelimiter(fn.getType()); + } + + public static boolean isJSPOpenDelimiter(String type) { + if (type == null) + return false; + return (type == XMLJSPRegionContexts.JSP_SCRIPTLET_OPEN || type == XMLJSPRegionContexts.JSP_DECLARATION_OPEN || type == XMLJSPRegionContexts.JSP_EXPRESSION_OPEN); + } + + /** + * Tells you if the flatnode is the <jsp:scriptlet>, <jsp:expression>, or + * <jsp:declaration>tag + * + * @param fn + * @return boolean + */ + public static boolean isXMLJSPDelimiter(IStructuredDocumentRegion fn) { + boolean isDelimiter = false; + if (fn != null && fn instanceof ITextRegionContainer) { + Object[] regions = ((ITextRegionContainer) fn).getRegions().toArray(); + ITextRegion temp = null; + String regionText = ""; //$NON-NLS-1$ + for (int i = 0; i < regions.length; i++) { + temp = (ITextRegion) regions[i]; + if (temp.getType() == XMLRegionContext.XML_TAG_NAME) { + regionText = fn.getText(temp); + if (regionText.equalsIgnoreCase("jsp:scriptlet") || regionText.equalsIgnoreCase("jsp:expression") || regionText.equalsIgnoreCase("jsp:declaration")) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + isDelimiter = true; + } + } + } + return isDelimiter; + } + + /** + * Returns "javascript" if language attribute is some form of javascript, + * "java" if language attribute is some form of java. Otherwise, just + * returns type. + * + * @param language + * @return + */ + public static String lookupScriptLanguage(String language) { + for (int i = 0; i < ScriptLanguageKeys.JAVASCRIPT_LANGUAGE_KEYS.length; i++) { + if (ScriptLanguageKeys.JAVASCRIPT_LANGUAGE_KEYS[i].equalsIgnoreCase(language)) + return ScriptLanguageKeys.JAVASCRIPT; + } + for (int i = 0; i < ScriptLanguageKeys.JAVA_LANGUAGE_KEYS.length; i++) { + if (ScriptLanguageKeys.JAVA_LANGUAGE_KEYS[i].equalsIgnoreCase(language)) + return ScriptLanguageKeys.JAVA; + } + return language; + } + + /** + * Returns "javascript" if type (used in <script type="xxx"> is actually + * javascript type. Otherwise, just returns type + * + * @param type + * @return + */ + public static String lookupScriptType(String type) { + for (int i = 0; i < ScriptLanguageKeys.JAVASCRIPT_MIME_TYPE_KEYS.length; i++) + if (ScriptLanguageKeys.JAVASCRIPT_MIME_TYPE_KEYS[i].equalsIgnoreCase(type)) + return ScriptLanguageKeys.JAVASCRIPT; + return type; + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/XMLContentModelGenerator.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/XMLContentModelGenerator.java new file mode 100644 index 0000000000..22cdb40a40 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/XMLContentModelGenerator.java @@ -0,0 +1,126 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.contentassist; + + + +import org.eclipse.wst.common.contentmodel.CMAttributeDeclaration; +import org.eclipse.wst.common.contentmodel.CMDataType; +import org.eclipse.wst.common.contentmodel.CMElementDeclaration; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.xml.core.document.XMLNode; +import org.eclipse.wst.xml.core.jsp.model.parser.temp.XMLJSPRegionContexts; +import org.w3c.dom.Node; + + +public class XMLContentModelGenerator extends AbstractContentModelGenerator { + + /** + * XMLContentModelGenerator constructor comment. + */ + public XMLContentModelGenerator() { + super(); + } + + public void generateAttribute(CMAttributeDeclaration attrDecl, StringBuffer buffer) { + if (attrDecl == null || buffer == null) + return; + int usage = attrDecl.getUsage(); + if (usage == CMAttributeDeclaration.REQUIRED) { + buffer.append(" "); //$NON-NLS-1$ + generateRequiredAttribute(null, attrDecl, buffer); //todo pass + // ownerNode as + // 1st param + } + return; + } + + protected void generateEndTag(String tagName, Node parentNode, CMElementDeclaration elementDecl, StringBuffer buffer) { + if (elementDecl == null) + return; + if (elementDecl.getContentType() != CMElementDeclaration.EMPTY) + buffer.append("</" + tagName + ">");//$NON-NLS-2$//$NON-NLS-1$ + return; + } + + public void generateRequiredAttribute(Node ownerNode, CMAttributeDeclaration attrDecl, StringBuffer buffer) { + if (attrDecl == null || buffer == null) + return; + + // attribute name + String attributeName = getRequiredName(ownerNode, attrDecl); + CMDataType attrType = attrDecl.getAttrType(); + // = sign + buffer.append(attributeName + "=\""); //$NON-NLS-1$ + // attribute value + if (attrType != null) { + // insert any value that is implied + if (attrType.getImpliedValueKind() != CMDataType.IMPLIED_VALUE_NONE && attrType.getImpliedValue() != null) { + buffer.append(attrType.getImpliedValue()); + } + // otherwise, if an enumerated list of values exists, use the + // first value + else if (attrType.getEnumeratedValues() != null && attrType.getEnumeratedValues().length > 0) { + buffer.append(attrType.getEnumeratedValues()[0]); + } + } + buffer.append("\""); //$NON-NLS-1$ + return; + } + + protected void generateStartTag(String tagName, Node parentNode, CMElementDeclaration elementDecl, StringBuffer buffer) { + if (elementDecl == null || buffer == null) + return; + buffer.append("<" + tagName);//$NON-NLS-1$ + generateAttributes(elementDecl, buffer); + buffer.append(getStartTagClose(parentNode, elementDecl)); + return; + } + + public int getMinimalStartTagLength(Node node, CMElementDeclaration elementDecl) { + if (elementDecl == null) + return 0; + if (requiresAttributes(elementDecl)) { + return getRequiredName(node, elementDecl).length() + 2; // < + + // name + + // space + } else { + return 1 + getRequiredName(node, elementDecl).length() + getStartTagClose(node, elementDecl).length(); // < + + // name + // + + // appropriate + // close + } + } + + protected String getOtherClose(Node notATagNode) { + if (notATagNode instanceof XMLNode) { + IStructuredDocumentRegion node = ((XMLNode) notATagNode).getStartStructuredDocumentRegion(); + if (node != null && node.getNumberOfRegions() > 1 && node.getRegions().get(0).getType() == XMLJSPRegionContexts.JSP_DIRECTIVE_OPEN) { + return "%>"; //$NON-NLS-1$ + } + } + return null; + } + + public String getStartTagClose(Node parentNode, CMElementDeclaration elementDecl) { + String other = getOtherClose(parentNode); + if (other != null) + return other; + if (elementDecl == null) + return ">";//$NON-NLS-1$ + if (elementDecl.getContentType() == CMElementDeclaration.EMPTY) + return "/>"; //$NON-NLS-1$ + return ">"; //$NON-NLS-1$ + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/XMLRelevanceConstants.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/XMLRelevanceConstants.java new file mode 100644 index 0000000000..0ac5df3932 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/XMLRelevanceConstants.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.contentassist; + +import org.eclipse.wst.sse.ui.internal.contentassist.IRelevanceConstants; + + + +/** + * some relevance constants for content assist higher relevance means it shows + * up higher on the list + */ +public interface XMLRelevanceConstants extends IRelevanceConstants { + + int R_CDATA = 400; + int R_CLOSE_TAG = 1500; + + int R_COMMENT = 100; + + // moved this above macros + int R_DOCTYPE = 600; + int R_END_TAG = 1400; + int R_END_TAG_NAME = 1100; + int R_ENTITY = 1000; + int R_JSP = 500; + + int R_JSP_ATTRIBUTE_VALUE = 700; + + // (pa) make these the same relevance so proposals are same order for V501 + int R_MACRO = 500; + + // add this onto "required" attrs, elements, etc to bubble them up on + // sorting... + // CMVC 246618 + int R_REQUIRED = 10; + int R_TAG_INSERTION = 500; + int R_TAG_NAME = 1200; + int R_XML_ATTRIBUTE_NAME = 900; + int R_XML_ATTRIBUTE_VALUE = 800; + int R_XML_DECLARATION = 1300; +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/XMLTemplateCompletionProcessor.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/XMLTemplateCompletionProcessor.java new file mode 100644 index 0000000000..c6aea8e33b --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/contentassist/XMLTemplateCompletionProcessor.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.contentassist; + +import org.eclipse.core.runtime.Platform; +import org.eclipse.jface.text.templates.ContextTypeRegistry; +import org.eclipse.jface.text.templates.persistence.TemplateStore; +import org.eclipse.wst.xml.ui.XMLEditorPlugin; +import org.eclipse.wst.xml.ui.templates.TemplateContextTypeXML; + + +/** + * Completion processor for XML Templates + */ +public class XMLTemplateCompletionProcessor extends AbstractTemplateCompletionProcessor { + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.xml.ui.contentassist.AbstractTemplateCompletionProcessor#getContextTypeId() + */ + protected String getContextTypeId() { + // turn the context type id into content type specific + return TemplateContextTypeXML.generateContextTypeId(super.getContextTypeId()); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.xml.ui.contentassist.AbstractTemplateCompletionProcessor#getTemplateContextRegistry() + */ + protected ContextTypeRegistry getTemplateContextRegistry() { + return getXMLEditorPlugin().getTemplateContextRegistry(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.xml.ui.contentassist.AbstractTemplateCompletionProcessor#getTemplateStore() + */ + protected TemplateStore getTemplateStore() { + return getXMLEditorPlugin().getTemplateStore(); + } + + /** + * Returns the XMLEditorPlugin + * + * @return XMLEditorPlugin + */ + private XMLEditorPlugin getXMLEditorPlugin() { + return (XMLEditorPlugin) Platform.getPlugin(XMLEditorPlugin.ID); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/EditAttributeDialog.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/EditAttributeDialog.java new file mode 100644 index 0000000000..ed7a5f7b7f --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/EditAttributeDialog.java @@ -0,0 +1,175 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ + + +package org.eclipse.wst.xml.ui.dialogs; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.graphics.Color; +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.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.help.WorkbenchHelp; +import org.eclipse.wst.xml.ui.nls.ResourceHandler; +import org.eclipse.wst.xml.ui.util.XMLCommonResources; +import org.eclipse.wst.xml.ui.util.XMLCommonUIContextIds; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; + + + +public class EditAttributeDialog extends Dialog implements ModifyListener { + protected Attr attribute; + protected String attributeName; + protected Text attributeNameField; + protected String attributeValue; + protected Text attributeValueField; + protected Label errorMessageLabel; + protected Button okButton; + protected Element ownerElement; + + public EditAttributeDialog(Shell parentShell, Element ownerElement, Attr attribute) { + super(parentShell); + setShellStyle(getShellStyle() | SWT.RESIZE); + this.ownerElement = ownerElement; + this.attribute = attribute; + } + + protected void buttonPressed(int buttonId) { + if (buttonId == IDialogConstants.OK_ID) { + attributeName = getModelValue(attributeNameField.getText()); + attributeValue = attributeValueField.getText(); + } + super.buttonPressed(buttonId); + } + + protected void createButtonsForButtonBar(Composite parent) { + okButton = createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true); + createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false); + } + + protected Control createContents(Composite parent) { + Control control = super.createContents(parent); + attributeNameField.forceFocus(); + attributeNameField.selectAll(); + updateErrorMessage(); + return control; + } + + + protected Control createDialogArea(Composite parent) { + Composite dialogArea = (Composite) super.createDialogArea(parent); + WorkbenchHelp.setHelp(dialogArea, XMLCommonUIContextIds.XCUI_ATTRIBUTE_DIALOG); + + Composite composite = new Composite(dialogArea, SWT.NONE); + GridLayout layout = new GridLayout(); + layout.numColumns = 2; + layout.marginWidth = 0; + composite.setLayout(layout); + + // + // Style convenience constants + composite.setLayoutData(new GridData(GridData.FILL_BOTH)); + + Label attributeNameLabel = new Label(composite, SWT.NONE); + attributeNameLabel.setText(XMLCommonResources.getInstance().getString("_UI_LABEL_NAME_COLON")); //$NON-NLS-1$ + + attributeNameField = new Text(composite, SWT.SINGLE | SWT.BORDER); + GridData gd = new GridData(GridData.FILL_HORIZONTAL); + gd.widthHint = 300; + attributeNameField.setLayoutData(gd); + attributeNameField.setText(getDisplayValue(attribute != null ? attribute.getName() : "")); //$NON-NLS-1$ + attributeNameField.addModifyListener(this); + + Label attributeValueLabel = new Label(composite, SWT.NONE); + attributeValueLabel.setText(XMLCommonResources.getInstance().getString("_UI_LABEL_VALUE_COLON")); //$NON-NLS-1$ + + String value = attribute != null ? attribute.getValue() : ""; //$NON-NLS-1$ + int style = SWT.SINGLE | SWT.BORDER; + if (value.indexOf("\n") != -1) { //$NON-NLS-1$ + style = SWT.MULTI | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL; + } + + attributeValueField = new Text(composite, style); + gd = new GridData(GridData.FILL_HORIZONTAL); + gd.widthHint = 300; + attributeValueField.setLayoutData(gd); + attributeValueField.setText(getDisplayValue(attribute != null ? attribute.getValue() : "")); //$NON-NLS-1$ + + // error message + errorMessageLabel = new Label(composite, SWT.WRAP); + errorMessageLabel.setText(ResourceHandler.getString("error_message_goes_here")); //$NON-NLS-1$ + gd = new GridData(GridData.FILL_HORIZONTAL); + gd.widthHint = 200; + gd.heightHint = Math.max(30, errorMessageLabel.computeSize(0, 0, false).y * 2); + gd.horizontalSpan = 2; + errorMessageLabel.setLayoutData(gd); + Color color = new Color(errorMessageLabel.getDisplay(), 200, 0, 0); + errorMessageLabel.setForeground(color); + + return dialogArea; + } + + public String getAttributeName() { + return attributeName; + } + + public String getAttributeValue() { + return attributeValue; + } + + protected String getDisplayValue(String string) { + return string != null ? string : ""; //$NON-NLS-1$ + } + + protected String getModelValue(String string) { + String result = null; + if (string != null && string.trim().length() > 0) { + result = string; + } + return result; + } + + public void modifyText(ModifyEvent e) { + updateErrorMessage(); + } + + protected void updateErrorMessage() { + String errorMessage = null; + String name = attributeNameField.getText().trim(); + if (name.length() > 0) { + Attr matchingAttribute = ownerElement.getAttributeNode(name); + if (matchingAttribute != null && matchingAttribute != attribute) { + errorMessage = XMLCommonResources.getInstance().getString("_ERROR_XML_ATTRIBUTE_ALREADY_EXISTS"); //$NON-NLS-1$ + } else { + // TODO get checkName from Model + //errorMessage = ValidateHelper.checkXMLName(name); + } + } else { + errorMessage = ""; //$NON-NLS-1$ + } + + errorMessageLabel.setText(errorMessage != null ? errorMessage : ""); //$NON-NLS-1$ + errorMessageLabel.getParent().layout(); + okButton.setEnabled(errorMessage == null); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/EditDoctypeDialog.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/EditDoctypeDialog.java new file mode 100644 index 0000000000..6fd0ea01b4 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/EditDoctypeDialog.java @@ -0,0 +1,241 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ + + +package org.eclipse.wst.xml.ui.dialogs; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Color; +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.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.help.WorkbenchHelp; +import org.eclipse.wst.xml.ui.util.XMLCommonResources; +import org.eclipse.wst.xml.ui.util.XMLCommonUIContextIds; +import org.w3c.dom.DocumentType; + + + +public class EditDoctypeDialog extends Dialog { + protected boolean computeSystemId; + protected String[] doctypeData; + protected boolean errorChecking; + protected Label errorMessageLabel; + protected Button okButton; + protected Button publicIdBrowseButton; + protected Text publicIdField; + protected IPath resourceLocation; + protected Text rootElementNameField; + protected Button systemIdBrowseButton; + protected Text systemIdField; + + public EditDoctypeDialog(Shell parentShell, DocumentType doctype) { + this(parentShell, doctype.getName(), doctype.getPublicId(), doctype.getSystemId()); + } + + public EditDoctypeDialog(Shell parentShell, String name, String publicId, String systemId) { + super(parentShell); + setShellStyle(getShellStyle() | SWT.RESIZE); + doctypeData = new String[3]; + doctypeData[0] = name; + doctypeData[1] = publicId; + doctypeData[2] = systemId; + } + + protected void buttonPressed(int buttonId) { + doctypeData[0] = getModelValue(rootElementNameField.getText()); + doctypeData[1] = getModelValue(publicIdField.getText()); + doctypeData[2] = getModelValue(systemIdField.getText()); + super.buttonPressed(buttonId); + } + + protected void createButtonsForButtonBar(Composite parent) { + okButton = createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true); + createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false); + } + + + protected Control createContents(Composite parent) { + Control control = super.createContents(parent); + updateErrorMessage(); + return control; + } + + protected Control createDialogArea(Composite parent) { + Composite dialogControl = (Composite) super.createDialogArea(parent); + WorkbenchHelp.setHelp(dialogControl, XMLCommonUIContextIds.XCUI_DOCTYPE_DIALOG); + + Composite composite = new Composite(dialogControl, SWT.NONE); + GridLayout layout = new GridLayout(); + layout.numColumns = 3; + layout.marginWidth = 0; + composite.setLayout(layout); + composite.setLayoutData(new GridData(GridData.FILL_BOTH)); + + + ModifyListener modifyListener = new ModifyListener() { + public void modifyText(ModifyEvent e) { + if (e.widget == systemIdField) { + computeSystemId = false; + } + updateErrorMessage(); + } + }; + + // row 1 + // + Label rootElementNameLabel = new Label(composite, SWT.NONE); + rootElementNameLabel.setText(XMLCommonResources.getInstance().getString("_UI_LABEL_ROOT_ELEMENT_NAME_COLON")); //$NON-NLS-1$ + + rootElementNameField = new Text(composite, SWT.SINGLE | SWT.BORDER); + WorkbenchHelp.setHelp(rootElementNameField, XMLCommonUIContextIds.XCUI_DOCTYPE_ROOT); + GridData gd = new GridData(GridData.FILL_HORIZONTAL); + gd.widthHint = 200; + rootElementNameField.setLayoutData(gd); + rootElementNameField.setText(getDisplayValue(doctypeData[0])); + rootElementNameField.addModifyListener(modifyListener); + + Label placeHolder = new Label(composite, SWT.NONE); + placeHolder.setLayoutData(new GridData()); + + // row 2 + // + Label publicIdLabel = new Label(composite, SWT.NONE); + publicIdLabel.setText(XMLCommonResources.getInstance().getString("_UI_LABEL_PUBLIC_ID_COLON")); //$NON-NLS-1$ + + publicIdField = new Text(composite, SWT.SINGLE | SWT.BORDER); + WorkbenchHelp.setHelp(publicIdField, XMLCommonUIContextIds.XCUI_DOCTYPE_PUBLIC); + publicIdField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + publicIdField.setText(getDisplayValue(doctypeData[1])); + + SelectionListener selectionListener = new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + EditEntityHelper helper = new EditEntityHelper(); + if (e.widget == publicIdBrowseButton) { + helper.performBrowseForPublicId(getShell(), publicIdField, computeSystemId ? systemIdField : null); + } else if (e.widget == systemIdBrowseButton) { + helper.performBrowseForSystemId(getShell(), systemIdField, resourceLocation); + } + } + }; + + publicIdBrowseButton = new Button(composite, SWT.NONE); + WorkbenchHelp.setHelp(publicIdBrowseButton, XMLCommonUIContextIds.XCUI_DOCTYPE_PUBLIC_BROWSE); + publicIdBrowseButton.setText(XMLCommonResources.getInstance().getString("_UI_LABEL_BROWSE")); //$NON-NLS-1$ + publicIdBrowseButton.addSelectionListener(selectionListener); + + // row 3 + Label systemIdLabel = new Label(composite, SWT.NONE); + systemIdLabel.setText(XMLCommonResources.getInstance().getString("_UI_LABEL_SYSTEM_ID_COLON")); //$NON-NLS-1$ + + systemIdField = new Text(composite, SWT.SINGLE | SWT.BORDER); + WorkbenchHelp.setHelp(systemIdField, XMLCommonUIContextIds.XCUI_DOCTYPE_SYSTEM); + systemIdField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + systemIdField.setText(getDisplayValue(doctypeData[2])); + systemIdField.addModifyListener(modifyListener); + + + systemIdBrowseButton = new Button(composite, SWT.NONE); + WorkbenchHelp.setHelp(systemIdBrowseButton, XMLCommonUIContextIds.XCUI_DOCTYPE_SYSTEM_BROWSE); + systemIdBrowseButton.setText(XMLCommonResources.getInstance().getString("_UI_LABEL_BROWSE")); //$NON-NLS-1$ + systemIdBrowseButton.addSelectionListener(selectionListener); + + // error message + errorMessageLabel = new Label(dialogControl, SWT.NONE); + errorMessageLabel.setText(""); //$NON-NLS-1$ + errorMessageLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + Color color = new Color(errorMessageLabel.getDisplay(), 200, 0, 0); + errorMessageLabel.setForeground(color); + + return dialogControl; + } + + + protected Label createMessageArea(Composite composite) { + Label label = new Label(composite, SWT.NONE); + //label.setText(message); + return label; + } + + + protected String getDisplayValue(String string) { + return string != null ? string : ""; //$NON-NLS-1$ + } + + public boolean getErrorChecking() { + return errorChecking; + } + + + protected String getModelValue(String string) { + String result = null; + if (string != null && string.trim().length() > 0) { + result = string; + } + return result; + } + + public String getName() { + return doctypeData[0]; + } + + public String getPublicId() { + return doctypeData[1]; + } + + public String getSystemId() { + return doctypeData[2]; + } + + public void setComputeSystemId(boolean computeSystemId) { + this.computeSystemId = computeSystemId; + } + + public void setErrorChecking(boolean errorChecking) { + this.errorChecking = errorChecking; + } + + public void setResourceLocation(IPath path) { + resourceLocation = path; + } + + public void updateErrorMessage() { + if (errorChecking) { + String errorMessage = null; + if (getModelValue(systemIdField.getText()) == null) { + errorMessage = XMLCommonResources.getInstance().getString("_UI_WARNING_SYSTEM_ID_MUST_BE_SPECIFIED"); //$NON-NLS-1$ + } else if (getModelValue(rootElementNameField.getText()) == null) { + errorMessage = XMLCommonResources.getInstance().getString("_UI_WARNING_ROOT_ELEMENT_MUST_BE_SPECIFIED"); //$NON-NLS-1$ + } + + errorMessageLabel.setText(errorMessage != null ? errorMessage : ""); //$NON-NLS-1$ + okButton.setEnabled(errorMessage == null); + } + } +} + + + diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/EditElementDialog.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/EditElementDialog.java new file mode 100644 index 0000000000..82e2bf8ba0 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/EditElementDialog.java @@ -0,0 +1,148 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ + + +package org.eclipse.wst.xml.ui.dialogs; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.graphics.Color; +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.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.help.WorkbenchHelp; +import org.eclipse.wst.xml.core.NameValidator; +import org.eclipse.wst.xml.ui.nls.ResourceHandler; +import org.eclipse.wst.xml.ui.util.XMLCommonResources; +import org.eclipse.wst.xml.ui.util.XMLCommonUIContextIds; +import org.w3c.dom.Element; + + + +public class EditElementDialog extends Dialog implements ModifyListener { + protected Element element; + protected String elementName; + protected Text elementNameField; + protected Label errorMessageLabel; + protected Button okButton; + + public EditElementDialog(Shell parentShell, Element element) { + super(parentShell); + setShellStyle(getShellStyle() | SWT.RESIZE); + this.element = element; + } + + protected void buttonPressed(int buttonId) { + if (buttonId == IDialogConstants.OK_ID) { + elementName = getModelValue(elementNameField.getText()); + } + super.buttonPressed(buttonId); + } + + + protected void createButtonsForButtonBar(Composite parent) { + okButton = createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true); + createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false); + } + + protected Control createContents(Composite parent) { + Control control = super.createContents(parent); + elementNameField.forceFocus(); + elementNameField.selectAll(); + updateErrorMessage(); + return control; + } + + + protected Control createDialogArea(Composite parent) { + Composite dialogArea = (Composite) super.createDialogArea(parent); + WorkbenchHelp.setHelp(dialogArea, XMLCommonUIContextIds.XCUI_ELEMENT_DIALOG); + + Composite composite = new Composite(dialogArea, SWT.NONE); + GridLayout layout = new GridLayout(); + layout.numColumns = 2; + layout.marginWidth = 0; + composite.setLayout(layout); + composite.setLayoutData(new GridData(GridData.FILL_BOTH)); + + Label elementNameLabel = new Label(composite, SWT.NONE); + elementNameLabel.setText(XMLCommonResources.getInstance().getString("_UI_LABEL_ELEMENT_NAME")); //$NON-NLS-1$ + + elementNameField = new Text(composite, SWT.SINGLE | SWT.BORDER); + GridData gd = new GridData(GridData.FILL_HORIZONTAL); + gd.widthHint = 200; + elementNameField.setLayoutData(gd); + elementNameField.setText(getDisplayValue(element != null ? element.getNodeName() : "")); //$NON-NLS-1$ + elementNameField.addModifyListener(this); + + // error message + errorMessageLabel = new Label(composite, SWT.NONE); + errorMessageLabel.setText(ResourceHandler.getString("error_message_goes_here")); //$NON-NLS-1$ + gd = new GridData(GridData.FILL_HORIZONTAL); + gd.horizontalSpan = 2; + errorMessageLabel.setLayoutData(gd); + Color color = new Color(errorMessageLabel.getDisplay(), 200, 0, 0); + errorMessageLabel.setForeground(color); + + return dialogArea; + } + + protected String getDisplayValue(String string) { + return string != null ? string : ""; //$NON-NLS-1$ + } + + public String getElementName() { + return elementName; + } + + protected String getModelValue(String string) { + String result = null; + if (string != null && string.trim().length() > 0) { + result = string; + } + return result; + } + + public void modifyText(ModifyEvent e) { + updateErrorMessage(); + } + + protected void updateErrorMessage() { + String errorMessage = null; + String name = elementNameField.getText(); + // String name = elementNameField.getText().trim(); + if (name.length() > 0) { + // TODO use checkName from model level + //errorMessage = ValidateHelper.checkXMLName(name); + if (!NameValidator.isValid(name)) { + errorMessage = XMLCommonResources.getInstance().getString("_UI_INVALID_NAME"); + } + } else { + errorMessage = ""; //$NON-NLS-1$ + } + + errorMessageLabel.setText(errorMessage != null ? errorMessage : ""); //$NON-NLS-1$ + okButton.setEnabled(errorMessage == null); + } +} + + + diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/EditEntityHelper.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/EditEntityHelper.java new file mode 100644 index 0000000000..8e61d1dde8 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/EditEntityHelper.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ + + +package org.eclipse.wst.xml.ui.dialogs; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.runtime.IPath; +import org.eclipse.jface.window.Window; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.eclipse.wst.xml.ui.util.XMLCommonResources; +import org.eclipse.wst.xml.uriresolver.XMLCatalogEntry; +import org.eclipse.wst.xml.uriresolver.util.URIHelper; + + + +public class EditEntityHelper { + + public void performBrowseForPublicId(Shell parentShell, Text publicIdField) { + performBrowseForPublicId(parentShell, publicIdField, null); + } + + public void performBrowseForPublicId(Shell parentShell, Text publicIdField, Text systemIdField) { + String[] extensions = {"dtd", "txt"}; //$NON-NLS-1$ //$NON-NLS-2$ + SelectXMLCatalogIdDialog dialog = new SelectXMLCatalogIdDialog(parentShell, extensions); + dialog.create(); + dialog.getShell().setText(XMLCommonResources.getInstance().getString("_UI_LABEL_SELECT_XML_CATALOG_ENTRY")); //$NON-NLS-1$ + dialog.setBlockOnOpen(true); + dialog.open(); + if (dialog.getReturnCode() == Window.OK) { + String id = dialog.getId(); + if (id != null) { + publicIdField.setText(id); + if (systemIdField != null && dialog.getSystemId() != null) { + systemIdField.setText(dialog.getSystemId()); + } + } + } + } + + public void performBrowseForSystemId(Shell parentShell, Text systemIdField, IPath resourceLocation) { + String[] extensions = {"dtd"}; //$NON-NLS-1$ + SelectFileOrXMLCatalogIdDialog dialog = new SelectFileOrXMLCatalogIdDialog(parentShell, extensions, XMLCatalogEntry.SYSTEM); + dialog.create(); + dialog.getShell().setText(XMLCommonResources.getInstance().getString("_UI_LABEL_SPECIFY_SYSTEM_ID")); //$NON-NLS-1$ + dialog.setBlockOnOpen(true); + dialog.open(); + if (dialog.getReturnCode() == Window.OK) { + String id = dialog.getId(); + IFile file = dialog.getFile(); + if (id != null) { + systemIdField.setText(id); + } else if (file != null) { + String uri = null; + if (resourceLocation != null) { + uri = URIHelper.getRelativeURI(file.getLocation(), resourceLocation); + } else { + uri = file.getLocation().toOSString(); + } + systemIdField.setText(uri); + } + } + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/EditNamespaceInfoDialog.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/EditNamespaceInfoDialog.java new file mode 100644 index 0000000000..8ff59ea164 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/EditNamespaceInfoDialog.java @@ -0,0 +1,255 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ + + +package org.eclipse.wst.xml.ui.dialogs; + +import java.util.List; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.runtime.IPath; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.window.Window; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Color; +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.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.eclipse.wst.common.contentmodel.CMDocument; +import org.eclipse.wst.common.contentmodel.CMPlugin; +import org.eclipse.wst.common.contentmodel.util.NamespaceInfo; +import org.eclipse.wst.xml.ui.nls.ResourceHandler; +import org.eclipse.wst.xml.ui.util.XMLCommonResources; +import org.eclipse.wst.xml.uriresolver.util.IdResolver; +import org.eclipse.wst.xml.uriresolver.util.IdResolverImpl; +import org.eclipse.wst.xml.uriresolver.util.URIHelper; + + + +public class EditNamespaceInfoDialog extends Dialog { + + public static EditNamespaceInfoDialog invokeDialog(Shell shell, String title, NamespaceInfo info, IPath resourceLocation) { + EditNamespaceInfoDialog dialog = new EditNamespaceInfoDialog(shell, info); + dialog.create(); + dialog.getShell().setText(title); + dialog.setBlockOnOpen(true); + dialog.setResourceLocation(resourceLocation); + dialog.open(); + return dialog; + } + + protected Button browseButton; + protected String errorMessage; + + protected Label errorMessageLabel; + protected NamespaceInfo info; + protected Text locationHintField; + + protected Button okButton; + protected Text prefixField; + protected IPath resourceLocation; + protected Text uriField; + + public EditNamespaceInfoDialog(Shell parentShell, NamespaceInfo info) { + super(parentShell); + setShellStyle(getShellStyle() | SWT.RESIZE); + this.info = info; + } + + protected void buttonPressed(int buttonId) { + if (buttonId == IDialogConstants.OK_ID) { + info.uri = uriField.getText(); + info.prefix = prefixField.getText(); + info.locationHint = locationHintField.getText(); + } + super.buttonPressed(buttonId); + } + + protected void computeErrorMessage() { + errorMessage = null; + } + + protected void createButtonsForButtonBar(Composite parent) { + okButton = createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true); + okButton.setEnabled(false); + createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false); + updateWidgets(); + } + + protected Control createDialogArea(Composite parent) { + Composite dialogArea = (Composite) super.createDialogArea(parent); + //TODO... SSE port + //WorkbenchHelp.setHelp(dialogArea, + // XMLCommonUIContextIds.XCUI_NAMESPACE_DIALOG); + + Composite composite = new Composite(dialogArea, SWT.NONE); + GridLayout layout = new GridLayout(); + layout.numColumns = 3; + layout.marginWidth = 0; + composite.setLayout(layout); + + GridData gd = new GridData(GridData.FILL_HORIZONTAL); + gd.widthHint = 350; + composite.setLayoutData(gd); + + ModifyListener modifyListener = new ModifyListener() { + public void modifyText(ModifyEvent e) { + updateWidgets(); + } + }; + + + // row 1 + // + Label uriLabel = new Label(composite, SWT.NONE); + uriLabel.setText(XMLCommonResources.getInstance().getString("_UI_LABEL_NAMESPACE_NAME_COLON")); //$NON-NLS-1$ + + uriField = new Text(composite, SWT.SINGLE | SWT.BORDER); + gd = new GridData(GridData.FILL_HORIZONTAL); + gd.grabExcessHorizontalSpace = true; + uriField.setLayoutData(gd); + uriField.setText(getDisplayValue(info.uri)); + uriField.addModifyListener(modifyListener); + uriField.setEnabled(info.getProperty("uri-readOnly") == null); //$NON-NLS-1$ + + Label placeHolder1 = new Label(composite, SWT.NONE); + + // row 2 + // + Label prefixLabel = new Label(composite, SWT.NONE); + prefixLabel.setText(XMLCommonResources.getInstance().getString("_UI_LABEL_PREFIX_COLON")); //$NON-NLS-1$ + + prefixField = new Text(composite, SWT.SINGLE | SWT.BORDER); + gd = new GridData(GridData.FILL_HORIZONTAL); + gd.grabExcessHorizontalSpace = true; + prefixField.setLayoutData(gd); + prefixField.setText(getDisplayValue(info.prefix)); + prefixField.addModifyListener(modifyListener); + prefixField.setEnabled(info.getProperty("prefix-readOnly") == null); //$NON-NLS-1$ + Label placeHolder2 = new Label(composite, SWT.NONE); + + // row 3 + // + Label locationHintLabel = new Label(composite, SWT.NONE); + locationHintLabel.setText(XMLCommonResources.getInstance().getString("_UI_LABEL_LOCATION_HINT_COLON")); //$NON-NLS-1$ + + locationHintField = new Text(composite, SWT.SINGLE | SWT.BORDER); + gd = new GridData(GridData.FILL_HORIZONTAL); + gd.grabExcessHorizontalSpace = true; + locationHintField.setLayoutData(gd); + locationHintField.setText(getDisplayValue(info.locationHint)); + locationHintField.addModifyListener(modifyListener); + locationHintField.setEnabled(info.getProperty("locationHint-readOnly") == null); //$NON-NLS-1$ + + SelectionListener selectionListener = new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + performBrowse(); + } + }; + + browseButton = new Button(composite, SWT.NONE); + browseButton.setText(XMLCommonResources.getInstance().getString("_UI_LABEL_BROWSE")); //$NON-NLS-1$ + browseButton.addSelectionListener(selectionListener); + browseButton.setEnabled(locationHintField.getEnabled()); + + // error message + errorMessageLabel = new Label(dialogArea, SWT.NONE); + errorMessageLabel.setText(ResourceHandler.getString("error_message_goes_here")); //$NON-NLS-1$ + errorMessageLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + Color color = new Color(errorMessageLabel.getDisplay(), 200, 0, 0); + errorMessageLabel.setForeground(color); + + return dialogArea; + } + + protected String getDisplayValue(String string) { + return string != null ? string : ""; //$NON-NLS-1$ + } + + protected void performBrowse() { + String[] extensions = {".xsd"}; //$NON-NLS-1$ + SelectFileOrXMLCatalogIdDialog dialog = new SelectFileOrXMLCatalogIdDialog(getShell(), extensions); + dialog.create(); + dialog.getShell().setText(XMLCommonResources.getInstance().getString("_UI_LABEL_SELECT_FILE")); //$NON-NLS-1$ + dialog.setBlockOnOpen(true); + dialog.open(); + + if (dialog.getReturnCode() == Window.OK) { + String grammarURI = null; + IFile file = dialog.getFile(); + String id = dialog.getId(); + if (file != null) { + String uri = null; + if (resourceLocation != null) { + uri = URIHelper.getRelativeURI(file.getLocation(), resourceLocation); + grammarURI = file.getLocation().toOSString(); + } else { + uri = file.getLocation().toOSString(); + grammarURI = uri; + } + locationHintField.setText(uri); + } else if (id != null) { + locationHintField.setText(id); + IdResolver resolver = new IdResolverImpl(null); + grammarURI = resolver.resolveId(id, id); + } + + try { + CMDocument document = CMPlugin.getInstance().createCMDocument(grammarURI, "xsd"); //$NON-NLS-1$ + List namespaceInfoList = (List) document.getProperty("http://com.ibm.etools/cm/properties/namespaceInfo"); //$NON-NLS-1$ + NamespaceInfo info = (NamespaceInfo) namespaceInfoList.get(0); + if (uriField.getText().trim().length() == 0 && info.uri != null) { + uriField.setText(info.uri); + } + if (prefixField.getText().trim().length() == 0 && info.prefix != null) { + prefixField.setText(info.prefix); + } + } catch (Exception e) { + } + } + } + + public void setResourceLocation(IPath path) { + resourceLocation = path; + } + + protected void updateErrorMessageLabel() { + errorMessageLabel.setText(errorMessage != null ? errorMessage : ""); //$NON-NLS-1$ + } + + protected void updateOKButtonState() { + if (okButton != null) { + if (uriField.getText().trim().length() == 0 && prefixField.getText().trim().length() == 0 && locationHintField.getText().trim().length() == 0) + okButton.setEnabled(false); + else + okButton.setEnabled(errorMessage == null); + } + } + + protected void updateWidgets() { + computeErrorMessage(); + updateErrorMessageLabel(); + updateOKButtonState(); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/EditProcessingInstructionDialog.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/EditProcessingInstructionDialog.java new file mode 100644 index 0000000000..be3ae9f817 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/EditProcessingInstructionDialog.java @@ -0,0 +1,124 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ + + +package org.eclipse.wst.xml.ui.dialogs; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +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.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.help.WorkbenchHelp; +import org.eclipse.wst.xml.ui.util.XMLCommonResources; +import org.eclipse.wst.xml.ui.util.XMLCommonUIContextIds; +import org.w3c.dom.ProcessingInstruction; + + + +public class EditProcessingInstructionDialog extends Dialog { + protected String data; + protected Text dataField; + protected String target; + protected Text targetField; + + public EditProcessingInstructionDialog(Shell parentShell, ProcessingInstruction pi) { + this(parentShell, pi.getTarget(), pi.getData()); + } + + public EditProcessingInstructionDialog(Shell parentShell, String target, String data) { + super(parentShell); + setShellStyle(getShellStyle() | SWT.RESIZE); + this.target = target; + this.data = data; + } + + protected void buttonPressed(int buttonId) { + target = getModelValue(targetField.getText()); + data = getModelValue(dataField.getText()); + super.buttonPressed(buttonId); + } + + protected void createButtonsForButtonBar(Composite parent) { + Button okButton = createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true); + createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false); + } + + protected Control createDialogArea(Composite parent) { + Composite dialogArea = (Composite) super.createDialogArea(parent); + WorkbenchHelp.setHelp(dialogArea, XMLCommonUIContextIds.XCUI_PROCESSING_DIALOG); + + Composite composite = new Composite(dialogArea, SWT.NONE); + GridLayout layout = new GridLayout(); + layout.numColumns = 2; + layout.marginWidth = 0; + composite.setLayout(layout); + composite.setLayoutData(new GridData(GridData.FILL_BOTH)); + + + GridData gd = new GridData(GridData.FILL_HORIZONTAL); + gd.widthHint = 250; + + Label targetLabel = new Label(composite, SWT.NONE); + targetLabel.setText(XMLCommonResources.getInstance().getString("_UI_LABEL_TARGET_COLON")); //$NON-NLS-1$ + + targetField = new Text(composite, SWT.SINGLE | SWT.BORDER); + targetField.setLayoutData(gd); + targetField.setText(getDisplayValue(target)); + + Label dataLabel = new Label(composite, SWT.NONE); + dataLabel.setText(XMLCommonResources.getInstance().getString("_UI_LABEL_DATA_COLON")); //$NON-NLS-1$ + + dataField = new Text(composite, SWT.SINGLE | SWT.BORDER); + dataField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + dataField.setText(getDisplayValue(data)); + + return dialogArea; + } + + protected Label createMessageArea(Composite composite) { + Label label = new Label(composite, SWT.NONE); + //label.setText(message); + return label; + } + + public String getData() { + return data; + } + + protected String getDisplayValue(String string) { + return string != null ? string : ""; //$NON-NLS-1$ + } + + protected String getModelValue(String string) { + String result = null; + if (string != null && string.trim().length() > 0) { + result = string; + } + return result; + } + + + public String getTarget() { + return target; + } +} + + + diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/EditSchemaInfoDialog.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/EditSchemaInfoDialog.java new file mode 100644 index 0000000000..93f26c98ec --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/EditSchemaInfoDialog.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.dialogs; + +import java.util.List; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.wst.xml.ui.nsedit.CommonEditNamespacesDialog; +import org.eclipse.wst.xml.ui.util.XMLCommonResources; + + +public class EditSchemaInfoDialog extends Dialog implements UpdateListener { + // protected NamespaceInfoTable namespaceInfoTable; + protected Label errorMessageLabel; + protected List namespaceInfoList; + protected IPath resourceLocation; + + public EditSchemaInfoDialog(Shell parentShell, IPath resourceLocation) { + super(parentShell); + setShellStyle(getShellStyle() | SWT.RESIZE); + this.resourceLocation = resourceLocation; + } + + protected void createButtonsForButtonBar(Composite parent) { + Button okButton = createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true); + createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false); + } + + protected Control createDialogArea(Composite parent) { + Composite dialogArea = (Composite) super.createDialogArea(parent); + CommonEditNamespacesDialog editNamespacesControl = new CommonEditNamespacesDialog(dialogArea, resourceLocation, XMLCommonResources.getInstance().getString("_UI_NAMESPACE_DECLARATIONS"), false, true); //$NON-NLS-1$ + editNamespacesControl.setNamespaceInfoList(namespaceInfoList); + + editNamespacesControl.updateErrorMessage(namespaceInfoList); + + return dialogArea; + } + + protected Control getDialogArea(Composite parent) { + return super.createDialogArea(parent); + } + + public List getNamespaceInfoList() { + return namespaceInfoList; + } + + public void setNamespaceInfoList(List list) { + namespaceInfoList = list; + } + + public void updateErrorMessage(List namespaceInfoList) { + NamespaceInfoErrorHelper helper = new NamespaceInfoErrorHelper(); + String errorMessage = helper.computeErrorMessage(namespaceInfoList, null); + errorMessageLabel.setText(errorMessage != null ? errorMessage : ""); //$NON-NLS-1$ + } + + public void updateOccured(Object object, Object arg) { + updateErrorMessage((List) arg); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/NamespaceInfoErrorHelper.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/NamespaceInfoErrorHelper.java new file mode 100644 index 0000000000..1a5f7c8378 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/NamespaceInfoErrorHelper.java @@ -0,0 +1,101 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.dialogs; + +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.wst.common.contentmodel.util.DOMNamespaceInfoManager; +import org.eclipse.wst.common.contentmodel.util.NamespaceInfo; +import org.eclipse.wst.xml.ui.util.XMLCommonResources; +import org.eclipse.wst.xml.uriresolver.util.IdResolver; +import org.eclipse.wst.xml.uriresolver.util.URIHelper; + + + +public class NamespaceInfoErrorHelper { + + protected List errorList; + + public NamespaceInfoErrorHelper() { + } + + public String computeErrorMessage(List namespaceInfoList, IdResolver idResolver) { + String result = null; + Hashtable prefixTable = new Hashtable(); + Hashtable uriTable = new Hashtable(); + for (Iterator iterator = namespaceInfoList.iterator(); iterator.hasNext();) { + NamespaceInfo nsInfo = (NamespaceInfo) iterator.next(); + nsInfo.normalize(); + + String urikey = nsInfo.uri != null ? nsInfo.uri : ""; //$NON-NLS-1$ + NamespaceInfo nsInfo2 = null; + if ((nsInfo2 = (NamespaceInfo) uriTable.get(urikey)) != null) { + if (nsInfo.uri != null && nsInfo.uri.equals(nsInfo2.uri)) { + result = XMLCommonResources.getInstance().getString("_UI_WARNING_MORE_THAN_ONE_NS_WITH_NAME") + "'" + nsInfo.uri + "'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } else { + result = XMLCommonResources.getInstance().getString("_UI_WARNING_MORE_THAN_ONE_NS_WITHOUT_NAME"); //$NON-NLS-1$ + } + break; + } else { + uriTable.put(urikey, nsInfo); + } + + if (nsInfo.uri != null) { + String key = nsInfo.prefix != null ? nsInfo.prefix : ""; //$NON-NLS-1$ + if (prefixTable.get(key) != null) { + if (nsInfo.prefix != null) { + result = XMLCommonResources.getInstance().getString("_UI_WARNING_MORE_THAN_ONE_NS_WITH_PREFIX") + "'" + nsInfo.prefix + "'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + break; + } else { + result = XMLCommonResources.getInstance().getString("_UI_WARNING_MORE_THAN_ONE_NS_WITHOUT_PREFIX"); //$NON-NLS-1$ + break; + } + } else { + prefixTable.put(key, nsInfo); + } + + if (nsInfo.locationHint != null && idResolver != null) { + String grammarURI = idResolver.resolveId(nsInfo.locationHint, nsInfo.locationHint); + if (!URIHelper.isReadableURI(grammarURI, false)) { + result = XMLCommonResources.getInstance().getString("_UI_WARNING_SCHEMA_CAN_NOT_BE_LOCATED") + " '" + nsInfo.locationHint + "'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + break; + } + } + if (idResolver != null && nsInfo.locationHint == null && !nsInfo.uri.equals(DOMNamespaceInfoManager.XSI_URI)) { + result = XMLCommonResources.getInstance().getString("_UI_WARNING_LOCATION_HINT_NOT_SPECIFIED") + " '" + nsInfo.uri + "'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + break; + } + } else { + if (nsInfo.prefix != null) { + result = XMLCommonResources.getInstance().getString("_UI_WARNING_NAMESPACE_NAME_NOT_SPECIFIED") + " '" + nsInfo.prefix + "'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + break; + } + } + } + // additional tests + if (result == null) { + for (Iterator iterator = namespaceInfoList.iterator(); iterator.hasNext();) { + NamespaceInfo nsInfo = (NamespaceInfo) iterator.next(); + nsInfo.normalize(); + if (nsInfo.uri != null && nsInfo.isPrefixRequired && nsInfo.prefix == null) { + result = XMLCommonResources.getInstance().getString("_UI_WARNING_PREFIX_NOT_SPECIFIED") + " '" + nsInfo.uri + "'"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + break; + } + } + } + + return result; + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/NamespaceInfoTable.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/NamespaceInfoTable.java new file mode 100644 index 0000000000..9a3c4aff15 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/NamespaceInfoTable.java @@ -0,0 +1,391 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.dialogs; + +import java.util.List; +import java.util.Vector; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.jface.viewers.CellEditor; +import org.eclipse.jface.viewers.ColumnWeightData; +import org.eclipse.jface.viewers.ILabelProviderListener; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.viewers.TableLayout; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.TextCellEditor; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.window.Window; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.MouseAdapter; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +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.Group; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.TableItem; +import org.eclipse.wst.common.contentmodel.util.NamespaceInfo; +import org.eclipse.wst.xml.ui.util.XMLCommonResources; + + +public class NamespaceInfoTable extends Composite { + + /** + * NamespaceInfoTableLabelProvider + */ + protected class NamespaceInfoTableLabelProvider implements ITableLabelProvider, IStructuredContentProvider { + + public void addListener(ILabelProviderListener listener) { + } + + public void dispose() { + } + + public Image getColumnImage(Object object, int columnIndex) { + return null; + } + + public String getColumnText(Object object, int column) { + NamespaceInfo info = (NamespaceInfo) object; + String result = null; + switch (column) { + case 0 : { + result = info.uri; + break; + } + case 1 : { + result = info.prefix; + break; + } + case 2 : { + result = info.locationHint; + break; + } + } + result = result != null ? result : ""; //$NON-NLS-1$ + if (result.equals("")) { //$NON-NLS-1$ + switch (column) { + case 0 : { + result = XMLCommonResources.getInstance().getString("_UI_NO_NAMESPACE_NAME"); //$NON-NLS-1$ + break; + } + case 1 : { + result = XMLCommonResources.getInstance().getString("_UI_NO_PREFIX"); //$NON-NLS-1$ + break; + } + } + } + return result; + } + + String getDefaultPrefix() { + String defaultPrefix = "p"; //$NON-NLS-1$ + if (namespaceInfoList == null) + return defaultPrefix; + Vector v = new Vector(); + for (int i = 0; i < namespaceInfoList.size(); i++) { + NamespaceInfo nsinfo = (NamespaceInfo) namespaceInfoList.get(i); + if (nsinfo.prefix != null) + v.addElement(nsinfo.prefix); + } + if (v.contains(defaultPrefix)) { + String s = defaultPrefix; + for (int j = 0; v.contains(s); j++) { + s = defaultPrefix + Integer.toString(j); + } + return s; + } else + return defaultPrefix; + } + + public Object[] getElements(Object inputElement) { + return namespaceInfoList.toArray(); + } + + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + } + + public boolean isDeleted(Object element) { + return false; + } + + public boolean isLabelProperty(Object object, Object property) { + return false; + } + + public boolean isLabelProperty(Object element, String property) { + return false; + } + + public void removeListener(ILabelProviderListener listener) { + } + } + + protected static final String LOCATION_HINT = XMLCommonResources.getInstance().getString("_UI_LABEL_LOCATION_HINT"); //$NON-NLS-1$ + protected static final String NAMESPACE_URI = XMLCommonResources.getInstance().getString("_UI_LABEL_NAMESPACE_NAME"); //$NON-NLS-1$ + protected static final String PREFIX = XMLCommonResources.getInstance().getString("_UI_LABEL_PREFIX"); //$NON-NLS-1$ + protected Button deleteButton; + protected boolean dummyRowsRemoved = false; + protected Button editButton; + protected List namespaceInfoList = new Vector(); + protected Button newButton; + protected NamespaceInfoTableLabelProvider provider; + protected IPath resourceLocation; + protected TableViewer tableViewer; + protected UpdateListener updateListener; + protected int visibleRows = -1; + + public NamespaceInfoTable(Composite parent) { + this(parent, -1, -1, -1); + } + + public NamespaceInfoTable(Composite parent, int visibleRows) { + this(parent, -1, -1, visibleRows); + } + + public NamespaceInfoTable(Composite parent, int widthHint, int heightHint) { + this(parent, widthHint, heightHint, -1); + } + + public NamespaceInfoTable(Composite parent, int widthHint, int heightHint, int visibleRows) { + super(parent, SWT.NONE); + setLayout(createGridLayout()); + setLayoutData(new GridData(GridData.FILL_BOTH)); + Group namespaceInfoGroup = new Group(this, SWT.NONE); + namespaceInfoGroup.setText(XMLCommonResources.getInstance().getString("_UI_LABEL_XML_SCHEMA_INFORMATION")); //$NON-NLS-1$ + namespaceInfoGroup.setLayout(new GridLayout()); + GridData gd = new GridData(GridData.FILL_BOTH); + if (widthHint != -1) { + gd.widthHint = widthHint; + } + if (heightHint != -1) { + gd.heightHint = heightHint; + } + namespaceInfoGroup.setLayoutData(gd); + //WorkbenchHelp.setHelp(namespaceInfoGroup, new + // ControlContextComputer(namespaceInfoGroup, + // XMLBuilderContextIds.XMLC_NAMESPACE_GROUP)); + String[] titleArray = {NAMESPACE_URI, PREFIX, LOCATION_HINT}; + tableViewer = new TableViewer(namespaceInfoGroup, SWT.FULL_SELECTION); + provider = new NamespaceInfoTableLabelProvider(); + tableViewer.setContentProvider(provider); + tableViewer.setLabelProvider(provider); + tableViewer.setColumnProperties(titleArray); + Table table = tableViewer.getTable(); + table.setHeaderVisible(true); + table.setLayoutData(new GridData(GridData.FILL_BOTH)); + int[] widthArray = {50, 20, 30}; + TableLayout layout = new TableLayout(); + for (int i = 0; i < titleArray.length; i++) { + TableColumn column = new TableColumn(table, i); + column.setText(titleArray[i]); + column.setAlignment(SWT.LEFT); + layout.addColumnData(new ColumnWeightData(widthArray[i], true)); + } + this.visibleRows = visibleRows; + for (int i = 0; i < visibleRows; i++) { + TableItem item = new TableItem(table, SWT.NONE); + item.setText("#######"); //$NON-NLS-1$ + } + table.setLayout(layout); + CellEditor[] cellEditors = new CellEditor[titleArray.length]; + cellEditors[1] = new TextCellEditor(table); + cellEditors[2] = new TextCellEditor(table); + tableViewer.setCellEditors(cellEditors); + MouseAdapter mouseAdapter = new MouseAdapter() { + public void mouseDoubleClick(MouseEvent e) { + if (tableViewer.getTable().getItem(new Point(e.x, e.y)) != null) { + performEdit(); + } + } + }; + table.addMouseListener(mouseAdapter); + createButtons(namespaceInfoGroup); + ISelectionChangedListener selectionChangedListener = new ISelectionChangedListener() { + public void selectionChanged(SelectionChangedEvent event) { + updateButtonEnabledState(); + } + }; + tableViewer.addSelectionChangedListener(selectionChangedListener); + } + + protected void createButtons(Composite parent) { + Composite composite = new Composite(parent, SWT.NONE); + composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + GridLayout gridLayout = new GridLayout(); + gridLayout.numColumns = 2; + gridLayout.marginHeight = 0; + gridLayout.marginWidth = 0; + composite.setLayout(gridLayout); + Button hiddenButton = new Button(composite, SWT.NONE); + hiddenButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + hiddenButton.setVisible(false); + hiddenButton.setEnabled(false); + SelectionListener selectionListener = new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + if (e.widget == newButton) { + performNew(); + } else if (e.widget == editButton) { + performEdit(); + } else if (e.widget == deleteButton) { + performDelete(); + } + } + }; + // create a composite to hold the three buttons + Composite buttonComposite = new Composite(composite, SWT.NONE); + buttonComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + GridLayout buttonGridLayout = new GridLayout(); + buttonGridLayout.numColumns = 3; + buttonGridLayout.makeColumnsEqualWidth = true; + buttonComposite.setLayout(buttonGridLayout); + // add the New button + // + newButton = new Button(buttonComposite, SWT.NONE); + newButton.setText(XMLCommonResources.getInstance().getString("_UI_BUTTON_NEW")); //$NON-NLS-1$ + newButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + newButton.addSelectionListener(selectionListener); + // add the Edit button + // + editButton = new Button(buttonComposite, SWT.NONE); + editButton.setText(XMLCommonResources.getInstance().getString("_UI_BUTTON_EDIT")); //$NON-NLS-1$ + editButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + editButton.addSelectionListener(selectionListener); + // add the Delete button + // + deleteButton = new Button(buttonComposite, SWT.NONE); + deleteButton.setText(XMLCommonResources.getInstance().getString("_UI_BUTTON_DELETE")); //$NON-NLS-1$ + deleteButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + deleteButton.addSelectionListener(selectionListener); + } + + public GridLayout createGridLayout() { + GridLayout gridLayout = new GridLayout(); + gridLayout.marginWidth = 0; + gridLayout.horizontalSpacing = 0; + return gridLayout; + } + + public List getNamespaceInfoList() { + return namespaceInfoList; + } + + protected NamespaceInfo getTargetNamespaceInfo() { + return (namespaceInfoList != null && namespaceInfoList.size() > 0) ? (NamespaceInfo) namespaceInfoList.get(0) : null; + } + + protected EditNamespaceInfoDialog invokeDialog(String title, NamespaceInfo info) { + Shell shell = XMLCommonResources.getInstance().getWorkbench().getActiveWorkbenchWindow().getShell(); + EditNamespaceInfoDialog dialog = new EditNamespaceInfoDialog(shell, info); + dialog.create(); + dialog.getShell().setText(title); + dialog.setBlockOnOpen(true); + dialog.setResourceLocation(resourceLocation); + dialog.open(); + return dialog; + } + + protected void performDelayedUpdate() { + Runnable delayedUpdate = new Runnable() { + public void run() { + update(); + } + }; + getDisplay().asyncExec(delayedUpdate); + if (updateListener != null) { + updateListener.updateOccured(this, namespaceInfoList); + } + } + + public void performDelete() { + ISelection selection = tableViewer.getSelection(); + Object selectedObject = (selection instanceof IStructuredSelection) ? ((IStructuredSelection) selection).getFirstElement() : null; + if (selectedObject != null) { + namespaceInfoList.remove(selectedObject); + performDelayedUpdate(); + } + } + + public void performEdit() { + ISelection selection = tableViewer.getSelection(); + Object selectedObject = (selection instanceof IStructuredSelection) ? ((IStructuredSelection) selection).getFirstElement() : null; + if (selectedObject instanceof NamespaceInfo) { + EditNamespaceInfoDialog dialog = invokeDialog(XMLCommonResources.getInstance().getString("_UI_LABEL_NEW_NAMESPACE_INFORMATION"), (NamespaceInfo) selectedObject); //$NON-NLS-1$ + performDelayedUpdate(); + } + } + + public void performNew() { + NamespaceInfo info = new NamespaceInfo(); + EditNamespaceInfoDialog dialog = invokeDialog(XMLCommonResources.getInstance().getString("_UI_LABEL_NEW_NAMESPACE_INFORMATION"), info); //$NON-NLS-1$ + if (dialog.getReturnCode() == Window.OK) { + namespaceInfoList.add(info); + performDelayedUpdate(); + } + } + + public void setNamespaceInfoList(List namespaceInfoList) { + this.namespaceInfoList = namespaceInfoList; + update(); + } + + public void setResourceLocation(IPath resourceLocation) { + this.resourceLocation = resourceLocation; + } + + public void setUpdateListener(UpdateListener updateListener) { + this.updateListener = updateListener; + } + + public void update() { + updateHelper(namespaceInfoList); + } + + public void updateButtonEnabledState() { + ISelection selection = tableViewer.getSelection(); + Object selectedObject = (selection instanceof IStructuredSelection) ? ((IStructuredSelection) selection).getFirstElement() : null; + NamespaceInfo info = (NamespaceInfo) selectedObject; + editButton.setEnabled(info != null); + deleteButton.setEnabled(info != null && info.getProperty("unremovable") == null); //$NON-NLS-1$ + } + + public void updateHelper(List namespaceInfoList) { + if (visibleRows != -1 && !dummyRowsRemoved) { + dummyRowsRemoved = true; + tableViewer.getTable().removeAll(); + } + ISelection selection = tableViewer.getSelection(); + tableViewer.setInput(namespaceInfoList); + if (selection.isEmpty()) { + if (namespaceInfoList.size() > 0) { + tableViewer.setSelection(new StructuredSelection(namespaceInfoList.get(0))); + } + } else { + tableViewer.setSelection(selection); + } + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/SelectFileOrXMLCatalogIdDialog.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/SelectFileOrXMLCatalogIdDialog.java new file mode 100644 index 0000000000..4c8397c90e --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/SelectFileOrXMLCatalogIdDialog.java @@ -0,0 +1,87 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.dialogs; + +import org.eclipse.core.resources.IFile; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Shell; + + +public class SelectFileOrXMLCatalogIdDialog extends Dialog { + protected int catalogEntryType; + protected String[] extensions; + protected IFile file; + protected String id; + protected Button okButton; + protected SelectFileOrXMLCatalogIdPanel panel; + + public SelectFileOrXMLCatalogIdDialog(Shell parentShell, String[] extensions) { + this(parentShell, extensions, 0); + } + + public SelectFileOrXMLCatalogIdDialog(Shell parentShell, String[] extensions, int catalogEntryType) { + super(parentShell); + setShellStyle(getShellStyle() | SWT.RESIZE); + this.extensions = extensions; + this.catalogEntryType = catalogEntryType; + } + + + protected void buttonPressed(int buttonId) { + if (buttonId == IDialogConstants.OK_ID) { + file = panel.getFile(); + id = panel.getXMLCatalogId(); + } + super.buttonPressed(buttonId); + } + + protected void createButtonsForButtonBar(Composite parent) { + okButton = createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true); + okButton.setEnabled(false); + createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false); + } + + protected Control createDialogArea(Composite parent) { + Composite dialogArea = (Composite) super.createDialogArea(parent); + + panel = new SelectFileOrXMLCatalogIdPanel(dialogArea); + panel.setCatalogEntryType(catalogEntryType); + panel.setFilterExtensions(extensions); + panel.setVisibleHelper(true); + SelectFileOrXMLCatalogIdPanel.Listener listener = new SelectFileOrXMLCatalogIdPanel.Listener() { + public void completionStateChanged() { + updateButtonState(); + } + }; + panel.setListener(listener); + + return dialogArea; + } + + public IFile getFile() { + return file; + } + + public String getId() { + return id; + } + + protected void updateButtonState() { + okButton.setEnabled(panel.getFile() != null || panel.getXMLCatalogId() != null); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/SelectFileOrXMLCatalogIdPanel.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/SelectFileOrXMLCatalogIdPanel.java new file mode 100644 index 0000000000..3805e8f4de --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/SelectFileOrXMLCatalogIdPanel.java @@ -0,0 +1,182 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ + + +package org.eclipse.wst.xml.ui.dialogs; + +import org.eclipse.core.resources.IFile; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +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.Control; +import org.eclipse.ui.part.PageBook; +import org.eclipse.wst.ui.viewers.SelectSingleFileView; +import org.eclipse.wst.xml.ui.util.XMLCommonResources; +import org.eclipse.wst.xml.uriresolver.XMLCatalog; +import org.eclipse.wst.xml.uriresolver.XMLCatalogEntry; +import org.eclipse.wst.xml.uriresolver.XMLCatalogPlugin; + + +public class SelectFileOrXMLCatalogIdPanel extends Composite implements SelectionListener { + + /** + * TODO: Change the name of this interface; "Listener" is used by SWT. + */ + public interface Listener { + void completionStateChanged(); + } + + protected class MySelectSingleFileView extends SelectSingleFileView implements SelectSingleFileView.Listener { + protected Control control; + + public MySelectSingleFileView(Composite parent) { + super(null, true); + //String[] ext = {".dtd"}; + //addFilterExtensions(ext); + control = createControl(parent); + control.setLayoutData(new GridData(GridData.FILL_BOTH)); + MySelectSingleFileView.this.setListener(this); + } + + public Control getControl() { + return control; + } + + public void setControlComplete(boolean isComplete) { + updateCompletionStateChange(); + } + + public void setVisibleHelper(boolean isVisible) { + super.setVisibleHelper(isVisible); + } + } + + protected Listener listener; + protected PageBook pageBook; + + protected Button[] radioButton; + protected MySelectSingleFileView selectSingleFileView; + protected SelectXMLCatalogIdPanel selectXMLCatalogIdPanel; + + public SelectFileOrXMLCatalogIdPanel(Composite parent) { + super(parent, SWT.NONE); + + // container group + setLayout(new GridLayout()); + GridData gd = new GridData(GridData.FILL_BOTH); + gd.heightHint = 400; + gd.widthHint = 400; + setLayoutData(gd); + + radioButton = new Button[2]; + radioButton[0] = new Button(this, SWT.RADIO); + radioButton[0].setText(XMLCommonResources.getInstance().getString("_UI_RADIO_BUTTON_SELECT_FROM_WORKSPACE")); //$NON-NLS-1$ + radioButton[0].setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + radioButton[0].setSelection(true); + radioButton[0].addSelectionListener(this); + + radioButton[1] = new Button(this, SWT.RADIO); + radioButton[1].setText(XMLCommonResources.getInstance().getString("_UI_RADIO_BUTTON_SELECT_FROM_CATALOG")); //$NON-NLS-1$ + radioButton[1].setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + radioButton[1].addSelectionListener(this); + + pageBook = new PageBook(this, SWT.NONE); + pageBook.setLayoutData(new GridData(GridData.FILL_BOTH)); + + selectSingleFileView = new MySelectSingleFileView(pageBook); + + XMLCatalog xmlCatalog = XMLCatalogPlugin.getInstance().getDefaultXMLCatalog(); + selectXMLCatalogIdPanel = new SelectXMLCatalogIdPanel(pageBook, xmlCatalog); + selectXMLCatalogIdPanel.getTableViewer().addSelectionChangedListener(new ISelectionChangedListener() { + public void selectionChanged(SelectionChangedEvent event) { + updateCompletionStateChange(); + } + }); + pageBook.showPage(selectSingleFileView.getControl()); + } + + public IFile getFile() { + IFile result = null; + if (radioButton[0].getSelection()) { + result = selectSingleFileView.getFile(); + } + return result; + } + + public XMLCatalogEntry getXMLCatalogEntry() { + XMLCatalogEntry result = null; + if (radioButton[1].getSelection()) { + result = selectXMLCatalogIdPanel.getXMLCatalogEntry(); + } + return result; + } + + public String getXMLCatalogId() { + String result = null; + if (radioButton[1].getSelection()) { + result = selectXMLCatalogIdPanel.getId(); + } + return result; + } + + public String getXMLCatalogURI() { + String result = null; + if (radioButton[1].getSelection()) { + result = selectXMLCatalogIdPanel.getURI(); + } + return result; + } + + public void setCatalogEntryType(int catalogEntryType) { + selectXMLCatalogIdPanel.setCatalogEntryType(catalogEntryType); + } + + public void setFilterExtensions(String[] filterExtensions) { + selectSingleFileView.resetFilters(); + selectSingleFileView.addFilterExtensions(filterExtensions); + + selectXMLCatalogIdPanel.getTableViewer().setFilterExtensions(filterExtensions); + } + + public void setListener(Listener listener) { + this.listener = listener; + } + + public void setVisibleHelper(boolean isVisible) { + selectSingleFileView.setVisibleHelper(isVisible); + } + + public void updateCompletionStateChange() { + if (listener != null) { + listener.completionStateChanged(); + } + } + + public void widgetDefaultSelected(SelectionEvent e) { + } + + public void widgetSelected(SelectionEvent e) { + if (e.widget == radioButton[0]) { + pageBook.showPage(selectSingleFileView.getControl()); + } else { + pageBook.showPage(selectXMLCatalogIdPanel); + } + updateCompletionStateChange(); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/SelectXMLCatalogIdDialog.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/SelectXMLCatalogIdDialog.java new file mode 100644 index 0000000000..65cb8bd065 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/SelectXMLCatalogIdDialog.java @@ -0,0 +1,111 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ + + +package org.eclipse.wst.xml.ui.dialogs; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.wst.xml.uriresolver.XMLCatalog; +import org.eclipse.wst.xml.uriresolver.XMLCatalogEntry; +import org.eclipse.wst.xml.uriresolver.XMLCatalogPlugin; + + + +public class SelectXMLCatalogIdDialog extends Dialog { + protected String[] extensions; + protected Button okButton; + protected SelectXMLCatalogIdPanel panel; + protected String publicId; + protected String systemId; + + public SelectXMLCatalogIdDialog(Shell parentShell, String[] extensions) { + super(parentShell); + setShellStyle(getShellStyle() | SWT.RESIZE); + this.extensions = extensions; + } + + + protected void buttonPressed(int buttonId) { + if (buttonId == IDialogConstants.OK_ID) { + ISelection selection = panel.getTableViewer().getSelection(); + Object selectedObject = (selection instanceof IStructuredSelection) ? ((IStructuredSelection) selection).getFirstElement() : null; + + if (selectedObject instanceof XMLCatalogEntry) { + XMLCatalogEntry mappingInfo = (XMLCatalogEntry) selectedObject; + publicId = mappingInfo.getKey(); + systemId = computeDefaultSystemId(mappingInfo); + } + } + super.buttonPressed(buttonId); + } + + protected String computeDefaultSystemId(XMLCatalogEntry mappingInfo) { + String result = mappingInfo.getWebAddress(); + if (result == null && mappingInfo.getURI() != null) { + int index = mappingInfo.getURI().lastIndexOf("/"); //$NON-NLS-1$ + String lastSegment = index != -1 ? mappingInfo.getURI().substring(index + 1) : mappingInfo.getURI(); + result = lastSegment; + } + return result; + } + + protected void createButtonsForButtonBar(Composite parent) { + okButton = createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true); + okButton.setEnabled(false); + createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false); + } + + protected Control createDialogArea(Composite parent) { + Composite dialogArea = (Composite) super.createDialogArea(parent); + // TODO... SSE port + //WorkbenchHelp.setHelp(dialogArea, + // XMLCommonUIContextIds.XCUI_CATALOG_DIALOG); + + XMLCatalog xmlCatalog = XMLCatalogPlugin.getInstance().getDefaultXMLCatalog(); + panel = new SelectXMLCatalogIdPanel(dialogArea, xmlCatalog); + + ISelectionChangedListener listener = new ISelectionChangedListener() { + public void selectionChanged(SelectionChangedEvent event) { + updateButtonState(); + } + }; + panel.getTableViewer().setFilterExtensions(extensions); + panel.getTableViewer().addSelectionChangedListener(listener); + return dialogArea; + } + + + + public String getId() { + return publicId; + } + + public String getSystemId() { + return systemId; + } + + protected void updateButtonState() { + ISelection selection = panel.getTableViewer().getSelection(); + okButton.setEnabled(!selection.isEmpty()); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/SelectXMLCatalogIdPanel.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/SelectXMLCatalogIdPanel.java new file mode 100644 index 0000000000..19390cc0fa --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/SelectXMLCatalogIdPanel.java @@ -0,0 +1,132 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ + + +package org.eclipse.wst.xml.ui.dialogs; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Vector; + +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.wst.xml.ui.util.XMLCommonResources; +import org.eclipse.wst.xml.uriresolver.XMLCatalog; +import org.eclipse.wst.xml.uriresolver.XMLCatalogEntry; + + +public class SelectXMLCatalogIdPanel extends Composite { + protected int catalogEntryType; + protected boolean doTableSizeHack = false; + + protected XMLCatalogTableViewer tableViewer; + protected XMLCatalog xmlCatalog; + + public SelectXMLCatalogIdPanel(Composite parent, XMLCatalog xmlCatalog) { + super(parent, SWT.NONE); + this.xmlCatalog = xmlCatalog; + + GridLayout gridLayout = new GridLayout(); + this.setLayout(gridLayout); + GridData gd = new GridData(GridData.FILL_HORIZONTAL); + gd.heightHint = 200; + gd.widthHint = 700; + this.setLayoutData(gd); + + Label label = new Label(this, SWT.NONE); + label.setText(XMLCommonResources.getInstance().getString("_UI_LABEL_XML_CATALOG_COLON")); //$NON-NLS-1$ + + tableViewer = createTableViewer(this); + tableViewer.getControl().setLayoutData(new GridData(GridData.FILL_BOTH)); + tableViewer.setInput("dummy"); //$NON-NLS-1$ + } + + protected XMLCatalogTableViewer createTableViewer(Composite parent) { + String headings[] = new String[2]; + headings[0] = XMLCommonResources.getInstance().getString("_UI_LABEL_KEY"); //$NON-NLS-1$ + headings[1] = XMLCommonResources.getInstance().getString("_UI_LABEL_URI"); //$NON-NLS-1$ + + XMLCatalogTableViewer theTableViewer = new XMLCatalogTableViewer(parent, headings) { + + protected void addXMLCatalogEntries(List list, Collection collection) { + for (Iterator i = collection.iterator(); i.hasNext();) { + XMLCatalogEntry entry = (XMLCatalogEntry) i.next(); + if (catalogEntryType == 0) { + list.add(entry); + } else if (catalogEntryType == entry.getType()) { + list.add(entry); + } + } + } + + public Collection getXMLCatalogEntries() { + List result = null; + + if (xmlCatalog == null || doTableSizeHack) { + // this lets us create a table with an initial height of + // 10 rows + // otherwise we get stuck with 0 row heigh table... that's + // too small + doTableSizeHack = false; + result = new Vector(); + for (int i = 0; i < 6; i++) { + result.add(""); //$NON-NLS-1$ + } + } else { + result = new Vector(); + + addXMLCatalogEntries(result, xmlCatalog.getChildCatalog(XMLCatalog.SYSTEM_CATALOG_ID).getEntries()); + addXMLCatalogEntries(result, xmlCatalog.getChildCatalog(XMLCatalog.USER_CATALOG_ID).getEntries()); + } + return result; + } + }; + return theTableViewer; + } + + + public String getId() { + XMLCatalogEntry entry = getXMLCatalogEntry(); + return entry != null ? entry.getKey() : null; + } + + public XMLCatalogTableViewer getTableViewer() { + return tableViewer; + } + + public String getURI() { + XMLCatalogEntry entry = getXMLCatalogEntry(); + return entry != null ? entry.getURI() : null; + } + + public XMLCatalogEntry getXMLCatalogEntry() { + XMLCatalogEntry result = null; + ISelection selection = tableViewer.getSelection(); + Object selectedObject = (selection instanceof IStructuredSelection) ? ((IStructuredSelection) selection).getFirstElement() : null; + if (selectedObject instanceof XMLCatalogEntry) { + result = (XMLCatalogEntry) selectedObject; + } + return result; + } + + public void setCatalogEntryType(int catalogEntryType) { + this.catalogEntryType = catalogEntryType; + tableViewer.refresh(); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/UpdateListener.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/UpdateListener.java new file mode 100644 index 0000000000..2ae05bdcb1 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/UpdateListener.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ + + +package org.eclipse.wst.xml.ui.dialogs; + +public interface UpdateListener { + + public void updateOccured(Object object, Object arg); +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/XMLCatalogTableViewer.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/XMLCatalogTableViewer.java new file mode 100644 index 0000000000..3f5262c8a5 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dialogs/XMLCatalogTableViewer.java @@ -0,0 +1,198 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ + + +package org.eclipse.wst.xml.ui.dialogs; + +import java.text.Collator; +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.viewers.ColumnWeightData; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.TableLayout; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerFilter; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.wst.xml.ui.internal.editor.XMLEditorPluginImageHelper; +import org.eclipse.wst.xml.ui.internal.editor.XMLEditorPluginImages; +import org.eclipse.wst.xml.uriresolver.XMLCatalogEntry; +import org.eclipse.wst.xml.uriresolver.util.URIHelper; + + +public class XMLCatalogTableViewer extends TableViewer { + + + public class CatalogEntryContentProvider implements IStructuredContentProvider { + + public void dispose() { + } + + public Object[] getElements(Object element) { + Object[] array = getXMLCatalogEntries().toArray(); + Comparator comparator = new Comparator() { + public int compare(Object o1, Object o2) { + int result = 0; + if (o1 instanceof XMLCatalogEntry && o2 instanceof XMLCatalogEntry) { + XMLCatalogEntry mappingInfo1 = (XMLCatalogEntry) o1; + XMLCatalogEntry mappingInfo2 = (XMLCatalogEntry) o2; + result = Collator.getInstance().compare(mappingInfo1.getKey(), mappingInfo2.getKey()); + } + return result; + } + }; + Arrays.sort(array, comparator); + return array; + } + + public void inputChanged(Viewer viewer, Object old, Object newobj) { + } + + public boolean isDeleted(Object object) { + return false; + } + } + + public class CatalogEntryLabelProvider extends LabelProvider implements ITableLabelProvider { + + public Image getColumnImage(Object object, int columnIndex) { + Image result = null; + if (columnIndex == 0) { + Image base = null; + if (object instanceof XMLCatalogEntry) { + XMLCatalogEntry catalogEntry = (XMLCatalogEntry) object; + String uri = catalogEntry.getURI(); + if (uri.endsWith("dtd")) { //$NON-NLS-1$ + base = dtdFileImage; + } else if (uri.endsWith("xsd")) { //$NON-NLS-1$ + base = xsdFileImage; + } else { + base = unknownFileImage; + } + + if (base != null) { + if (URIHelper.isReadableURI(uri, false)) { + result = base; + } else { + //TODO... SSE port + result = base;//imageFactory.createCompositeImage(base, + // errorImage, + // ImageFactory.BOTTOM_LEFT); + } + } + } + } + return result; + } + + public String getColumnText(Object object, int columnIndex) { + String result = null; + if (object instanceof XMLCatalogEntry) { + XMLCatalogEntry catalogEntry = (XMLCatalogEntry) object; + result = columnIndex == 0 ? catalogEntry.getKey() : catalogEntry.getURI(); + result = URIHelper.removePlatformResourceProtocol(result); + } + return result != null ? result : ""; //$NON-NLS-1$ + } + } + + + class XMLCatalogTableViewerFilter extends ViewerFilter { + protected String[] extensions; + + public XMLCatalogTableViewerFilter(String[] extensions) { + this.extensions = extensions; + } + + public boolean isFilterProperty(Object element, Object property) { + return false; + } + + public boolean select(Viewer viewer, Object parent, Object element) { + boolean result = false; + if (element instanceof XMLCatalogEntry) { + XMLCatalogEntry catalogEntry = (XMLCatalogEntry) element; + for (int i = 0; i < extensions.length; i++) { + if (catalogEntry.getURI().endsWith(extensions[i])) { + result = true; + break; + } + } + } + return result; + } + } + + protected static Image dtdFileImage = XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_DTDFILE); + + protected static String ERROR_STATE_KEY = "errorstatekey"; //$NON-NLS-1$ + protected static Image errorImage = XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OVR_ERROR); + + protected static Image unknownFileImage = XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_TXTEXT); + protected static Image xsdFileImage = XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_XSDFILE); + + //protected ImageFactory imageFactory = new ImageFactory(); + + public XMLCatalogTableViewer(Composite parent, String[] columnProperties) { + super(parent, SWT.FULL_SELECTION); + + Table table = getTable(); + table.setLinesVisible(true); + table.setHeaderVisible(true); + table.setLinesVisible(true); + + TableLayout layout = new TableLayout(); + for (int i = 0; i < columnProperties.length; i++) { + TableColumn column = new TableColumn(table, i); + column.setText(columnProperties[i]); + column.setAlignment(SWT.LEFT); + layout.addColumnData(new ColumnWeightData(50, true)); + } + table.setLayout(layout); + table.setLinesVisible(false); + + setColumnProperties(columnProperties); + + setContentProvider(new CatalogEntryContentProvider()); + setLabelProvider(new CatalogEntryLabelProvider()); + } + + public Collection getXMLCatalogEntries() { + return null; + } + + + public void menuAboutToShow(IMenuManager menuManager) { + Action action = new Action("hello") { //$NON-NLS-1$ + public void run() { + System.out.println("run!"); //$NON-NLS-1$ + } + }; + menuManager.add(action); + } + + public void setFilterExtensions(String[] extensions) { + resetFilters(); + addFilter(new XMLCatalogTableViewerFilter(extensions)); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dnd/DragNodeCommand.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dnd/DragNodeCommand.java new file mode 100644 index 0000000000..94118e20a5 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dnd/DragNodeCommand.java @@ -0,0 +1,229 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.dnd; + + +import java.util.Collection; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Vector; + +import org.eclipse.swt.dnd.DND; +import org.eclipse.wst.sse.core.IStructuredModel; +import org.eclipse.wst.ui.dnd.DefaultDragAndDropCommand; +import org.eclipse.wst.xml.core.document.XMLNode; +import org.eclipse.wst.xml.ui.nls.ResourceHandler; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +public class DragNodeCommand extends DefaultDragAndDropCommand { + public DragNodeCommand(Object target, float location, int operations, int operation, Collection sources) { + super(target, location, operations, operation, sources); + } + + protected void beginModelChange(Node node, boolean batchUpdate) { + IStructuredModel structuredModel = getStructedModel(node); + if (structuredModel != null) { + structuredModel.beginRecording(this, ResourceHandler.getString("DragNodeCommand.0")); //$NON-NLS-1$ + if (batchUpdate) { + // structuredModel.aboutToChangeModel(); + } + } + } + + public boolean canExecute() { + return executeHelper(true); + } + + + public boolean doMove(Node source, Node parentNode, Node refChild, boolean testOnly) { + boolean result = false; + if (source.getNodeType() == Node.ATTRIBUTE_NODE) { + Attr sourceAttribute = (Attr) source; + Element sourceAttributeOwnerElement = sourceAttribute.getOwnerElement(); + if (parentNode.getNodeType() == Node.ELEMENT_NODE && sourceAttributeOwnerElement != parentNode) { + result = true; + if (!testOnly) { + try { + Element targetElement = (Element) parentNode; + targetElement.setAttribute(sourceAttribute.getName(), sourceAttribute.getValue()); + sourceAttributeOwnerElement.removeAttributeNode(sourceAttribute); + } catch (Exception e) { + } + } + } + } else { + if ((parentNode.getNodeType() == Node.ELEMENT_NODE || parentNode.getNodeType() == Node.DOCUMENT_NODE) && !(refChild instanceof Attr)) { + result = true; + + if (!testOnly) { + if (isAncestor(source, parentNode)) { + //System.out.println("can not perform this drag drop + // operation.... todo... pop up dialog"); + } else { + // defect 221055 this test is required or else the + // node will + // be removed from the tree and the insert will fail + if (source != refChild) { + source.getParentNode().removeChild(source); + parentNode.insertBefore(source, refChild); + } + } + } + } + } + return result; + } + + protected void endModelChange(Node node, boolean batchUpdate) { + IStructuredModel structuredModel = getStructedModel(node); + if (structuredModel != null) { + structuredModel.endRecording(this); + if (batchUpdate) { + // structuredModel.changedModel(); + } + } + } + + public void execute() { + executeHelper(false); + } + + // + // + public boolean executeHelper(boolean testOnly) { + boolean result = true; + if (target instanceof Node) { + Node targetNode = (Node) target; + Node parentNode = getParentForDropPosition(targetNode); + Node refChild = getRefChild(targetNode); + + Vector sourcesList = new Vector(); + sourcesList.addAll(sources); + + removeMemberDescendants(sourcesList); + boolean performBatchUpdate = sourcesList.size() > 5; + + if (!testOnly) { + beginModelChange(targetNode, performBatchUpdate); + } + for (Iterator i = sourcesList.iterator(); i.hasNext();) { + Object source = i.next(); + if (source instanceof Node) { + if (!(refChild == null && targetNode instanceof Attr)) { + result = doMove((Node) source, parentNode, refChild, testOnly); + } else { + result = false; + } + if (!result) { + break; + } + } + } + if (!testOnly) { + endModelChange(targetNode, performBatchUpdate); + } + } else { + result = false; + } + return result; + } + + + public int getFeedback() { + int result = DND.FEEDBACK_SELECT; + if (location > 0.75) { + result = DND.FEEDBACK_INSERT_AFTER; + } else if (location < 0.25) { + result = DND.FEEDBACK_INSERT_BEFORE; + } + return result; + } + + protected Node getParentForDropPosition(Node node) { + Node result = null; + + int feedback = getFeedback(); + if (feedback == DND.FEEDBACK_SELECT) { + result = node; + } else { + result = getParentOrOwner(node); + } + return result; + } + + + protected Node getParentOrOwner(Node node) { + return (node.getNodeType() == Node.ATTRIBUTE_NODE) ? ((Attr) node).getOwnerElement() : node.getParentNode(); + } + + + protected Node getRefChild(Node node) { + Node result = null; + + int feedback = getFeedback(); + + if (feedback == DND.FEEDBACK_INSERT_BEFORE) { + result = node; + } else if (feedback == DND.FEEDBACK_INSERT_AFTER) { + result = node.getNextSibling(); + } + return result; + } + + protected IStructuredModel getStructedModel(Node node) { + IStructuredModel result = null; + if (node instanceof XMLNode) { + result = ((XMLNode) node).getModel(); + } + return result; + } + + // returns true if a is an ancestore of b + // + protected boolean isAncestor(Node a, Node b) { + boolean result = false; + for (Node parent = b; parent != null; parent = parent.getParentNode()) { + if (parent == a) { + result = true; + break; + } + } + return result; + } + + + /** + * This method removes members of the list that have ancestors that are + * also members of the list. + */ + protected void removeMemberDescendants(List list) { + Hashtable table = new Hashtable(); + for (Iterator i = list.iterator(); i.hasNext();) { + Object node = i.next(); + table.put(node, node); + } + + for (int i = list.size() - 1; i >= 0; i--) { + Node node = (Node) list.get(i); + for (Node parent = getParentOrOwner(node); parent != null; parent = getParentOrOwner(parent)) { + if (table.get(parent) != null) { + list.remove(i); + break; + } + } + } + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dnd/XMLDragAndDropManager.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dnd/XMLDragAndDropManager.java new file mode 100644 index 0000000000..432cafd73b --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/dnd/XMLDragAndDropManager.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ + + +package org.eclipse.wst.xml.ui.dnd; + +import java.util.Collection; + +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.swt.dnd.DND; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.wst.ui.dnd.DragAndDropCommand; +import org.eclipse.wst.ui.dnd.DragAndDropManager; +import org.eclipse.wst.ui.dnd.ObjectTransfer; +import org.eclipse.wst.ui.dnd.ViewerDragAdapter; +import org.eclipse.wst.ui.dnd.ViewerDropAdapter; +import org.w3c.dom.Node; + +public class XMLDragAndDropManager implements DragAndDropManager { + public static void addDragAndDropSupport(TreeViewer viewer) { + int dndOperations = DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_LINK; + Transfer[] transfers = new Transfer[]{ObjectTransfer.getInstance()}; + viewer.addDragSupport(dndOperations, transfers, new ViewerDragAdapter(viewer)); + viewer.addDropSupport(dndOperations, transfers, new ViewerDropAdapter(viewer, new XMLDragAndDropManager())); + } + + public XMLDragAndDropManager() { + } + + public DragAndDropCommand createCommand(Object target, float location, int operations, int operation, Collection source) { + DragAndDropCommand result = null; + if (target instanceof Node) { + Node node = (Node) target; + result = new DragNodeCommand(target, location, operations, operation, source); + } + return result; + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/doubleclick/XMLDoubleClickStrategy.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/doubleclick/XMLDoubleClickStrategy.java new file mode 100644 index 0000000000..aca4617ed0 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/doubleclick/XMLDoubleClickStrategy.java @@ -0,0 +1,292 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.doubleclick; + +import org.eclipse.core.runtime.Platform; +import org.eclipse.jface.text.DefaultTextDoubleClickStrategy; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.swt.graphics.Point; +import org.eclipse.wst.sse.core.IModelManager; +import org.eclipse.wst.sse.core.IModelManagerPlugin; +import org.eclipse.wst.sse.core.IStructuredModel; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.ui.StructuredTextViewer; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; +import org.w3c.dom.Node; + + +public class XMLDoubleClickStrategy extends DefaultTextDoubleClickStrategy { + protected static final char DOUBLE_QUOTE = '\"'; + protected static final char SINGLE_QUOTE = '\''; + protected static final char SPACE = ' '; + protected int fCaretPosition = -1; + protected int fDoubleClickCount = 0; + protected Node fNode = null; + protected IStructuredDocumentRegion fStructuredDocumentRegion = null; + protected String fStructuredDocumentRegionText = ""; //$NON-NLS-1$ + protected IStructuredModel fStructuredModel = null; + protected StructuredTextViewer fStructuredTextViewer; + protected ITextRegion fTextRegion = null; + + public void doubleClicked(ITextViewer textViewer) { + if (textViewer instanceof StructuredTextViewer) { + fStructuredTextViewer = (StructuredTextViewer) textViewer; + try { + fStructuredModel = getModelManager().getExistingModelForRead(fStructuredTextViewer.getDocument()); + + if (fStructuredModel != null) { + int caretPosition = textViewer.getSelectedRange().x; + if (caretPosition < 0) + return; + + fNode = (Node) fStructuredModel.getIndexedRegion(caretPosition); + if (fNode == null) + return; + + updateDoubleClickCount(caretPosition); + updateStructuredDocumentRegion(); + updateTextRegion(); + + if (fNode.getNodeType() == Node.TEXT_NODE) + processTextDoubleClicked(); + else + processElementDoubleClicked(); + } + } finally { + if (fStructuredModel != null) + fStructuredModel.releaseFromRead(); + } + } + } + + protected IModelManager getModelManager() { + IModelManagerPlugin plugin = (IModelManagerPlugin) Platform.getPlugin(IModelManagerPlugin.ID); + return plugin.getModelManager(); + } + + protected Point getWord(String string, int cursor) { + if (string == null) + return null; + + int wordStart = 0; + int wordEnd = string.length(); + + wordStart = string.lastIndexOf(SPACE, cursor - 1); + int temp = string.lastIndexOf(SINGLE_QUOTE, cursor - 1); + wordStart = Math.max(wordStart, temp); + temp = string.lastIndexOf(DOUBLE_QUOTE, cursor - 1); + wordStart = Math.max(wordStart, temp); + if (wordStart == -1) + wordStart = cursor; + else + wordStart++; + + wordEnd = string.indexOf(SPACE, cursor); + if (wordEnd == -1) + wordEnd = string.length(); + temp = string.indexOf(SINGLE_QUOTE, cursor); + if (temp == -1) + temp = string.length(); + wordEnd = Math.min(wordEnd, temp); + temp = string.indexOf(DOUBLE_QUOTE, cursor); + if (temp == -1) + temp = string.length(); + wordEnd = Math.min(wordEnd, temp); + if (wordEnd == string.length()) + wordEnd = cursor; + + if ((wordStart == wordEnd) && !isQuoted(string)) { + wordStart = 0; + wordEnd = string.length(); + } + + return new Point(wordStart, wordEnd); + } + + protected boolean isQuoted(String string) { + if ((string == null) || (string.length() < 2)) + return false; + + int lastIndex = string.length() - 1; + char firstChar = string.charAt(0); + char lastChar = string.charAt(lastIndex); + + return (((firstChar == SINGLE_QUOTE) && (lastChar == SINGLE_QUOTE)) || ((firstChar == DOUBLE_QUOTE) && (lastChar == DOUBLE_QUOTE))); + } + + protected void processElementAttrEqualsDoubleClicked2Times() { + int prevRegionOffset = fStructuredDocumentRegion.getStartOffset(fTextRegion) - 1; + ITextRegion prevRegion = fStructuredDocumentRegion.getRegionAtCharacterOffset(prevRegionOffset); + int nextRegionOffset = fStructuredDocumentRegion.getEndOffset(fTextRegion); + ITextRegion nextRegion = fStructuredDocumentRegion.getRegionAtCharacterOffset(nextRegionOffset); + + if ((prevRegion != null) && (prevRegion.getType() == XMLRegionContext.XML_TAG_ATTRIBUTE_NAME) && (nextRegion != null) && (nextRegion.getType() == XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE)) { + fStructuredTextViewer.setSelectedRange(fStructuredDocumentRegion.getStartOffset(prevRegion), nextRegion.getTextEnd() - prevRegion.getStart()); + } + } + + protected void processElementAttrNameDoubleClicked2Times() { + int nextRegionOffset = fStructuredDocumentRegion.getEndOffset(fTextRegion); + ITextRegion nextRegion = fStructuredDocumentRegion.getRegionAtCharacterOffset(nextRegionOffset); + + if (nextRegion != null) { + nextRegionOffset = fStructuredDocumentRegion.getEndOffset(nextRegion); + nextRegion = fStructuredDocumentRegion.getRegionAtCharacterOffset(nextRegionOffset); + if ((nextRegion != null) && (nextRegion.getType() == XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE)) { + fStructuredTextViewer.setSelectedRange(fStructuredDocumentRegion.getStartOffset(fTextRegion), nextRegion.getTextEnd() - fTextRegion.getStart()); + } else { + // attribute has no value + fStructuredTextViewer.setSelectedRange(fStructuredDocumentRegion.getStart(), fStructuredDocumentRegion.getLength()); + fDoubleClickCount = 0; + } + } + } + + protected void processElementAttrValueDoubleClicked() { + String regionText = fStructuredDocumentRegion.getText(fTextRegion); + + if (fDoubleClickCount == 1) { + Point word = getWord(regionText, fCaretPosition - fStructuredDocumentRegion.getStartOffset(fTextRegion)); + if (word.x == word.y) { // no word found; select whole region + fStructuredTextViewer.setSelectedRange(fStructuredDocumentRegion.getStartOffset(fTextRegion), regionText.length()); + fDoubleClickCount++; + } else + fStructuredTextViewer.setSelectedRange(fStructuredDocumentRegion.getStartOffset(fTextRegion) + word.x, word.y - word.x); + } else if (fDoubleClickCount == 2) { + if (isQuoted(regionText)) { + // ==> // Point word = getWord(regionText, fCaretPosition - + // fStructuredDocumentRegion.getStartOffset(fTextRegion)); + fStructuredTextViewer.setSelectedRange(fStructuredDocumentRegion.getStartOffset(fTextRegion), regionText.length()); + } else + processElementAttrValueDoubleClicked2Times(); + } else if (fDoubleClickCount == 3) { + if (isQuoted(regionText)) + processElementAttrValueDoubleClicked2Times(); + else { + fStructuredTextViewer.setSelectedRange(fStructuredDocumentRegion.getStart(), fStructuredDocumentRegion.getLength()); + fDoubleClickCount = 0; + } + } else { // fDoubleClickCount == 4 + fStructuredTextViewer.setSelectedRange(fStructuredDocumentRegion.getStart(), fStructuredDocumentRegion.getLength()); + fDoubleClickCount = 0; + } + } + + protected void processElementAttrValueDoubleClicked2Times() { + int prevRegionOffset = fStructuredDocumentRegion.getStartOffset(fTextRegion) - 1; + ITextRegion prevRegion = fStructuredDocumentRegion.getRegionAtCharacterOffset(prevRegionOffset); + + if (prevRegion != null) { + prevRegionOffset = fStructuredDocumentRegion.getStartOffset(prevRegion) - 1; + prevRegion = fStructuredDocumentRegion.getRegionAtCharacterOffset(prevRegionOffset); + if ((prevRegion != null) && (prevRegion.getType() == XMLRegionContext.XML_TAG_ATTRIBUTE_NAME)) { + fStructuredTextViewer.setSelectedRange(fStructuredDocumentRegion.getStartOffset(prevRegion), fTextRegion.getTextEnd() - prevRegion.getStart()); + } + } + } + + protected void processElementDoubleClicked() { + if (fTextRegion.getType() == XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE) + processElementAttrValueDoubleClicked(); // special handling for + // XML_TAG_ATTRIBUTE_VALUE + else { + if (fDoubleClickCount == 1) { + fStructuredTextViewer.setSelectedRange(fStructuredDocumentRegion.getStart() + fTextRegion.getStart(), fTextRegion.getTextLength()); + } else if (fDoubleClickCount == 2) { + if (fTextRegion.getType() == XMLRegionContext.XML_TAG_ATTRIBUTE_NAME) + processElementAttrNameDoubleClicked2Times(); + else if (fTextRegion.getType() == XMLRegionContext.XML_TAG_ATTRIBUTE_EQUALS) + processElementAttrEqualsDoubleClicked2Times(); + else { + fStructuredTextViewer.setSelectedRange(fStructuredDocumentRegion.getStart(), fStructuredDocumentRegion.getLength()); + fDoubleClickCount = 0; + } + } else { // fDoubleClickCount == 3 + fStructuredTextViewer.setSelectedRange(fStructuredDocumentRegion.getStart(), fStructuredDocumentRegion.getLength()); + fDoubleClickCount = 0; + } + } + } + + protected void processTextDoubleClicked() { + if (fDoubleClickCount == 1) { + super.doubleClicked(fStructuredTextViewer); + + Point selectedRange = fStructuredTextViewer.getSelectedRange(); + if ((selectedRange.x == fStructuredDocumentRegion.getStartOffset(fTextRegion)) && (selectedRange.y == fTextRegion.getTextLength())) + // only one word in region, skip one level of double click + // selection + fDoubleClickCount++; + } else if (fDoubleClickCount == 2) { + if (fTextRegion.getType() == XMLRegionContext.UNDEFINED) { + fStructuredTextViewer.setSelectedRange(fStructuredDocumentRegion.getStart(), fStructuredDocumentRegion.getLength()); + fDoubleClickCount = 0; + } else { + if (isQuoted(fStructuredDocumentRegion.getFullText(fTextRegion))) + fStructuredTextViewer.setSelectedRange(fStructuredDocumentRegion.getStartOffset(fTextRegion) + 1, fTextRegion.getTextLength() - 2); + else + fStructuredTextViewer.setSelectedRange(fStructuredDocumentRegion.getStartOffset(fTextRegion), fTextRegion.getTextLength()); + } + } else { + if ((fDoubleClickCount == 3) && isQuoted(fStructuredDocumentRegion.getFullText(fTextRegion))) + fStructuredTextViewer.setSelectedRange(fStructuredDocumentRegion.getStartOffset(fTextRegion), fTextRegion.getTextLength()); + else { + if ((fDoubleClickCount == 3) && isQuoted(fStructuredDocumentRegionText)) + fStructuredTextViewer.setSelectedRange(fStructuredDocumentRegion.getStart() + 1, fStructuredDocumentRegion.getLength() - 2); + else { + fStructuredTextViewer.setSelectedRange(fStructuredDocumentRegion.getStart(), fStructuredDocumentRegion.getLength()); + fDoubleClickCount = 0; + } + } + } + } + + public void setModel(IStructuredModel structuredModel) { + fStructuredModel = structuredModel; + } + + protected void updateDoubleClickCount(int caretPosition) { + if (fCaretPosition == caretPosition) { + if (fStructuredDocumentRegion != null) + fDoubleClickCount++; + else + fDoubleClickCount = 1; + } else { + fCaretPosition = caretPosition; + fDoubleClickCount = 1; + } + } + + protected void updateStructuredDocumentRegion() { + fStructuredDocumentRegion = fStructuredModel.getStructuredDocument().getRegionAtCharacterOffset(fCaretPosition); + if (fStructuredDocumentRegion != null) + fStructuredDocumentRegionText = fStructuredDocumentRegion.getText(); + else + fStructuredDocumentRegionText = ""; //$NON-NLS-1$ + } + + protected void updateTextRegion() { + if (fStructuredDocumentRegion != null) { + fTextRegion = fStructuredDocumentRegion.getRegionAtCharacterOffset(fCaretPosition); + // if fTextRegion is null, it means we are at just past the last + // fStructuredDocumentRegion, + // at the very end of the document, so we'll use the last text + // region in the document + if (fTextRegion == null) { + fTextRegion = fStructuredDocumentRegion.getRegionAtCharacterOffset(fCaretPosition - 1); + } + } else + fTextRegion = null; + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/extension/IDesignViewerSelectionManager.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/extension/IDesignViewerSelectionManager.java new file mode 100644 index 0000000000..5792dbf777 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/extension/IDesignViewerSelectionManager.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.extension; + +import org.eclipse.wst.sse.ui.ViewerSelectionManager; +import org.w3c.dom.Node; +import org.w3c.dom.ranges.Range; + + +/* + * This class is currently an internal class used by Quick Edit view. + */ +public interface IDesignViewerSelectionManager extends ViewerSelectionManager { + Node getFocusedNode(); + + Range getRange(); + + void pause(); + + void reset(); + + void resume(); +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/extension/IExtendedDesignEditor.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/extension/IExtendedDesignEditor.java new file mode 100644 index 0000000000..c73b66f47c --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/extension/IExtendedDesignEditor.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.extension; + +import org.eclipse.ui.IEditorInput; +import org.eclipse.wst.sse.core.IStructuredModel; +import org.eclipse.wst.sse.ui.extension.IExtendedMarkupEditorExtension; + + +/* + * This class is currently an internal class used by Quick Edit view. + */ +public interface IExtendedDesignEditor extends IExtendedMarkupEditorExtension { + + IEditorInput getActiveEditorInput(); + + IStructuredModel getActiveModel(); + + IDesignViewerSelectionManager getDesignViewerSelectionMediator(); + + IEditorInput getEditorInput(); + + IStructuredModel getModel(); +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/extensions/XMLSourceEditingTextTools.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/extensions/XMLSourceEditingTextTools.java new file mode 100644 index 0000000000..6d610cab75 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/extensions/XMLSourceEditingTextTools.java @@ -0,0 +1,143 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.extensions; + + + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.Platform; +import org.eclipse.wst.sse.core.IModelManager; +import org.eclipse.wst.sse.core.IModelManagerPlugin; +import org.eclipse.wst.sse.core.INodeAdapter; +import org.eclipse.wst.sse.core.INodeNotifier; +import org.eclipse.wst.sse.core.IStructuredModel; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.ui.extensions.breakpoint.NodeLocation; +import org.eclipse.wst.sse.ui.extensions.breakpoint.SourceEditingTextTools; +import org.eclipse.wst.xml.core.document.XMLModel; +import org.eclipse.wst.xml.core.document.XMLNode; +import org.eclipse.wst.xml.core.document.XMLText; +import org.w3c.dom.Document; +import org.w3c.dom.Node; + + +/** + * Implements SourceEditingTextTools interface + */ +public class XMLSourceEditingTextTools implements SourceEditingTextTools, INodeAdapter { + + protected class NodeLocationImpl implements NodeLocation { + private XMLNode node; + + public NodeLocationImpl(XMLNode xmlnode) { + super(); + node = xmlnode; + } + + public int getEndTagEndOffset() { + if (node.getEndStructuredDocumentRegion() != null) + return node.getEndStructuredDocumentRegion().getEndOffset(); + return -1; + } + + public int getEndTagStartOffset() { + if (node.getEndStructuredDocumentRegion() != null) + return node.getEndStructuredDocumentRegion().getStartOffset(); + return -1; + } + + public int getStartTagEndOffset() { + if (node.getStartStructuredDocumentRegion() != null) + return node.getStartStructuredDocumentRegion().getEndOffset(); + return -1; + } + + public int getStartTagStartOffset() { + if (node.getStartStructuredDocumentRegion() != null) + return node.getStartStructuredDocumentRegion().getStartOffset(); + return -1; + } + } + + /** + * @see org.eclipse.wst.sse.ui.extensions.SourceEditingTextTools#getDOMDocument(org.eclipse.core.resources.IMarker) + */ + public Document getDOMDocument(IMarker marker) { + if (marker == null) + return null; + + IResource res = marker.getResource(); + if (res == null || !(res instanceof IFile)) + return null; + + IModelManagerPlugin plugin = (IModelManagerPlugin) Platform.getPlugin(IModelManagerPlugin.ID); + IModelManager mm = plugin.getModelManager(); + IStructuredModel model = null; + try { + model = mm.getExistingModelForRead((IFile) res); + if (model == null || !(model instanceof XMLModel)) + return null; + + return ((XMLModel) model).getDocument(); + } finally { + if (model != null) + model.releaseFromRead(); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.ui.extensions.SourceEditingTextTools#getNodeLocation(org.w3c.dom.Node) + */ + public NodeLocation getNodeLocation(Node node) { + if (node.getNodeType() == Node.ELEMENT_NODE && node instanceof XMLNode) + return new NodeLocationImpl((XMLNode) node); + return null; + } + + public String getPageLanguage(Node node) { + return ""; //$NON-NLS-1$ + } + + /** + * @see org.eclipse.wst.sse.ui.extensions.SourceEditingTextTools#getStartOffset(org.w3c.dom.Node) + */ + public int getStartOffset(Node node) { + if (node == null || !(node instanceof XMLText)) + return -1; + + IStructuredDocumentRegion fnode = ((XMLText) node).getFirstStructuredDocumentRegion(); + return fnode.getStartOffset(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.core.core.INodeAdapter#isAdapterForType(java.lang.Object) + */ + public boolean isAdapterForType(Object type) { + return SourceEditingTextTools.class.equals(type); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.core.core.INodeAdapter#notifyChanged(org.eclipse.wst.sse.core.core.INodeNotifier, + * int, java.lang.Object, java.lang.Object, java.lang.Object, int) + */ + public void notifyChanged(INodeNotifier notifier, int eventType, Object changedFeature, Object oldValue, Object newValue, int pos) { + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/autoedit/StructuredAutoEditStrategyXML.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/autoedit/StructuredAutoEditStrategyXML.java new file mode 100644 index 0000000000..0d7f5a692e --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/autoedit/StructuredAutoEditStrategyXML.java @@ -0,0 +1,122 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.internal.autoedit; + +import org.eclipse.core.runtime.Platform; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.DocumentCommand; +import org.eclipse.jface.text.IDocument; +import org.eclipse.ui.texteditor.ITextEditorExtension3; +import org.eclipse.wst.sse.core.IModelManager; +import org.eclipse.wst.sse.core.IModelManagerPlugin; +import org.eclipse.wst.sse.core.IStructuredModel; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.ui.StructuredDocumentCommand; +import org.eclipse.wst.sse.ui.edit.util.BasicAutoEditStrategy; +import org.eclipse.wst.xml.core.document.XMLElement; +import org.eclipse.wst.xml.core.document.XMLNode; +import org.eclipse.wst.xml.ui.Logger; +import org.w3c.dom.Node; + + +public class StructuredAutoEditStrategyXML extends BasicAutoEditStrategy { + public void customizeDocumentCommand(IDocument document, DocumentCommand command) { + StructuredDocumentCommand structuredDocumentCommand = (StructuredDocumentCommand) command; + Object textEditor = getActiveTextEditor(); + if (!(textEditor instanceof ITextEditorExtension3 && ((ITextEditorExtension3) textEditor).getInsertMode() == ITextEditorExtension3.SMART_INSERT)) + return; + + IStructuredModel model = null; + try { + model = getModelManager().getExistingModelForRead(document); + if (model != null) { + if (structuredDocumentCommand.text != null) { + smartInsertForComment(structuredDocumentCommand, document, model); + smartInsertForEndTag(structuredDocumentCommand, document, model); + } + } + } finally { + if (model != null) + model.releaseFromRead(); + } + } + + private IModelManager getModelManager() { + + IModelManagerPlugin plugin = (IModelManagerPlugin) Platform.getPlugin(IModelManagerPlugin.ID); + return plugin.getModelManager(); + } + + private boolean isCommentNode(XMLNode node) { + return (node != null && node instanceof XMLElement && ((XMLElement) node).isCommentTag()); + } + + private boolean isDocumentNode(XMLNode node) { + return (node != null && node.getNodeType() == Node.DOCUMENT_NODE); + } + + protected boolean isEndTagRequired(XMLNode node) { + + if (node == null) + return false; + return node.isContainer(); + } + + protected boolean prefixedWith(IDocument document, int offset, String string) { + + try { + return document.getLength() >= string.length() && document.get(offset - string.length(), string.length()).equals(string); + } catch (BadLocationException e) { + Logger.logException(e); + return false; + } + } + + protected void smartInsertForComment(StructuredDocumentCommand structuredDocumentCommand, IDocument document, IStructuredModel model) { + try { + if (structuredDocumentCommand.text.equals("-") && document.getLength() >= 3 && document.get(structuredDocumentCommand.offset - 3, 3).equals("<!-")) { //$NON-NLS-1$ //$NON-NLS-2$ + structuredDocumentCommand.text += " "; //$NON-NLS-1$ + structuredDocumentCommand.doit = false; + structuredDocumentCommand.addCommand(structuredDocumentCommand.offset, 0, " -->", null); //$NON-NLS-1$ + } + } catch (BadLocationException e) { + Logger.logException(e); + } + + } + + protected void smartInsertForEndTag(StructuredDocumentCommand structuredDocumentCommand, IDocument document, IStructuredModel model) { + try { + if (structuredDocumentCommand.text.equals("/") && document.getLength() >= 1 && document.get(structuredDocumentCommand.offset - 1, 1).equals("<")) { //$NON-NLS-1$ //$NON-NLS-2$ + XMLNode parentNode = (XMLNode) ((XMLNode) model.getIndexedRegion(structuredDocumentCommand.offset - 1)).getParentNode(); + if (isCommentNode(parentNode)) { + // loop and find non comment node parent + while (parentNode != null && isCommentNode(parentNode)) { + parentNode = (XMLNode) parentNode.getParentNode(); + } + } + + if (!isDocumentNode(parentNode)) { + IStructuredDocumentRegion endTagStructuredDocumentRegion = parentNode.getEndStructuredDocumentRegion(); + if (endTagStructuredDocumentRegion == null) { + structuredDocumentCommand.text += parentNode.getNodeName(); + structuredDocumentCommand.text += ">"; //$NON-NLS-1$ + } + } + } + } catch (BadLocationException e) { + Logger.logException(e); + } + + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/correction/CorrectionProcessorXML.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/correction/CorrectionProcessorXML.java new file mode 100644 index 0000000000..bfb47cb15d --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/correction/CorrectionProcessorXML.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.internal.correction; + +import org.eclipse.ui.texteditor.ITextEditor; +import org.eclipse.wst.sse.ui.internal.correction.IQuickAssistProcessor; +import org.eclipse.wst.sse.ui.internal.correction.IQuickFixProcessor; +import org.eclipse.wst.sse.ui.internal.correction.StructuredCorrectionProcessor; + + +public class CorrectionProcessorXML extends StructuredCorrectionProcessor { + protected IQuickAssistProcessor fQuickAssistProcessor; + protected IQuickFixProcessor fQuickFixProcessor; + + public CorrectionProcessorXML(ITextEditor editor) { + super(editor); + } + + protected IQuickAssistProcessor getQuickAssistProcessor() { + if (fQuickAssistProcessor == null) + fQuickAssistProcessor = new QuickAssistProcessorXML(); + + return fQuickAssistProcessor; + } + + protected IQuickFixProcessor getQuickFixProcessor() { + if (fQuickFixProcessor == null) + fQuickFixProcessor = new QuickFixProcessorXML(); + + return fQuickFixProcessor; + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/correction/InsertRequiredAttrsQuickAssistProposal.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/correction/InsertRequiredAttrsQuickAssistProposal.java new file mode 100644 index 0000000000..1624d44452 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/correction/InsertRequiredAttrsQuickAssistProposal.java @@ -0,0 +1,175 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.internal.correction; + +import java.util.List; + +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.DocumentEvent; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.contentassist.ICompletionProposal; +import org.eclipse.jface.text.contentassist.ICompletionProposalExtension2; +import org.eclipse.jface.text.contentassist.IContextInformation; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.text.edits.InsertEdit; +import org.eclipse.text.edits.MultiTextEdit; +import org.eclipse.wst.common.contentmodel.CMAttributeDeclaration; +import org.eclipse.wst.sse.core.exceptions.SourceEditingRuntimeException; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.ui.StructuredTextViewer; +import org.eclipse.wst.sse.ui.internal.contentassist.ContentAssistUtils; +import org.eclipse.wst.xml.core.document.XMLNode; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; +import org.eclipse.wst.xml.ui.internal.editor.XMLEditorPluginImageHelper; +import org.eclipse.wst.xml.ui.internal.editor.XMLEditorPluginImages; +import org.eclipse.wst.xml.ui.nls.ResourceHandler; + + +public class InsertRequiredAttrsQuickAssistProposal implements ICompletionProposal, ICompletionProposalExtension2 { + private final List fRequiredAttrs; + + /** + * @param requiredAttrs + */ + public InsertRequiredAttrsQuickAssistProposal(List requiredAttrs) { + fRequiredAttrs = requiredAttrs; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.ICompletionProposal#apply(org.eclipse.jface.text.IDocument) + */ + public void apply(IDocument document) { + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension2#apply(org.eclipse.jface.text.ITextViewer, + * char, int, int) + */ + public void apply(ITextViewer viewer, char trigger, int stateMask, int offset) { + XMLNode node = (XMLNode) ContentAssistUtils.getNodeAt((StructuredTextViewer) viewer, offset); + IStructuredDocumentRegion startStructuredDocumentRegion = node.getStartStructuredDocumentRegion(); + int index = startStructuredDocumentRegion.getEndOffset(); + ITextRegion lastRegion = startStructuredDocumentRegion.getLastRegion(); + if (lastRegion.getType() == XMLRegionContext.XML_TAG_CLOSE) { + index--; + lastRegion = startStructuredDocumentRegion.getRegionAtCharacterOffset(index - 1); + } else if (lastRegion.getType() == XMLRegionContext.XML_EMPTY_TAG_CLOSE) { + index = index - 2; + lastRegion = startStructuredDocumentRegion.getRegionAtCharacterOffset(index - 1); + } + MultiTextEdit multiTextEdit = new MultiTextEdit(); + try { + for (int i = 0; i < fRequiredAttrs.size(); i++) { + CMAttributeDeclaration attrDecl = (CMAttributeDeclaration) fRequiredAttrs.get(i); + String requiredAttributeName = attrDecl.getAttrName(); + String defaultValue = attrDecl.getDefaultValue(); + if (defaultValue == null) + defaultValue = ""; //$NON-NLS-1$ + String nameAndDefaultValue = " "; //$NON-NLS-1$ + if (i == 0 && lastRegion.getLength() > lastRegion.getTextLength()) + nameAndDefaultValue = ""; //$NON-NLS-1$ + nameAndDefaultValue += requiredAttributeName + "=\"" + defaultValue + "\""; //$NON-NLS-1$//$NON-NLS-2$ + multiTextEdit.addChild(new InsertEdit(index, nameAndDefaultValue)); + // BUG3381: MultiTextEdit applies all child TextEdit's basing + // on offsets + // in the document before the first TextEdit, not after each + // child TextEdit. Therefore, do not need to advance the + // index. + //index += nameAndDefaultValue.length(); + } + multiTextEdit.apply(viewer.getDocument()); + } catch (BadLocationException e) { + throw new SourceEditingRuntimeException(e); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getAdditionalProposalInfo() + */ + public String getAdditionalProposalInfo() { + return ResourceHandler.getString("InsertRequiredAttrsQuickAssistProposal.0"); //$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getContextInformation() + */ + public IContextInformation getContextInformation() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getDisplayString() + */ + public String getDisplayString() { + return ResourceHandler.getString("InsertRequiredAttrsQuickAssistProposal.1"); //$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getImage() + */ + public Image getImage() { + // return JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_LOCAL); + return XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_ADD_CORRECTION); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getSelection(org.eclipse.jface.text.IDocument) + */ + public Point getSelection(IDocument document) { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension2#selected(org.eclipse.jface.text.ITextViewer, + * boolean) + */ + public void selected(ITextViewer viewer, boolean smartToggle) { + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension2#unselected(org.eclipse.jface.text.ITextViewer) + */ + public void unselected(ITextViewer viewer) { + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension2#validate(org.eclipse.jface.text.IDocument, + * int, org.eclipse.jface.text.DocumentEvent) + */ + public boolean validate(IDocument document, int offset, DocumentEvent event) { + return false; + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/correction/ProblemIDsXML.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/correction/ProblemIDsXML.java new file mode 100644 index 0000000000..4d0008bb7a --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/correction/ProblemIDsXML.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.internal.correction; + +public interface ProblemIDsXML { + int AttrsInEndTag = 3; + int AttrValueNotQuoted = 13; + int EmptyTag = 1; + int InvalidAttrValue = 11; + int MissingAttrValue = 4; + int MissingClosingBracket = 14; + int MissingEndTag = 2; + int MissingRequiredAttr = 12; + int NamespaceInPI = 8; + int NoAttrValue = 5; + int SpacesBeforePI = 7; + int SpacesBeforeTagName = 6; + int Unclassified = 0; + int UnknownAttr = 10; + int UnknownElement = 9; +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/correction/QuickAssistProcessorXML.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/correction/QuickAssistProcessorXML.java new file mode 100644 index 0000000000..b2f00fa8dd --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/correction/QuickAssistProcessorXML.java @@ -0,0 +1,169 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.internal.correction; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jface.text.contentassist.ICompletionProposal; +import org.eclipse.wst.common.contentmodel.CMAttributeDeclaration; +import org.eclipse.wst.common.contentmodel.CMElementDeclaration; +import org.eclipse.wst.common.contentmodel.CMNamedNodeMap; +import org.eclipse.wst.common.contentmodel.modelquery.ModelQuery; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.ui.StructuredTextViewer; +import org.eclipse.wst.sse.ui.internal.contentassist.ContentAssistUtils; +import org.eclipse.wst.sse.ui.internal.correction.IQuickAssistProcessor; +import org.eclipse.wst.xml.core.document.XMLNode; +import org.eclipse.wst.xml.core.modelquery.ModelQueryUtil; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + + +public class QuickAssistProcessorXML implements IQuickAssistProcessor { + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.ui.correction.IQuickAssistProcessor#canAssist(org.eclipse.wst.sse.core.text.IStructuredDocument, + * int) + */ + public boolean canAssist(StructuredTextViewer viewer, int offset) { + return true; + } + + /** + * @param proposals + * @param viewer + * @param offset + */ + protected void getInsertRequiredAttrs(ArrayList proposals, StructuredTextViewer viewer, int offset) { + XMLNode node = (XMLNode) ContentAssistUtils.getNodeAt(viewer, offset); + if (node != null && node.getNodeType() == Node.ELEMENT_NODE) { + IStructuredDocumentRegion startStructuredDocumentRegion = node.getStartStructuredDocumentRegion(); + if (startStructuredDocumentRegion != null && startStructuredDocumentRegion.containsOffset(offset)) { + XMLNode cursorNode = (XMLNode) ContentAssistUtils.getNodeAt(viewer, offset); + List requiredAttrs = getRequiredAttrs(cursorNode); + if (requiredAttrs.size() > 0) { + NamedNodeMap currentAttrs = node.getAttributes(); + List insertAttrs = new ArrayList(); + if (currentAttrs.getLength() == 0) + insertAttrs.addAll(requiredAttrs); + else { + for (int i = 0; i < requiredAttrs.size(); i++) { + String requiredAttrName = ((CMAttributeDeclaration) requiredAttrs.get(i)).getAttrName(); + boolean found = false; + for (int j = 0; j < currentAttrs.getLength(); j++) { + String currentAttrName = currentAttrs.item(j).getNodeName(); + if (requiredAttrName.compareToIgnoreCase(currentAttrName) == 0) { + found = true; + break; + } + } + if (!found) + insertAttrs.add(requiredAttrs.get(i)); + } + } + if (insertAttrs.size() > 0) + proposals.add(new InsertRequiredAttrsQuickAssistProposal(insertAttrs)); + } + } + } + } + + /** + * @param proposals + * @param viewer + * @param offset + */ + protected void getLocalRenameQuickAssistProposal(ArrayList proposals, StructuredTextViewer viewer, int offset) { + XMLNode node = (XMLNode) ContentAssistUtils.getNodeAt(viewer, offset); + IStructuredDocumentRegion startStructuredDocumentRegion = node == null ? null : node.getStartStructuredDocumentRegion(); + IStructuredDocumentRegion endStructuredDocumentRegion = node == null ? null : node.getEndStructuredDocumentRegion(); + + ITextRegion region = null; + int regionTextEndOffset = 0; + if (startStructuredDocumentRegion != null && startStructuredDocumentRegion.containsOffset(offset)) { + region = startStructuredDocumentRegion.getRegionAtCharacterOffset(offset); + regionTextEndOffset = startStructuredDocumentRegion.getTextEndOffset(region); + } else if (endStructuredDocumentRegion != null && endStructuredDocumentRegion.containsOffset(offset)) { + region = endStructuredDocumentRegion.getRegionAtCharacterOffset(offset); + regionTextEndOffset = endStructuredDocumentRegion.getTextEndOffset(region); + } + + if (region != null && (region.getType() == XMLRegionContext.XML_TAG_NAME || region.getType() == XMLRegionContext.XML_TAG_ATTRIBUTE_NAME) && offset <= regionTextEndOffset) + proposals.add(new RenameInFileQuickAssistProposal()); + } + + protected ModelQuery getModelQuery(Node node) { + if (node.getNodeType() == Node.DOCUMENT_NODE) { + return ModelQueryUtil.getModelQuery((Document) node); + } else { + return ModelQueryUtil.getModelQuery(node.getOwnerDocument()); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.ui.correction.IQuickAssistProcessor#getProposals(org.eclipse.wst.sse.core.text.IStructuredDocument, + * int) + */ + public ICompletionProposal[] getProposals(StructuredTextViewer viewer, int offset) throws CoreException { + ArrayList proposals = new ArrayList(); + + getLocalRenameQuickAssistProposal(proposals, viewer, offset); + getSurroundWithNewElementQuickAssistProposal(proposals, viewer, offset); + getInsertRequiredAttrs(proposals, viewer, offset); + + return (ICompletionProposal[]) proposals.toArray(new ICompletionProposal[proposals.size()]); + } + + protected List getRequiredAttrs(Node node) { + List result = new ArrayList(); + + ModelQuery modelQuery = getModelQuery(node); + if (modelQuery != null) { + CMElementDeclaration elementDecl = modelQuery.getCMElementDeclaration((Element) node); + if (elementDecl != null) { + CMNamedNodeMap attrMap = elementDecl.getAttributes(); + Iterator it = attrMap.iterator(); + CMAttributeDeclaration attr = null; + while (it.hasNext()) { + attr = (CMAttributeDeclaration) it.next(); + if (attr.getUsage() == CMAttributeDeclaration.REQUIRED) { + result.add(attr); + } + } + } + } + + return result; + } + + /** + * @param proposals + * @param viewer + * @param offset + */ + protected void getSurroundWithNewElementQuickAssistProposal(ArrayList proposals, StructuredTextViewer viewer, int offset) { + XMLNode node = (XMLNode) ContentAssistUtils.getNodeAt(viewer, offset); + if (node != null) + proposals.add(new SurroundWithNewElementQuickAssistProposal()); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/correction/QuickFixProcessorXML.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/correction/QuickFixProcessorXML.java new file mode 100644 index 0000000000..27444d8067 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/correction/QuickFixProcessorXML.java @@ -0,0 +1,148 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.internal.correction; + +import java.util.ArrayList; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jface.text.contentassist.CompletionProposal; +import org.eclipse.jface.text.contentassist.ICompletionProposal; +import org.eclipse.jface.text.source.Annotation; +import org.eclipse.swt.graphics.Image; +import org.eclipse.wst.sse.ui.internal.correction.IQuickFixProcessor; +import org.eclipse.wst.sse.ui.internal.reconcile.TemporaryAnnotation; +import org.eclipse.wst.xml.ui.internal.editor.XMLEditorPluginImageHelper; +import org.eclipse.wst.xml.ui.internal.editor.XMLEditorPluginImages; +import org.eclipse.wst.xml.ui.nls.ResourceHandler; + + +public class QuickFixProcessorXML implements IQuickFixProcessor { + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.ui.correction.IQuickFixProcessor#canFix(int) + */ + public boolean canFix(Annotation annotation) { + boolean result = false; + + if (annotation instanceof TemporaryAnnotation) { + TemporaryAnnotation tempAnnotation = (TemporaryAnnotation) annotation; + int problemID = tempAnnotation.getProblemID(); + switch (problemID) { + case ProblemIDsXML.EmptyTag : + case ProblemIDsXML.MissingEndTag : + case ProblemIDsXML.AttrsInEndTag : + case ProblemIDsXML.MissingAttrValue : + case ProblemIDsXML.NoAttrValue : + case ProblemIDsXML.SpacesBeforeTagName : + case ProblemIDsXML.SpacesBeforePI : + case ProblemIDsXML.NamespaceInPI : + case ProblemIDsXML.UnknownElement : + case ProblemIDsXML.UnknownAttr : + case ProblemIDsXML.InvalidAttrValue : + case ProblemIDsXML.MissingRequiredAttr : + case ProblemIDsXML.AttrValueNotQuoted : + case ProblemIDsXML.MissingClosingBracket : + result = true; + } + } + + return result; + } + + public Image getImage() { + //return + // JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); + return XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_CORRECTION_CHANGE); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.ui.correction.IQuickFixProcessor#getProposals(org.eclipse.wst.sse.ui.internal.reconcile.TemporaryAnnotation) + */ + public ICompletionProposal[] getProposals(Annotation annotation) throws CoreException { + ArrayList proposals = new ArrayList(); + + if (annotation instanceof TemporaryAnnotation) { + TemporaryAnnotation tempAnnotation = (TemporaryAnnotation) annotation; + int problemID = tempAnnotation.getProblemID(); + switch (problemID) { + case ProblemIDsXML.EmptyTag : + proposals.add(new CompletionProposal("", tempAnnotation.getPosition().getOffset(), tempAnnotation.getPosition().getLength(), 0, getImage(), ResourceHandler.getString("QuickFixProcessorXML.0"), null, "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + break; + case ProblemIDsXML.MissingEndTag : + String tagName = (String) ((Object[]) tempAnnotation.getAdditionalFixInfo())[0]; + String tagClose = (String) ((Object[]) tempAnnotation.getAdditionalFixInfo())[1]; + int tagCloseOffset = ((Integer) ((Object[]) tempAnnotation.getAdditionalFixInfo())[2]).intValue(); + int startTagEndOffset = ((Integer) ((Object[]) tempAnnotation.getAdditionalFixInfo())[3]).intValue(); + int firstChildStartOffset = ((Integer) ((Object[]) tempAnnotation.getAdditionalFixInfo())[4]).intValue(); + int endOffset = ((Integer) ((Object[]) tempAnnotation.getAdditionalFixInfo())[5]).intValue(); + proposals.add(new CompletionProposal(tagClose, tagCloseOffset, 0, 0, getImage(), ResourceHandler.getString("QuickFixProcessorXML.1"), null, "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + proposals.add(new CompletionProposal("", tempAnnotation.getPosition().getOffset(), startTagEndOffset - tempAnnotation.getPosition().getOffset(), 0, getImage(), ResourceHandler.getString("QuickFixProcessorXML.2"), null, "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + proposals.add(new CompletionProposal("</" + tagName + ">", firstChildStartOffset, 0, 0, getImage(), ResourceHandler.getString("QuickFixProcessorXML.3"), null, "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + proposals.add(new CompletionProposal("</" + tagName + ">", endOffset, 0, 0, getImage(), ResourceHandler.getString("QuickFixProcessorXML.4"), null, "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + break; + case ProblemIDsXML.AttrsInEndTag : + proposals.add(new CompletionProposal("", tempAnnotation.getPosition().getOffset(), tempAnnotation.getPosition().getLength(), 0, getImage(), ResourceHandler.getString("QuickFixProcessorXML.5"), null, "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + break; + case ProblemIDsXML.MissingAttrValue : + String defaultAttrValue = (String) ((Object[]) tempAnnotation.getAdditionalFixInfo())[0]; + int insertOffset = ((Integer) ((Object[]) tempAnnotation.getAdditionalFixInfo())[1]).intValue(); + proposals.add(new CompletionProposal("\"" + defaultAttrValue + "\"", tempAnnotation.getPosition().getOffset() + tempAnnotation.getPosition().getLength() + insertOffset, 0, defaultAttrValue.length() + 2, getImage(), ResourceHandler.getString("QuickFixProcessorXML.6"), null, "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + proposals.add(new CompletionProposal("", tempAnnotation.getPosition().getOffset(), tempAnnotation.getPosition().getLength(), 0, getImage(), ResourceHandler.getString("QuickFixProcessorXML.7"), null, "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + break; + case ProblemIDsXML.NoAttrValue : + defaultAttrValue = (String) tempAnnotation.getAdditionalFixInfo(); + proposals.add(new CompletionProposal("=\"" + defaultAttrValue + "\"", tempAnnotation.getPosition().getOffset() + tempAnnotation.getPosition().getLength(), 0, defaultAttrValue.length() + 3, getImage(), ResourceHandler.getString("QuickFixProcessorXML.6"), null, "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + proposals.add(new CompletionProposal("", tempAnnotation.getPosition().getOffset(), tempAnnotation.getPosition().getLength(), 0, getImage(), ResourceHandler.getString("QuickFixProcessorXML.7"), null, "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + break; + case ProblemIDsXML.SpacesBeforeTagName : + proposals.add(new CompletionProposal("", tempAnnotation.getPosition().getOffset(), tempAnnotation.getPosition().getLength(), 0, getImage(), ResourceHandler.getString("QuickFixProcessorXML.8"), null, "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + break; + case ProblemIDsXML.SpacesBeforePI : + proposals.add(new CompletionProposal("", tempAnnotation.getPosition().getOffset(), tempAnnotation.getPosition().getLength(), 0, getImage(), ResourceHandler.getString("QuickFixProcessorXML.9"), null, "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + break; + case ProblemIDsXML.NamespaceInPI : + proposals.add(new CompletionProposal("", tempAnnotation.getPosition().getOffset(), tempAnnotation.getPosition().getLength(), 0, getImage(), ResourceHandler.getString("QuickFixProcessorXML.10"), null, "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + break; + case ProblemIDsXML.UnknownElement : + proposals.add(new RemoveUnknownElementQuickFixProposal(tempAnnotation.getAdditionalFixInfo(), getImage(), ResourceHandler.getString("QuickFixProcessorXML.11"))); //$NON-NLS-1$ + proposals.add(new RenameInFileQuickAssistProposal()); + break; + case ProblemIDsXML.UnknownAttr : + proposals.add(new CompletionProposal("", tempAnnotation.getPosition().getOffset(), tempAnnotation.getPosition().getLength(), 0, getImage(), ResourceHandler.getString("QuickFixProcessorXML.7"), null, "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + proposals.add(new RenameInFileQuickAssistProposal()); + break; + case ProblemIDsXML.InvalidAttrValue : + proposals.add(new CompletionProposal("", tempAnnotation.getPosition().getOffset(), tempAnnotation.getPosition().getLength(), 0, getImage(), ResourceHandler.getString("QuickFixProcessorXML.12"), null, "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + break; + case ProblemIDsXML.MissingRequiredAttr : + String requiredAttr = (String) ((Object[]) tempAnnotation.getAdditionalFixInfo())[0]; + insertOffset = ((Integer) ((Object[]) tempAnnotation.getAdditionalFixInfo())[1]).intValue(); + proposals.add(new CompletionProposal(requiredAttr, tempAnnotation.getPosition().getOffset() + insertOffset, 0, requiredAttr.length(), getImage(), ResourceHandler.getString("QuickFixProcessorXML.13"), null, "")); //$NON-NLS-1$ //$NON-NLS-2$ + break; + case ProblemIDsXML.AttrValueNotQuoted : + String attrValue = (String) tempAnnotation.getAdditionalFixInfo(); + proposals.add(new CompletionProposal("\"" + attrValue + "\"", tempAnnotation.getPosition().getOffset(), tempAnnotation.getPosition().getLength(), attrValue.length() + 2, getImage(), ResourceHandler.getString("QuickFixProcessorXML.14"), null, "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + break; + case ProblemIDsXML.MissingClosingBracket : + proposals.add(new CompletionProposal(">", tempAnnotation.getPosition().getOffset() + tempAnnotation.getPosition().getLength(), 0, 1, getImage(), ResourceHandler.getString("QuickFixProcessorXML.15"), null, "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + break; + } + } + + return (ICompletionProposal[]) proposals.toArray(new ICompletionProposal[proposals.size()]); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/correction/RemoveUnknownElementQuickFixProposal.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/correction/RemoveUnknownElementQuickFixProposal.java new file mode 100644 index 0000000000..909b06a151 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/correction/RemoveUnknownElementQuickFixProposal.java @@ -0,0 +1,162 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.internal.correction; + +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.DocumentEvent; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.contentassist.ICompletionProposal; +import org.eclipse.jface.text.contentassist.ICompletionProposalExtension2; +import org.eclipse.jface.text.contentassist.IContextInformation; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.text.edits.DeleteEdit; +import org.eclipse.text.edits.MalformedTreeException; +import org.eclipse.text.edits.MultiTextEdit; +import org.eclipse.wst.sse.core.exceptions.SourceEditingRuntimeException; +import org.eclipse.wst.xml.ui.nls.ResourceHandler; + + +public class RemoveUnknownElementQuickFixProposal implements ICompletionProposal, ICompletionProposalExtension2 { + private Object fAdditionalFixInfo = null; + private String fDisplayString; + private Image fImage; + private Point fSelection; // initialized by apply() + + /** + * @param additionalFixInfo + * @param image + * @param string + */ + public RemoveUnknownElementQuickFixProposal(Object additionalFixInfo, Image image, String displayString) { + fAdditionalFixInfo = additionalFixInfo; + fImage = image; + fDisplayString = displayString; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.ICompletionProposal#apply(org.eclipse.jface.text.IDocument) + */ + public void apply(IDocument document) { + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension2#apply(org.eclipse.jface.text.ITextViewer, + * char, int, int) + */ + public void apply(ITextViewer viewer, char trigger, int stateMask, int offset) { + int startTagOffset = ((Integer) ((Object[]) fAdditionalFixInfo)[0]).intValue(); + int startTagLength = ((Integer) ((Object[]) fAdditionalFixInfo)[1]).intValue(); + int endTagOffset = ((Integer) ((Object[]) fAdditionalFixInfo)[2]).intValue(); + int endTagLength = ((Integer) ((Object[]) fAdditionalFixInfo)[3]).intValue(); + + MultiTextEdit multiTextEdit = new MultiTextEdit(); + if (endTagOffset != -1) { + multiTextEdit.addChild(new DeleteEdit(endTagOffset, endTagLength)); + fSelection = new Point(endTagOffset, 0); + } + if (startTagOffset != -1) { + multiTextEdit.addChild(new DeleteEdit(startTagOffset, startTagLength)); + fSelection = new Point(startTagOffset, 0); + } + + try { + multiTextEdit.apply(viewer.getDocument()); + } catch (MalformedTreeException e) { + throw new SourceEditingRuntimeException(e); + } catch (BadLocationException e) { + throw new SourceEditingRuntimeException(e); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getAdditionalProposalInfo() + */ + public String getAdditionalProposalInfo() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getContextInformation() + */ + public IContextInformation getContextInformation() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getDisplayString() + */ + public String getDisplayString() { + if (fDisplayString == null) + fDisplayString = ResourceHandler.getString("QuickFixProcessorXML.11"); //$NON-NLS-1$ + + return fDisplayString; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getImage() + */ + public Image getImage() { + return fImage; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getSelection(org.eclipse.jface.text.IDocument) + */ + public Point getSelection(IDocument document) { + return fSelection; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension2#selected(org.eclipse.jface.text.ITextViewer, + * boolean) + */ + public void selected(ITextViewer viewer, boolean smartToggle) { + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension2#unselected(org.eclipse.jface.text.ITextViewer) + */ + public void unselected(ITextViewer viewer) { + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension2#validate(org.eclipse.jface.text.IDocument, + * int, org.eclipse.jface.text.DocumentEvent) + */ + public boolean validate(IDocument document, int offset, DocumentEvent event) { + return false; + } + +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/correction/RenameInFileQuickAssistProposal.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/correction/RenameInFileQuickAssistProposal.java new file mode 100644 index 0000000000..c1e655f9f5 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/correction/RenameInFileQuickAssistProposal.java @@ -0,0 +1,183 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.internal.correction; + +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.DocumentEvent; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.contentassist.ICompletionProposal; +import org.eclipse.jface.text.contentassist.ICompletionProposalExtension2; +import org.eclipse.jface.text.contentassist.IContextInformation; +import org.eclipse.jface.text.link.LinkedModeModel; +import org.eclipse.jface.text.link.LinkedModeUI; +import org.eclipse.jface.text.link.LinkedPosition; +import org.eclipse.jface.text.link.LinkedPositionGroup; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.ui.texteditor.link.EditorLinkedModeUI; +import org.eclipse.wst.sse.core.exceptions.SourceEditingRuntimeException; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.ui.StructuredTextViewer; +import org.eclipse.wst.sse.ui.internal.contentassist.ContentAssistUtils; +import org.eclipse.wst.xml.core.document.XMLNode; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; +import org.eclipse.wst.xml.ui.internal.editor.XMLEditorPluginImageHelper; +import org.eclipse.wst.xml.ui.internal.editor.XMLEditorPluginImages; +import org.eclipse.wst.xml.ui.nls.ResourceHandler; + + +public class RenameInFileQuickAssistProposal implements ICompletionProposal, ICompletionProposalExtension2 { + protected IRegion fSelectedRegion; // initialized by apply() + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.ICompletionProposal#apply(org.eclipse.jface.text.IDocument) + */ + public void apply(IDocument document) { + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension2#apply(org.eclipse.jface.text.ITextViewer, + * char, int, int) + */ + public void apply(ITextViewer viewer, char trigger, int stateMask, int offset) { + IDocument document = viewer.getDocument(); + LinkedPositionGroup group = new LinkedPositionGroup(); + try { + if (viewer instanceof StructuredTextViewer) { + XMLNode node = (XMLNode) ContentAssistUtils.getNodeAt((StructuredTextViewer) viewer, offset); + IStructuredDocumentRegion startStructuredDocumentRegion = node.getStartStructuredDocumentRegion(); + ITextRegion region = (startStructuredDocumentRegion == null) ? null : startStructuredDocumentRegion.getRegionAtCharacterOffset(offset); + if (region != null) { + group.addPosition(new LinkedPosition(document, startStructuredDocumentRegion.getStartOffset() + region.getStart(), region.getTextLength(), 0)); + + if (region.getType() == XMLRegionContext.XML_TAG_NAME && node.getEndStructuredDocumentRegion() != null) { + region = node.getEndStructuredDocumentRegion().getRegions().get(1); + if (region != null) + group.addPosition(new LinkedPosition(document, node.getEndStructuredDocumentRegion().getStartOffset() + region.getStart(), region.getTextLength(), 1)); + } + } else { + IStructuredDocumentRegion endStructuredDocumentRegion = node.getEndStructuredDocumentRegion(); + region = (endStructuredDocumentRegion == null) ? null : endStructuredDocumentRegion.getRegionAtCharacterOffset(offset); + if (region != null) { + if (region.getType() == XMLRegionContext.XML_TAG_NAME && node.getStartStructuredDocumentRegion() != null) { + ITextRegion startTagNameRegion = node.getStartStructuredDocumentRegion().getRegions().get(1); + if (region != null) { + group.addPosition(new LinkedPosition(document, node.getStartStructuredDocumentRegion().getStartOffset() + startTagNameRegion.getStart(), startTagNameRegion.getTextLength(), 0)); + group.addPosition(new LinkedPosition(document, endStructuredDocumentRegion.getStartOffset() + region.getStart(), region.getTextLength(), 1)); + } + } else + group.addPosition(new LinkedPosition(document, endStructuredDocumentRegion.getStartOffset() + region.getStart(), region.getTextLength(), 0)); + } + } + + // TODO CompletionProposalPopup#insertProposal() calls + // IRewriteTarget.beginCompoundChange() + // which disables redraw in ITextViewer. Workaround for now. + ((StructuredTextViewer) viewer).setRedraw(true); + } + + LinkedModeModel linkedModeModel = new LinkedModeModel(); + linkedModeModel.addGroup(group); + linkedModeModel.forceInstall(); + + LinkedModeUI ui = new EditorLinkedModeUI(linkedModeModel, viewer); + ui.setExitPosition(viewer, offset, 0, LinkedPositionGroup.NO_STOP); + ui.enter(); + + fSelectedRegion = ui.getSelectedRegion(); + } catch (BadLocationException e) { + throw new SourceEditingRuntimeException(e); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getAdditionalProposalInfo() + */ + public String getAdditionalProposalInfo() { + return ResourceHandler.getString("RenameInFileQuickAssistProposal.0"); //$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getContextInformation() + */ + public IContextInformation getContextInformation() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getDisplayString() + */ + public String getDisplayString() { + return ResourceHandler.getString("RenameInFileQuickAssistProposal.1"); //$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getImage() + */ + public Image getImage() { + // return JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_LOCAL); + return XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_LOCAL_VARIABLE); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getSelection(org.eclipse.jface.text.IDocument) + */ + public Point getSelection(IDocument document) { + return new Point(fSelectedRegion.getOffset(), fSelectedRegion.getLength()); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension2#selected(org.eclipse.jface.text.ITextViewer, + * boolean) + */ + public void selected(ITextViewer viewer, boolean smartToggle) { + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension2#unselected(org.eclipse.jface.text.ITextViewer) + */ + public void unselected(ITextViewer viewer) { + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension2#validate(org.eclipse.jface.text.IDocument, + * int, org.eclipse.jface.text.DocumentEvent) + */ + public boolean validate(IDocument document, int offset, DocumentEvent event) { + return false; + } + +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/correction/SurroundWithNewElementQuickAssistProposal.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/correction/SurroundWithNewElementQuickAssistProposal.java new file mode 100644 index 0000000000..07dca4d9ef --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/correction/SurroundWithNewElementQuickAssistProposal.java @@ -0,0 +1,108 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.internal.correction; + +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.swt.graphics.Image; +import org.eclipse.text.edits.InsertEdit; +import org.eclipse.text.edits.MalformedTreeException; +import org.eclipse.text.edits.MultiTextEdit; +import org.eclipse.wst.sse.core.exceptions.SourceEditingRuntimeException; +import org.eclipse.wst.sse.core.format.IStructuredFormatProcessor; +import org.eclipse.wst.sse.ui.StructuredTextViewer; +import org.eclipse.wst.sse.ui.internal.contentassist.ContentAssistUtils; +import org.eclipse.wst.xml.core.document.XMLNode; +import org.eclipse.wst.xml.core.format.FormatProcessorXML; +import org.eclipse.wst.xml.ui.internal.editor.XMLEditorPluginImageHelper; +import org.eclipse.wst.xml.ui.internal.editor.XMLEditorPluginImages; +import org.eclipse.wst.xml.ui.nls.ResourceHandler; +import org.w3c.dom.Node; + + +public class SurroundWithNewElementQuickAssistProposal extends RenameInFileQuickAssistProposal { + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.ICompletionProposalExtension2#apply(org.eclipse.jface.text.ITextViewer, + * char, int, int) + */ + public void apply(ITextViewer viewer, char trigger, int stateMask, int offset) { + try { + int startTagOffset = offset; + int endTagOffset = offset + viewer.getSelectedRange().y; + + // surround the node if no selection + if (startTagOffset == endTagOffset) { + XMLNode cursorNode = (XMLNode) ContentAssistUtils.getNodeAt((StructuredTextViewer) viewer, offset); + // use parent node if text node is empty + if (cursorNode.getNodeType() == Node.TEXT_NODE && cursorNode.getNodeValue().trim().length() == 0) + cursorNode = (XMLNode) cursorNode.getParentNode(); + + startTagOffset = cursorNode.getStartOffset(); + endTagOffset = cursorNode.getEndOffset(); + } + + // insert new element + MultiTextEdit multiTextEdit = new MultiTextEdit(); + // element tag name cannot be DBCS, do not translate "<element>" + // and "</element>" + multiTextEdit.addChild(new InsertEdit(startTagOffset, "<element>")); //$NON-NLS-1$ + multiTextEdit.addChild(new InsertEdit(endTagOffset, "</element>")); //$NON-NLS-1$ + multiTextEdit.apply(viewer.getDocument()); + + // get new element node + XMLNode newElementNode = (XMLNode) ContentAssistUtils.getNodeAt((StructuredTextViewer) viewer, startTagOffset); + + // format new element + IStructuredFormatProcessor formatProcessor = new FormatProcessorXML(); + formatProcessor.formatNode(newElementNode); + + // rename new element + super.apply(viewer, trigger, stateMask, newElementNode.getStartOffset() + 1); + } catch (MalformedTreeException e) { + throw new SourceEditingRuntimeException(e); + } catch (BadLocationException e) { + throw new SourceEditingRuntimeException(e); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getAdditionalProposalInfo() + */ + public String getAdditionalProposalInfo() { + return ResourceHandler.getString("SurroundWithNewElementQuickAssistProposal.0"); //$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getDisplayString() + */ + public String getDisplayString() { + return ResourceHandler.getString("SurroundWithNewElementQuickAssistProposal.1"); //$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.contentassist.ICompletionProposal#getImage() + */ + public Image getImage() { + // return JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_LOCAL); + return XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_ADD_CORRECTION); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/editor/IHelpContextIds.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/editor/IHelpContextIds.java new file mode 100644 index 0000000000..e4c41c4826 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/editor/IHelpContextIds.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.internal.editor; + +import org.eclipse.wst.xml.ui.XMLEditorPlugin; + +/** + * Help context ids for the XML Source Editor. + * <p> + * This interface contains constants only; it is not intended to be + * implemented. + * </p> + * + */ +public interface IHelpContextIds { + // org.eclipse.wst.xml.ui. + public static final String PREFIX = XMLEditorPlugin.ID + "."; //$NON-NLS-1$ + + // XML Source page editor + public static final String XML_SOURCEVIEW_HELPID = PREFIX + "exml0000"; //$NON-NLS-1$ + + // XML Files Preference page + public static final String XML_PREFWEBX_FILES_HELPID = PREFIX + "webx0060"; //$NON-NLS-1$ + // XML Source Preference page + public static final String XML_PREFWEBX_SOURCE_HELPID = PREFIX + "webx0061"; //$NON-NLS-1$ + // XML Styles Preference page + public static final String XML_PREFWEBX_STYLES_HELPID = PREFIX + "webx0062"; //$NON-NLS-1$ + // XML Templates Preference page + public static final String XML_PREFWEBX_TEMPLATES_HELPID = PREFIX + "webx0063"; //$NON-NLS-1$ + + // XML Cleanup dialog + public static final String CLEANUP_XML_HELPID = PREFIX + "xmlm1200"; //$NON-NLS-1$ +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/editor/XMLEditorPluginImageHelper.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/editor/XMLEditorPluginImageHelper.java new file mode 100644 index 0000000000..4fe20d3b42 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/editor/XMLEditorPluginImageHelper.java @@ -0,0 +1,155 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.internal.editor; + +import java.util.HashMap; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.resource.ImageRegistry; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.swt.graphics.Image; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.eclipse.wst.xml.ui.XMLEditorPlugin; + + +/** + * Helper class to handle images provided by this plug-in. + * + * NOTE: For internal use only. For images used externally, please use the + * Shared***ImageHelper class instead. + * + * @author amywu + */ +public class XMLEditorPluginImageHelper { + private static XMLEditorPluginImageHelper instance = null; + + /** + * Gets the instance. + * + * @return Returns a XMLEditorPluginImageHelper + */ + public synchronized static XMLEditorPluginImageHelper getInstance() { + if (instance == null) + instance = new XMLEditorPluginImageHelper(); + return instance; + } + + // save a descriptor for each image + private HashMap fImageDescRegistry = null; + private final String PLUGINID = XMLEditorPlugin.ID; + + /** + * Creates an image from the given resource and adds the image to the + * image registry. + * + * @param resource + * @return Image + */ + private Image createImage(String resource) { + ImageDescriptor desc = getImageDescriptor(resource); + Image image = null; + + if (desc != null) { + image = desc.createImage(); + // dont add the missing image descriptor image to the image + // registry + if (!desc.equals(ImageDescriptor.getMissingImageDescriptor())) + getImageRegistry().put(resource, image); + } + return image; + } + + /** + * Creates an image descriptor from the given imageFilePath and adds the + * image descriptor to the image descriptor registry. If an image + * descriptor could not be created, the default "missing" image descriptor + * is returned but not added to the image descriptor registry. + * + * @param imageFilePath + * @return ImageDescriptor image descriptor for imageFilePath or default + * "missing" image descriptor if resource could not be found + */ + private ImageDescriptor createImageDescriptor(String imageFilePath) { + ImageDescriptor imageDescriptor = AbstractUIPlugin.imageDescriptorFromPlugin(PLUGINID, imageFilePath); + if (imageDescriptor != null) { + getImageDescriptorRegistry().put(imageFilePath, imageDescriptor); + } else { + imageDescriptor = ImageDescriptor.getMissingImageDescriptor(); + } + + return imageDescriptor; + } + + /** + * Retrieves the image associated with resource from the image registry. + * If the image cannot be retrieved, attempt to find and load the image at + * the location specified in resource. + * + * @param resource + * the image to retrieve + * @return Image the image associated with resource or null if one could + * not be found + */ + public Image getImage(String resource) { + Image image = getImageRegistry().get(resource); + if (image == null) { + // create an image + image = createImage(resource); + } + return image; + } + + /** + * Retrieves the image descriptor associated with resource from the image + * descriptor registry. If the image descriptor cannot be retrieved, + * attempt to find and load the image descriptor at the location specified + * in resource. + * + * @param resource + * the image descriptor to retrieve + * @return ImageDescriptor the image descriptor assocated with resource or + * the default "missing" image descriptor if one could not be + * found + */ + public ImageDescriptor getImageDescriptor(String resource) { + ImageDescriptor imageDescriptor = null; + Object o = getImageDescriptorRegistry().get(resource); + if (o == null) { + //create a descriptor + imageDescriptor = createImageDescriptor(resource); + } else { + imageDescriptor = (ImageDescriptor) o; + } + return imageDescriptor; + } + + /** + * Returns the image descriptor registry for this plugin. + * + * @return HashMap - image descriptor registry for this plugin + */ + private HashMap getImageDescriptorRegistry() { + if (fImageDescRegistry == null) + fImageDescRegistry = new HashMap(); + return fImageDescRegistry; + } + + /** + * Returns the image registry for this plugin. + * + * @return ImageRegistry - image registry for this plugin + */ + private ImageRegistry getImageRegistry() { + return JFaceResources.getImageRegistry(); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/editor/XMLEditorPluginImages.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/editor/XMLEditorPluginImages.java new file mode 100644 index 0000000000..8160f7781c --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/editor/XMLEditorPluginImages.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.internal.editor; + +/** + * Bundle of most images used by the XML Source Editor plug-in. + */ +public class XMLEditorPluginImages { + + public static final String IMG_DTOOL_CONSTRAINOFF = "icons/full/dtool16/constrainoff.gif"; //$NON-NLS-1$ + public static final String IMG_DTOOL_CONSTRAINON = "icons/full/dtool16/constrainon.gif"; //$NON-NLS-1$ + public static final String IMG_DTOOL_RLDGRMR = "icons/full/dtool16/rldgrmr.gif"; //$NON-NLS-1$ + public static final String IMG_DTOOL_VALIDATE = "icons/full/dtool16/validate.gif"; //$NON-NLS-1$ + public static final String IMG_ETOOL_CONSTRAINOFF = "icons/full/etool16/constrainoff.gif"; //$NON-NLS-1$ + public static final String IMG_ETOOL_CONSTRAINON = "icons/full/etool16/constrainon.gif"; //$NON-NLS-1$ + public static final String IMG_ETOOL_RLDGRMR = "icons/full/etool16/rldgrmr.gif"; //$NON-NLS-1$ + public static final String IMG_ETOOL_VALIDATE = "icons/full/etool16/validate.gif"; //$NON-NLS-1$ + public static final String IMG_OBJ_ADD_CORRECTION = "icons/full/obj16/add_correction.gif"; //$NON-NLS-1$ + public static final String IMG_OBJ_ATT_REQ_OBJ = "icons/full/obj16/att_req_obj.gif"; //$NON-NLS-1$ + + public static final String IMG_OBJ_ATTRIBUTE = "icons/full/obj16/attribute_obj.gif"; //$NON-NLS-1$ + public static final String IMG_OBJ_CDATASECTION = "icons/full/obj16/cdatasection.gif"; //$NON-NLS-1$ + public static final String IMG_OBJ_COMMENT = "icons/full/obj16/comment_obj.gif"; //$NON-NLS-1$ + public static final String IMG_OBJ_CORRECTION_CHANGE = "icons/full/obj16/correction_change.gif"; //$NON-NLS-1$ + public static final String IMG_OBJ_DOCTYPE = "icons/full/obj16/doctype.gif"; //$NON-NLS-1$ + public static final String IMG_OBJ_DTDFILE = "icons/full/obj16/dtdfile.gif"; //$NON-NLS-1$ + public static final String IMG_OBJ_ELEMENT = "icons/full/obj16/element_obj.gif"; //$NON-NLS-1$ + public static final String IMG_OBJ_ENTITY = "icons/full/obj16/entity.gif"; //$NON-NLS-1$ + public static final String IMG_OBJ_ENTITY_REFERENCE = "icons/full/obj16/entity_reference.gif"; //$NON-NLS-1$ + public static final String IMG_OBJ_ENUM = "icons/full/obj16/enum.gif"; //$NON-NLS-1$ + public static final String IMG_OBJ_LOCAL_VARIABLE = "icons/full/obj16/localvariable_obj.gif"; //$NON-NLS-1$ + public static final String IMG_OBJ_NOTATION = "icons/full/obj16/notation.gif"; //$NON-NLS-1$ + public static final String IMG_OBJ_PROCESSINGINSTRUCTION = "icons/full/obj16/proinst_obj.gif"; //$NON-NLS-1$ + public static final String IMG_OBJ_TAG_GENERIC = "icons/full/obj16/tag-generic.gif"; //$NON-NLS-1$ + public static final String IMG_OBJ_TAG_MACRO = "icons/full/obj16/tag-macro.gif"; //$NON-NLS-1$ + public static final String IMG_OBJ_TXTEXT = "icons/full/obj16/text.gif"; //$NON-NLS-1$ + public static final String IMG_OBJ_WARNING_OBJ = "icons/full/obj16/warning_obj.gif"; //$NON-NLS-1$ + public static final String IMG_OBJ_XSDFILE = "icons/full/obj16/XSDFile.gif"; //$NON-NLS-1$ + + public static final String IMG_OVR_ERROR = "icons/full/ovr16/error_ovr.gif"; //$NON-NLS-1$ + public static final String IMG_OVR_STALE_ERROR = "icons/full/ovr16/stale_error_ovr.gif"; //$NON-NLS-1$ + public static final String IMG_OVR_WARN = "icons/full/ovr16/warn_ovr.gif"; //$NON-NLS-1$ +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/search/XMLFindOccurrencesAction.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/search/XMLFindOccurrencesAction.java new file mode 100644 index 0000000000..825eb9ae8d --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/search/XMLFindOccurrencesAction.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.internal.search; + +import java.util.ResourceBundle; + +import org.eclipse.ui.texteditor.ITextEditor; +import org.eclipse.wst.sse.ui.internal.search.BasicFindOccurrencesAction; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; +import org.eclipse.wst.xml.core.text.rules.StructuredTextPartitionerForXML; + + + +/** + * <p> + * Configures a BasicFindOccurrencesAction with XML partitions and regions + * </p> + * + * <p> + * Uses default <code>getSearchQuery()</code>. + * </p> + * + * @author pavery + */ +public class XMLFindOccurrencesAction extends BasicFindOccurrencesAction { + + public XMLFindOccurrencesAction(ResourceBundle bundle, String prefix, ITextEditor editor) { + super(bundle, prefix, editor); + } + + /** + * @see org.eclipse.wst.sse.ui.internal.search.BasicFindOccurrencesAction#getPartitionType() + */ + public String[] getPartitionTypes() { + + return new String[]{StructuredTextPartitionerForXML.ST_DEFAULT_XML}; + } + + /** + * @see org.eclipse.wst.sse.ui.internal.search.IFindOccurrencesAction#getRegionTypes() + */ + public String[] getRegionTypes() { + + return new String[]{XMLRegionContext.XML_TAG_NAME, XMLRegionContext.XML_TAG_ATTRIBUTE_NAME, XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE}; + } + +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/nls/ResourceHandler.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/nls/ResourceHandler.java new file mode 100644 index 0000000000..a34ab91a25 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/nls/ResourceHandler.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.nls; + +import java.text.MessageFormat; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +public class ResourceHandler { + + + private static ResourceBundle fgResourceBundle; + + /** + * Returns the resource bundle used by all classes in this Project + */ + public static ResourceBundle getResourceBundle() { + try { + return ResourceBundle.getBundle("EditingXML");//$NON-NLS-1$ + } catch (MissingResourceException e) { + // does nothing - this method will return null and + // getString(String) will return the key + // it was called with + } + return null; + } + + public static String getString(String key) { + if (fgResourceBundle == null) { + fgResourceBundle = getResourceBundle(); + } + + if (fgResourceBundle != null) { + try { + return fgResourceBundle.getString(key); + } catch (MissingResourceException e) { + return "!" + key + "!";//$NON-NLS-2$//$NON-NLS-1$ + } + } else { + return "!" + key + "!";//$NON-NLS-2$//$NON-NLS-1$ + } + } + + public static String getString(String key, Object[] args) { + + try { + return MessageFormat.format(getString(key), args); + } catch (IllegalArgumentException e) { + return getString(key); + } + + } + + public static String getString(String key, Object[] args, int x) { + + return getString(key); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/nsedit/CommonAddNamespacesControl.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/nsedit/CommonAddNamespacesControl.java new file mode 100644 index 0000000000..be8c926e31 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/nsedit/CommonAddNamespacesControl.java @@ -0,0 +1,267 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.nsedit; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.runtime.IPath; +import org.eclipse.jface.window.Window; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.TableItem; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.part.PageBook; +import org.eclipse.wst.common.contentmodel.util.NamespaceInfo; +import org.eclipse.wst.xml.ui.dialogs.SelectFileOrXMLCatalogIdDialog; +import org.eclipse.wst.xml.ui.util.XMLCommonResources; +import org.eclipse.wst.xml.uriresolver.util.IdResolver; +import org.eclipse.wst.xml.uriresolver.util.IdResolverImpl; +import org.eclipse.wst.xml.uriresolver.util.URIHelper; + + + +public class CommonAddNamespacesControl extends Composite implements SelectionListener { + + class EditNamespaceControl extends Composite { + protected Button browseButton; + Text locationHintField; + Text prefixField; + Text uriField; + + //protected NamespaceInfo info; + + public EditNamespaceControl(Composite parent) { + super(parent, SWT.NONE); //BORDER); + setLayout(new GridLayout()); + setLayoutData(new GridData(GridData.FILL_BOTH)); + + Label label = new Label(this, SWT.NONE); + label.setText(XMLCommonResources.getInstance().getString("_UI_ENTER_REQ_PREFIX_AND_NAMESPACE")); //$NON-NLS-1$ + + Composite composite = new Composite(this, SWT.NONE); + GridLayout layout = new GridLayout(); + layout.numColumns = 3; + layout.marginWidth = 0; + layout.verticalSpacing = 1; + composite.setLayout(layout); + + GridData gd = new GridData(GridData.FILL_HORIZONTAL); + gd.widthHint = 350; + composite.setLayoutData(gd); + + // row 1 + // + Label prefixLabel = new Label(composite, SWT.NONE); + prefixLabel.setText(XMLCommonResources.getInstance().getString("_UI_LABEL_PREFIX_COLON")); //$NON-NLS-1$ + + prefixField = new Text(composite, SWT.SINGLE | SWT.BORDER); + prefixField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + //prefixField.setText(getDisplayValue(info.prefix)); + //prefixField.addModifyListener(modifyListener); + //prefixField.setEnabled(info.getProperty("prefix-readOnly") == + // null); + Label placeHolder1 = new Label(composite, SWT.NONE); + + // row 2 + // + Label uriLabel = new Label(composite, SWT.NONE); + uriLabel.setText(XMLCommonResources.getInstance().getString("_UI_LABEL_NAMESPACE_NAME_COLON")); //$NON-NLS-1$ + + uriField = new Text(composite, SWT.SINGLE | SWT.BORDER); + uriField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + //uriField.setText(getDisplayValue(info.uri)); + //uriField.addModifyListener(modifyListener); + //uriField.setEnabled(info.getProperty("uri-readOnly") == null); + + Label placeHolder2 = new Label(composite, SWT.NONE); + + // row 3 + // + Label locationHintLabel = new Label(composite, SWT.NONE); + locationHintLabel.setText(XMLCommonResources.getInstance().getString("_UI_LABEL_LOCATION_HINT_COLON")); //$NON-NLS-1$ + + locationHintField = new Text(composite, SWT.SINGLE | SWT.BORDER); + locationHintField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + //locationHintField.setText(getDisplayValue(info.locationHint)); + //locationHintField.addModifyListener(modifyListener); + //locationHintField.setEnabled(info.getProperty("locationHint-readOnly") + // == null); + + SelectionListener selectionListener = new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + performBrowse(); + } + }; + + browseButton = new Button(composite, SWT.NONE); + browseButton.setText(XMLCommonResources.getInstance().getString("_UI_LABEL_BROWSE")); //$NON-NLS-1$ + browseButton.addSelectionListener(selectionListener); + browseButton.setEnabled(locationHintField.getEnabled()); + } + + protected void performBrowse() { + String[] extensions = {".xsd"}; //$NON-NLS-1$ + SelectFileOrXMLCatalogIdDialog dialog = new SelectFileOrXMLCatalogIdDialog(getShell(), extensions); + dialog.create(); + dialog.getShell().setText(XMLCommonResources.getInstance().getString("_UI_LABEL_SELECT_FILE")); //$NON-NLS-1$ + dialog.setBlockOnOpen(true); + dialog.open(); + + if (dialog.getReturnCode() == Window.OK) { + String grammarURI = null; + IFile file = dialog.getFile(); + String id = dialog.getId(); + if (file != null) { + String uri = null; + if (resourceLocation != null) { + uri = URIHelper.getRelativeURI(file.getLocation(), resourceLocation); + grammarURI = file.getLocation().toOSString(); + } else { + uri = file.getLocation().toOSString(); + grammarURI = uri; + } + locationHintField.setText(uri); + } else if (id != null) { + locationHintField.setText(id); + IdResolver resolver = new IdResolverImpl(null); + grammarURI = resolver.resolveId(id, id); + } + + try { + //TODO CMDocument document = + // CMDocumentBuilderRegistry.getInstance().buildCMDocument(grammarURI); + // List namespaceInfoList = + // (List)document.getProperty("http://com.ibm.etools/cm/properties/namespaceInfo"); + // NamespaceInfo info = + // (NamespaceInfo)namespaceInfoList.get(0); + // if (uriField.getText().trim().length() == 0 && info.uri + // != null) + // { + // uriField.setText(info.uri); + // } + // if (prefixField.getText().trim().length() == 0 && + // info.prefix != null) + // { + // prefixField.setText(info.prefix); + // } + } catch (Exception e) { + } + } + } + } + + protected Button deleteButton; + protected Button editButton; + protected EditNamespaceControl editNamespaceControl; + protected int heightHint = 250; + protected List namespaceInfoList = new ArrayList(); + protected Button newButton; + protected PageBook pageBook; + protected Button radio1; + protected Button radio2; + protected IPath resourceLocation; + protected Composite tableSection; + protected CommonNamespaceInfoTable tableViewer; + protected int widthHint = 500; + + + public CommonAddNamespacesControl(Composite parent, int style, IPath resourceLocation) { + super(parent, style); + this.resourceLocation = resourceLocation; + GridData gd = new GridData(GridData.FILL_BOTH); + if (widthHint != -1) { + gd.widthHint = widthHint; + } + if (heightHint != -1) { + gd.heightHint = heightHint; + } + setLayoutData(gd); + setLayout(new GridLayout()); + + radio1 = new Button(this, SWT.RADIO); + radio1.setText(XMLCommonResources.getInstance().getString("_UI_SELECT_REGISTERED_NAMESPACES")); //$NON-NLS-1$ + radio1.addSelectionListener(this); + + radio2 = new Button(this, SWT.RADIO); + radio2.setText(XMLCommonResources.getInstance().getString("_UI_SPECIFY_NEW_NAMESPACE")); //$NON-NLS-1$ + radio2.addSelectionListener(this); + + Label separator = new Label(this, SWT.SEPARATOR | SWT.HORIZONTAL); + separator.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + //Group namespaceInfoGroup = new Group(this, SWT.NONE); + //namespaceInfoGroup.setText("Namespace Declarations"); + // //XMLCommonUIPlugin.getInstance().getString("_UI_LABEL_XML_SCHEMA_INFORMATION")); + //namespaceInfoGroup.setLayout(new GridLayout(2, false)); + //namespaceInfoGroup.setLayoutData(new GridData(GridData.FILL_BOTH)); + pageBook = new PageBook(this, SWT.NONE); + pageBook.setLayoutData(new GridData(GridData.FILL_BOTH)); + + tableSection = new Composite(pageBook, SWT.NONE); + tableSection.setLayout(new GridLayout()); + Label label = new Label(tableSection, SWT.NONE); + label.setText(XMLCommonResources.getInstance().getString("_UI_SELECT_NAMESPACE_TO_ADD")); //$NON-NLS-1$ + + tableViewer = new CommonNamespaceInfoTable(tableSection, SWT.CHECK, 6); + editNamespaceControl = new EditNamespaceControl(pageBook); + pageBook.showPage(tableSection); + + tableViewer.setInput(namespaceInfoList); + } + + + + public List getNamespaceInfoList() { + List list = new ArrayList(); + if (radio1.getSelection()) { + TableItem[] items = tableViewer.getTable().getItems(); + for (int i = 0; i < items.length; i++) { + TableItem item = items[i]; + if (item.getChecked()) { + list.add(item.getData()); + } + } + } else { + NamespaceInfo info = new NamespaceInfo(); + info.prefix = editNamespaceControl.prefixField.getText(); + info.uri = editNamespaceControl.uriField.getText(); + info.locationHint = editNamespaceControl.locationHintField.getText(); + list.add(info); + } + return list; + } + + public void setNamespaceInfoList(List list) { + namespaceInfoList = list; + tableViewer.setInput(namespaceInfoList); + } + + public void widgetDefaultSelected(SelectionEvent e) { + } + + public void widgetSelected(SelectionEvent e) { + if (e.widget == radio1) { + pageBook.showPage(tableSection); + } else if (e.widget == radio2) { + pageBook.showPage(editNamespaceControl); + } + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/nsedit/CommonAddNamespacesDialog.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/nsedit/CommonAddNamespacesDialog.java new file mode 100644 index 0000000000..a1ba50f0cb --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/nsedit/CommonAddNamespacesDialog.java @@ -0,0 +1,188 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.nsedit; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.wst.common.contentmodel.util.NamespaceInfo; +import org.eclipse.wst.xml.uriresolver.XMLCatalog; +import org.eclipse.wst.xml.uriresolver.XMLCatalogEntry; +import org.eclipse.wst.xml.uriresolver.XMLCatalogPlugin; + + +public class CommonAddNamespacesDialog extends Dialog { + protected CommonAddNamespacesControl addNamespacesControl; + protected List existingNamespaces; + protected List namespaceInfoList; + protected Button okButton; + protected HashMap preferredPrefixTable = new HashMap(); + protected IPath resourceLocation; + protected String title; + + public CommonAddNamespacesDialog(Shell parentShell, String title, IPath resourceLocation, List existingNamespaces) { + super(parentShell); + this.resourceLocation = resourceLocation; + setShellStyle(getShellStyle() | SWT.RESIZE); + this.title = title; + this.existingNamespaces = existingNamespaces; + preferredPrefixTable.put("http://schemas.xmlsoap.org/wsdl/", "wsdl"); //$NON-NLS-1$ //$NON-NLS-2$ + preferredPrefixTable.put("http://schemas.xmlsoap.org/wsdl/soap/", "soap"); //$NON-NLS-1$ //$NON-NLS-2$ + preferredPrefixTable.put("http://schemas.xmlsoap.org/wsdl/http/", "http"); //$NON-NLS-1$ //$NON-NLS-2$ + preferredPrefixTable.put("http://schemas.xmlsoap.org/wsdl/mime/", "mime"); //$NON-NLS-1$ //$NON-NLS-2$ + preferredPrefixTable.put("http://schemas.xmlsoap.org/soap/encoding/", "soapenc"); //$NON-NLS-1$ //$NON-NLS-2$ + preferredPrefixTable.put("http://schemas.xmlsoap.org/soap/envelope/", "soapenv"); //$NON-NLS-1$ //$NON-NLS-2$ + preferredPrefixTable.put("http://www.w3.org/2001/XMLSchema-instance", "xsi"); //$NON-NLS-1$ //$NON-NLS-2$ + preferredPrefixTable.put("http://www.w3.org/2001/XMLSchema", "xsd"); //$NON-NLS-1$ //$NON-NLS-2$ + } + + protected void addBuiltInNamespaces(List list) { + String xsiNamespace = "http://www.w3.org/2001/XMLSchema-instance"; //$NON-NLS-1$ + String xsdNamespace = "http://www.w3.org/2001/XMLSchema"; //$NON-NLS-1$ + if (!isAlreadyDeclared(xsiNamespace)) { + list.add(new NamespaceInfo("http://www.w3.org/2001/XMLSchema-instance", "xsi", null)); //$NON-NLS-1$ //$NON-NLS-2$ + } + if (!isAlreadyDeclared(xsdNamespace)) { + list.add(new NamespaceInfo("http://www.w3.org/2001/XMLSchema", "xsd", null)); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + + protected void addCatalogMapToList(XMLCatalog catalog, List list) { + for (Iterator i = catalog.getEntries().iterator(); i.hasNext();) { + XMLCatalogEntry entry = (XMLCatalogEntry) i.next(); + if (entry.getType() == XMLCatalogEntry.PUBLIC && entry.getURI().endsWith(".xsd")) { //$NON-NLS-1$ + if (!isAlreadyDeclared(entry.getKey())) { + NamespaceInfo namespaceInfo = new NamespaceInfo(entry.getKey(), "xx", null); //$NON-NLS-1$ + list.add(namespaceInfo); + } + } + } + } + + protected void buttonPressed(int buttonId) { + if (buttonId == IDialogConstants.OK_ID) { + namespaceInfoList = addNamespacesControl.getNamespaceInfoList(); + } + super.buttonPressed(buttonId); + } + + public void computeAddablePrefixes(List addableList, List exisitingList) { + HashMap map = new HashMap(); + for (Iterator i = exisitingList.iterator(); i.hasNext();) { + NamespaceInfo info = (NamespaceInfo) i.next(); + if (info.prefix != null) { + map.put(info.prefix, info); + } + } + for (Iterator i = addableList.iterator(); i.hasNext();) { + NamespaceInfo info = (NamespaceInfo) i.next(); + if (info.uri != null) { + String prefix = (String) preferredPrefixTable.get(info.uri); + info.prefix = getUniquePrefix(map, prefix, info.uri); + map.put(info.prefix, info); + } + } + } + + public int createAndOpen() { + create(); + getShell().setText(title); + Rectangle r = getShell().getBounds(); + getShell().setBounds(r.x + 80, r.y + 80, r.width, r.height); + setBlockOnOpen(true); + return open(); + } + + protected void createButtonsForButtonBar(Composite parent) { + okButton = createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true); + createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false); + } + + protected Control createContents(Composite parent) { + Control control = super.createContents(parent); + return control; + } + + + + protected Control createDialogArea(Composite parent) { + Composite dialogArea = (Composite) super.createDialogArea(parent); + addNamespacesControl = new CommonAddNamespacesControl(dialogArea, SWT.NONE, resourceLocation); + List list = new ArrayList(); + + addBuiltInNamespaces(list); + XMLCatalog catalog = XMLCatalogPlugin.getInstance().getDefaultXMLCatalog(); + addCatalogMapToList(catalog.getChildCatalog(XMLCatalog.USER_CATALOG_ID), list); + addCatalogMapToList(catalog.getChildCatalog(XMLCatalog.SYSTEM_CATALOG_ID), list); + + computeAddablePrefixes(list, existingNamespaces); + + addNamespacesControl.setNamespaceInfoList(list); + return dialogArea; + } + + public List getNamespaceInfoList() { + return namespaceInfoList; + } + + protected String getPreferredPrefix(String namespaceURI) { + return (String) preferredPrefixTable.get(namespaceURI); + } + + private String getUniquePrefix(HashMap prefixMap, String prefix, String uri) { + if (prefix == null) { + int lastIndex = uri.lastIndexOf('/'); + if (lastIndex == uri.length() - 1) { + uri = uri.substring(0, lastIndex); + lastIndex = uri.lastIndexOf('/'); + } + prefix = uri.substring(lastIndex + 1); + if (prefix.length() > 20 || prefix.indexOf(':') != -1) { + prefix = null; + } + } + if (prefix == null) { + prefix = "p"; //$NON-NLS-1$ + } + if (prefixMap.get(prefix) != null) { + String base = prefix; + for (int count = 0; prefixMap.get(prefix) != null; count++) { + prefix = base + count; + } + } + return prefix; + } + + protected boolean isAlreadyDeclared(String namespaceURI) { + boolean result = false; + for (Iterator i = existingNamespaces.iterator(); i.hasNext();) { + NamespaceInfo namespaceInfo = (NamespaceInfo) i.next(); + if (namespaceURI.equals(namespaceInfo.uri)) { + result = true; + break; + } + } + return result; + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/nsedit/CommonEditNamespacesDialog.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/nsedit/CommonEditNamespacesDialog.java new file mode 100644 index 0000000000..179566735a --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/nsedit/CommonEditNamespacesDialog.java @@ -0,0 +1,320 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.nsedit; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.window.Window; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Color; +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.Group; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.wst.common.contentmodel.util.NamespaceInfo; +import org.eclipse.wst.xml.ui.dialogs.EditNamespaceInfoDialog; +import org.eclipse.wst.xml.ui.dialogs.NamespaceInfoErrorHelper; +import org.eclipse.wst.xml.ui.nls.ResourceHandler; +import org.eclipse.wst.xml.ui.util.XMLCommonResources; + + +public class CommonEditNamespacesDialog { + protected Composite commonComposite; + protected Button deleteButton; + protected Button editButton; + + protected Label errorMessageLabel; + protected int heightHint = 250; + protected List namespaceInfoList = new ArrayList(); + + protected Button newButton; + protected IPath resourceLocation; + + private boolean showLocationText = false; + protected String tableLabel = ""; //$NON-NLS-1$ + protected CommonNamespaceInfoTable tableViewer; + + protected Composite topComposite; + protected boolean useGroup; + protected int widthHint = 500; + + public CommonEditNamespacesDialog(Composite parent, IPath resourceLocation, String stringTableLabel) { + this(parent, resourceLocation, stringTableLabel, false, false); + } + + public CommonEditNamespacesDialog(Composite parent, IPath resourceLocation, String stringTableLabel, boolean useGroup, boolean showLocText) { + this.resourceLocation = resourceLocation; + tableLabel = stringTableLabel; + this.useGroup = useGroup; + showLocationText = showLocText; + + GridData gd = new GridData(GridData.FILL_BOTH); + if (widthHint != -1) { + gd.widthHint = widthHint; + } + if (heightHint != -1) { + gd.heightHint = heightHint; + } + + // Set GridData and GridLayout for the parent Composite + parent.setLayoutData(gd); + parent.setLayout(new GridLayout()); + + // Create the top Composite + topComposite = new Composite(parent, SWT.NONE); + GridData topData = new GridData(GridData.FILL_HORIZONTAL); + topData.heightHint = 0; + topComposite.setLayoutData(topData); + topComposite.setLayout(new GridLayout()); + + // Create the 'common'/middle Composite + if (useGroup) { + commonComposite = new Group(parent, SWT.NONE); + } else { + commonComposite = new Composite(parent, SWT.NONE); + } + commonComposite.setLayoutData(new GridData(GridData.FILL_BOTH)); + commonComposite.setLayout(new GridLayout(3, false)); + + // Add the error Message Label + errorMessageLabel = new Label(parent, SWT.NONE); + errorMessageLabel.setLayoutData(createHorizontalFill()); + Color color = new Color(errorMessageLabel.getDisplay(), 200, 0, 0); + errorMessageLabel.setForeground(color); + + createControlArea(); + } + + + protected void createButtons(Composite parent) { + Composite composite = new Composite(parent, SWT.NONE); + composite.setLayoutData(new GridData(GridData.FILL_VERTICAL)); + GridLayout gridLayout = new GridLayout(); + gridLayout.numColumns = 1; + gridLayout.marginHeight = 0; + gridLayout.marginWidth = 0; + composite.setLayout(gridLayout); + + SelectionListener selectionListener = new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + if (e.widget == newButton) { + performNew(); + } else if (e.widget == editButton) { + performEdit(); + } else if (e.widget == deleteButton) { + performDelete(); + } + } + }; + + // create a composite to hold the three buttons + Composite buttonComposite = new Composite(composite, SWT.NONE); + buttonComposite.setLayoutData(createHorizontalFill()); + GridLayout buttonGridLayout = new GridLayout(); + //buttonGridLayout.numColumns = 3; + //buttonGridLayout.makeColumnsEqualWidth = true; + buttonComposite.setLayout(buttonGridLayout); + + // add the New button + // + newButton = new Button(buttonComposite, SWT.NONE); + //newButton.setText(" " + + // XMLCommonUIPlugin.getInstance().getString("_UI_BUTTON_NEW") + " "); + newButton.setText(" " + ResourceHandler.getString("CommonEditNamespacesDialog.0") + " "); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + newButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); //ViewUtility.createHorizontalFill()); + newButton.addSelectionListener(selectionListener); + + // add the Edit button + // + //gd = new GridData(); + //gd.horizontalAlignment = gd.FILL; + //gd.grabExcessHorizontalSpace = true; + + editButton = new Button(buttonComposite, SWT.NONE); + editButton.setText(XMLCommonResources.getInstance().getString("_UI_BUTTON_EDIT")); //$NON-NLS-1$ + editButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); //ViewUtility.createHorizontalFill()); + editButton.addSelectionListener(selectionListener); + + // add the Delete button + // + //gd = new GridData(); + //gd.horizontalAlignment = gd.FILL; + //gd.grabExcessHorizontalSpace = true; + + deleteButton = new Button(buttonComposite, SWT.NONE); + deleteButton.setText(XMLCommonResources.getInstance().getString("_UI_BUTTON_DELETE")); //$NON-NLS-1$ + deleteButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); //ViewUtility.createHorizontalFill()); + deleteButton.addSelectionListener(selectionListener); + } + + private void createControlArea() { + if (useGroup) { + ((Group) commonComposite).setText(tableLabel); + } else { + Label label = new Label(commonComposite, SWT.NONE); + label.setText(tableLabel); + label.setLayoutData(createGridData(false, 3)); + } + + tableViewer = new CommonNamespaceInfoTable(commonComposite, 6, showLocationText); + tableViewer.getControl().setLayoutData(createGridData(true, 2)); + createButtons(commonComposite); + + tableViewer.setInput(namespaceInfoList); + updateButtonEnabledState(); + ISelectionChangedListener selectionChangedListener = new ISelectionChangedListener() { + public void selectionChanged(SelectionChangedEvent event) { + updateButtonEnabledState(); + } + }; + tableViewer.addSelectionChangedListener(selectionChangedListener); + } + + protected GridData createGridData(boolean both, int span) { + GridData gd = new GridData(both ? GridData.FILL_BOTH : GridData.FILL_HORIZONTAL); + gd.horizontalSpan = 2; + return gd; + } + + private GridData createHorizontalFill() { + GridData gd = new GridData(); + gd.horizontalAlignment = GridData.FILL; + gd.grabExcessHorizontalSpace = true; + return gd; + } + + + + public NamespaceInfo getNamespaceInfo(String namespace) { + NamespaceInfo result = null; + for (Iterator i = namespaceInfoList.iterator(); i.hasNext();) { + NamespaceInfo info = (NamespaceInfo) i.next(); + if (info.uri != null && info.uri.equals(namespace)) { + result = info; + break; + } + } + return result; + } + + protected Object getSelection(ISelection selection) { + if (selection == null) { + return null; + } // end of if () + + Object result = null; + if (selection instanceof IStructuredSelection) { + IStructuredSelection es = (IStructuredSelection) selection; + Iterator i = es.iterator(); + if (i.hasNext()) { + result = i.next(); + } + } + return result; + } + + /* + * Use the returned Composite to add content above the 'common contents'. + * Note: The GridData for the returned Composite has a heightHint = 0. + * This means when using the returned Composite, the GridData must be + * reset, else the Composite and it's contents will not appear. + */ + protected Composite getTopComposite() { + return topComposite; + } + + protected EditNamespaceInfoDialog invokeDialog(String title, NamespaceInfo info) { + Shell shell = XMLCommonResources.getInstance().getWorkbench().getActiveWorkbenchWindow().getShell(); + EditNamespaceInfoDialog dialog = new EditNamespaceInfoDialog(shell, info); + dialog.create(); + dialog.getShell().setText(title); + dialog.setBlockOnOpen(true); + dialog.setResourceLocation(resourceLocation); + dialog.open(); + return dialog; + } + + protected void performDelayedUpdate() { + tableViewer.refresh(); + /* + * Runnable delayedUpdate = new Runnable() { public void run() { + * tableViewer.refresh(); } }; + * Display.getCurrent().asyncExec(delayedUpdate); + */ + //if (updateListener != null) + //{ + // updateListener.updateOccured(this, namespaceInfoList); + //} + } + + public void performDelete() { + ISelection selection = tableViewer.getSelection(); + if (selection instanceof IStructuredSelection) { + IStructuredSelection structuredSelection = (IStructuredSelection) selection; + namespaceInfoList.removeAll(structuredSelection.toList()); + updateErrorMessage(namespaceInfoList); + performDelayedUpdate(); + } + } + + public void performEdit() { + Object selection = getSelection(tableViewer.getSelection()); + if (selection != null) { + EditNamespaceInfoDialog dialog = invokeDialog(XMLCommonResources.getInstance().getString("_UI_LABEL_NEW_NAMESPACE_INFORMATION"), (NamespaceInfo) selection); //$NON-NLS-1$ + updateErrorMessage(namespaceInfoList); + performDelayedUpdate(); + } + } + + public void performNew() { + Shell shell = XMLCommonResources.getInstance().getWorkbench().getActiveWorkbenchWindow().getShell(); + CommonAddNamespacesDialog dialog = new CommonAddNamespacesDialog(shell, XMLCommonResources.getInstance().getString("_UI_ADD_NAMESPACE_DECLARATIONS"), resourceLocation, namespaceInfoList); //$NON-NLS-1$ + dialog.createAndOpen(); + if (dialog.getReturnCode() == Window.OK) { + namespaceInfoList.addAll(dialog.getNamespaceInfoList()); + updateErrorMessage(namespaceInfoList); + performDelayedUpdate(); + } + } + + public void setNamespaceInfoList(List list) { + namespaceInfoList = list; + tableViewer.setInput(namespaceInfoList); + } + + public void updateButtonEnabledState() { + Object selection = getSelection(tableViewer.getSelection()); + NamespaceInfo info = (NamespaceInfo) selection; + editButton.setEnabled(info != null); + deleteButton.setEnabled(info != null && info.getProperty("unremovable") == null); //$NON-NLS-1$ + } + + public void updateErrorMessage(List namespaceInfoList) { + NamespaceInfoErrorHelper helper = new NamespaceInfoErrorHelper(); + String errorMessage = helper.computeErrorMessage(namespaceInfoList, null); + errorMessageLabel.setText(errorMessage != null ? errorMessage : ""); //$NON-NLS-1$ + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/nsedit/CommonEditNamespacesTargetFieldDialog.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/nsedit/CommonEditNamespacesTargetFieldDialog.java new file mode 100644 index 0000000000..27546a5a6f --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/nsedit/CommonEditNamespacesTargetFieldDialog.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.nsedit; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; +import org.eclipse.wst.common.contentmodel.util.NamespaceInfo; +import org.eclipse.wst.xml.ui.dialogs.EditNamespaceInfoDialog; +import org.eclipse.wst.xml.ui.util.XMLCommonResources; + + +/* + * This class is an extension of CommonEditNamespacesDialog. This class adds + * the target namespaces dialog field. + */ +public class CommonEditNamespacesTargetFieldDialog extends CommonEditNamespacesDialog { + + class TargetNamespaceModifyListener implements ModifyListener { + public void modifyText(ModifyEvent e) { + String oldTargetNamespace = targetNamespace; + targetNamespace = targetNamespaceField.getText(); + updateTargetNamespaceAndNamespaceInfo(oldTargetNamespace, targetNamespace); + } + } + + protected String targetNamespace; + protected Text targetNamespaceField; + + public CommonEditNamespacesTargetFieldDialog(Composite parent, IPath resourceLocation) { + super(parent, resourceLocation, XMLCommonResources.getInstance().getString("_UI_NAMESPACE_DECLARATIONS")); //$NON-NLS-1$ + + Composite targetComp = getTopComposite(); + targetComp.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + + GridData gd = new GridData(GridData.FILL_BOTH); + Label targetNamespaceLabel = new Label(targetComp, SWT.NONE); + targetNamespaceLabel.setLayoutData(gd); + targetNamespaceLabel.setText(XMLCommonResources.getInstance().getString("_UI_TARGET_NAMESPACE")); //$NON-NLS-1$ + + targetNamespaceField = new Text(targetComp, SWT.BORDER); + targetNamespaceField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + targetNamespaceField.addModifyListener(new TargetNamespaceModifyListener()); + + // createControlArea(); + } + + public String getTargetNamespace() { + return targetNamespace; + } + + public void performEdit() { + Object selection = getSelection(tableViewer.getSelection()); + if (selection != null) { + boolean editTargetNamespace = false; + NamespaceInfo nsInfo = (NamespaceInfo) selection; + if (getTargetNamespace().equals(nsInfo.uri)) { + editTargetNamespace = true; + } + + EditNamespaceInfoDialog dialog = invokeDialog(XMLCommonResources.getInstance().getString("_UI_LABEL_NEW_NAMESPACE_INFORMATION"), nsInfo); //$NON-NLS-1$ + updateErrorMessage(namespaceInfoList); + performDelayedUpdate(); + + if (editTargetNamespace) { + targetNamespaceField.setText(nsInfo.uri); + } + } + } + + public void setTargetNamespace(String theTargetNamespace) { + targetNamespace = theTargetNamespace != null ? theTargetNamespace : ""; //$NON-NLS-1$ + targetNamespaceField.setText(targetNamespace); + //updateTargetNamespaceAndNamespaceInfo(targetNamespace); + } + + private void updateTargetNamespaceAndNamespaceInfo(String oldTargetNamespace, String newTargetNamespace) { + NamespaceInfo info = getNamespaceInfo(newTargetNamespace); + if (info == null) { + info = getNamespaceInfo(oldTargetNamespace); + if (info == null) { + info = new NamespaceInfo(newTargetNamespace, "tns", null); //$NON-NLS-1$ + namespaceInfoList.add(info); + } else { + info.uri = targetNamespace; + } + } + tableViewer.refresh(); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/nsedit/CommonNamespaceInfoTable.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/nsedit/CommonNamespaceInfoTable.java new file mode 100644 index 0000000000..ae58de57b4 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/nsedit/CommonNamespaceInfoTable.java @@ -0,0 +1,341 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.nsedit; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jface.viewers.ColumnWeightData; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.TableLayout; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.MouseAdapter; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.TableItem; +import org.eclipse.wst.common.contentmodel.util.NamespaceInfo; +import org.eclipse.wst.xml.ui.util.XMLCommonResources; + + +public class CommonNamespaceInfoTable extends TableViewer { + + /** + * NamespaceInfoTableLabelProvider + */ + protected class Provider extends LabelProvider implements ITableLabelProvider, IStructuredContentProvider { + Viewer viewer; + + public Image getColumnImage(Object object, int columnIndex) { + Image result = null; + int columnCode = getColumnCode(columnIndex); + if (columnCode == COLUMN_LOCATION_HINT) { + NamespaceInfo info = (NamespaceInfo) object; + if (info.locationHint == null || info.locationHint.trim().equals("")) { //$NON-NLS-1$ + // Comment this out until we solve the alignment/(space + // for image being allocated + // to prefix column) ...... + // result = + // XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_WARNING_OBJ); + } + } + + return result; + } + + public String getColumnText(Object object, int column) { + NamespaceInfo info = (NamespaceInfo) object; + String result = null; + int columnCode = getColumnCode(column); + switch (columnCode) { + case COLUMN_PREFIX : { + result = info.prefix; + break; + } + case COLUMN_NAMESPACE_URI : { + result = info.uri; + break; + } + case COLUMN_CHECKBOX : { + result = ""; //info.locationHint; //$NON-NLS-1$ + break; + } + case COLUMN_LOCATION_HINT : { + result = info.locationHint; + break; + } + } + result = result != null ? result : ""; //$NON-NLS-1$ + if (result.equals("")) { //$NON-NLS-1$ + switch (columnCode) { + case COLUMN_PREFIX : { + result = XMLCommonResources.getInstance().getString("_UI_NO_PREFIX"); //$NON-NLS-1$ + break; + } + case COLUMN_NAMESPACE_URI : { + result = XMLCommonResources.getInstance().getString("_UI_NO_NAMESPACE_NAME"); //$NON-NLS-1$ + break; + } + } + } + return result; + } + + public Object[] getElements(Object inputElement) { + List list = (List) viewer.getInput(); + return list != null ? list.toArray() : null; + } + + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + this.viewer = viewer; + } + } + + class TableItemChecker extends MouseAdapter { + public void mouseDown(MouseEvent e) { + TableItem item = getTable().getItem(new Point(e.x, e.y)); + if (item != null) { + Object obj = item.getData(); + if (obj != null) { + NamespaceInfo info = (NamespaceInfo) obj; + TableColumn col = getTable().getColumn(0); + if (e.x < col.getWidth()) // if the point falls within the + // Select column then perform + // check/uncheck + { + String currentState = (String) info.getProperty("checked"); //$NON-NLS-1$ + System.out.println("currentState" + currentState); //$NON-NLS-1$ + if (currentState == null || currentState.equals("false")) //$NON-NLS-1$ + { + info.setProperty("checked", "true"); //$NON-NLS-1$ //$NON-NLS-2$ + } else { + info.setProperty("checked", "false"); //$NON-NLS-1$ //$NON-NLS-2$ + } + refresh(); + } + } + } + } + } + + protected static final int COLUMN_CHECKBOX = 1; + protected static final int COLUMN_LOCATION_HINT = 4; + protected static final int COLUMN_NAMESPACE_URI = 2; + protected static final int COLUMN_PREFIX = 3; + + protected static final String LABEL_CHECKBOX = ""; //$NON-NLS-1$ + protected static final String LABEL_LOCATION_HINT = XMLCommonResources.getInstance().getString("_UI_LABEL_LOCATION_HINT"); //$NON-NLS-1$ + protected static final String LABEL_NAMESPACE_URI = XMLCommonResources.getInstance().getString("_UI_LABEL_NAMESPACE_NAME"); //$NON-NLS-1$ + protected static final String LABEL_PREFIX = XMLCommonResources.getInstance().getString("_UI_LABEL_PREFIX"); //$NON-NLS-1$ + protected List checkedList = new ArrayList(); + + //protected List namespaceInfoList = new ArrayList(); + protected int[] columnIndexMap; + protected boolean showCheckBoxes = true; + private boolean showLocationText = false; + + private Table table; + protected int visibleRows = -1; + + public CommonNamespaceInfoTable(Composite parent, int visibleRows) { + this(parent, SWT.FULL_SELECTION | SWT.MULTI | SWT.BORDER, visibleRows, false); + } + + //protected CellEditor getCellEditor(int column) + // { + // return (column == COLUMN_CHECKBOX) ? checkBoxCellEditor : + // textCellEditor; + // } + + public CommonNamespaceInfoTable(Composite parent, int visibleRows, boolean showLocationText) { + this(parent, SWT.FULL_SELECTION | SWT.MULTI | SWT.BORDER, visibleRows, showLocationText); + } + + public CommonNamespaceInfoTable(Composite parent, int style, int visibleRows) { + this(parent, SWT.FULL_SELECTION | SWT.MULTI | SWT.BORDER | style, visibleRows, false); + } + + public CommonNamespaceInfoTable(Composite parent, int style, int visibleRows, boolean showLocationText) { + super(new Table(parent, style)); + getTable().setLinesVisible(true); + this.showCheckBoxes = (style & SWT.CHECK) != 0; + columnIndexMap = createColumnIndexMap(); + this.showLocationText = showLocationText; + + Provider provider = new Provider(); + setContentProvider(provider); + setLabelProvider(provider); + + String[] columnPropertiesArray = createColumnPropertiesArray(); + setColumnProperties(columnPropertiesArray); + + table = getTable(); + table.setHeaderVisible(true); + table.setLayoutData(new GridData(GridData.FILL_BOTH)); + + TableLayout layout = new TableLayout(); + + for (int i = 0; i < columnPropertiesArray.length; i++) { + TableColumn column = new TableColumn(table, i); + if ((columnPropertiesArray[i]).equals(LABEL_LOCATION_HINT)) { + if (showLocationText) { + column.setText(columnPropertiesArray[i]); + } else { + // Comment this out until we solve the alignment/(space + // for image being allocated + // to prefix column) ...... + // column.setImage(XMLEditorPluginImageHelper.getInstance().getImage(XMLEditorPluginImages.IMG_OBJ_TXTEXT)); + } + } else { + column.setText(columnPropertiesArray[i]); + } + column.setAlignment(SWT.LEFT); + layout.addColumnData(new ColumnWeightData(getColumnWidth(i), true)); + } + table.setLayout(layout); + + this.visibleRows = visibleRows; + //for (int i = 0; i < visibleRows; i++) + // { + // TableItem item = new TableItem(table, SWT.NONE); + // item.setText("#######"); + //} + //checkBoxCellEditor = new NamespaceInfoCheckboxCellEditor(table); + //textCellEditor = new TextCellEditor(table); + + /* + * CellEditor[] cellEditors = new + * CellEditor[columnPropertiesArray.length]; for (int i = 0; i < + * columnPropertiesArray.length; i++) { cellEditors[i] = + * getCellEditor(i); } setCellEditors(cellEditors); + */ + //if (showCheckBoxes) + //{ + // getTable().addMouseListener(new TableItemChecker()); + //} + } + + //protected CellEditor checkBoxCellEditor; + //protected CellEditor textCellEditor; + + protected int[] createColumnIndexMap() { + int[] result = new int[showCheckBoxes ? 4 : 3]; + int i = 0; + if (showCheckBoxes) { + result[i++] = COLUMN_CHECKBOX; + } + result[i++] = COLUMN_PREFIX; + result[i++] = COLUMN_NAMESPACE_URI; + if (!showCheckBoxes) { + result[i++] = COLUMN_LOCATION_HINT; + } + return result; + } + + protected String[] createColumnPropertiesArray() { + String[] result = new String[3]; + int i = 0; + if (showCheckBoxes) { + result[i++] = LABEL_CHECKBOX; + } + result[i++] = LABEL_PREFIX; + result[i++] = LABEL_NAMESPACE_URI; + if (!showCheckBoxes) { + result[i++] = LABEL_LOCATION_HINT; + } + return result; + } + + protected int getColumnCode(int column) { + int result = 0; + if (column < columnIndexMap.length) { + result = columnIndexMap[column]; + } + return result; + } + + protected int getColumnWidth(int column) { + int result = 0; + switch (getColumnCode(column)) { + case COLUMN_PREFIX : { + result = 5; + break; + } + case COLUMN_NAMESPACE_URI : { + // Size columns differently when location hint text label is + // displayed + if (showLocationText) { + result = 10; + } else { + result = 20; + } + break; + } + case COLUMN_CHECKBOX : { + result = 1; //info.locationHint; + break; + } + case COLUMN_LOCATION_HINT : { + // Size columns differently when location hint text label is + // displayed + if (showLocationText) { + result = 10; + } else { + result = 2; + } + break; + } + } + return result; + } + /* + * protected class NamespaceInfoCellModifier implements ICellModifier { + * public NamespaceInfoCellModifier() { } + * + * public boolean canModify(Object element, String property) { if + * (property.equals(LABEL_CHECKBOX)) { return true; } else if + * (property.equals(LABEL_PREFIX)) { return true; } return false; } + * + * public Object getValue(Object element, String property) { int column = + * 0; if (property.equals(LABEL_CHECKBOX)) { column = 0; } else if + * (property.equals(LABEL_PREFIX)) { column = 1; } else if + * (property.equals(LABEL_NAMESPACE_URI)) { column = 2; } + * + * //if (element instanceof TableElement) //{ // return + * provider.getColumnText(element, column); //} //else //{ // return null; // } + * return "hello"; } + * + * public void modify(Object element, String property, Object value) { } } + * + * protected class NamespaceInfoCheckboxCellEditor extends + * CheckboxCellEditor implements MouseListener { public + * NamespaceInfoCheckboxCellEditor(Composite parent) { super(parent); } + * + * protected void doSetValue(Object value) { } + * + * public void activate() { super.activate(); deactivate(); + * Display.getCurrent().getFocusControl().redraw(); } + * + * public void mouseDown(MouseEvent e) { if (getTable().getItem(new + * Point(e.x, e.y)) != null) { } } public void mouseDoubleClick(MouseEvent + * e) { } public void mouseUp(MouseEvent e) { } } + */ +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/openon/DefaultOpenOnXML.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/openon/DefaultOpenOnXML.java new file mode 100644 index 0000000000..878d044eda --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/openon/DefaultOpenOnXML.java @@ -0,0 +1,342 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.openon; + + + +import java.util.StringTokenizer; + +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.Region; +import org.eclipse.wst.common.contentmodel.CMAttributeDeclaration; +import org.eclipse.wst.common.contentmodel.CMDataType; +import org.eclipse.wst.common.contentmodel.modelquery.ModelQuery; +import org.eclipse.wst.common.contentmodel.util.DOMNamespaceHelper; +import org.eclipse.wst.sse.core.IStructuredModel; +import org.eclipse.wst.sse.core.IndexedRegion; +import org.eclipse.wst.sse.core.util.StringUtils; +import org.eclipse.wst.sse.ui.openon.AbstractOpenOn; +import org.eclipse.wst.uriresolver.URIResolverPlugin; +import org.eclipse.wst.xml.core.document.XMLAttr; +import org.eclipse.wst.xml.core.document.XMLNode; +import org.eclipse.wst.xml.core.modelquery.ModelQueryUtil; +import org.w3c.dom.Attr; +import org.w3c.dom.DocumentType; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + + +/** + * This action class retrieves the link/file selected by the cursor and + * attempts to open the link/file in the default editor or web browser + */ +public class DefaultOpenOnXML extends AbstractOpenOn { + private final String NO_NAMESPACE_SCHEMA_LOCATION = "noNamespaceSchemaLocation"; //$NON-NLS-1$ + private final String SCHEMA_LOCATION = "schemaLocation"; //$NON-NLS-1$ + private final String XMLNS = "xmlns"; //$NON-NLS-1$ + private final String XSI_NAMESPACE_URI = "http://www.w3.org/2001/XMLSchema-instance"; //$NON-NLS-1$ + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.ui.AbstractOpenOn#doGetOpenOnRegion(int) + */ + protected IRegion doGetOpenOnRegion(int offset) { + // find the element for this node + Node currNode = getCurrentNode(offset); + if (currNode != null) { + // handle doc type node + if (currNode.getNodeType() == Node.DOCUMENT_TYPE_NODE) { + XMLNode docNode = (XMLNode) currNode; + return new Region(docNode.getStartOffset(), docNode.getEndOffset()); + } + + Attr linkableAtt = getLinkableAttrFromNode(currNode, offset); + // found attribute to open on + if (linkableAtt != null) { + XMLAttr att = (XMLAttr) linkableAtt; + // do not include quotes in attribute value region + int regOffset = att.getValueRegionStartOffset(); + int regLength = att.getValueRegion().getTextLength(); + String attValue = att.getValueRegionText(); + if (StringUtils.isQuoted(attValue)) { + regOffset = ++regOffset; + regLength = regLength - 2; + } + return new Region(regOffset, regLength); + } + } + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.ui.AbstractOpenOn#doOpenOn(org.eclipse.jface.text.IRegion) + */ + protected void doOpenOn(IRegion region) { + String uriString = getURIString(region.getOffset()); + openFileInEditor(uriString); + } + + /** + * Get the base location from the current model + * + * @return + */ + protected String getBaseLocation() { + String baseLoc = null; + + // get the base location from the current model + IStructuredModel sModel = null; + try { + sModel = getModelManager().getExistingModelForRead(getDocument()); + if (sModel != null) { + baseLoc = sModel.getBaseLocation(); + } + } finally { + if (sModel != null) { + sModel.releaseFromRead(); + } + } + return baseLoc; + } + + /** + * Returns the attribute node within node at offset + * + * @param node + * @param offset + * @return Node + */ + private Node getCurrentAttrNode(Node node, int offset) { + if ((node instanceof IndexedRegion) && ((IndexedRegion) node).contains(offset) && (node.hasAttributes())) { + NamedNodeMap attrs = node.getAttributes(); + // go through each attribute in node and if attribute contains + // offset, return that attribute + for (int i = 0; i < attrs.getLength(); ++i) { + // assumption that if parent node is of type IndexedRegion, + // then its attributes will also be of type IndexedRegion + IndexedRegion attRegion = (IndexedRegion) attrs.item(i); + if (attRegion.contains(offset)) { + return attrs.item(i); + } + } + } + return null; + } + + /** + * Returns the node the cursor is currently on in the document. null if no + * node is selected + * + * @param offset + * @return Node + */ + protected Node getCurrentNode(int offset) { + // get the current node at the offset (returns element, doctype, text) + IndexedRegion inode = null; + IStructuredModel sModel = getModelManager().getExistingModelForRead(getDocument()); + inode = sModel.getIndexedRegion(offset); + if (inode == null) + inode = sModel.getIndexedRegion(offset - 1); + sModel.releaseFromRead(); + + if (inode instanceof Node) { + return (Node) inode; + } + return null; + } + + /** + * Return an attr of element that is "openOn-able" if one exists. null + * otherwise + * + * @param element - + * cannot be null + * @return Attr attribute that can be used for open on, null if no + * attribute could be found + */ + protected Attr getLinkableAttr(Element element) { + ModelQuery mq = ModelQueryUtil.getModelQuery(element.getOwnerDocument()); + if (mq != null) { + // get the list of attributes for this node + NamedNodeMap attrs = element.getAttributes(); + for (int i = 0; i < attrs.getLength(); ++i) { + // check if this attribute is "openOn-able" + Attr att = (Attr) attrs.item(i); + if (isLinkableAttr(att, mq)) { + return att; + } + } + } + return null; + } + + /** + * Return an attr of element that is "openOn-able" if one exists. null + * otherwise + * + * @param node - + * cannot be null + * @return Attr attribute that can be used for open on, null if no + * attribute could be found + */ + protected Attr getLinkableAttrFromNode(Node node, int offset) { + // check to see if we're already on an attribute we can work with + Attr currentAtt = null; + if (node.getNodeType() == Node.ATTRIBUTE_NODE) { + currentAtt = (Attr) node; + } else { + Node attN = getCurrentAttrNode(node, offset); + if (attN != null) + currentAtt = (Attr) attN; + } + if ((currentAtt != null) && isLinkableAttr(currentAtt, null)) { + return currentAtt; + } + + // now check the whole element tag and see if there's an attribute we + // can work with + if (node.getNodeType() == Node.ELEMENT_NODE) { + // find an attribute that is "openOn-able" + return getLinkableAttr((Element) node); + } + return null; + } + + /** + * Find the location hint for the given namespaceURI if it exists + * + * @param elementNode - + * cannot be null + * @param namespaceURI - + * cannot be null + * @return location hint (systemId) if it was found, null otherwise + */ + private String getLocationHint(Element elementNode, String namespaceURI) { + Attr schemaLocNode = elementNode.getAttributeNodeNS(XSI_NAMESPACE_URI, SCHEMA_LOCATION); + if (schemaLocNode != null) { + StringTokenizer st = new StringTokenizer(schemaLocNode.getValue()); + while (st.hasMoreTokens()) { + String publicId = st.hasMoreTokens() ? st.nextToken() : null; + String systemId = st.hasMoreTokens() ? st.nextToken() : null; + // found location hint + if (namespaceURI.equalsIgnoreCase(publicId)) + return systemId; + } + } + return null; + } + + /** + * Returns the URI string + * + * @param offset + * @return + */ + protected String getURIString(int offset) { + Node currNode = getCurrentNode(offset); + if (currNode != null) { + // need the base location, publicId, and systemId for URIResolver + String baseLoc = null; + String publicId = null; + String systemId = null; + + // handle doc type node + if (currNode.getNodeType() == Node.DOCUMENT_TYPE_NODE) { + baseLoc = getBaseLocation(); + publicId = ((DocumentType) currNode).getPublicId(); + systemId = ((DocumentType) currNode).getSystemId(); + } else { // handle all other types of nodes + Attr linkableAtt = getLinkableAttrFromNode(currNode, offset); + // found attribute to open on + if (linkableAtt != null) { + baseLoc = getBaseLocation(); + String attrName = linkableAtt.getName(); + String attrValue = linkableAtt.getValue(); + attrValue = StringUtils.strip(attrValue); + + // handle schemaLocation attribute + String prefix = DOMNamespaceHelper.getPrefix(attrName); + String unprefixedName = DOMNamespaceHelper.getUnprefixedName(attrName); + if ((XMLNS.equals(prefix)) || (XMLNS.equals(unprefixedName))) { + publicId = attrValue; + systemId = getLocationHint(linkableAtt.getOwnerElement(), publicId); + } else if ((XSI_NAMESPACE_URI.equals(DOMNamespaceHelper.getNamespaceURI(linkableAtt))) && (unprefixedName.equals("schemaLocation"))) { //$NON-NLS-1$ + // for now just use the first pair + // need to look into being more precise + StringTokenizer st = new StringTokenizer(attrValue); + publicId = st.hasMoreTokens() ? st.nextToken() : null; + systemId = st.hasMoreTokens() ? st.nextToken() : null; + // else check if xmlns publicId = value + } else { + systemId = attrValue; + } + } + } + + String resolvedURI = resolveURI(baseLoc, publicId, systemId); + return resolvedURI; + } + return null; + } + + /** + * Checks to see if the given attribute is openOn-able. Attribute is + * openOn-able if it is a namespace declaration attribute or if the + * attribute value is of type URI. + * + * @param attr + * cannot be null + * @param query + * ModelQuery associated with the attribute (can be null) + * @return true if this attribute is "openOn-able" false otherwise + */ + protected boolean isLinkableAttr(Attr attr, ModelQuery query) { + String prefix = DOMNamespaceHelper.getPrefix(attr.getName()); + String unprefixedName = DOMNamespaceHelper.getUnprefixedName(attr.getName()); + // determine if attribute is namespace declaration + if ((XMLNS.equals(prefix)) || (XMLNS.equals(unprefixedName))) + return true; + + // determine if attribute contains schema location + if ((XSI_NAMESPACE_URI.equals(DOMNamespaceHelper.getNamespaceURI(attr))) && ((SCHEMA_LOCATION.equals(unprefixedName)) || (NO_NAMESPACE_SCHEMA_LOCATION.equals(unprefixedName)))) + return true; + + // determine if attribute value is of type URI + if (query != null) { + CMAttributeDeclaration attrDecl = query.getCMAttributeDeclaration(attr); + if ((attrDecl != null) && (attrDecl.getAttrType() != null) && (CMDataType.URI.equals(attrDecl.getAttrType().getDataTypeName()))) { + return true; + } + } + return false; + } + + /** + * Resolves the given URI information + * + * @param baseLocation + * @param publicId + * @param systemId + * @return String resolved uri. + */ + protected String resolveURI(String baseLocation, String publicId, String systemId) { + // dont resolve if there's nothing to resolve + if ((baseLocation == null) && (publicId == null) && (systemId == null)) + return null; + return URIResolverPlugin.createResolver().resolve(baseLocation, publicId, systemId); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/preferences/EncodingSettings.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/preferences/EncodingSettings.java new file mode 100644 index 0000000000..1582d29c70 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/preferences/EncodingSettings.java @@ -0,0 +1,357 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.preferences; + +import java.util.Vector; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; +import org.eclipse.wst.common.encoding.CommonCharsetNames; +import org.eclipse.wst.sse.ui.Logger; +import org.eclipse.wst.xml.ui.nls.ResourceHandler; + + +/** + * EncodingSettings is a composite that can be used to display the set of + * encoding values that are available to the user. The list of encoding values + * is based off the SupportedJavaEncoding class. As the user selects an + * encoding from the combo box, the readonly field below it changes to show + * the IANA tag for that particular encoding description. The labels for the + * widgets are configurable and the initial value to display to the user can + * be set using the setIANATag(). The currently selected entry's IANA tag can + * be retrieved with getIANATag(). Entries displayed to the user can be added + * and removed. + */ +public class EncodingSettings extends Composite { + + private class ComboListener implements ModifyListener { + public void modifyText(ModifyEvent e) { + int i = encodingCombo.getSelectionIndex(); + if (i >= 0 && i < ianaVector.size()) + ianaText.setText((String) (ianaVector.elementAt(encodingCombo.getSelectionIndex()))); + } + } + + private static String ENCODING_LABEL = ResourceHandler.getString("EncodingSettings.1"); //$NON-NLS-1$ + + private static String IANA_LABEL = ResourceHandler.getString("EncodingSettings.0"); //$NON-NLS-1$ + + private ModifyListener comboListener = new ComboListener(); + protected Combo encodingCombo; + protected Label encodingLabel, ianaLabel; + protected Text ianaText; + protected Vector ianaVector; + + /** + * Method EncodingSettings. + * + * @param parent + */ + public EncodingSettings(Composite parent) { + super(parent, SWT.NONE); + init(IANA_LABEL, ENCODING_LABEL); + } + + /** + * Method EncodingSettings. + * + * @param parent + * @param encodingLabel - + * text label to use beside the locale sensitive description of + * the currently selected encoding + */ + public EncodingSettings(Composite parent, String encodingLabel) { + super(parent, SWT.NONE); + init(IANA_LABEL, encodingLabel); + } + + /** + * Method EncodingSettings. + * + * @param parent + * @param ianaLabel = + * text label to use beside the display only IANA field + * @param encodingLabel - + * text label to use beside the locale sensitive description of + * the currently selected encoding + */ + public EncodingSettings(Composite parent, String ianaLabel, String encodingLabel) { + super(parent, SWT.NONE); + init(ianaLabel, encodingLabel); + } + + /** + * Method addEntry. Add an entry to the end of the Encoding Combobox + * + * @param description - + * encoding description to display + * @param ianaTag - + * IANA tag for the description + */ + public void addEntry(String description, String ianaTag) { + encodingCombo.add(description); + ianaVector.add(ianaTag); + } + + /** + * Method addEntry. Add an entry to the Encoding Combobox at index index + * + * @param description - + * encoding description to display + * @param ianaTag - + * IANA tag for the description + * @param index - + * index into the combo to add to + */ + public void addEntry(String description, String ianaTag, int index) { + if (index == ianaVector.size()) { + // just add to the end + addEntry(description, ianaTag); + return; + } + + if (0 <= index && index < ianaVector.size()) { + encodingCombo.add(description, index); + ianaVector.add(index, ianaTag); + } + } + + protected Combo createComboBox(Composite parent, boolean isReadOnly) { + int style = isReadOnly == true ? SWT.READ_ONLY : SWT.DROP_DOWN; + + Combo combo = new Combo(parent, style); + + GridData data = new GridData(); + data.horizontalAlignment = GridData.FILL; + data.grabExcessHorizontalSpace = true; + combo.setLayoutData(data); + return combo; + } + + /** + * Helper method for creating labels. + */ + protected Label createLabel(Composite parent, String text) { + Label label = new Label(parent, SWT.LEFT); + label.setText(text); + + GridData data = new GridData(); + data.horizontalAlignment = GridData.FILL; + label.setLayoutData(data); + return label; + } + + protected Text createTextField(Composite parent, int width) { + Text text = new Text(parent, SWT.SINGLE | SWT.READ_ONLY); + + GridData data = new GridData(); + data.horizontalAlignment = GridData.FILL; + data.grabExcessHorizontalSpace = true; + data.widthHint = width; + text.setLayoutData(data); + + return text; + } + + /** + * @see org.eclipse.swt.widgets.Widget#dispose() + */ + public void dispose() { + encodingCombo.removeModifyListener(comboListener); + super.dispose(); + } + + private void fillCombo() { + try { + String[] ianaTags = CommonCharsetNames.getCommonCharsetNames(); + int totalNum = ianaTags.length; + for (int i = 0; i < totalNum; i++) { + String iana = ianaTags[i]; + String enc = CommonCharsetNames.getDisplayString(iana); + + if (enc != null) { + encodingCombo.add(enc); + } else { + Logger.log(Logger.WARNING, "CommonCharsetNames.getDisplayString(" + iana + ") returned null"); //$NON-NLS-1$ //$NON-NLS-2$ + encodingCombo.add(iana); + } + ianaVector.add(iana); + } + } catch (Exception e) { + //e.printStackTrace(); + //MessageDialog.openError(getShell(), "Resource exception", + // "Unable to obtain encoding strings. Check resource file"); + //XMLEncodingPlugin.getPlugin().getMsgLogger().write(e.toString()); + //XMLEncodingPlugin.getPlugin().getMsgLogger().writeCurrentThread(); + Logger.log(Logger.ERROR, "Exception", e); //$NON-NLS-1$ + } + } + + /** + * <code>getEncoding</code> Get the descriptive encoding name that was + * selected. + * + * @return a <code>String</code> value + */ + public String getEncoding() { + return encodingCombo.getText(); + } + + /** + * Method getEncodingCombo. Returns the combo used to display the encoding + * descriptions. + * + * @return Combo + */ + public Combo getEncodingCombo() { + return encodingCombo; + } + + /** + * <code>getIANATag</code> Get the IANA tag equivalent of the selected + * descriptive encoding name + * + * @return a <code>String</code> value + */ + public String getIANATag() { + int i = encodingCombo.getSelectionIndex(); + if (i >= 0) { + return (String) (ianaVector.elementAt(i)); + } + return ""; //$NON-NLS-1$ + } + + protected void init(String ianaLabelStr, String encodingLabelStr) { + GridLayout layout = new GridLayout(); + layout.numColumns = 2; + setLayout(layout); + GridData data = new GridData(); + data.verticalAlignment = GridData.FILL; + data.horizontalAlignment = GridData.FILL; + data.grabExcessHorizontalSpace = true; + setLayoutData(data); + + encodingLabel = createLabel(this, encodingLabelStr); + encodingCombo = createComboBox(this, true); + ianaLabel = createLabel(this, ianaLabelStr); + ianaText = createTextField(this, 20); + ianaVector = new Vector(); + + fillCombo(); + resetToDefaultEncoding(); + encodingCombo.addModifyListener(comboListener); + } + + /** + * <code>isEncodingInList</code> Checks whether the encoding name is in + * the combo + * + * @param enc + * a <code>string</code> value. The encoding name. + * @return a <code>boolean</code> value. TRUE if encoding is in list. + * FALSE if encoding is not in list. + */ + public boolean isEncodingInList(String enc) { + int i = encodingCombo.indexOf(enc); + if (i >= 0) { + return true; + } + return false; + } + + /** + * <code>isIANATagInList</code> Checks whether the IANA tag is in the + * combo + * + * @param ianaTag + * a <code>string</code> value. The IANA tag. + * @return a <code>boolean</code> value. TRUE if tag is in list. FALSE + * if tag is not in list. + */ + public boolean isIANATagInList(String ianaTag) { + int i = ianaVector.indexOf(ianaTag); + if (i >= 0) { + return true; + } + return false; + } + + /** + * Method removeEntry. Removes both the description and the IANA tag at + * the specified index + * + * @param index + */ + public void removeEntry(int index) { + if (0 <= index && index < ianaVector.size()) { + encodingCombo.remove(index); + ianaVector.remove(index); + } + } + + /** + * Method resetToDefaultEncoding. Reset the control to the default + * encoding. Currently UTF-8 + */ + public void resetToDefaultEncoding() { + String defaultIANATag = "UTF-8"; //$NON-NLS-1$ + ianaText.setText(defaultIANATag); + setIANATag(defaultIANATag); + } + + /** + * Method setEnabled. Enable/disable the EncodingSettings composite. + * + * @param enabled + */ + public void setEnabled(boolean enabled) { + encodingCombo.setEnabled(enabled); + encodingLabel.setEnabled(enabled); + ianaLabel.setEnabled(enabled); + ianaText.setEnabled(enabled); + } + + /** + * <code>setEncoding</code> Set the selection in the combo to the + * descriptive encoding name. + * + * @param enc + * a <code>string</code> value. Note this is not the IANA + * tag. + */ + public void setEncoding(String enc) { + encodingCombo.setText(enc); + encodingCombo.select(encodingCombo.indexOf(enc)); + } + + /** + * <code>setIANATag</code> Set the IANA tag for the combo + * + * @param ianaTag + * a <code>string</code> value. The IANA tag. + */ + public void setIANATag(String ianaTag) { + int i = ianaVector.indexOf(ianaTag); + if (i >= 0) { + encodingCombo.select(i); + } + } + +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/preferences/WorkbenchDefaultEncodingSettings.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/preferences/WorkbenchDefaultEncodingSettings.java new file mode 100644 index 0000000000..705f07bb6c --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/preferences/WorkbenchDefaultEncodingSettings.java @@ -0,0 +1,147 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.preferences; + +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +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.wst.common.encoding.CommonCharsetNames; +import org.eclipse.wst.xml.ui.nls.ResourceHandler; + + +/** + * WorkbenchDefaultEncodingSettings is an extension of EncodingSettings. This + * composite contains EncodingSettings for users to select the encoding they + * desire as well as a checkbox for users to select to use the default + * workbench encoding instead. + * + * @see org.eclipse.wst.xml.ui.preferences.EncodingSettings + */ +public class WorkbenchDefaultEncodingSettings extends Composite { + + private final static int INDENT = 15; + private static final String WORKBENCH_DEFAULT = ""; //$NON-NLS-1$ + private EncodingSettings fEncodingSettings; + private String fNonDefaultIANA = null; + private Button fUseDefaultButton; + + /** + * Constructor for WorkbenchDefaultEncodingSettings. + * + * @param parent + * @param style + */ + public WorkbenchDefaultEncodingSettings(Composite parent) { + super(parent, SWT.NONE); + createControls(); + } + + private void createControls() { + GridLayout layout = new GridLayout(); + layout.numColumns = 1; + layout.marginWidth = 0; + setLayout(layout); + GridData data = new GridData(); + data.verticalAlignment = GridData.FILL; + data.horizontalAlignment = GridData.FILL; + data.grabExcessHorizontalSpace = true; + setLayoutData(data); + + Composite defaultEncodingComposite = new Composite(this, SWT.NONE); + layout = new GridLayout(); + layout.marginWidth = 0; + layout.marginHeight = 0; + data = new GridData(GridData.FILL_BOTH); + defaultEncodingComposite.setLayout(layout); + defaultEncodingComposite.setLayoutData(data); + + fUseDefaultButton = new Button(defaultEncodingComposite, SWT.CHECK); + fUseDefaultButton.setText(ResourceHandler.getString("WorkbenchDefaultEncodingSettings.0")); //$NON-NLS-1$ + + fUseDefaultButton.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent e) { + handleUseDefaultButtonSelected(); + } + }); + + fEncodingSettings = new EncodingSettings(this); + ((GridLayout) fEncodingSettings.getLayout()).marginWidth = 0; + ((GridData) fEncodingSettings.getLayoutData()).horizontalIndent = INDENT; + + } + + private Combo getEncodingCombo() { + return fEncodingSettings.getEncodingCombo(); + } + + /** + * <code>getIANATag</code> Get the IANA tag equivalent of the selected + * descriptive encoding name. Returns empty string if using workbench + * encoding. + * + * @return a <code>String</code> value + */ + public String getIANATag() { + if (!isDefault()) + return fEncodingSettings.getIANATag(); + return WORKBENCH_DEFAULT; + } + + private String getWorkbenchEncoding() { + return ResourcesPlugin.getEncoding(); + } + + private void handleUseDefaultButtonSelected() { + if (fUseDefaultButton.getSelection()) { + fNonDefaultIANA = fEncodingSettings.getIANATag(); + String workbenchValue = getWorkbenchEncoding(); + workbenchValue = CommonCharsetNames.getIanaPreferredCharsetName(workbenchValue); + fEncodingSettings.setIANATag(workbenchValue); + } else if (fNonDefaultIANA != null) { + fEncodingSettings.setIANATag(fNonDefaultIANA); + } + getEncodingCombo().setEnabled(!fUseDefaultButton.getSelection()); + fEncodingSettings.setEnabled(!fUseDefaultButton.getSelection()); + } + + private boolean isDefault() { + return fUseDefaultButton.getSelection(); + } + + /** + * <code>setEncoding</code> Set the selection in the combo to the + * descriptive encoding name. Selects use workbench encoding if ianaTag is + * null or empty string. + * + * @param enc + * a <code>string</code> value. Note this is not the IANA + * tag. + */ + public void setIANATag(String ianaTag) { + if (ianaTag == null || ianaTag.equals(WORKBENCH_DEFAULT)) { + fUseDefaultButton.setSelection(true); + handleUseDefaultButtonSelected(); + } else { + fUseDefaultButton.setSelection(false); + handleUseDefaultButtonSelected(); + if (!isDefault()) + fEncodingSettings.setIANATag(ianaTag); + } + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/preferences/XMLColorPage.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/preferences/XMLColorPage.java new file mode 100644 index 0000000000..71aef4ed0d --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/preferences/XMLColorPage.java @@ -0,0 +1,230 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.preferences; + + + +import java.util.ArrayList; +import java.util.Dictionary; +import java.util.Hashtable; +import java.util.Iterator; + +import org.eclipse.core.runtime.Platform; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.ui.help.WorkbenchHelp; +import org.eclipse.wst.common.encoding.content.IContentTypeIdentifier; +import org.eclipse.wst.sse.core.IModelManager; +import org.eclipse.wst.sse.core.IModelManagerPlugin; +import org.eclipse.wst.sse.ui.EditorPlugin; +import org.eclipse.wst.sse.ui.internal.preferences.OverlayPreferenceStore; +import org.eclipse.wst.sse.ui.internal.preferences.OverlayPreferenceStore.OverlayKey; +import org.eclipse.wst.sse.ui.preferences.PreferenceKeyGenerator; +import org.eclipse.wst.sse.ui.preferences.ui.AbstractColorPage; +import org.eclipse.wst.sse.ui.preferences.ui.StyledTextColorPicker; +import org.eclipse.wst.xml.core.internal.parser.XMLSourceParser; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; +import org.eclipse.wst.xml.ui.internal.editor.IHelpContextIds; +import org.eclipse.wst.xml.ui.nls.ResourceHandler; +import org.eclipse.wst.xml.ui.style.IStyleConstantsXML; + + + +public class XMLColorPage extends AbstractColorPage { + + protected Control createContents(Composite parent) { + Composite pageComponent = createComposite(parent, 1); + ((GridData) pageComponent.getLayoutData()).horizontalAlignment = GridData.HORIZONTAL_ALIGN_FILL; + + super.createContents(pageComponent); + WorkbenchHelp.setHelp(pageComponent, IHelpContextIds.XML_PREFWEBX_STYLES_HELPID); + return pageComponent; + } + + /** + * Set up all the style preference keys in the overlay store + */ + protected OverlayKey[] createOverlayStoreKeys() { + ArrayList overlayKeys = new ArrayList(); + + ArrayList styleList = new ArrayList(); + initStyleList(styleList); + Iterator i = styleList.iterator(); + while (i.hasNext()) { + overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.STRING, PreferenceKeyGenerator.generateKey((String) i.next(), IContentTypeIdentifier.ContentTypeID_SSEXML))); + } + + OverlayPreferenceStore.OverlayKey[] keys = new OverlayPreferenceStore.OverlayKey[overlayKeys.size()]; + overlayKeys.toArray(keys); + return keys; + } + + protected IPreferenceStore doGetPreferenceStore() { + return EditorPlugin.getDefault().getPreferenceStore(); + } + + public String getSampleText() { + return ResourceHandler.getString("Sample_XML_doc"); //$NON-NLS-1$ = "<?xml version=\"1.0\"?>\n<?customProcessingInstruction\n\tXML processor specific\n\tcontent ?>\n<!DOCTYPE colors\n\tPUBLIC \"//IBM/XML/COLORS/\" \"colors.dtd\">\n<colors>\n\t<!-- begin color definitions -->\n\t<color name=\"plaintext\" foreground=\"#000000\"\n\t\tbackground=\"#D4D0C8\"/>\n\t<color name=\"bold\" foreground=\"#000000\"\n\t\tbackground=\"#B3ACA0\">\n\t<![CDATA[<123456789>]]>\n\tNormal text content.\n\t<color name=\"inverse\" foreground=\"#F0F0F0\"\n\t\tbackground=\"#D4D0C8\"/>\n\n</colors>\n"; + } + + protected void initCommonContextStyleMap(Dictionary contextStyleMap) { + + contextStyleMap.put(XMLRegionContext.XML_COMMENT_OPEN, IStyleConstantsXML.COMMENT_BORDER); + contextStyleMap.put(XMLRegionContext.XML_COMMENT_TEXT, IStyleConstantsXML.COMMENT_TEXT); + contextStyleMap.put(XMLRegionContext.XML_COMMENT_CLOSE, IStyleConstantsXML.COMMENT_BORDER); + + contextStyleMap.put(XMLRegionContext.XML_TAG_OPEN, IStyleConstantsXML.TAG_BORDER); + contextStyleMap.put(XMLRegionContext.XML_END_TAG_OPEN, IStyleConstantsXML.TAG_BORDER); + contextStyleMap.put(XMLRegionContext.XML_TAG_NAME, IStyleConstantsXML.TAG_NAME); + contextStyleMap.put(XMLRegionContext.XML_TAG_ATTRIBUTE_NAME, IStyleConstantsXML.TAG_ATTRIBUTE_NAME); + contextStyleMap.put(XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE, IStyleConstantsXML.TAG_ATTRIBUTE_VALUE); + contextStyleMap.put(XMLRegionContext.XML_TAG_CLOSE, IStyleConstantsXML.TAG_BORDER); + contextStyleMap.put(XMLRegionContext.XML_EMPTY_TAG_CLOSE, IStyleConstantsXML.TAG_BORDER); + + contextStyleMap.put(XMLRegionContext.XML_DECLARATION_OPEN, IStyleConstantsXML.DECL_BORDER); + contextStyleMap.put(XMLRegionContext.XML_DECLARATION_CLOSE, IStyleConstantsXML.DECL_BORDER); + contextStyleMap.put(XMLRegionContext.XML_ELEMENT_DECLARATION, IStyleConstantsXML.DECL_BORDER); + contextStyleMap.put(XMLRegionContext.XML_ELEMENT_DECL_CLOSE, IStyleConstantsXML.DECL_BORDER); + + contextStyleMap.put(XMLRegionContext.XML_CONTENT, IStyleConstantsXML.XML_CONTENT); + } + + protected void initCommonDescriptions(Dictionary descriptions) { + + // create descriptions for hilighting types + descriptions.put(IStyleConstantsXML.COMMENT_BORDER, ResourceHandler.getString("Comment_Delimiters_UI_")); //$NON-NLS-1$ = "Comment Delimiters" + descriptions.put(IStyleConstantsXML.COMMENT_TEXT, ResourceHandler.getString("Comment_Content_UI_")); //$NON-NLS-1$ = "Comment Content" + descriptions.put(IStyleConstantsXML.TAG_BORDER, ResourceHandler.getString("Tag_Delimiters_UI_")); //$NON-NLS-1$ = "Tag Delimiters" + descriptions.put(IStyleConstantsXML.TAG_NAME, ResourceHandler.getString("Tag_Names_UI_")); //$NON-NLS-1$ = "Tag Names" + descriptions.put(IStyleConstantsXML.TAG_ATTRIBUTE_NAME, ResourceHandler.getString("Attribute_Names_UI_")); //$NON-NLS-1$ = "Attribute Names" + descriptions.put(IStyleConstantsXML.TAG_ATTRIBUTE_VALUE, ResourceHandler.getString("Attribute_Values_UI_")); //$NON-NLS-1$ = "Attribute Values" + descriptions.put(IStyleConstantsXML.DECL_BORDER, ResourceHandler.getString("Declaration_Delimiters_UI_")); //$NON-NLS-1$ = "Declaration Delimiters" + descriptions.put(IStyleConstantsXML.XML_CONTENT, ResourceHandler.getString("Content_UI_")); //$NON-NLS-1$ = "Content" + } + + protected void initCommonStyleList(ArrayList list) { + + //list.add(IStyleConstantsXML.CDATA_BORDER); + //list.add(IStyleConstantsXML.CDATA_TEXT); + //list.add(IStyleConstantsXML.PI_BORDER); + //list.add(IStyleConstantsXML.PI_CONTENT); + + list.add(IStyleConstantsXML.TAG_BORDER); + list.add(IStyleConstantsXML.TAG_NAME); + list.add(IStyleConstantsXML.TAG_ATTRIBUTE_NAME); + list.add(IStyleConstantsXML.TAG_ATTRIBUTE_VALUE); + list.add(IStyleConstantsXML.COMMENT_BORDER); + list.add(IStyleConstantsXML.COMMENT_TEXT); + list.add(IStyleConstantsXML.DECL_BORDER); + list.add(IStyleConstantsXML.XML_CONTENT); + } + + protected void initContextStyleMap(Dictionary contextStyleMap) { + + initCommonContextStyleMap(contextStyleMap); + initDocTypeContextStyleMap(contextStyleMap); + contextStyleMap.put(XMLRegionContext.XML_CDATA_OPEN, IStyleConstantsXML.CDATA_BORDER); + contextStyleMap.put(XMLRegionContext.XML_CDATA_TEXT, IStyleConstantsXML.CDATA_TEXT); + contextStyleMap.put(XMLRegionContext.XML_CDATA_CLOSE, IStyleConstantsXML.CDATA_BORDER); + + contextStyleMap.put(XMLRegionContext.XML_PI_OPEN, IStyleConstantsXML.PI_BORDER); + contextStyleMap.put(XMLRegionContext.XML_PI_CONTENT, IStyleConstantsXML.PI_CONTENT); + contextStyleMap.put(XMLRegionContext.XML_PI_CLOSE, IStyleConstantsXML.PI_BORDER); + + } + + protected void initDescriptions(Dictionary descriptions) { + + initCommonDescriptions(descriptions); + initDocTypeDescriptions(descriptions); + descriptions.put(IStyleConstantsXML.CDATA_BORDER, ResourceHandler.getString("CDATA_Delimiters_UI_")); //$NON-NLS-1$ = "CDATA Delimiters" + descriptions.put(IStyleConstantsXML.CDATA_TEXT, ResourceHandler.getString("CDATA_Content_UI_")); //$NON-NLS-1$ = "CDATA Content" + descriptions.put(IStyleConstantsXML.PI_BORDER, ResourceHandler.getString("Processing_Instruction_Del_UI_")); //$NON-NLS-1$ = "Processing Instruction Delimiters" + descriptions.put(IStyleConstantsXML.PI_CONTENT, ResourceHandler.getString("Processing_Instruction_Con_UI__UI_")); //$NON-NLS-1$ = "Processing Instruction Content" + } + + protected void initDocTypeContextStyleMap(Dictionary contextStyleMap) { + + contextStyleMap.put(XMLRegionContext.XML_ELEMENT_DECL_NAME, IStyleConstantsXML.DOCTYPE_NAME); + contextStyleMap.put(XMLRegionContext.XML_DOCTYPE_DECLARATION, IStyleConstantsXML.TAG_NAME); + contextStyleMap.put(XMLRegionContext.XML_DOCTYPE_DECLARATION_CLOSE, IStyleConstantsXML.DECL_BORDER); + + contextStyleMap.put(XMLRegionContext.XML_DOCTYPE_NAME, IStyleConstantsXML.DOCTYPE_NAME); + contextStyleMap.put(XMLRegionContext.XML_DOCTYPE_EXTERNAL_ID_PUBLIC, IStyleConstantsXML.DOCTYPE_EXTERNAL_ID); + contextStyleMap.put(XMLRegionContext.XML_DOCTYPE_EXTERNAL_ID_PUBREF, IStyleConstantsXML.DOCTYPE_EXTERNAL_ID_PUBREF); + contextStyleMap.put(XMLRegionContext.XML_DOCTYPE_EXTERNAL_ID_SYSTEM, IStyleConstantsXML.DOCTYPE_EXTERNAL_ID); + contextStyleMap.put(XMLRegionContext.XML_DOCTYPE_EXTERNAL_ID_SYSREF, IStyleConstantsXML.DOCTYPE_EXTERNAL_ID_SYSREF); + } + + protected void initDocTypeDescriptions(Dictionary descriptions) { + + // create descriptions for hilighting types for DOCTYPE related items + descriptions.put(IStyleConstantsXML.DOCTYPE_NAME, ResourceHandler.getString("DOCTYPE_Name_UI_")); //$NON-NLS-1$ = "DOCTYPE Name" + descriptions.put(IStyleConstantsXML.DOCTYPE_EXTERNAL_ID, ResourceHandler.getString("DOCTYPE_SYSTEM/PUBLIC_Keyw_UI_")); //$NON-NLS-1$ = "DOCTYPE SYSTEM/PUBLIC Keyword" + descriptions.put(IStyleConstantsXML.DOCTYPE_EXTERNAL_ID_PUBREF, ResourceHandler.getString("DOCTYPE_Public_Reference_UI_")); //$NON-NLS-1$ = "DOCTYPE Public Reference" + descriptions.put(IStyleConstantsXML.DOCTYPE_EXTERNAL_ID_SYSREF, ResourceHandler.getString("DOCTYPE_System_Reference_UI_")); //$NON-NLS-1$ = "DOCTYPE System Reference" + } + + protected void initDocTypeStyleList(ArrayList list) { + + list.add(IStyleConstantsXML.DOCTYPE_NAME); + list.add(IStyleConstantsXML.DOCTYPE_EXTERNAL_ID); + list.add(IStyleConstantsXML.DOCTYPE_EXTERNAL_ID_PUBREF); + list.add(IStyleConstantsXML.DOCTYPE_EXTERNAL_ID_SYSREF); + } + + protected void initStyleList(ArrayList list) { + initCommonStyleList(list); + initDocTypeStyleList(list); + list.add(IStyleConstantsXML.CDATA_BORDER); + list.add(IStyleConstantsXML.CDATA_TEXT); + list.add(IStyleConstantsXML.PI_BORDER); + list.add(IStyleConstantsXML.PI_CONTENT); + } + + public boolean performOk() { + // required since the superclass *removes* existing preferences before + // saving its own + super.performOk(); + + EditorPlugin.getDefault().savePluginPreferences(); + return true; + } + + protected void setupPicker(StyledTextColorPicker picker) { + + IModelManagerPlugin plugin = (IModelManagerPlugin) Platform.getPlugin(IModelManagerPlugin.ID); + if (plugin != null) { + IModelManager mmanager = plugin.getModelManager(); + picker.setParser(mmanager.createStructuredDocumentFor(IContentTypeIdentifier.ContentTypeID_SSEXML).getParser()); + } else + picker.setParser(new XMLSourceParser()); + + Dictionary descriptions = new Hashtable(); + initDescriptions(descriptions); + + Dictionary contextStyleMap = new Hashtable(); + initContextStyleMap(contextStyleMap); + + ArrayList styleList = new ArrayList(); + initStyleList(styleList); + + picker.setContextStyleMap(contextStyleMap); + picker.setDescriptions(descriptions); + picker.setStyleList(styleList); + + picker.setGeneratorKey(IContentTypeIdentifier.ContentTypeID_SSEXML); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/preferences/XMLFilesPreferencePage.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/preferences/XMLFilesPreferencePage.java new file mode 100644 index 0000000000..4a159c642a --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/preferences/XMLFilesPreferencePage.java @@ -0,0 +1,206 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.preferences; + + + +import java.util.Vector; + +import org.eclipse.core.runtime.Preferences; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; +import org.eclipse.ui.help.WorkbenchHelp; +import org.eclipse.wst.common.encoding.CommonEncodingPreferenceNames; +import org.eclipse.wst.sse.ui.EditorPlugin; +import org.eclipse.wst.sse.ui.nls.ResourceHandler; +import org.eclipse.wst.sse.ui.preferences.ui.AbstractPreferencePage; +import org.eclipse.wst.xml.core.XMLModelPlugin; +import org.eclipse.wst.xml.ui.internal.editor.IHelpContextIds; + + +public class XMLFilesPreferencePage extends AbstractPreferencePage { + protected EncodingSettings fEncodingSettings = null; + + protected Combo fEndOfLineCode = null; + private Vector fEOLCodes = null; + + protected Control createContents(Composite parent) { + Composite composite = (Composite) super.createContents(parent); + WorkbenchHelp.setHelp(composite, IHelpContextIds.XML_PREFWEBX_FILES_HELPID); + createContentsForCreatingOrSavingGroup(composite); + createContentsForCreatingGroup(composite); + + setSize(composite); + loadPreferences(); + + return composite; + } + + protected void createContentsForCreatingGroup(Composite parent) { + Group creatingGroup = createGroup(parent, 1); + creatingGroup.setText(ResourceHandler.getString("Creating_files")); //$NON-NLS-1$ + + Label label = createLabel(creatingGroup, ResourceHandler.getString("Encoding_desc")); //$NON-NLS-1$ + + fEncodingSettings = new EncodingSettings(creatingGroup, ResourceHandler.getString("Encoding")); //$NON-NLS-1$ + } + + protected void createContentsForCreatingOrSavingGroup(Composite parent) { + Group creatingOrSavingGroup = createGroup(parent, 2); + creatingOrSavingGroup.setText(ResourceHandler.getString("Creating_or_saving_files")); //$NON-NLS-1$ + + Label label = createLabel(creatingOrSavingGroup, ResourceHandler.getString("End-of-line_code_desc")); //$NON-NLS-1$ + ((GridData) label.getLayoutData()).horizontalSpan = 2; + ((GridData) label.getLayoutData()).grabExcessHorizontalSpace = true; + + createLabel(creatingOrSavingGroup, ResourceHandler.getString("End-of-line_code")); //$NON-NLS-1$ + fEndOfLineCode = createDropDownBox(creatingOrSavingGroup); + populateLineDelimiters(); + } + + protected IPreferenceStore doGetPreferenceStore() { + return EditorPlugin.getDefault().getPreferenceStore(); + } + + protected void doSavePreferenceStore() { + XMLModelPlugin.getDefault().savePluginPreferences(); // model + } + + /** + * Return the currently selected line delimiter preference + * + * @return a line delimiter constant from CommonEncodingPreferenceNames + */ + private String getCurrentEOLCode() { + int i = fEndOfLineCode.getSelectionIndex(); + if (i >= 0) { + return (String) (fEOLCodes.elementAt(i)); + } + return ""; //$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.ui.preferences.ui.AbstractPreferencePage#getModelPreferences() + */ + protected Preferences getModelPreferences() { + return XMLModelPlugin.getDefault().getPluginPreferences(); + } + + protected void initializeValues() { + initializeValuesForCreatingOrSavingGroup(); + initializeValuesForCreatingGroup(); + } + + protected void initializeValuesForCreatingGroup() { + String encoding = getModelPreferences().getString(CommonEncodingPreferenceNames.OUTPUT_CODESET); + + fEncodingSettings.setIANATag(encoding); + } + + protected void initializeValuesForCreatingOrSavingGroup() { + String endOfLineCode = getModelPreferences().getString(CommonEncodingPreferenceNames.END_OF_LINE_CODE); + + if (endOfLineCode.length() > 0) + setCurrentEOLCode(endOfLineCode); + else + setCurrentEOLCode(CommonEncodingPreferenceNames.NO_TRANSLATION); + } + + protected void performDefaults() { + performDefaultsForCreatingOrSavingGroup(); + performDefaultsForCreatingGroup(); + + super.performDefaults(); + } + + protected void performDefaultsForCreatingGroup() { + String encoding = getModelPreferences().getDefaultString(CommonEncodingPreferenceNames.OUTPUT_CODESET); + + fEncodingSettings.setIANATag(encoding); + // fEncodingSettings.resetToDefaultEncoding(); + } + + protected void performDefaultsForCreatingOrSavingGroup() { + String endOfLineCode = getModelPreferences().getDefaultString(CommonEncodingPreferenceNames.END_OF_LINE_CODE); + + if (endOfLineCode.length() > 0) + setCurrentEOLCode(endOfLineCode); + else + setCurrentEOLCode(CommonEncodingPreferenceNames.NO_TRANSLATION); + } + + public boolean performOk() { + boolean result = super.performOk(); + + doSavePreferenceStore(); + + return result; + } + + /** + * Populates the vector containing the line delimiter to display string + * mapping and the combobox displaying line delimiters + */ + private void populateLineDelimiters() { + fEOLCodes = new Vector(); + fEndOfLineCode.add(ResourceHandler.getString("EOL_Unix")); //$NON-NLS-1$ + fEOLCodes.add(CommonEncodingPreferenceNames.LF); + + fEndOfLineCode.add(ResourceHandler.getString("EOL_Mac")); //$NON-NLS-1$ + fEOLCodes.add(CommonEncodingPreferenceNames.CR); + + fEndOfLineCode.add(ResourceHandler.getString("EOL_Windows")); //$NON-NLS-1$ + fEOLCodes.add(CommonEncodingPreferenceNames.CRLF); + + fEndOfLineCode.add(ResourceHandler.getString("EOL_NoTranslation")); //$NON-NLS-1$ + fEOLCodes.add(CommonEncodingPreferenceNames.NO_TRANSLATION); + } + + /** + * Select the line delimiter in the eol combobox + * + * @param eol + * a line delimiter constant from CommonEncodingPreferenceNames + */ + private void setCurrentEOLCode(String eolCode) { + // Clear the current selection. + fEndOfLineCode.clearSelection(); + fEndOfLineCode.deselectAll(); + + int i = fEOLCodes.indexOf(eolCode); + if (i >= 0) { + fEndOfLineCode.select(i); + } + } + + protected void storeValues() { + storeValuesForCreatingOrSavingGroup(); + storeValuesForCreatingGroup(); + } + + protected void storeValuesForCreatingGroup() { + getModelPreferences().setValue(CommonEncodingPreferenceNames.OUTPUT_CODESET, fEncodingSettings.getIANATag()); + } + + protected void storeValuesForCreatingOrSavingGroup() { + String eolCode = getCurrentEOLCode(); + getModelPreferences().setValue(CommonEncodingPreferenceNames.END_OF_LINE_CODE, eolCode); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/preferences/XMLSourcePreferencePage.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/preferences/XMLSourcePreferencePage.java new file mode 100644 index 0000000000..25689e1503 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/preferences/XMLSourcePreferencePage.java @@ -0,0 +1,250 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.preferences; + + + +import org.eclipse.core.runtime.Preferences; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.IWorkbenchPreferencePage; +import org.eclipse.ui.help.WorkbenchHelp; +import org.eclipse.wst.common.encoding.content.IContentTypeIdentifier; +import org.eclipse.wst.sse.core.preferences.CommonModelPreferenceNames; +import org.eclipse.wst.sse.ui.EditorPlugin; +import org.eclipse.wst.sse.ui.nls.ResourceHandler; +import org.eclipse.wst.sse.ui.preferences.CommonEditorPreferenceNames; +import org.eclipse.wst.sse.ui.preferences.PreferenceKeyGenerator; +import org.eclipse.wst.sse.ui.preferences.ui.AbstractPreferencePage; +import org.eclipse.wst.xml.core.XMLModelPlugin; +import org.eclipse.wst.xml.ui.internal.editor.IHelpContextIds; + + +public class XMLSourcePreferencePage extends AbstractPreferencePage implements ModifyListener, SelectionListener, IWorkbenchPreferencePage { + // Content Assist + protected Button fAutoPropose; + protected Label fAutoProposeLabel; + protected Text fAutoProposeText; + protected Button fClearAllBlankLines; + protected Button fIndentUsingTabs; + // Formatting + protected Label fLineWidthLabel; + protected Text fLineWidthText; + protected Button fSplitMultiAttrs; + // grammar constraints + protected Button fUseInferredGrammar; + + protected Control createContents(Composite parent) { + Composite composite = (Composite) super.createContents(parent); + WorkbenchHelp.setHelp(composite, IHelpContextIds.XML_PREFWEBX_SOURCE_HELPID); + + createContentsForFormattingGroup(composite); + createContentsForContentAssistGroup(composite); + createContentsForGrammarConstraintsGroup(composite); + setSize(composite); + loadPreferences(); + + return composite; + } + + protected void createContentsForContentAssistGroup(Composite parent) { + Group contentAssistGroup = createGroup(parent, 2); + contentAssistGroup.setText(ResourceHandler.getString("Content_assist_UI_")); //$NON-NLS-1$ = "Content assist" + + fAutoPropose = createCheckBox(contentAssistGroup, ResourceHandler.getString("Automatically_make_suggest_UI_")); //$NON-NLS-1$ = "Automatically make suggestions" + ((GridData) fAutoPropose.getLayoutData()).horizontalSpan = 2; + fAutoPropose.addSelectionListener(this); + + fAutoProposeLabel = createLabel(contentAssistGroup, ResourceHandler.getString("Prompt_when_these_characte_UI_")); //$NON-NLS-1$ = "Prompt when these characters are inserted:" + fAutoProposeText = createTextField(contentAssistGroup); + } + + protected void createContentsForFormattingGroup(Composite parent) { + Group formattingGroup = createGroup(parent, 2); + formattingGroup.setText(ResourceHandler.getString("Formatting_UI_")); //$NON-NLS-1$ = "Formatting" + + fLineWidthLabel = createLabel(formattingGroup, ResourceHandler.getString("Line_width__UI_")); //$NON-NLS-1$ = "Line width:" + fLineWidthText = new Text(formattingGroup, SWT.SINGLE | SWT.BORDER); + GridData gData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING | GridData.BEGINNING); + gData.widthHint = 25; + fLineWidthText.setLayoutData(gData); + fLineWidthText.addModifyListener(this); + + fSplitMultiAttrs = createCheckBox(formattingGroup, ResourceHandler.getString("Split_&multiple_attributes_2")); //$NON-NLS-1$ + ((GridData) fSplitMultiAttrs.getLayoutData()).horizontalSpan = 2; + + fIndentUsingTabs = createCheckBox(formattingGroup, ResourceHandler.getString("&Indent_using_tabs_3")); //$NON-NLS-1$ + ((GridData) fIndentUsingTabs.getLayoutData()).horizontalSpan = 2; + + fClearAllBlankLines = createCheckBox(formattingGroup, ResourceHandler.getString("Clear_all_blank_lines_UI_")); //$NON-NLS-1$ = "Clear all blank lines" + ((GridData) fClearAllBlankLines.getLayoutData()).horizontalSpan = 2; + } + + protected void createContentsForGrammarConstraintsGroup(Composite parent) { + Group grammarConstraintsGroup = createGroup(parent, 1); + grammarConstraintsGroup.setText(ResourceHandler.getString("Grammar_Constraints")); //$NON-NLS-1$ + grammarConstraintsGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL)); + + fUseInferredGrammar = createCheckBox(grammarConstraintsGroup, ResourceHandler.getString("Use_inferred_grammar_in_absence_of_DTD/Schema")); //$NON-NLS-1$ + } + + protected IPreferenceStore doGetPreferenceStore() { + return EditorPlugin.getDefault().getPreferenceStore(); + } + + protected void doSavePreferenceStore() { + EditorPlugin.getDefault().savePluginPreferences(); // editor + XMLModelPlugin.getDefault().savePluginPreferences(); // model + } + + protected void enableValues() { + if (fAutoPropose != null) { + if (fAutoPropose.getSelection()) { + fAutoProposeLabel.setEnabled(true); + fAutoProposeText.setEnabled(true); + } else { + fAutoProposeLabel.setEnabled(false); + fAutoProposeText.setEnabled(false); + } + } + } + + /* + * helper method to generate content type id specific preference keys + */ + protected String getKey(String key) { + String contentTypeId = IContentTypeIdentifier.ContentTypeID_SSEXML; + return PreferenceKeyGenerator.generateKey(key, contentTypeId); + } + + protected Preferences getModelPreferences() { + return XMLModelPlugin.getDefault().getPluginPreferences(); + } + + protected void initializeValues() { + initializeValuesForFormattingGroup(); + initializeValuesForContentAssistGroup(); + initializeValuesForGrammarConstraintsGroup(); + } + + protected void initializeValuesForContentAssistGroup() { + // Content Assist + fAutoPropose.setSelection(getPreferenceStore().getBoolean(getKey(CommonEditorPreferenceNames.AUTO_PROPOSE))); + fAutoProposeText.setText(getPreferenceStore().getString(getKey(CommonEditorPreferenceNames.AUTO_PROPOSE_CODE))); + } + + protected void initializeValuesForFormattingGroup() { + // Formatting + fLineWidthText.setText(getModelPreferences().getString(CommonModelPreferenceNames.LINE_WIDTH)); + fSplitMultiAttrs.setSelection(getModelPreferences().getBoolean(CommonModelPreferenceNames.SPLIT_MULTI_ATTRS)); + fIndentUsingTabs.setSelection(getModelPreferences().getBoolean(CommonModelPreferenceNames.INDENT_USING_TABS)); + fClearAllBlankLines.setSelection(getModelPreferences().getBoolean(CommonModelPreferenceNames.CLEAR_ALL_BLANK_LINES)); + } + + protected void initializeValuesForGrammarConstraintsGroup() { + fUseInferredGrammar.setSelection(getPreferenceStore().getBoolean(getKey(CommonEditorPreferenceNames.EDITOR_USE_INFERRED_GRAMMAR))); + } + + protected void performDefaults() { + performDefaultsForFormattingGroup(); + performDefaultsForContentAssistGroup(); + performDefaultsForGrammarConstraintsGroup(); + + validateValues(); + enableValues(); + + super.performDefaults(); + } + + protected void performDefaultsForContentAssistGroup() { + // Content Assist + fAutoPropose.setSelection(getPreferenceStore().getDefaultBoolean(getKey(CommonEditorPreferenceNames.AUTO_PROPOSE))); + fAutoProposeText.setText(getPreferenceStore().getDefaultString(getKey(CommonEditorPreferenceNames.AUTO_PROPOSE_CODE))); + } + + protected void performDefaultsForFormattingGroup() { + // Formatting + fLineWidthText.setText(getModelPreferences().getDefaultString(CommonModelPreferenceNames.LINE_WIDTH)); + fSplitMultiAttrs.setSelection(getModelPreferences().getDefaultBoolean(CommonModelPreferenceNames.SPLIT_MULTI_ATTRS)); + fIndentUsingTabs.setSelection(getModelPreferences().getDefaultBoolean(CommonModelPreferenceNames.INDENT_USING_TABS)); + fClearAllBlankLines.setSelection(getModelPreferences().getDefaultBoolean(CommonModelPreferenceNames.CLEAR_ALL_BLANK_LINES)); + } + + protected void performDefaultsForGrammarConstraintsGroup() { + fUseInferredGrammar.setSelection(getPreferenceStore().getDefaultBoolean(getKey(CommonEditorPreferenceNames.EDITOR_USE_INFERRED_GRAMMAR))); + } + + public boolean performOk() { + boolean result = super.performOk(); + + doSavePreferenceStore(); + + return result; + } + + protected void storeValues() { + storeValuesForFormattingGroup(); + storeValuesForContentAssistGroup(); + storeValuesForGrammarConstraintsGroup(); + } + + protected void storeValuesForContentAssistGroup() { + // Content Assist + getPreferenceStore().setValue(getKey(CommonEditorPreferenceNames.AUTO_PROPOSE), fAutoPropose.getSelection()); + getPreferenceStore().setValue(getKey(CommonEditorPreferenceNames.AUTO_PROPOSE_CODE), fAutoProposeText.getText()); + } + + protected void storeValuesForFormattingGroup() { + // Formatting + getModelPreferences().setValue(CommonModelPreferenceNames.LINE_WIDTH, fLineWidthText.getText()); + getModelPreferences().setValue(CommonModelPreferenceNames.SPLIT_MULTI_ATTRS, fSplitMultiAttrs.getSelection()); + getModelPreferences().setValue(CommonModelPreferenceNames.INDENT_USING_TABS, fIndentUsingTabs.getSelection()); + getModelPreferences().setValue(CommonModelPreferenceNames.CLEAR_ALL_BLANK_LINES, fClearAllBlankLines.getSelection()); + } + + protected void storeValuesForGrammarConstraintsGroup() { + getPreferenceStore().setValue(getKey(CommonEditorPreferenceNames.EDITOR_USE_INFERRED_GRAMMAR), fUseInferredGrammar.getSelection()); + } + + protected void validateValues() { + boolean isError = false; + String widthText = null; + + if (fLineWidthText != null) { + try { + widthText = fLineWidthText.getText(); + int formattingLineWidth = Integer.parseInt(widthText); + if ((formattingLineWidth < WIDTH_VALIDATION_LOWER_LIMIT) || (formattingLineWidth > WIDTH_VALIDATION_UPPER_LIMIT)) + throw new NumberFormatException(); + } catch (NumberFormatException nfexc) { + setInvalidInputMessage(widthText); + setValid(false); + isError = true; + } + } + + if (!isError) { + setErrorMessage(null); + setValid(true); + } + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/preferences/XMLTemplatePreferencePage.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/preferences/XMLTemplatePreferencePage.java new file mode 100644 index 0000000000..2b05119f2c --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/preferences/XMLTemplatePreferencePage.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.preferences; + +import org.eclipse.core.runtime.Platform; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.ui.help.WorkbenchHelp; +import org.eclipse.ui.texteditor.templates.TemplatePreferencePage; +import org.eclipse.wst.xml.ui.XMLEditorPlugin; +import org.eclipse.wst.xml.ui.internal.editor.IHelpContextIds; + + +/** + * Preference page for XML templates + */ +public class XMLTemplatePreferencePage extends TemplatePreferencePage { + + public XMLTemplatePreferencePage() { + XMLEditorPlugin xmlEditorPlugin = (XMLEditorPlugin) Platform.getPlugin(XMLEditorPlugin.ID); + + setPreferenceStore(xmlEditorPlugin.getPreferenceStore()); + setTemplateStore(xmlEditorPlugin.getTemplateStore()); + setContextTypeRegistry(xmlEditorPlugin.getTemplateContextRegistry()); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.preference.PreferencePage#createContents(org.eclipse.swt.widgets.Composite) + */ + protected Control createContents(Composite ancestor) { + Control c = super.createContents(ancestor); + WorkbenchHelp.setHelp(c, IHelpContextIds.XML_PREFWEBX_TEMPLATES_HELPID); + return c; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ui.texteditor.templates.TemplatePreferencePage#isShowFormatterSetting() + */ + protected boolean isShowFormatterSetting() { + // template formatting has not been implemented + return false; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.preference.IPreferencePage#performOk() + */ + public boolean performOk() { + boolean ok = super.performOk(); + Platform.getPlugin(XMLEditorPlugin.ID).savePluginPreferences(); + return ok; + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/reconcile/AbstractReconcileStepAdapter.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/reconcile/AbstractReconcileStepAdapter.java new file mode 100644 index 0000000000..46e23bf3e0 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/reconcile/AbstractReconcileStepAdapter.java @@ -0,0 +1,158 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.reconcile; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.ITypedRegion; +import org.eclipse.jface.text.reconciler.IReconcileResult; +import org.eclipse.wst.sse.core.INodeNotifier; +import org.eclipse.wst.sse.core.IndexedRegion; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.rules.StructuredTextPartitioner; +import org.eclipse.wst.sse.ui.Logger; +import org.eclipse.wst.sse.ui.StructuredTextReconciler; +import org.eclipse.wst.sse.ui.internal.reconcile.IReconcileAnnotationKey; +import org.eclipse.wst.sse.ui.internal.reconcile.IReconcileStepAdapter; +import org.eclipse.wst.sse.ui.internal.reconcile.IStructuredReconcileStep; +import org.eclipse.wst.sse.ui.internal.reconcile.ReconcileAnnotationKey; + + +/** + * This reconcile step is an adapter on the IStructuredModel. Validation is + * triggered from StructuredDocumentEvents + * + * @author pavery + */ +public class AbstractReconcileStepAdapter implements IReconcileStepAdapter { + + protected static final IReconcileResult[] EMPTY_RECONCILE_RESULT_SET = new IReconcileResult[0]; + protected List fDirtyElements = new ArrayList(); + private IStructuredReconcileStep fParentStep = null; + private HashSet fPartitionTypes = null; + + public AbstractReconcileStepAdapter() { + super(); + fPartitionTypes = new HashSet(); + } + + public IReconcileAnnotationKey createKey(IStructuredDocumentRegion sdRegion, int scope) { + ITypedRegion tr = null; + if (!sdRegion.isDeleted()) { + try { + tr = sdRegion.getParentDocument().getPartition(sdRegion.getStartOffset()); + } catch (BadLocationException e) { + // do nothing but leave tr as null + // probably due to changes made on another thread + } + } + String partitionType = (tr != null) ? tr.getType() : StructuredTextPartitioner.ST_UNKNOWN_PARTITION; + return createKey(partitionType, scope); + } + + public IReconcileAnnotationKey createKey(String partitionType, int scope) { + fPartitionTypes.add(partitionType); + return new ReconcileAnnotationKey(getParentStep(), partitionType, scope); + } + + public IStructuredReconcileStep getParentStep() { + return fParentStep; + } + + public String[] getPartitionTypes() { + String[] results = new String[fPartitionTypes.size()]; + System.arraycopy(fPartitionTypes.toArray(), 0, results, 0, results.length); + return results; + } + + /** + * @see com.ibm.sed.model.INodeAdapter#isAdapterForType(java.lang.Object) + */ + public boolean isAdapterForType(Object type) { + return type == IReconcileStepAdapter.class; + } + + protected boolean isCanceled(IProgressMonitor monitor) { + return monitor != null && monitor.isCanceled(); + } + + /** + * @param notifier + */ + public void markForReconciling(Object notifier) { + synchronized (fDirtyElements) { + // pa_TODO possible bottleneck + if (!fDirtyElements.contains(notifier)) { + Logger.trace(StructuredTextReconciler.TRACE_FILTER, "marking :" + notifier + ": for reconciling"); //$NON-NLS-1$ //$NON-NLS-2$ + fDirtyElements.add(notifier); + } + } + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.model.INodeAdapter#notifyChanged(com.ibm.sed.model.INodeNotifier, + * int, java.lang.Object, java.lang.Object, java.lang.Object, int) + */ + public void notifyChanged(INodeNotifier notifier, int eventType, Object changedFeature, Object oldValue, Object newValue, int pos) { + // Adapters are notified before the JFace Document events are sent to + // the IReconciler + markForReconciling(notifier); + } + + public IReconcileResult[] reconcile(IProgressMonitor monitor, IndexedRegion xmlNode) { + List workingElements = null; + List results = new ArrayList(); + + IReconcileResult[] temp = EMPTY_RECONCILE_RESULT_SET; + synchronized (fDirtyElements) { + if (fDirtyElements != null && fDirtyElements.size() > 0) { + workingElements = new ArrayList(); + workingElements.addAll(0, fDirtyElements); + fDirtyElements = new ArrayList(); + } + } + if (workingElements != null) { + Iterator elements = workingElements.iterator(); + while (elements.hasNext() && !isCanceled(monitor)) { + temp = reconcile(elements.next(), monitor); + for (int i = 0; i < temp.length; i++) + results.add(temp[i]); + } + } + temp = new IReconcileResult[results.size()]; + System.arraycopy(results.toArray(), 0, temp, 0, results.size()); + return temp; + } + + protected IReconcileResult[] reconcile(Object o, IProgressMonitor monitor) { + return EMPTY_RECONCILE_RESULT_SET; + } + + /** + * @see org.eclipse.wst.sse.ui.IReleasable#release() + */ + public void release() { + // nothing to release + } + + public void setParentStep(IStructuredReconcileStep parentStep) { + fParentStep = parentStep; + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/reconcile/ReconcileStepAdapterForXML.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/reconcile/ReconcileStepAdapterForXML.java new file mode 100644 index 0000000000..91cc0a70df --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/reconcile/ReconcileStepAdapterForXML.java @@ -0,0 +1,720 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.reconcile; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.StringTokenizer; +import java.util.Vector; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jface.text.Position; +import org.eclipse.jface.text.reconciler.IReconcileResult; +import org.eclipse.wst.common.contentmodel.CMAttributeDeclaration; +import org.eclipse.wst.common.contentmodel.CMDocument; +import org.eclipse.wst.common.contentmodel.CMElementDeclaration; +import org.eclipse.wst.common.contentmodel.CMNamedNodeMap; +import org.eclipse.wst.common.contentmodel.CMNode; +import org.eclipse.wst.common.contentmodel.modelquery.CMDocumentManager; +import org.eclipse.wst.common.contentmodel.modelquery.ModelQuery; +import org.eclipse.wst.common.contentmodel.util.CMDocumentCache; +import org.eclipse.wst.common.contentmodel.util.CMDocumentCacheListener; +import org.eclipse.wst.sse.core.INodeNotifier; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.ui.IReleasable; +import org.eclipse.wst.sse.ui.Logger; +import org.eclipse.wst.sse.ui.StructuredTextReconciler; +import org.eclipse.wst.sse.ui.internal.reconcile.IReconcileAnnotationKey; +import org.eclipse.wst.sse.ui.internal.reconcile.TemporaryAnnotation; +import org.eclipse.wst.sse.ui.nls.ResourceHandler; +import org.eclipse.wst.xml.core.document.XMLAttr; +import org.eclipse.wst.xml.core.document.XMLElement; +import org.eclipse.wst.xml.core.document.XMLNode; +import org.eclipse.wst.xml.core.modelquery.ModelQueryUtil; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; +import org.eclipse.wst.xml.ui.internal.correction.ProblemIDsXML; +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + + +public class ReconcileStepAdapterForXML extends AbstractReconcileStepAdapter implements CMDocumentCacheListener, IReleasable { + + /** + * Record of notification sent to this adapter. Will be queued up so + * they're not dealt with until reconciling is actually called from the + * reconciler thread. + */ + public class NotificationEvent { + + public Object changedFeature; + + public int eventType; + + public Object newValue; + + public INodeNotifier notifier; + + public Object oldValue; + + public int pos; + + public NotificationEvent(INodeNotifier notifier, int eventType, Object changedFeature, Object oldValue, Object newValue, int pos) { + + this.notifier = notifier; + this.eventType = eventType; + this.changedFeature = changedFeature; + this.oldValue = oldValue; + this.newValue = newValue; + this.pos = pos; + } + + // used (to see if notifications vector "contains()") + // so we don't queue up "duplicate" events, + // (indicates same eventType, notifier, and changedFeature) + public boolean equals(Object o) { + + boolean result = false; + if (o instanceof NotificationEvent) { + NotificationEvent e2 = (NotificationEvent) o; + if (this.notifier == null || e2.notifier == null || this.changedFeature == null || e2.changedFeature == null) { + result = false; + } + result = (this.eventType == e2.eventType && this.notifier == e2.notifier && this.changedFeature == e2.changedFeature); + } + return result; + } + } + + protected boolean fCaseSensitive = true; + protected CMDocumentCache fCMDocumentCache; + protected DocumentType fDocumentTypeForRefresh; + + protected boolean fNeedsRefreshAll = false; + + // required for thread safety + protected List fNotifications = new Vector(); + + // these are used in conjunction w/ cacheUpdated() notification + // in order to refresh the whole document + protected IProgressMonitor fProgressMonitorForRefresh; + + // counter used for repeated reconcile opreations + // to yield the thread control to the next thread + // to improve workbench performance + protected short fReconcileCount = 0; + + // will not attempt to validate attribute names starting with the + // following: + protected String[] ignoreAttributeNamesStartingWith = new String[]{"xmlns", "xsi:", "xml:"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + + // changing these elements may have an impact on the current content model + // (which suggests to mark everything dirty) + protected String[] mayImpactContentModel = new String[]{"DOCTYPE", "xmlns", "xsi", "xmlns:xsi", "xmlns:xsl", "xsi:schemaLocation", "taglib"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ + protected String SEVERITY_MISSING_REQUIRED_ATTR = TemporaryAnnotation.ANNOT_WARNING; + + // severities for the problems discoverable by this reconciler; possibly + // user configurable later + protected String SEVERITY_STRUCTURE = TemporaryAnnotation.ANNOT_ERROR; + protected String SEVERITY_UNKNOWN_ATTR = TemporaryAnnotation.ANNOT_ERROR; + protected String SEVERITY_UNKNOWN_ELEMENT = TemporaryAnnotation.ANNOT_ERROR; + + public ReconcileStepAdapterForXML() { + + super(); + } + + /** + * @see org.eclipse.wst.common.contentmodel.util.CMDocumentCacheListener#cacheCleared(org.eclipse.wst.common.contentmodel.utilbase.CMDocumentCache) + */ + public void cacheCleared(CMDocumentCache arg0) { + // do nothing + } + + /** + * @see org.eclipse.wst.common.contentmodel.util.CMDocumentCacheListener#cacheUpdated(org.eclipse.wst.common.contentmodel.utilbase.CMDocumentCache, + * java.lang.String, int, int, + * org.eclipse.wst.common.contentmodel.CMDocument) + */ + public void cacheUpdated(CMDocumentCache arg0, String arg1, int arg2, int arg3, CMDocument arg4) { + + // revalidate all + if (Logger.isTracing(StructuredTextReconciler.TRACE_FILTER)) { + String message = "[trace reconciler] > \r\n====================" + "\n cache updated:" + "\n arg0 :" + arg0 + "\n arg1 :" + arg1 + "\n arg3 :" + arg3 + "\n arg4 :" + arg4; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ + Logger.trace(StructuredTextReconciler.TRACE_FILTER, message); + } + if (arg3 == CMDocumentCache.STATUS_LOADED) { + Logger.trace(StructuredTextReconciler.TRACE_FILTER, "CMDocument finished loading :" + arg1); //$NON-NLS-1$ + doRefreshAll((INodeNotifier) fDocumentTypeForRefresh, fProgressMonitorForRefresh); + } + } + + protected IReconcileResult[] doRefreshAll(INodeNotifier notifier, IProgressMonitor monitor) { + + Logger.trace(StructuredTextReconciler.TRACE_FILTER, "[trace reconciler] > refreshing all"); //$NON-NLS-1$ + + synchronized (fDirtyElements) { + fDirtyElements.clear(); + } + Document doc = (((Node) notifier).getNodeType() != Node.DOCUMENT_NODE) ? ((Node) notifier).getOwnerDocument() : (Document) notifier; + return reconcileSubtree((INodeNotifier) doc, monitor); + } + + protected ModelQuery getModelQuery(Node node) { + + return (node.getNodeType() == Node.DOCUMENT_NODE) ? ModelQueryUtil.getModelQuery((Document) node) : ModelQueryUtil.getModelQuery(node.getOwnerDocument()); + } + + /** + * returns a list of required CMAttributeDeclarations for the given + * element. + * + * @param elementDecl + * @return + */ + protected List getRequiredAttributes(CMElementDeclaration elementDecl) { + + CMNamedNodeMap attrMap = elementDecl.getAttributes(); + Iterator it = attrMap.iterator(); + CMAttributeDeclaration attr = null; + List result = new ArrayList(); + while (it.hasNext()) { + attr = (CMAttributeDeclaration) it.next(); + if (attr.getUsage() == CMAttributeDeclaration.REQUIRED) { + result.add(attr); + } + } + return result; + } + + /** + * Determine if this Document is an XML/XHTML Document and whether to be + * case sensitive + */ + protected boolean isCaseSensitive(Node node) { + + return true; + } + + // CMVC 254838 + /** + * Indicates if the element is not in the ContentModel (if it's not in the + * ContentModel, but its parent is) + * + * @param element + * @param modelQuery + * @return whether or not the element is unknown according to its + * associated ContentModel. + */ + protected boolean isUnknown(Element element, ModelQuery modelQuery) { + + boolean result = false; + CMElementDeclaration ed = modelQuery.getCMElementDeclaration(element); + if (ed == null) { + // make sure parent declaration exists, and is not inferred + Node parentNode = element.getParentNode(); + if (parentNode != null && parentNode.getNodeType() == Node.ELEMENT_NODE) { + CMElementDeclaration parentEd = modelQuery.getCMElementDeclaration((Element) parentNode); + // 2/19/04 porting iFix for lax schema suppport + result = (parentEd != null) && !Boolean.TRUE.equals(parentEd.getProperty("isInferred")) //$NON-NLS-1$ + && !Boolean.TRUE.equals(parentEd.getProperty("isLax")); //$NON-NLS-1$ + } + // need one error for the root at least + // to indicate the document is wrong... + Document ownerDoc = element.getOwnerDocument(); + if (ownerDoc != null && ownerDoc.getDocumentElement() == element) { + CMDocument cmDoc = modelQuery.getCorrespondingCMDocument(ownerDoc); + result = (cmDoc != null && cmDoc.getElements().getLength() > 0); + } + } else { + if (ed.getProperty("isInferred") != null && Boolean.TRUE.equals(ed.getProperty("isInferred")) //$NON-NLS-1$ //$NON-NLS-2$ + || (ed.getProperty("partialContentModel") != null && Boolean.TRUE.equals(ed.getProperty("partialContentModel")))) { //$NON-NLS-1$ //$NON-NLS-2$ + result = false; + } + } + return result; + } + + /** + * Checks if name matches any mayImpactContentModel[] strings + * + * @param name + * @return if a match is found, return true, else return false + */ + private boolean mayAffectContentModel(String name) { + + // TODO (pa) may need to be smarter if the attribute name is broken... + StringTokenizer st = new StringTokenizer(name, ":", false); //$NON-NLS-1$ + String prefix = ""; //$NON-NLS-1$ + if (st.hasMoreTokens()) + prefix = st.nextToken(); + for (int i = 0; i < mayImpactContentModel.length; i++) { + if (mayImpactContentModel[i].indexOf(name) != -1 || mayImpactContentModel[i].startsWith(prefix)) + return true; + } + return false; + } + + public void notifyChanged(INodeNotifier notifier, int eventType, Object changedFeature, Object oldValue, Object newValue, int pos) { + + synchronized (fNotifications) { + NotificationEvent newEvent = new NotificationEvent(notifier, eventType, changedFeature, oldValue, newValue, pos); + if (!fNotifications.contains(newEvent)) + fNotifications.add(newEvent); + } + } + + /** + * @see com.ibm.sed.model.INodeAdapter#notifyChanged(com.ibm.sed.model.Notifier, + * int, java.lang.Object, java.lang.Object, java.lang.Object, int) + */ + public void processNotification(INodeNotifier notifier, int eventType, Object changedFeature, Object oldValue, Object newValue, int pos, IProgressMonitor monitor) { + + if (isCanceled(monitor)) + return; + + // (nsd) pa_TODO: we need to mark more or widen the scope affected by + // the next reconcile() call + // TODO: Handle multi-Node changes from Doctype Declarations, Taglib + // directives, + // and schema and namespace related attributes (DOCTYPE, taglib, + // xmlns, + // xsi...) + // ** we currently don't get a notify on changed taglib... + + // we're going to validate everything again anyways after + // proccessNotifications() has completed (in reconcile(): + // processNotifications() > refreshAll()), + // no sense to do it here if we refreshingAll + if (fNeedsRefreshAll) + return; + if (eventType == INodeNotifier.CHANGE || eventType == INodeNotifier.REMOVE) { + if (changedFeature instanceof Node && ((Node) changedFeature).getNodeType() == Node.ATTRIBUTE_NODE) { + if (mayAffectContentModel(((Node) changedFeature).getNodeName())) { + fNeedsRefreshAll = true; + } + } else if (changedFeature instanceof Node && ((Node) changedFeature).getNodeType() == Node.DOCUMENT_TYPE_NODE) { + fNeedsRefreshAll = true; + } else if (notifier instanceof Node && ((Node) notifier).getNodeType() == Node.DOCUMENT_TYPE_NODE) { + fNeedsRefreshAll = true; + } else { + // pa_TODO need to handle taglib definition changes... + //if(mayAffectContentModel(((Node)changedFeature).getNodeName())) + // { + //System.out.println("dunno what changed > " + + // changedFeature); + //fNeedsRefreshAll = true; + //} + } + if (isCanceled(monitor)) + return; + fNeedsRefreshAll = true; + } + if (eventType == INodeNotifier.CHANGE && changedFeature instanceof Element) { + markForReconciling(changedFeature); + } else if (eventType == INodeNotifier.ADD && newValue instanceof Node) { + Node newNode = (Node) newValue; + if (newNode.getNodeType() == Node.DOCUMENT_TYPE_NODE || newNode.getNodeName().equals("jsp:directive.taglib")) { // $NON-NLS-1$ + // //$NON-NLS-1$ + fNeedsRefreshAll = true; + } else { + markForReconciling(newNode); + } + } + markForReconciling(notifier); + } + + protected void processNotifications(IProgressMonitor monitor) { + + fProgressMonitorForRefresh = monitor; + NotificationEvent[] events = null; + synchronized (fNotifications) { + if (fNotifications.isEmpty()) { + return; + } + events = (NotificationEvent[]) fNotifications.toArray(new NotificationEvent[0]); + fNotifications.clear(); + } + for (int i = 0; i < events.length; i++) { + processNotification(events[i].notifier, events[i].eventType, events[i].changedFeature, events[i].oldValue, events[i].newValue, events[i].pos, monitor); + } + } + + /** + * @see com.ibm.sed.internal.ui.text.ReconcilerAdapter#reconcile(org.eclipse.jface.text.source.IAnnotationModel, + * org.eclipse.core.runtime.IProgressMonitor) + */ + public IReconcileResult[] reconcile(IProgressMonitor monitor, XMLNode xmlNode) { + + processNotifications(monitor); + IReconcileResult[] results = EMPTY_RECONCILE_RESULT_SET; + if (fNeedsRefreshAll) { + results = doRefreshAll(xmlNode, monitor); + fNeedsRefreshAll = false; + } else { + results = super.reconcile(monitor, xmlNode); + } + return results; + } + + /** + * Called by super.reconcile(IAnnotationModel) on each Notifier + * + * @see com.ibm.sed.internal.ui.text.AbstractReconcilerAdapter#reconcile(org.eclipse.jface.text.source.IAnnotationModel, + * java.lang.Object) + */ + protected IReconcileResult[] reconcile(Object o, IProgressMonitor monitor) { + + super.reconcile(o, monitor); + ModelQuery mq = null; + if (o instanceof XMLNode) { + XMLNode xmlNode = (XMLNode) o; + mq = getModelQuery(xmlNode); + if (mq != null) { + fCaseSensitive = isCaseSensitive(xmlNode); + return validate(mq, xmlNode); + } + } + + // if we are in a large reconciling loop (like when reconciling the + // entire doc), this ensures + // that other Threads have a chance to run. + yieldIfNeeded(); + return EMPTY_RECONCILE_RESULT_SET; + } + + /** + * Reconcile the Node and all children of the Notifier passed in. + * + * @param notifier + * @param annotationModel + * @param monitor + */ + protected IReconcileResult[] reconcileSubtree(INodeNotifier notifier, IProgressMonitor monitor) { + + IReconcileResult[] temp = EMPTY_RECONCILE_RESULT_SET; + List results = new ArrayList(); + if (!isCanceled(monitor)) { + if (notifier != null && notifier instanceof XMLNode) { + XMLNode current = (XMLNode) notifier; + // loop siblings + while (current != null) { + // mark whatever type nodes we wanna make dirty + if (current.getNodeType() == Node.ELEMENT_NODE || current.getNodeType() == Node.DOCUMENT_TYPE_NODE || current.getNodeType() == Node.DOCUMENT_NODE || current.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) { + temp = reconcile(current, monitor); + for (int i = 0; i < temp.length; i++) + results.add(temp[i]); + } + // drop one level deeper if necessary + if (current.getFirstChild() != null) { + temp = reconcileSubtree((INodeNotifier) current.getFirstChild(), monitor); + for (int i = 0; i < temp.length; i++) + results.add(temp[i]); + } + current = (XMLNode) current.getNextSibling(); + } + } + temp = new IReconcileResult[results.size()]; + System.arraycopy(results.toArray(), 0, temp, 0, results.size()); + } + return temp; + } + + /** + * Called from the ReconcileAdapterFactory + * + * @see com.ibm.sed.internal.ui.text.AbstractReconcilerAdapter#release() + */ + public void release() { + + if (fCMDocumentCache != null) { + fCMDocumentCache.removeListener(this); + fCMDocumentCache = null; + } + } + + /** + * Determines whether the given Attr should not be validated according to + * the ignoreAttributeNamesStartingWith array + * + * @param attr + * @return + */ + protected boolean shouldIgnore(Attr attr) { + + boolean result = false; + String name = attr.getNodeName(); + for (int i = 0; i < ignoreAttributeNamesStartingWith.length; i++) { + if (fCaseSensitive) { + if (name.startsWith(ignoreAttributeNamesStartingWith[i])) + result = true; + } else { + try { + if (name.length() >= ignoreAttributeNamesStartingWith[i].length() && ignoreAttributeNamesStartingWith[i].equalsIgnoreCase(name.substring(0, ignoreAttributeNamesStartingWith[i].length()))) + result = true; + } catch (StringIndexOutOfBoundsException e) { + result = true; + } + } + } + return result; + } + + private void updateCMDocumentCache(ModelQuery mq, XMLNode xmlNode) { + + if (mq != null) { + CMDocumentManager cmDocManager = mq.getCMDocumentManager(); + if (cmDocManager != null) { + CMDocumentCache newCache = cmDocManager.getCMDocumentCache(); + if (newCache != null) { + if (fCMDocumentCache == null) { + // create fCMDocCache if necessary + fCMDocumentCache = newCache; + fCMDocumentCache.addListener(this); + fDocumentTypeForRefresh = (DocumentType) xmlNode; + } else if (fCMDocumentCache != newCache) { + fCMDocumentCache.removeListener(this); + fCMDocumentCache = newCache; + fCMDocumentCache.addListener(this); + fDocumentTypeForRefresh = (DocumentType) xmlNode; + } + } + } + } + } + + /** + * Called by reconcile(IAnnotationModel, Object) when the Object is a + * Notifier + * + * @see com.ibm.sed.internal.editor.StructuredTextReconcilingStrategy#reconcile(org.eclipse.jface.text.source.IAnnotationModel, + * com.ibm.sed.model.IndexedRegion) + */ + protected IReconcileResult[] validate(ModelQuery mq, XMLNode xmlNode) { + + List results = new ArrayList(); + if (xmlNode == null || !(xmlNode.getNodeType() == Node.ELEMENT_NODE || xmlNode.getNodeType() == Node.DOCUMENT_TYPE_NODE)) + return EMPTY_RECONCILE_RESULT_SET; + // return early if the Node has gone stale + if (xmlNode.getParentNode() == null || xmlNode.getOwnerDocument() == null) { + return EMPTY_RECONCILE_RESULT_SET; + } + if (xmlNode.getNodeType() == Node.DOCUMENT_TYPE_NODE) { + // sets CMDocumentCacheListener (this) + updateCMDocumentCache(mq, xmlNode); + } + CMDocument doc = mq.getCorrespondingCMDocument(xmlNode.getOwnerDocument()); + // looks like this is a bad check to do... I thought we took it out + // before + // if(doc == null) + // return EMPTY_RECONCILE_RESULT_SET; + if (doc != null && doc.getElements().getLength() == 0) { + // an empty document + return EMPTY_RECONCILE_RESULT_SET; + } + // continue on null or FALSE; inferred grammars aren't predefined so + // there's no point in continuing + if (doc != null && doc.getProperty("isInferred") != null && Boolean.TRUE.equals(doc.getProperty("isInferred"))) { //$NON-NLS-1$ //$NON-NLS-2$ + return EMPTY_RECONCILE_RESULT_SET; + } + + // if xmlNode is DOCTYPE, skip to the first element + // if there are no elements, return (don't validate) + XMLNode elementNode = xmlNode; + if (xmlNode.getNodeType() == Node.DOCUMENT_TYPE_NODE) { + boolean elementFound = false; + while ((elementNode = (XMLNode) elementNode.getNextSibling()) != null) { + if (elementNode.getNodeType() == Node.ELEMENT_NODE) { + elementFound = true; + break; + } + } + if (!elementFound) + return EMPTY_RECONCILE_RESULT_SET; + } + XMLElement element = (XMLElement) elementNode; + //boolean needsEndTag = true; + + // test for a known element, if it's known, continue validating it + CMElementDeclaration elementDecl = mq.getCMElementDeclaration(element); + if (elementDecl != null) { + //needsEndTag = needsEndTag(elementNode, elementDecl); + NamedNodeMap attrs = element.getAttributes(); + List reqAttrList = getRequiredAttributes(elementDecl); + for (int i = 0; i < attrs.getLength(); i++) { + XMLAttr attr = (XMLAttr) attrs.item(i); + if (!shouldIgnore(attr)) { + + // iFix V511i + // CMVC 272647, attributes with namespace prefix get + // marked + // as error (even though they aren't) + //CMNode attrDecl = + // elementDecl.getAttributes().getNamedItem(attr.getNodeName()); + CMNode attrDecl = elementDecl.getAttributes().getNamedItem(attr.getLocalName()); + + // test for a known attribute + if (attrDecl != null) { + // test for a known value (if there is an enumerated + // list of them) + String[] values = mq.getPossibleDataTypeValues(element, attrDecl); + String currentValue = attr.getValue(); + boolean found = valueMatch(values, currentValue); + if (!found) { + int start = attr.getValueRegionStartOffset(); + int length = attr.getValueRegion().getTextLength(); + MessageFormat messageFormat = new MessageFormat(ResourceHandler.getString("Invalid_value_{0}")); //$NON-NLS-1$ + Object[] args = {currentValue.trim()}; + String message = messageFormat.format(args); + Position p = new Position(start, length); + IReconcileAnnotationKey key = createKey(elementNode.getFirstStructuredDocumentRegion(), IReconcileAnnotationKey.PARTIAL); + results.add(new TemporaryAnnotation(p, SEVERITY_UNKNOWN_ATTR, message, key)); + } + // remove from known required attribute list + reqAttrList.remove(attrDecl); + } else { + MessageFormat messageFormat = new MessageFormat(ResourceHandler.getString("Unknown_attribute_{0}")); //$NON-NLS-1$ + Object[] args = {attr.getName()}; + String message = messageFormat.format(args); + int start = attr.getNameRegionStartOffset(); + int length = attr.getNameRegion().getTextLength(); + Position p = new Position(start, length); + IReconcileAnnotationKey key = createKey(elementNode.getFirstStructuredDocumentRegion(), IReconcileAnnotationKey.PARTIAL); + results.add(new TemporaryAnnotation(p, SEVERITY_UNKNOWN_ATTR, message, key, ProblemIDsXML.UnknownAttr)); + } + } else { + // remove so we don't flag "ignored" attributes as missing + reqAttrList.remove(elementDecl.getAttributes().getNamedItem(attr.getNodeName())); + } + } + // if there are missing required attributes, create annotations + // for + // them + if (reqAttrList != null && !reqAttrList.isEmpty()) { + Iterator it = reqAttrList.iterator(); + int start = 0; + int length = 1; + CMAttributeDeclaration attr = null; + while (it.hasNext()) { + attr = (CMAttributeDeclaration) it.next(); + // sometimes getFirstStructuredDocumentRegion can return + // null, this is a safety + start = (element.getFirstStructuredDocumentRegion() != null) ? element.getFirstStructuredDocumentRegion().getStartOffset() : element.getStartOffset(); + length = (element.getFirstStructuredDocumentRegion() != null) ? element.getFirstStructuredDocumentRegion().getLength() : 1; + + MessageFormat messageFormat = new MessageFormat(ResourceHandler.getString("Missing_required_attribute_{0}")); //$NON-NLS-1$ + Object[] args = {attr.getAttrName()}; + String message = messageFormat.format(args); + + Position p = new Position(start, length); + IReconcileAnnotationKey key = createKey(elementNode.getFirstStructuredDocumentRegion(), IReconcileAnnotationKey.PARTIAL); + TemporaryAnnotation annotation = new TemporaryAnnotation(p, SEVERITY_MISSING_REQUIRED_ATTR, message, key, ProblemIDsXML.MissingRequiredAttr); + + IStructuredDocumentRegion startStructuredDocumentRegion = element.getStartStructuredDocumentRegion(); + if (startStructuredDocumentRegion != null) { + String requiredAttrName = attr.getAttrName(); + String defaultAttrValue = attr.getDefaultValue(); + String insertString; + if (defaultAttrValue == null) + insertString = requiredAttrName + "=\"" + requiredAttrName + "\""; //$NON-NLS-1$ //$NON-NLS-2$ + else + insertString = requiredAttrName + "=\"" + defaultAttrValue + "\""; //$NON-NLS-1$ //$NON-NLS-2$ + + ITextRegion lastRegion = startStructuredDocumentRegion.getLastRegion(); + int insertOffset = lastRegion.getEnd(); + if (lastRegion.getEnd() == lastRegion.getTextEnd()) + insertString = " " + insertString; //$NON-NLS-1$ + if (lastRegion.getType() == XMLRegionContext.XML_TAG_CLOSE) + insertOffset = lastRegion.getStart(); + Object[] additionalFixInfo = {insertString, new Integer(insertOffset)}; + annotation.setAdditionalFixInfo(additionalFixInfo); + results.add(annotation); + } + } + } + } else if (isUnknown(element, mq)) { // CMVC 254838 + int start = element.getStartOffset(); + int length = element.getEndOffset() - element.getStartOffset(); + if (element.getStartStructuredDocumentRegion() != null && element.getStartStructuredDocumentRegion().getNumberOfRegions() > 1) { + ITextRegion name = element.getStartStructuredDocumentRegion().getRegions().get(1); + start = element.getStartStructuredDocumentRegion().getStartOffset(name); + length = name.getTextLength(); + } + MessageFormat messageFormat = new MessageFormat(ResourceHandler.getString("Unknown_element_{0}")); //$NON-NLS-1$ + Object[] args = {element.getNodeName()}; + String message = messageFormat.format(args); + Position p = new Position(start, length); + IReconcileAnnotationKey key = createKey(elementNode.getFirstStructuredDocumentRegion(), IReconcileAnnotationKey.PARTIAL); + TemporaryAnnotation annotation = new TemporaryAnnotation(p, SEVERITY_UNKNOWN_ELEMENT, message, key, ProblemIDsXML.UnknownElement); + + // quick fix info + int startTagOffset = -1, startTagLength = -1, endTagOffset = -1, endTagLength = -1; + if (element.getStartStructuredDocumentRegion() != null) { + startTagOffset = element.getStartStructuredDocumentRegion().getStartOffset(); + startTagLength = element.getStartStructuredDocumentRegion().getLength(); + } + if (element.getEndStructuredDocumentRegion() != null) { + endTagOffset = element.getEndStructuredDocumentRegion().getStartOffset(); + endTagLength = element.getEndStructuredDocumentRegion().getLength(); + } + Object[] additionalFixInfo = {new Integer(startTagOffset), new Integer(startTagLength), new Integer(endTagOffset), new Integer(endTagLength)}; + + annotation.setAdditionalFixInfo(additionalFixInfo); + results.add(annotation); + } + IReconcileResult[] reconcileResults = new IReconcileResult[results.size()]; + System.arraycopy(results.toArray(), 0, reconcileResults, 0, results.size()); + return reconcileResults; + } + + /** + * Determines if String value is within the values array given the current + * case sensitivity + * + * @param values + * @param value + * @return + */ + protected boolean valueMatch(String[] values, String value) { + + boolean found = (values == null || values.length == 0 || value.length() == 0); + for (int j = 0; j < values.length && !found; j++) { + if (fCaseSensitive) { + if (values[j].equals(value)) + found = true; + } else if (values[j].equalsIgnoreCase(value)) + found = true; + } + return found; + } + + // CMVC 255301 + // If we are in a large reconciling loop, this ensures + // that other Threads have a chance to run. + protected void yieldIfNeeded() { + + // 100 is arbitrary, may need a better number + if (fReconcileCount >= 100) { + Thread.yield(); + fReconcileCount = 0; + } else { + fReconcileCount++; + } + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/reconcile/ReconcileStepForContentModel.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/reconcile/ReconcileStepForContentModel.java new file mode 100644 index 0000000000..2078296369 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/reconcile/ReconcileStepForContentModel.java @@ -0,0 +1,234 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.reconcile; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; + +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.reconciler.DirtyRegion; +import org.eclipse.jface.text.reconciler.IReconcileResult; +import org.eclipse.jface.text.reconciler.IReconcileStep; +import org.eclipse.wst.sse.core.AdapterFactory; +import org.eclipse.wst.sse.core.INodeNotifier; +import org.eclipse.wst.sse.core.IndexedRegion; +import org.eclipse.wst.sse.core.PropagatingAdapter; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.ui.Logger; +import org.eclipse.wst.sse.ui.StructuredTextReconciler; +import org.eclipse.wst.sse.ui.StructuredTextViewer; +import org.eclipse.wst.sse.ui.internal.reconcile.IReconcileAnnotationKey; +import org.eclipse.wst.sse.ui.internal.reconcile.IReconcileStepAdapter; +import org.eclipse.wst.sse.ui.internal.reconcile.StructuredReconcileStep; +import org.eclipse.wst.xml.core.document.XMLDocument; +import org.eclipse.wst.xml.core.document.XMLModel; +import org.eclipse.wst.xml.core.document.XMLNode; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; + + +/** + * A reconcile step for ContentModel based documents. + */ +public class ReconcileStepForContentModel extends StructuredReconcileStep { + private HashSet fLocalPartitionTypes = null; + + protected boolean fRanInitialValidate = false; + + public ReconcileStepForContentModel() { + super(); + fLocalPartitionTypes = new HashSet(); + } + + public ReconcileStepForContentModel(StructuredTextViewer viewer, IReconcileStep step) { + super(step); + fLocalPartitionTypes = new HashSet(); + } + + private void addPartitionTypes(String[] types) { + for (int i = 0; i < types.length; i++) + fLocalPartitionTypes.add(types[i]); + } + + /** + * Need to add partition types for ReconcileStepAdapterForXML here... + * + * @see org.eclipse.wst.xml.ui.reconcile.StructuredReconcileStep#getPartitionTypes() + */ + public String[] getPartitionTypes() { + String[] superPartitionTypes = super.getPartitionTypes(); + String[] results = new String[superPartitionTypes.length + fLocalPartitionTypes.size()]; + System.arraycopy(superPartitionTypes, 0, results, 0, superPartitionTypes.length); + System.arraycopy(fLocalPartitionTypes.toArray(), 0, results, superPartitionTypes.length, fLocalPartitionTypes.size()); + return results; + } + + public int getScope() { + return IReconcileAnnotationKey.PARTIAL; + } + + public void initialValidate() { + + // (pa) perf: add the adapter for every node here + XMLModel xModel = (XMLModel) getModelManager().getExistingModelForRead(getDocument()); + XMLDocument doc = xModel.getDocument(); + xModel.releaseFromRead(); + PropagatingAdapter propagatingAdapter = (PropagatingAdapter) doc.getAdapterFor(PropagatingAdapter.class); + + List factories = propagatingAdapter.getAdaptOnCreateFactories(); + ReconcilerAdapterFactoryForXML rAdapterFactoryForXML = null; + AdapterFactory temp = null; + // find the ReconcileStepAdapterFactory + for (int i = 0; i < factories.size(); i++) { + temp = (AdapterFactory) factories.get(i); + if (temp.isFactoryForType(IReconcileStepAdapter.class)) { + rAdapterFactoryForXML = (ReconcilerAdapterFactoryForXML) temp; + break; + } + } + + if (rAdapterFactoryForXML != null) { + rAdapterFactoryForXML.setShouldMarkForReconciling(false); + initialValidateTree(doc, rAdapterFactoryForXML); + rAdapterFactoryForXML.setShouldMarkForReconciling(true); + } + } + + /** + * Mark the INodeNotifier (Node) and all children of the INodeNotifier + * passed in. + * + * @param notifier + */ + protected void initialValidateTree(INodeNotifier notifier, AdapterFactory rAdapterFactoryForXML) { + if (isCanceled()) + return; + + if (notifier != null && notifier instanceof XMLNode) { + XMLNode current = (XMLNode) notifier; + IReconcileStepAdapter adapter = null; + // loop siblings + // pa_TODO for large XML files this loop goes for a LONG time + // and the progress monitor never gets canceled + while (current != null && !isCanceled()) { + // adapt this notifier + adapter = (IReconcileStepAdapter) rAdapterFactoryForXML.adapt(current); + if (adapter != null) { + ((AbstractReconcileStepAdapter) adapter).setParentStep(this); + adapter.markForReconciling(current); + current.addAdapter(adapter); + adapter.reconcile(getProgressMonitor(), current); + } + if (current.getFirstChild() != null) { + initialValidateTree((XMLNode) current.getFirstChild(), rAdapterFactoryForXML); + } + current = (XMLNode) current.getNextSibling(); + } + } + } + + + // Determines whether the IStructuredDocumentRegion is a XML "end tag" + // since they're not allowed to have + // attribute ITextRegions + protected boolean isEndTag(IStructuredDocumentRegion structuredDocumentRegion) { + return structuredDocumentRegion.getFirstRegion().getType() == XMLRegionContext.XML_END_TAG_OPEN; + } + + // Determines whether the IStructuredDocumentRegion is a XML "start tag" + // since they need to be + // checked for proper XML attribute region sequences + protected boolean isStartTag(IStructuredDocumentRegion structuredDocumentRegion) { + return structuredDocumentRegion.getFirstRegion().getType() == XMLRegionContext.XML_TAG_OPEN; + } + + // Because we check the "proper" closing separately from attribute + // sequencing, we need to know what's + // an appropriate close. + protected boolean isTagCloseTextRegion(ITextRegion textRegion) { + return textRegion.getType() == XMLRegionContext.XML_TAG_CLOSE || textRegion.getType() == XMLRegionContext.XML_EMPTY_TAG_CLOSE; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.ui.internal.ui.text.StructuredReconcileStep#reconcileModel(org.eclipse.jface.text.reconciler.DirtyRegion, + * org.eclipse.jface.text.IRegion) + */ + protected IReconcileResult[] reconcileModel(DirtyRegion dirtyRegion, IRegion subRegion) { + if (dirtyRegion == null) + return EMPTY_RECONCILE_RESULT_SET; + + // logging ------------------ + Logger.trace(StructuredTextReconciler.TRACE_FILTER, "[trace reconciler] > reconciling model in CONTENT MODEL step w/ dirty region: [" + dirtyRegion.getOffset() + ":" + dirtyRegion.getLength() + "]" + dirtyRegion.getText()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + // -------------------------- + + int start = dirtyRegion.getOffset(); + int length = dirtyRegion.getLength(); + + IReconcileResult[] results = validate(start, length); + + // logging ------------------ + Logger.trace(StructuredTextReconciler.TRACE_FILTER, "[trace reconciler] > CONTENT MODEL step done"); //$NON-NLS-1$ + // -------------------------- + return results; + } + + /** + * Forces the IReconcilerAdapters for XMLNodes overlapping the given + * region to "validate" their Nodes. + * + * @param startOffset + * @param length + */ + protected IReconcileResult[] validate(int startOffset, int length) { + List results = new ArrayList(); + IReconcileResult[] temp = EMPTY_RECONCILE_RESULT_SET; + + if (!fRanInitialValidate) { + initialValidate(); + fRanInitialValidate = true; + } else { + XMLModel model = (XMLModel) getModelManager().getExistingModelForRead(getDocument()); + int endOffset = startOffset + length; + + IndexedRegion indexedNode = model.getIndexedRegion(startOffset); + IReconcileStepAdapter adapter = null; + + // sometimes for single key type length can be 0 (startOffset == + // endOffset) + for (int i = startOffset; indexedNode != null && i <= endOffset && !isCanceled(); i++) { + + XMLNode xmlNode = (XMLNode) indexedNode; + adapter = (IReconcileStepAdapter) xmlNode.getAdapterFor(IReconcileStepAdapter.class); + if (adapter != null) { + temp = adapter.reconcile(getProgressMonitor(), xmlNode); + for (int j = 0; j < temp.length; j++) + results.add(temp[j]); + // this is for removal purposes later + addPartitionTypes(adapter.getPartitionTypes()); + } + // visited.add(indexedNode); + if (xmlNode.getFirstStructuredDocumentRegion() != null) + i += xmlNode.getFirstStructuredDocumentRegion().getLength(); + else + i++; + + indexedNode = model.getIndexedRegion(i); + } + model.releaseFromRead(); + } + return (IReconcileResult[]) results.toArray(new IReconcileResult[results.size()]); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/reconcile/ReconcileStepForMarkup.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/reconcile/ReconcileStepForMarkup.java new file mode 100644 index 0000000000..07c8907a0d --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/reconcile/ReconcileStepForMarkup.java @@ -0,0 +1,572 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.reconcile; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.List; +import java.util.StringTokenizer; + +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.Position; +import org.eclipse.jface.text.reconciler.DirtyRegion; +import org.eclipse.jface.text.reconciler.IReconcileResult; +import org.eclipse.jface.text.reconciler.IReconcileStep; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.core.text.ITextRegionList; +import org.eclipse.wst.sse.ui.Logger; +import org.eclipse.wst.sse.ui.StructuredTextReconciler; +import org.eclipse.wst.sse.ui.internal.reconcile.IReconcileAnnotationKey; +import org.eclipse.wst.sse.ui.internal.reconcile.StructuredReconcileStep; +import org.eclipse.wst.sse.ui.internal.reconcile.TemporaryAnnotation; +import org.eclipse.wst.sse.ui.nls.ResourceHandler; +import org.eclipse.wst.xml.core.document.XMLModel; +import org.eclipse.wst.xml.core.document.XMLNode; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; +import org.eclipse.wst.xml.ui.internal.correction.ProblemIDsXML; +import org.w3c.dom.Node; + + +/** + * Basic XML syntax checking step. + * + * @author pavery + */ +public class ReconcileStepForMarkup extends StructuredReconcileStep { + private String DQUOTE = "\""; //$NON-NLS-1$ + + protected String SEVERITY_ATTR_MISSING_VALUE = TemporaryAnnotation.ANNOT_ERROR; + protected String SEVERITY_ATTR_NO_VALUE = TemporaryAnnotation.ANNOT_ERROR; + // severities for the problems discoverable by this reconciler; possibly + // user configurable later + protected String SEVERITY_GENERIC_ILLFORMED_SYNTAX = TemporaryAnnotation.ANNOT_WARNING; + protected String SEVERITY_STRUCTURE = TemporaryAnnotation.ANNOT_ERROR; + protected String SEVERITY_SYNTAX_ERROR = TemporaryAnnotation.ANNOT_ERROR; + // used for attribute quote checking + private String SQUOTE = "'"; //$NON-NLS-1$ + + public ReconcileStepForMarkup() { + super(); + } + + public ReconcileStepForMarkup(IReconcileStep step) { + super(step); + } + + private void addAttributeError(String message, String attributeValueText, int start, int length, int problemId, IStructuredDocumentRegion sdRegion, List results) { + Position p = new Position(start, length); + IReconcileAnnotationKey key = createKey(sdRegion, getScope()); + TemporaryAnnotation annotation = new TemporaryAnnotation(p, SEVERITY_SYNTAX_ERROR, message, key, problemId); + annotation.setAdditionalFixInfo(attributeValueText); + results.add(annotation); + } + + private void checkAttributesInEndTag(IStructuredDocumentRegion structuredDocumentRegion, List results) { + ITextRegionList textRegions = structuredDocumentRegion.getRegions(); + int errorCount = 0; + int start = structuredDocumentRegion.getEndOffset(); + int end = structuredDocumentRegion.getEndOffset(); + for (int i = 0; i < textRegions.size() && errorCount < ELEMENT_ERROR_LIMIT; i++) { + ITextRegion textRegion = textRegions.get(i); + if (textRegion.getType() == XMLRegionContext.XML_TAG_ATTRIBUTE_NAME || textRegion.getType() == XMLRegionContext.XML_TAG_ATTRIBUTE_EQUALS || textRegion.getType() == XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE) { + if (start > structuredDocumentRegion.getStartOffset(textRegion)) + start = structuredDocumentRegion.getStartOffset(textRegion); + end = structuredDocumentRegion.getEndOffset(textRegion); + errorCount++; + } + } + // create one error for all attributes in the end tag + if (errorCount > 0) { + Position p = new Position(start, end - start); + String message = ResourceHandler.getString("End_tag_has_attributes"); //$NON-NLS-1$ + results.add(new TemporaryAnnotation(p, SEVERITY_GENERIC_ILLFORMED_SYNTAX, message, createKey(structuredDocumentRegion, getScope()), ProblemIDsXML.AttrsInEndTag)); + } + } + + + /** + * @param structuredDocumentRegion + * @param results + */ + private void checkClosingBracket(IStructuredDocumentRegion structuredDocumentRegion, List results) { + ITextRegionList regions = structuredDocumentRegion.getRegions(); + ITextRegion r = null; + boolean closed = false; + for (int i = 0; i < regions.size(); i++) { + r = regions.get(i); + if (r.getType() == XMLRegionContext.XML_TAG_CLOSE || r.getType() == XMLRegionContext.XML_EMPTY_TAG_CLOSE) + closed = true; + } + if (!closed) { + + String message = ResourceHandler.getString("ReconcileStepForMarkup.6"); //$NON-NLS-1$ + + int start = structuredDocumentRegion.getStartOffset(); + int length = structuredDocumentRegion.getText().trim().length(); + Position p = new Position(start, length); + IReconcileAnnotationKey key = createKey(structuredDocumentRegion, getScope()); + + TemporaryAnnotation annotation = new TemporaryAnnotation(p, SEVERITY_SYNTAX_ERROR, message, key, ProblemIDsXML.MissingClosingBracket); + results.add(annotation); + } + } + + /** + * @param annotationModel + * @param structuredDocumentRegion + */ + private void checkEmptyTag(IStructuredDocumentRegion structuredDocumentRegion, List results) { + // navigate to name + ITextRegionList regions = structuredDocumentRegion.getRegions(); + if (regions.size() == 2) { + // missing name region + if (regions.get(0).getType() == XMLRegionContext.XML_TAG_OPEN && regions.get(1).getType() == XMLRegionContext.XML_TAG_CLOSE) { + String message = ResourceHandler.getString("ReconcileStepForMarkup.3"); //$NON-NLS-1$ + int start = structuredDocumentRegion.getStartOffset(); + int length = structuredDocumentRegion.getLength(); + Position p = new Position(start, length); + IReconcileAnnotationKey key = createKey(structuredDocumentRegion, getScope()); + + TemporaryAnnotation annotation = new TemporaryAnnotation(p, SEVERITY_SYNTAX_ERROR, message, key, ProblemIDsXML.EmptyTag); + results.add(annotation); + } + } + } + + private void checkForAttributeValue(IStructuredDocumentRegion structuredDocumentRegion, List results) { + // check for attributes without a value + + // track the attribute/equals/value sequence using a state of 0, 1 ,2 + // representing the name, =, and value, respectively + int attrState = 0; + ITextRegionList textRegions = structuredDocumentRegion.getRegions(); + IReconcileAnnotationKey key = createKey(structuredDocumentRegion, getScope()); + int errorCount = 0; + for (int i = 0; i < textRegions.size() && errorCount < ELEMENT_ERROR_LIMIT; i++) { + ITextRegion textRegion = textRegions.get(i); + if (textRegion.getType() == XMLRegionContext.XML_TAG_ATTRIBUTE_NAME || isTagCloseTextRegion(textRegion)) { + // dangling name and '=' + if (attrState == 2 && i >= 2) { + // create annotation + ITextRegion nameRegion = textRegions.get(i - 2); + MessageFormat messageFormat = new MessageFormat(ResourceHandler.getString("Attribute_{0}_is_missing_a_value")); //$NON-NLS-1$ + Object[] args = {structuredDocumentRegion.getText(nameRegion)}; + String message = messageFormat.format(args); + int start = structuredDocumentRegion.getStartOffset(nameRegion); + int end = structuredDocumentRegion.getTextEndOffset(nameRegion); + Position p = new Position(start, end - start); + TemporaryAnnotation annotation = new TemporaryAnnotation(p, SEVERITY_ATTR_MISSING_VALUE, message, key, ProblemIDsXML.MissingAttrValue); + + // quick fix info + ITextRegion equalsRegion = textRegions.get(i - 2 + 1); + int insertOffset = structuredDocumentRegion.getTextEndOffset(equalsRegion) - end; + Object[] additionalFixInfo = {structuredDocumentRegion.getText(nameRegion), new Integer(insertOffset)}; + annotation.setAdditionalFixInfo(additionalFixInfo); + + results.add(annotation); + errorCount++; + } + // name but no '=' (XML only) + else if (attrState == 1 && i >= 1) { + // create annotation + ITextRegion previousRegion = textRegions.get(i - 1); + MessageFormat messageFormat = new MessageFormat(ResourceHandler.getString("Attribute_{0}_has_no_value")); //$NON-NLS-1$ + Object[] args = {structuredDocumentRegion.getText(previousRegion)}; + String message = messageFormat.format(args); + int start = structuredDocumentRegion.getStartOffset(previousRegion); + int end = structuredDocumentRegion.getTextEndOffset(previousRegion); + Position p = new Position(start, end - start); + TemporaryAnnotation annotation = new TemporaryAnnotation(p, SEVERITY_ATTR_NO_VALUE, message, key, ProblemIDsXML.NoAttrValue); + + // quick fix info + annotation.setAdditionalFixInfo(structuredDocumentRegion.getText(previousRegion)); + + results.add(annotation); + errorCount++; + } + attrState = 1; + } else if (textRegion.getType() == XMLRegionContext.XML_TAG_ATTRIBUTE_EQUALS) { + attrState = 2; + } else if (textRegion.getType() == XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE) { + attrState = 0; + } + } + + } + + /** + * @param annotationModel + * @param structuredDocumentRegion + */ + private void checkForSpaceBeforeName(IStructuredDocumentRegion structuredDocumentRegion, List results) { + String sdRegionText = structuredDocumentRegion.getFullText(); + if (sdRegionText.startsWith(" ")) { //$NON-NLS-1$ + IStructuredDocumentRegion prev = structuredDocumentRegion.getPrevious(); + if (prev != null) { + // this is possibly the case of "< tag" + if (prev.getRegions().size() == 1 && isStartTag(prev)) { + // add the error for preceding space in tag name + String message = ResourceHandler.getString("ReconcileStepForMarkup.2"); //$NON-NLS-1$ + int start = structuredDocumentRegion.getStartOffset(); + // find length of whitespace + int length = sdRegionText.trim().equals("") ? sdRegionText.length() : sdRegionText.indexOf(sdRegionText.trim()); //$NON-NLS-1$ + + Position p = new Position(start, length); + IReconcileAnnotationKey key = createKey(structuredDocumentRegion, getScope()); + + TemporaryAnnotation annotation = new TemporaryAnnotation(p, SEVERITY_SYNTAX_ERROR, message, key, ProblemIDsXML.SpacesBeforeTagName); + results.add(annotation); + } + } + } + } + + /** + * @param annotationModel + * @param structuredDocumentRegion + */ + private void checkNoNamespaceInPI(IStructuredDocumentRegion structuredDocumentRegion, List results) { + // navigate to name + ITextRegionList regions = structuredDocumentRegion.getRegions(); + ITextRegion r = null; + int errorCount = 0; + for (int i = 0; i < regions.size() && errorCount < ELEMENT_ERROR_LIMIT; i++) { + r = regions.get(i); + if (r.getType() == XMLRegionContext.XML_TAG_NAME) { + String piText = structuredDocumentRegion.getText(r); + int index = piText.indexOf(":"); //$NON-NLS-1$ + if (index != -1) { + String message = ResourceHandler.getString("ReconcileStepForMarkup.4"); //$NON-NLS-1$ + int start = structuredDocumentRegion.getStartOffset(r) + index; + int length = piText.trim().length() - index; + Position p = new Position(start, length); + IReconcileAnnotationKey key = createKey(structuredDocumentRegion, getScope()); + + TemporaryAnnotation annotation = new TemporaryAnnotation(p, SEVERITY_SYNTAX_ERROR, message, key, ProblemIDsXML.NamespaceInPI); + results.add(annotation); + errorCount++; + } + } + } + } + + /** + * @param structuredDocumentRegion + * @param results + */ + private void checkQuotesForAttributeValues(IStructuredDocumentRegion structuredDocumentRegion, List results) { + ITextRegionList regions = structuredDocumentRegion.getRegions(); + ITextRegion r = null; + String attrValueText = ""; //$NON-NLS-1$ + int errorCount = 0; + for (int i = 0; i < regions.size() && errorCount < ELEMENT_ERROR_LIMIT; i++) { + r = regions.get(i); + if (r.getType() != XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE) + continue; + + attrValueText = structuredDocumentRegion.getText(r); + // attribute value includes quotes in the string + // split up attribute value on quotes + StringTokenizer st = new StringTokenizer(attrValueText, "\"'", true); //$NON-NLS-1$ + int size = st.countTokens(); + // get the pieces of the attribute value + String one = "", two = ""; //$NON-NLS-1$ //$NON-NLS-2$ + if (size > 0) + one = st.nextToken(); + if (size > 1) + two = st.nextToken(); + if (size > 2) { + // should be handled by parsing... + // as in we can't have an attribute value like: <element + // attr="a"b"c"/> + // and <element attr='a"b"c' /> is legal + continue; + } + + + if (size == 1) { + if (one.equals(DQUOTE) || one.equals(SQUOTE)) { + // missing closing quote + String message = ResourceHandler.getString("ReconcileStepForMarkup.0"); //$NON-NLS-1$ + addAttributeError(message, attrValueText, structuredDocumentRegion.getStartOffset(r), attrValueText.trim().length(), ProblemIDsXML.Unclassified, structuredDocumentRegion, results); + errorCount++; + } else { + // missing both + String message = ResourceHandler.getString("ReconcileStepForMarkup.1"); //$NON-NLS-1$ + addAttributeError(message, attrValueText, structuredDocumentRegion.getStartOffset(r), attrValueText.trim().length(), ProblemIDsXML.AttrValueNotQuoted, structuredDocumentRegion, results); + errorCount++; + } + } else if (size == 2) { + if (one.equals(SQUOTE) && !two.equals(SQUOTE) || one.equals(DQUOTE) && !two.equals(DQUOTE)) { + // missing closing quote + String message = ResourceHandler.getString("ReconcileStepForMarkup.0"); //$NON-NLS-1$ + addAttributeError(message, attrValueText, structuredDocumentRegion.getStartOffset(r), attrValueText.trim().length(), ProblemIDsXML.Unclassified, structuredDocumentRegion, results); + errorCount++; + } + } + } + // end of region for loop + } + + private void checkStartEndTagPairs(IStructuredDocumentRegion sdRegion, List results) { + // check start/end tag pairs + XMLNode xmlNode = getXMLNode(sdRegion); + boolean selfClosed = false; + String tagName = null; + int length = 0; + + if (xmlNode.isContainer()) { + IStructuredDocumentRegion endNode = xmlNode.getEndStructuredDocumentRegion(); + if (endNode == null) { + // analyze the tag (check self closing) + ITextRegionList regions = xmlNode.getStartStructuredDocumentRegion().getRegions(); + ITextRegion r = null; + for (int i = 0; i < regions.size(); i++) { + r = regions.get(i); + if (r.getType() == XMLRegionContext.XML_TAG_OPEN || r.getType() == XMLRegionContext.XML_TAG_CLOSE) { + length++; + } else if (r.getType() == XMLRegionContext.XML_TAG_NAME) { + tagName = sdRegion.getText(r); + length += tagName.length(); + } else if (r.getType() == XMLRegionContext.XML_EMPTY_TAG_CLOSE) { + selfClosed = true; + } + } + + if (!selfClosed && tagName != null) { + MessageFormat messageFormat = new MessageFormat(ResourceHandler.getString("Missing_end_tag_{0}")); //$NON-NLS-1$ + Object[] args = {tagName}; + String message = messageFormat.format(args); + + int start = sdRegion.getStart(); + Position p = new Position(start, length); + TemporaryAnnotation annotation = new TemporaryAnnotation(p, SEVERITY_STRUCTURE, message, createKey(sdRegion, getScope()), ProblemIDsXML.MissingEndTag); + + // quick fix info + String tagClose = "/>"; //$NON-NLS-1$ + int tagCloseOffset = xmlNode.getFirstStructuredDocumentRegion().getEndOffset(); + if (r != null && r.getType() == XMLRegionContext.XML_TAG_CLOSE) { + tagClose = "/"; //$NON-NLS-1$ + tagCloseOffset--; + } + XMLNode firstChild = (XMLNode) xmlNode.getFirstChild(); + while (firstChild != null && firstChild.getNodeType() == Node.TEXT_NODE) { + firstChild = (XMLNode) firstChild.getNextSibling(); + } + int endOffset = xmlNode.getEndOffset(); + int firstChildStartOffset = firstChild == null ? endOffset : firstChild.getStartOffset(); + Object[] additionalFixInfo = {tagName, tagClose, new Integer(tagCloseOffset), new Integer(xmlNode.getFirstStructuredDocumentRegion().getEndOffset()), // startTagEndOffset + new Integer(firstChildStartOffset), // firstChildStartOffset + new Integer(endOffset)}; // endOffset + annotation.setAdditionalFixInfo(additionalFixInfo); + + results.add(annotation); + } + } + + } + } + + /** + * @param annotationModel + * @param structuredDocumentRegion + */ + private void checkStartingSpaceForPI(IStructuredDocumentRegion structuredDocumentRegion, List results) { + IStructuredDocumentRegion prev = structuredDocumentRegion.getPrevious(); + if (prev != null) { + String prevText = prev.getFullText(); + if (prev.getType() == XMLRegionContext.XML_CONTENT && prevText.endsWith(" ")) { //$NON-NLS-1$ + String message = ResourceHandler.getString("ReconcileStepForMarkup.5"); //$NON-NLS-1$ + int start = prev.getStartOffset(); + int length = prev.getLength(); + Position p = new Position(start, length); + IReconcileAnnotationKey key = createKey(structuredDocumentRegion, getScope()); + + TemporaryAnnotation annotation = new TemporaryAnnotation(p, SEVERITY_SYNTAX_ERROR, message, key, ProblemIDsXML.SpacesBeforePI); + results.add(annotation); + } + } + } + + public int getScope() { + return IReconcileAnnotationKey.PARTIAL; + } + + /** + * A DirtyRegion can span multiple StructuredDocumentRegions. This method + * returns the StructuredDocumentRegions in a given dirty region. + * + * @param dirtyRegion + */ + private IStructuredDocumentRegion[] getStructuredDocumentRegions(DirtyRegion dirtyRegion) { + List regions = new ArrayList(); + IStructuredDocumentRegion sdRegion = getStructuredDocument().getRegionAtCharacterOffset(dirtyRegion.getOffset()); + if (sdRegion != null) { + if (!sdRegion.isDeleted()) + regions.add(sdRegion); + while ((sdRegion = sdRegion.getNext()) != null && sdRegion.getEndOffset() <= getXMLNode(sdRegion).getEndOffset()) { + if (!sdRegion.isDeleted()) + regions.add(sdRegion); + } + } + return (IStructuredDocumentRegion[]) regions.toArray(new IStructuredDocumentRegion[regions.size()]); + } + + private XMLNode getXMLNode(IStructuredDocumentRegion sdRegion) { + XMLModel xModel = null; + XMLNode xmlNode = null; + // get/release models should always be in a try/finally block + try { + xModel = (XMLModel) getModelManager().getExistingModelForRead(getDocument()); + // xModel is sometime null, when closing editor, for example + if (xModel != null) { + xmlNode = (XMLNode) xModel.getIndexedRegion(sdRegion.getStart()); + } + } finally { + if (xModel != null) { + xModel.releaseFromRead(); + } + } + return xmlNode; + } + + /** + * Determines whether the IStructuredDocumentRegion is a XML "end tag" + * since they're not allowed to have attribute ITextRegions + * + * @param structuredDocumentRegion + * @return + */ + private boolean isEndTag(IStructuredDocumentRegion structuredDocumentRegion) { + if (structuredDocumentRegion == null) + return false; + return structuredDocumentRegion.getFirstRegion().getType() == XMLRegionContext.XML_END_TAG_OPEN; + } + + /** + * Determines if the IStructuredDocumentRegion is an XML Processing + * Instruction + * + * @param structuredDocumentRegion + * @return + */ + private boolean isPI(IStructuredDocumentRegion structuredDocumentRegion) { + return structuredDocumentRegion.getFirstRegion().getType() == XMLRegionContext.XML_PI_OPEN; + } + + /** + * Determines whether the IStructuredDocumentRegion is a XML "start tag" + * since they need to be checked for proper XML attribute region sequences + * + * @param structuredDocumentRegion + * @return + */ + private boolean isStartTag(IStructuredDocumentRegion structuredDocumentRegion) { + if (structuredDocumentRegion == null) + return false; + return structuredDocumentRegion.getFirstRegion().getType() == XMLRegionContext.XML_TAG_OPEN; + } + + // Because we check the "proper" closing separately from attribute + // sequencing, we need to know what's + // an appropriate close. + private boolean isTagCloseTextRegion(ITextRegion textRegion) { + return textRegion.getType() == XMLRegionContext.XML_TAG_CLOSE || textRegion.getType() == XMLRegionContext.XML_EMPTY_TAG_CLOSE; + } + + /** + * Determines if the IStructuredDocumentRegion is XML Content + * + * @param structuredDocumentRegion + * @return + */ + private boolean isXMLContent(IStructuredDocumentRegion structuredDocumentRegion) { + return structuredDocumentRegion.getFirstRegion().getType() == XMLRegionContext.XML_CONTENT; + } + + /* + * check syntax of dirty region + */ + protected IReconcileResult[] reconcile(IStructuredDocumentRegion structuredDocumentRegion) { + List results = new ArrayList(); + + // fix for https://w3.opensource.ibm.com/bugzilla/show_bug.cgi?id=1939 + // not sure why this was being done before + // if (structuredDocumentRegion.getType() == + // XMLRegionContext.XML_CONTENT) { + // // rollback to an open tag + // // ** can this be bad? removal region must exactly match add region + // // or else we may get duplicates + // while ((structuredDocumentRegion = + // structuredDocumentRegion.getPrevious()) != null && + // !isStartTag(structuredDocumentRegion)) { + // continue; + // } + // } + if (structuredDocumentRegion == null) + return EMPTY_RECONCILE_RESULT_SET; + + if (isStartTag(structuredDocumentRegion)) { + // check for attributes without a value + checkForAttributeValue(structuredDocumentRegion, results); + // check if started tag is ended + checkStartEndTagPairs(structuredDocumentRegion, results); + // check empty tag <> + checkEmptyTag(structuredDocumentRegion, results); + // check that each attribute has quotes + checkQuotesForAttributeValues(structuredDocumentRegion, results); + // check that the closing '>' is there + checkClosingBracket(structuredDocumentRegion, results); + } else if (isEndTag(structuredDocumentRegion)) { + checkAttributesInEndTag(structuredDocumentRegion, results); + // check that the closing '>' is there + checkClosingBracket(structuredDocumentRegion, results); + } else if (isPI(structuredDocumentRegion)) { + // check validity of processing instruction + checkStartingSpaceForPI(structuredDocumentRegion, results); + checkNoNamespaceInPI(structuredDocumentRegion, results); + } else if (isXMLContent(structuredDocumentRegion)) { + checkForSpaceBeforeName(structuredDocumentRegion, results); + } + + return (IReconcileResult[]) results.toArray(new IReconcileResult[results.size()]); + } + + /* + * @see org.eclipse.text.reconcilerpipe.AbstractReconcilePipeParticipant#reconcileModel(org.eclipse.jface.text.reconciler.DirtyRegion, + * org.eclipse.jface.text.IRegion) + */ + protected IReconcileResult[] reconcileModel(DirtyRegion dirtyRegion, IRegion subRegion) { + if (dirtyRegion == null) + return EMPTY_RECONCILE_RESULT_SET; + Logger.trace(StructuredTextReconciler.TRACE_FILTER, "[trace reconciler] > reconcile model in MARKUP step w/ dirty region: [" + dirtyRegion.getOffset() + ":" + dirtyRegion.getLength() + "]" + (dirtyRegion == null ? "null" : dirtyRegion.getText())); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + + IReconcileResult[] results = EMPTY_RECONCILE_RESULT_SET; + + // TODO: may need to add back some synch(doc) and/or synch(region[i]) + // to + // be thread safe + IStructuredDocumentRegion[] regions = getStructuredDocumentRegions(dirtyRegion); + for (int i = 0; i < regions.length; i++) { + // the region may be irrelevant at this point + // if the user has deleted it + if (!regions[i].isDeleted()) { + results = merge(results, reconcile(regions[i])); + } + } + + Logger.trace(StructuredTextReconciler.TRACE_FILTER, "[trace reconciler] > MARKUP step done"); //$NON-NLS-1$ + return results; + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/reconcile/ReconcilerAdapterFactoryForXML.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/reconcile/ReconcilerAdapterFactoryForXML.java new file mode 100644 index 0000000000..9bb05141fc --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/reconcile/ReconcilerAdapterFactoryForXML.java @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.reconcile; + +import org.eclipse.wst.sse.core.AbstractAdapterFactory; +import org.eclipse.wst.sse.core.INodeAdapter; +import org.eclipse.wst.sse.core.INodeNotifier; +import org.eclipse.wst.sse.ui.internal.reconcile.IReconcileStepAdapter; +import org.eclipse.wst.xml.core.document.XMLModel; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + + +public class ReconcilerAdapterFactoryForXML extends AbstractAdapterFactory { + + /** + * This flag governs whether or not this ReconcilerFactory is responsible + * for marking nodes "dirty" when an adapter is created for them. This is + * true on startup, then set to false thereafter. + */ + protected boolean fShouldMarkForReconciling = false; + + protected AbstractReconcileStepAdapter singleton = null; + + public ReconcilerAdapterFactoryForXML() { + this(IReconcileStepAdapter.class, true); + } + + /** + * @param adapterKey + * @param registerAdapters + */ + public ReconcilerAdapterFactoryForXML(Object adapterKey, boolean registerAdapters) { + super(adapterKey, registerAdapters); + } + + protected void adaptAll(Node top) { + int length = top.getChildNodes().getLength(); + NodeList children = top.getChildNodes(); + for (int i = 0; i < length; i++) { + adaptAll(children.item(i)); + } + ((INodeNotifier) top).getAdapterFor(adapterKey); + } + + public void adaptAll(XMLModel model) { + if (adapterKey != null) + adaptAll(model.getDocument()); + } + + /* + * (non-Javadoc) + * + * @see com.ibm.sed.model.AbstractAdapterFactory#createAdapter(com.ibm.sed.model.INodeNotifier) + */ + protected INodeAdapter createAdapter(INodeNotifier target) { + if (target instanceof Node) { + Node nodeTarget = (Node) target; + if (nodeTarget.getNodeType() == Node.ELEMENT_NODE || nodeTarget.getNodeType() == Node.DOCUMENT_NODE || nodeTarget.getNodeType() == Node.DOCUMENT_TYPE_NODE) { + if (singleton == null) { + this.singleton = new ReconcileStepAdapterForXML(); + } + // (pa) perf: don't do this on initial startup + if (shouldMarkForReconciling()) + singleton.markForReconciling(target); + return singleton; + } + } + return null; + } + + public void release() { + if (this.singleton != null) + this.singleton.release(); + } + + public void setShouldMarkForReconciling(boolean should) { + fShouldMarkForReconciling = should; + } + + public boolean shouldMarkForReconciling() { + return fShouldMarkForReconciling; + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/reconcile/StructuredTextReconcilingStrategyForContentModel.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/reconcile/StructuredTextReconcilingStrategyForContentModel.java new file mode 100644 index 0000000000..de6c0660c2 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/reconcile/StructuredTextReconcilingStrategyForContentModel.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.reconcile; + +import org.eclipse.jface.text.reconciler.IReconcileStep; +import org.eclipse.ui.texteditor.ITextEditor; +import org.eclipse.wst.sse.ui.internal.reconcile.AbstractStructuredTextReconcilingStrategy; + + +/** + * + * @author pavery + */ +public class StructuredTextReconcilingStrategyForContentModel extends AbstractStructuredTextReconcilingStrategy { + + public StructuredTextReconcilingStrategyForContentModel(ITextEditor editor) { + super(editor); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.ui.internal.ui.text.AbstractStructuredTextReconcilingStrategy#createReconcileSteps() + */ + public void createReconcileSteps() { + + IReconcileStep cmStep = new ReconcileStepForContentModel(); + fFirstStep = new ReconcileStepForMarkup(cmStep); + } + +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/reconcile/StructuredTextReconcilingStrategyForMarkup.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/reconcile/StructuredTextReconcilingStrategyForMarkup.java new file mode 100644 index 0000000000..e4c0c2701a --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/reconcile/StructuredTextReconcilingStrategyForMarkup.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.reconcile; + +import org.eclipse.ui.texteditor.ITextEditor; +import org.eclipse.wst.sse.ui.internal.reconcile.AbstractStructuredTextReconcilingStrategy; + + +/** + * + * @author pavery + * + */ +public class StructuredTextReconcilingStrategyForMarkup extends AbstractStructuredTextReconcilingStrategy { + + public StructuredTextReconcilingStrategyForMarkup(ITextEditor editor) { + super(editor); + } + + public void createReconcileSteps() { + // only one step, to check syntax + fFirstStep = new ReconcileStepForMarkup(); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/registry/AdapterFactoryProviderForEmbeddedXML.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/registry/AdapterFactoryProviderForEmbeddedXML.java new file mode 100644 index 0000000000..690355de54 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/registry/AdapterFactoryProviderForEmbeddedXML.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.registry; + +import org.eclipse.wst.sse.core.IStructuredModel; +import org.eclipse.wst.sse.core.modelhandler.EmbeddedTypeHandler; +import org.eclipse.wst.sse.ui.registry.embedded.EmbeddedAdapterFactoryProvider; +import org.eclipse.wst.xml.core.document.XMLDocument; +import org.eclipse.wst.xml.core.document.XMLModel; +import org.eclipse.wst.xml.core.modelhandler.EmbeddedXML; + + +public class AdapterFactoryProviderForEmbeddedXML implements EmbeddedAdapterFactoryProvider { + + /* + * @see AdapterFactoryProvider#addAdapterFactories(IStructuredModel) + */ + public void addAdapterFactories(IStructuredModel structuredModel) { + if (structuredModel instanceof XMLModel) { + XMLDocument doc = ((XMLModel) structuredModel).getDocument(); + } + } + + /* + * @see AdapterFactoryProvider#isFor(ContentTypeDescription) + */ + public boolean isFor(EmbeddedTypeHandler contentTypeDescription) { + return (contentTypeDescription instanceof EmbeddedXML); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/registry/AdapterFactoryProviderForXML.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/registry/AdapterFactoryProviderForXML.java new file mode 100644 index 0000000000..18858c10c1 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/registry/AdapterFactoryProviderForXML.java @@ -0,0 +1,143 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.registry; + +import org.eclipse.core.runtime.Platform; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.eclipse.ui.views.properties.IPropertySource; +import org.eclipse.wst.common.contentmodel.modelquery.CMDocumentManager; +import org.eclipse.wst.common.contentmodel.modelquery.ModelQuery; +import org.eclipse.wst.common.encoding.content.IContentTypeIdentifier; +import org.eclipse.wst.sse.core.AdapterFactory; +import org.eclipse.wst.sse.core.IFactoryRegistry; +import org.eclipse.wst.sse.core.IStructuredModel; +import org.eclipse.wst.sse.core.PropagatingAdapter; +import org.eclipse.wst.sse.core.modelhandler.IDocumentTypeHandler; +import org.eclipse.wst.sse.core.util.Assert; +import org.eclipse.wst.sse.ui.preferences.CommonEditorPreferenceNames; +import org.eclipse.wst.sse.ui.preferences.PreferenceKeyGenerator; +import org.eclipse.wst.sse.ui.registry.AdapterFactoryProvider; +import org.eclipse.wst.sse.ui.views.contentoutline.IJFaceNodeAdapter; +import org.eclipse.wst.xml.core.document.XMLDocument; +import org.eclipse.wst.xml.core.document.XMLModel; +import org.eclipse.wst.xml.core.modelhandler.ModelHandlerForXML; +import org.eclipse.wst.xml.core.modelquery.ModelQueryUtil; +import org.eclipse.wst.xml.ui.DOMObserver; +import org.eclipse.wst.xml.ui.reconcile.ReconcilerAdapterFactoryForXML; +import org.eclipse.wst.xml.ui.views.contentoutline.JFaceNodeAdapterFactory; +import org.eclipse.wst.xml.ui.views.properties.XMLPropertySourceAdapterFactory; + + +/** + * + */ +public class AdapterFactoryProviderForXML implements AdapterFactoryProvider { + + private final String EDITOR_PLUGIN_ID = "org.eclipse.wst.sse.ui"; // $NON-NLS-1$ + + // //$NON-NLS-1$ + + /* + * @see AdapterFactoryProvider#addAdapterFactories(IStructuredModel) + */ + public void addAdapterFactories(IStructuredModel structuredModel) { + + // add the normal content based factories to model's registry + addContentBasedFactories(structuredModel); + // Must update/add to propagating adapter here too + + if (structuredModel instanceof XMLModel) { + addPropagatingAdapters(structuredModel); + } + } + + protected void addContentBasedFactories(IStructuredModel structuredModel) { + IFactoryRegistry factoryRegistry = structuredModel.getFactoryRegistry(); + Assert.isNotNull(factoryRegistry, "Program Error: client caller must ensure model has factory registry"); //$NON-NLS-1$ + AdapterFactory factory = null; + // == this list came from the previous "XML only" list + + // what was this still here? (6/4/03) + // I commented out on 6/4/03) but may have been something "extra" + // initializing + // old content assist adapter unnecessarily? + //factory = + // factoryRegistry.getFactoryFor(com.ibm.sed.edit.adapters.ContentAssistAdapter.class); + + factory = factoryRegistry.getFactoryFor(IPropertySource.class); + if (factory == null) { + factory = new XMLPropertySourceAdapterFactory(); + factoryRegistry.addFactory(factory); + } + factory = factoryRegistry.getFactoryFor(IJFaceNodeAdapter.class); + if (factory == null) { + factory = new JFaceNodeAdapterFactory(); + factoryRegistry.addFactory(factory); + } + + // cs... added for inferred grammar support + // + if (structuredModel != null) { + ModelQuery modelQuery = ModelQueryUtil.getModelQuery(structuredModel); + if (modelQuery != null) { + CMDocumentManager documentManager = modelQuery.getCMDocumentManager(); + if (documentManager != null) { + IPreferenceStore store = ((AbstractUIPlugin) Platform.getPlugin(EDITOR_PLUGIN_ID)).getPreferenceStore(); + boolean useInferredGrammar = (store != null) ? store.getBoolean(PreferenceKeyGenerator.generateKey(CommonEditorPreferenceNames.EDITOR_USE_INFERRED_GRAMMAR, IContentTypeIdentifier.ContentTypeID_SSEXML)) : true; + + documentManager.setPropertyEnabled(CMDocumentManager.PROPERTY_ASYNC_LOAD, true); + documentManager.setPropertyEnabled(CMDocumentManager.PROPERTY_AUTO_LOAD, false); + documentManager.setPropertyEnabled(CMDocumentManager.PROPERTY_USE_CACHED_RESOLVED_URI, true); + DOMObserver domObserver = new DOMObserver(structuredModel); + domObserver.setGrammarInferenceEnabled(useInferredGrammar); + domObserver.init(); + } + } + } + } + + protected void addPropagatingAdapters(IStructuredModel structuredModel) { + AdapterFactory factory; + XMLModel xmlModel = (XMLModel) structuredModel; + XMLDocument document = xmlModel.getDocument(); + PropagatingAdapter propagatingAdapter = (PropagatingAdapter) document.getAdapterFor(PropagatingAdapter.class); + if (propagatingAdapter != null) { + // checking if we should bother adding this factory + // if the preference says not to check validity, we don't bother + // creating this factory + // to improve performance... + String contentTypeId = IContentTypeIdentifier.ContentTypeID_SSEXML; + IPreferenceStore store = ((AbstractUIPlugin) Platform.getPlugin(EDITOR_PLUGIN_ID)).getPreferenceStore(); + if (store.getString(PreferenceKeyGenerator.generateKey(CommonEditorPreferenceNames.EDITOR_VALIDATION_METHOD, contentTypeId)).equals(CommonEditorPreferenceNames.EDITOR_VALIDATION_CONTENT_MODEL)) { + factory = new ReconcilerAdapterFactoryForXML(); + propagatingAdapter.addAdaptOnCreateFactory(factory); + // (pa) perf: + //propagatingAdapter.initializeForFactory(factory, + // xmlModel.getDocument()); + } + } + } + + + /* + * @see AdapterFactoryProvider#isFor(ContentTypeDescription) + */ + public boolean isFor(IDocumentTypeHandler contentTypeDescription) { + return (contentTypeDescription instanceof ModelHandlerForXML); + } + + public void reinitializeFactories(IStructuredModel structuredModel) { + // nothing to do, since no embedded type + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/style/IStyleConstantsXML.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/style/IStyleConstantsXML.java new file mode 100644 index 0000000000..1164ca609d --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/style/IStyleConstantsXML.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.style; + +/** + * Contains the symbolic name of styles used by LineStyleProvider, + * ColorManager, and any others who may be interested + */ +public interface IStyleConstantsXML { + public static final String BACKGROUND = "background"; //$NON-NLS-1$ + public static final String CDATA_BORDER = "cdataBorder";//$NON-NLS-1$ + public static final String CDATA_TEXT = "cdataText";//$NON-NLS-1$ + public static final String COMMENT_BORDER = "commentBorder";//$NON-NLS-1$ + public static final String COMMENT_TEXT = "commentText";//$NON-NLS-1$ + public static final String DECL_BORDER = "declBoder";//$NON-NLS-1$ + public static final String DOCTYPE_EXTERNAL_ID = "doctypeExternalId";//$NON-NLS-1$ + public static final String DOCTYPE_EXTERNAL_ID_PUBREF = "doctypeExternalPubref";//$NON-NLS-1$ + public static final String DOCTYPE_EXTERNAL_ID_SYSREF = "doctypeExtrenalSysref";//$NON-NLS-1$ + public static final String DOCTYPE_NAME = "doctypeName";//$NON-NLS-1$ + + public static final String FOREGROUND = "foreground"; //$NON-NLS-1$ + public static final String PI_BORDER = "piBorder";//$NON-NLS-1$ + public static final String PI_CONTENT = "piContent";//$NON-NLS-1$ + + public static final String TAG_ATTRIBUTE_EQUALS = "tagAttributeEquals"; //$NON-NLS-1$ + public static final String TAG_ATTRIBUTE_NAME = "tagAttributeName";//$NON-NLS-1$ + public static final String TAG_ATTRIBUTE_VALUE = "tagAttributeValue";//$NON-NLS-1$ + public static final String TAG_BORDER = "tagBorder";//$NON-NLS-1$ + public static final String TAG_NAME = "tagName";//$NON-NLS-1$ + public static final String XML_CONTENT = "xmlContent";//$NON-NLS-1$ +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/style/LineStyleProviderForXML.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/style/LineStyleProviderForXML.java new file mode 100644 index 0000000000..96c2b15f64 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/style/LineStyleProviderForXML.java @@ -0,0 +1,181 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.style; + +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.text.TextAttribute; +import org.eclipse.jface.util.PropertyChangeEvent; +import org.eclipse.wst.common.encoding.content.IContentTypeIdentifier; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.ui.EditorPlugin; +import org.eclipse.wst.sse.ui.preferences.PreferenceKeyGenerator; +import org.eclipse.wst.sse.ui.style.AbstractLineStyleProvider; +import org.eclipse.wst.sse.ui.style.LineStyleProvider; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; + + +public class LineStyleProviderForXML extends AbstractLineStyleProvider implements LineStyleProvider { + public LineStyleProviderForXML() { + super(); + loadColors(); + } + + protected void clearColors() { + getTextAttributes().clear(); + } + + protected TextAttribute getAttributeFor(ITextRegion region) { + /** + * a method to centralize all the "format rules" for regions + * specifically associated for how to "open" the region. + */ + // not sure why this is coming through null, but just to catch it + if (region == null) { + return (TextAttribute) getTextAttributes().get(IStyleConstantsXML.CDATA_TEXT); + } + String type = region.getType(); + if ((type == XMLRegionContext.XML_CONTENT) || (type == XMLRegionContext.XML_DOCTYPE_INTERNAL_SUBSET)) { + return (TextAttribute) getTextAttributes().get(IStyleConstantsXML.XML_CONTENT); + } else if ((type == XMLRegionContext.XML_TAG_OPEN) || (type == XMLRegionContext.XML_END_TAG_OPEN) || (type == XMLRegionContext.XML_TAG_CLOSE) || (type == XMLRegionContext.XML_EMPTY_TAG_CLOSE)) { + return (TextAttribute) getTextAttributes().get(IStyleConstantsXML.TAG_BORDER); + } else if ((type == XMLRegionContext.XML_CDATA_OPEN) || (type == XMLRegionContext.XML_CDATA_CLOSE)) { + return (TextAttribute) getTextAttributes().get(IStyleConstantsXML.CDATA_BORDER); + } else if (type == XMLRegionContext.XML_CDATA_TEXT) { + return (TextAttribute) getTextAttributes().get(IStyleConstantsXML.CDATA_TEXT); + } else if (type == XMLRegionContext.XML_TAG_ATTRIBUTE_NAME) { + return (TextAttribute) getTextAttributes().get(IStyleConstantsXML.TAG_ATTRIBUTE_NAME); + } else if (type == XMLRegionContext.XML_DOCTYPE_DECLARATION) { + return (TextAttribute) getTextAttributes().get(IStyleConstantsXML.TAG_NAME); + } else if (type == XMLRegionContext.XML_TAG_NAME) { + return (TextAttribute) getTextAttributes().get(IStyleConstantsXML.TAG_NAME); + } else if ((type == XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE)) { + return (TextAttribute) getTextAttributes().get(IStyleConstantsXML.TAG_ATTRIBUTE_VALUE); + } else if (type == XMLRegionContext.XML_TAG_ATTRIBUTE_EQUALS) { + return (TextAttribute) getTextAttributes().get(IStyleConstantsXML.TAG_ATTRIBUTE_EQUALS); + } else if ((type == XMLRegionContext.XML_COMMENT_OPEN) || (type == XMLRegionContext.XML_COMMENT_CLOSE)) { + return (TextAttribute) getTextAttributes().get(IStyleConstantsXML.COMMENT_BORDER); + } else if (type == XMLRegionContext.XML_COMMENT_TEXT) { + return (TextAttribute) getTextAttributes().get(IStyleConstantsXML.COMMENT_TEXT); + } else if (type == XMLRegionContext.XML_DOCTYPE_NAME) { + return (TextAttribute) getTextAttributes().get(IStyleConstantsXML.DOCTYPE_NAME); + } else if (type == XMLRegionContext.XML_PI_CONTENT) { + return (TextAttribute) getTextAttributes().get(IStyleConstantsXML.PI_CONTENT); + } else if ((type == XMLRegionContext.XML_PI_OPEN) || (type == XMLRegionContext.XML_PI_CLOSE)) { + return (TextAttribute) getTextAttributes().get(IStyleConstantsXML.PI_BORDER); + } else if ((type == XMLRegionContext.XML_DECLARATION_OPEN) || (type == XMLRegionContext.XML_DECLARATION_CLOSE)) { + return (TextAttribute) getTextAttributes().get(IStyleConstantsXML.DECL_BORDER); + } else if (type == XMLRegionContext.XML_DOCTYPE_EXTERNAL_ID_SYSREF) { + return (TextAttribute) getTextAttributes().get(IStyleConstantsXML.DOCTYPE_EXTERNAL_ID_SYSREF); + } else if (type == XMLRegionContext.XML_DOCTYPE_EXTERNAL_ID_PUBREF) { + return (TextAttribute) getTextAttributes().get(IStyleConstantsXML.DOCTYPE_EXTERNAL_ID_PUBREF); + } else if (type == XMLRegionContext.XML_DOCTYPE_EXTERNAL_ID_PUBLIC || type == XMLRegionContext.XML_DOCTYPE_EXTERNAL_ID_SYSTEM) { + return (TextAttribute) getTextAttributes().get(IStyleConstantsXML.DOCTYPE_EXTERNAL_ID); + } else if (type == XMLRegionContext.UNDEFINED) { + return (TextAttribute) getTextAttributes().get(IStyleConstantsXML.CDATA_TEXT); + } else if (type == XMLRegionContext.WHITE_SPACE) { + // white space is normall not on its own ... but when it is, we'll + // treat as content + return (TextAttribute) getTextAttributes().get(IStyleConstantsXML.XML_CONTENT); + } else if ((type == XMLRegionContext.XML_CHAR_REFERENCE) || (type == XMLRegionContext.XML_ENTITY_REFERENCE) || (type == XMLRegionContext.XML_PE_REFERENCE)) { + // we may want to character and entity references to have it own + // color in future, + // but for now, we'll make attribute value + return (TextAttribute) getTextAttributes().get(IStyleConstantsXML.TAG_ATTRIBUTE_VALUE); + } else { + // default, return null to signal "not handled" + // in which case, other factories should be tried + return null; + } + } + + protected IPreferenceStore getColorPreferences() { + return EditorPlugin.getDefault().getPreferenceStore(); + } + + protected String getPreferenceKey(String key) { + String contentTypeId = IContentTypeIdentifier.ContentTypeID_SSEXML; + return PreferenceKeyGenerator.generateKey(key, contentTypeId); + } + + protected void handlePropertyChange(PropertyChangeEvent event) { + String styleKey = null; + + if (event != null) { + String prefKey = event.getProperty(); + // check if preference changed is a style preference + if (getPreferenceKey(IStyleConstantsXML.TAG_NAME).equals(prefKey)) { + styleKey = IStyleConstantsXML.TAG_NAME; + } else if (getPreferenceKey(IStyleConstantsXML.TAG_BORDER).equals(prefKey)) { + styleKey = IStyleConstantsXML.TAG_BORDER; + } else if (getPreferenceKey(IStyleConstantsXML.TAG_ATTRIBUTE_NAME).equals(prefKey)) { + styleKey = IStyleConstantsXML.TAG_ATTRIBUTE_NAME; + } else if (getPreferenceKey(IStyleConstantsXML.TAG_ATTRIBUTE_VALUE).equals(prefKey)) { + styleKey = IStyleConstantsXML.TAG_ATTRIBUTE_VALUE; + } else if (getPreferenceKey(IStyleConstantsXML.TAG_ATTRIBUTE_EQUALS).equals(prefKey)) { + styleKey = IStyleConstantsXML.TAG_ATTRIBUTE_EQUALS; + } else if (getPreferenceKey(IStyleConstantsXML.COMMENT_BORDER).equals(prefKey)) { + styleKey = IStyleConstantsXML.COMMENT_BORDER; + } else if (getPreferenceKey(IStyleConstantsXML.COMMENT_TEXT).equals(prefKey)) { + styleKey = IStyleConstantsXML.COMMENT_TEXT; + } else if (getPreferenceKey(IStyleConstantsXML.CDATA_BORDER).equals(prefKey)) { + styleKey = IStyleConstantsXML.CDATA_BORDER; + } else if (getPreferenceKey(IStyleConstantsXML.CDATA_TEXT).equals(prefKey)) { + styleKey = IStyleConstantsXML.CDATA_TEXT; + } else if (getPreferenceKey(IStyleConstantsXML.DECL_BORDER).equals(prefKey)) { + styleKey = IStyleConstantsXML.DECL_BORDER; + } else if (getPreferenceKey(IStyleConstantsXML.DOCTYPE_EXTERNAL_ID).equals(prefKey)) { + styleKey = IStyleConstantsXML.DOCTYPE_EXTERNAL_ID; + } else if (getPreferenceKey(IStyleConstantsXML.DOCTYPE_EXTERNAL_ID_PUBREF).equals(prefKey)) { + styleKey = IStyleConstantsXML.DOCTYPE_EXTERNAL_ID_PUBREF; + } else if (getPreferenceKey(IStyleConstantsXML.DOCTYPE_EXTERNAL_ID_SYSREF).equals(prefKey)) { + styleKey = IStyleConstantsXML.DOCTYPE_EXTERNAL_ID_SYSREF; + } else if (getPreferenceKey(IStyleConstantsXML.DOCTYPE_NAME).equals(prefKey)) { + styleKey = IStyleConstantsXML.DOCTYPE_NAME; + } else if (getPreferenceKey(IStyleConstantsXML.PI_CONTENT).equals(prefKey)) { + styleKey = IStyleConstantsXML.PI_CONTENT; + } else if (getPreferenceKey(IStyleConstantsXML.PI_BORDER).equals(prefKey)) { + styleKey = IStyleConstantsXML.PI_BORDER; + } else if (getPreferenceKey(IStyleConstantsXML.XML_CONTENT).equals(prefKey)) { + styleKey = IStyleConstantsXML.XML_CONTENT; + } + } + + if (styleKey != null) { + // overwrite style preference with new value + addTextAttribute(styleKey); + super.handlePropertyChange(event); + } + } + + protected void loadColors() { + clearColors(); + + addTextAttribute(IStyleConstantsXML.TAG_NAME); + addTextAttribute(IStyleConstantsXML.TAG_BORDER); + addTextAttribute(IStyleConstantsXML.TAG_ATTRIBUTE_NAME); + addTextAttribute(IStyleConstantsXML.TAG_ATTRIBUTE_VALUE); + addTextAttribute(IStyleConstantsXML.TAG_ATTRIBUTE_EQUALS); + addTextAttribute(IStyleConstantsXML.COMMENT_BORDER); + addTextAttribute(IStyleConstantsXML.COMMENT_TEXT); + addTextAttribute(IStyleConstantsXML.CDATA_BORDER); + addTextAttribute(IStyleConstantsXML.CDATA_TEXT); + addTextAttribute(IStyleConstantsXML.DECL_BORDER); + addTextAttribute(IStyleConstantsXML.DOCTYPE_EXTERNAL_ID); + addTextAttribute(IStyleConstantsXML.DOCTYPE_EXTERNAL_ID_PUBREF); + addTextAttribute(IStyleConstantsXML.DOCTYPE_EXTERNAL_ID_SYSREF); + addTextAttribute(IStyleConstantsXML.DOCTYPE_NAME); + addTextAttribute(IStyleConstantsXML.PI_CONTENT); + addTextAttribute(IStyleConstantsXML.PI_BORDER); + addTextAttribute(IStyleConstantsXML.XML_CONTENT); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/taginfo/MarkupTagInfoProvider.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/taginfo/MarkupTagInfoProvider.java new file mode 100644 index 0000000000..4409635fd0 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/taginfo/MarkupTagInfoProvider.java @@ -0,0 +1,201 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.taginfo; + + + +import org.eclipse.wst.common.contentmodel.CMAttributeDeclaration; +import org.eclipse.wst.common.contentmodel.CMDataType; +import org.eclipse.wst.common.contentmodel.CMDocumentation; +import org.eclipse.wst.common.contentmodel.CMElementDeclaration; +import org.eclipse.wst.common.contentmodel.CMNode; +import org.eclipse.wst.common.contentmodel.CMNodeList; +import org.eclipse.wst.common.contentmodel.util.CMDescriptionBuilder; +import org.eclipse.wst.sse.ui.nls.ResourceHandler; + + +/** + * Provides basic tag information such as element/attribute name, data type, + * and tag info/documentation for CMNodes. Uses HTML to enhance presentation. + */ +public class MarkupTagInfoProvider { + protected final static String BOLD_END = "</b>"; //$NON-NLS-1$ + protected final static String BOLD_START = "<b>"; //$NON-NLS-1$ + protected final static String HEADING_END = "</h5>"; //$NON-NLS-1$ + protected final static String HEADING_START = "<h5>"; //$NON-NLS-1$ + protected final static String LIST_BEGIN = "<ul>"; //$NON-NLS-1$ + protected final static String LIST_ELEMENT = "<li>"; //$NON-NLS-1$ + protected final static String NEW_LINE = "<dl>"; //$NON-NLS-1$ + protected final static String PARAGRAPH_END = "</p>"; //$NON-NLS-1$ + protected final static String PARAGRAPH_START = "<p>"; //$NON-NLS-1$ + protected final static String SPACE = " "; //$NON-NLS-1$ + + /** + * Returns basic tag information for display given a CMNode + * + * @param CMNode + * node - node to display information for + * + * @return String + */ + public String getInfo(CMNode node) { + if (node == null) + return null; + StringBuffer sb = new StringBuffer(); + // we assume that if there is tagInfo present, only display tagInfo + printTagInfo(sb, node); + + // no tagInfo present, so try to display tag description + if (sb.length() == 0) { + printDescription(sb, node); + } + + // no tag description present either, so display default info + if (sb.length() == 0) { + printDefaultInfo(node, sb); + } + + return sb.toString(); + } + + /** + * Adds dataType's data type information, including enumerated type values + * to string buffer, sb + * + * @param StringBuffer + * sb - string to place data type info into + * @param CMDataType + * dataType - data type object to get info from (should not be + * null) + */ + protected void printDataTypeInfo(StringBuffer sb, CMDataType dataType) { + String dataTypeName = dataType.getNodeName(); + if ((dataTypeName != null) && (dataTypeName.length() > 0)) { + sb.append(PARAGRAPH_START + BOLD_START + ResourceHandler.getString("Data_Type____4") + SPACE + BOLD_END); //$NON-NLS-1$ + sb.append(dataTypeName); + sb.append(PARAGRAPH_END); + } + String[] enumeratedValue = dataType.getEnumeratedValues(); + if (enumeratedValue != null && enumeratedValue.length > 0) { + sb.append(PARAGRAPH_START + BOLD_START + ResourceHandler.getString("Enumerated_Values____5") + SPACE + BOLD_END); //$NON-NLS-1$ + sb.append(LIST_BEGIN); + for (int i = 0; i < enumeratedValue.length; i++) { + sb.append(LIST_ELEMENT + enumeratedValue[i]); + } + sb.append(PARAGRAPH_END); + } + } + + /** + * Adds the default info (element name, content model, data type) of + * CMNode to the string buffer, sb + * + * @param StringBuffer + * sb - string to place display info into + * @param CMNode + * node - node to get tag info from + */ + protected void printDefaultInfo(CMNode node, StringBuffer sb) { + { + + if (node.getNodeType() == CMNode.ELEMENT_DECLARATION) { + CMElementDeclaration ed = (CMElementDeclaration) node; + sb.append(PARAGRAPH_START + BOLD_START + ResourceHandler.getString("Element____1") + SPACE + BOLD_END); //$NON-NLS-1$ + sb.append(node.getNodeName()); + sb.append(PARAGRAPH_END); + if (ed.getContentType() == CMElementDeclaration.PCDATA) { + CMDataType dataType = ed.getDataType(); + if (dataType != null) { + printDataTypeInfo(sb, dataType); + } + } else { + CMDescriptionBuilder builder = new CMDescriptionBuilder(); + String description = builder.buildDescription(node); + if ((description != null) && (description.length() > 0)) { + sb.append(PARAGRAPH_START + BOLD_START + ResourceHandler.getString("Content_Model____2") + SPACE + BOLD_END); //$NON-NLS-1$ + sb.append(description + PARAGRAPH_END); + } + } + printDocumentation(sb, node); + } else if (node.getNodeType() == CMNode.ATTRIBUTE_DECLARATION) { + CMAttributeDeclaration ad = (CMAttributeDeclaration) node; + sb.append(PARAGRAPH_START + BOLD_START + ResourceHandler.getString("Attribute____3") + SPACE + BOLD_END); //$NON-NLS-1$ + sb.append(node.getNodeName()); + sb.append(PARAGRAPH_END); + CMDataType dataType = ad.getAttrType(); + if (dataType != null) { + printDataTypeInfo(sb, dataType); + } + printDocumentation(sb, node); + } else if (node.getNodeType() == CMNode.DATA_TYPE) { + sb.append(PARAGRAPH_START + BOLD_START + ResourceHandler.getString("Data_Type____4") + SPACE + BOLD_END); //$NON-NLS-1$ + sb.append(node.getNodeName()); + sb.append(PARAGRAPH_END); + printDocumentation(sb, node); + } + } + } + + /** + * Adds the description property of the CMNode to the string buffer, sb + * + * @param StringBuffer + * sb - string to place display info into + * @param CMNode + * node - node to get tag description from + */ + protected void printDescription(StringBuffer sb, CMNode node) { + String tagInfo = (String) node.getProperty("description"); //$NON-NLS-1$ + if (tagInfo != null) { + sb.append(PARAGRAPH_START + tagInfo.trim() + PARAGRAPH_END); + } + } + + /** + * Adds the tag documentation property of the CMNode to the string buffer, + * sb + * + * @param StringBuffer + * sb - string to place display info into + * @param CMNode + * node - node to get tag documentation from + */ + protected void printDocumentation(StringBuffer sb, CMNode node) { + CMNodeList nodeList = (CMNodeList) node.getProperty("documentation"); //$NON-NLS-1$ + if ((nodeList != null) && (nodeList.getLength() > 0)) { + sb.append(NEW_LINE); + for (int i = 0; i < nodeList.getLength(); i++) { + CMDocumentation documentation = (CMDocumentation) nodeList.item(i); + String doc = documentation.getValue(); + if (doc != null) { + sb.append(PARAGRAPH_START + doc.trim() + PARAGRAPH_END); + } + } + } + } + + /** + * Adds the tag info property of the CMNode to the string buffer, sb + * + * @param StringBuffer + * sb - string to place display info into + * @param CMNode + * node - node to get tag info from + */ + protected void printTagInfo(StringBuffer sb, CMNode node) { + String tagInfo = (String) node.getProperty("tagInfo"); //$NON-NLS-1$ + if (tagInfo != null) { + sb.append(PARAGRAPH_START + tagInfo.trim() + PARAGRAPH_END); + } + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/taginfo/XMLBestMatchHoverProcessor.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/taginfo/XMLBestMatchHoverProcessor.java new file mode 100644 index 0000000000..fb93c7e348 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/taginfo/XMLBestMatchHoverProcessor.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.taginfo; + +import org.eclipse.jface.text.ITextHover; +import org.eclipse.wst.sse.ui.taginfo.AbstractBestMatchHoverProcessor; + + +/** + * Provides the best xml hover help documentation (by using other hover help + * processors) Priority of hover help processors is: ProblemHoverProcessor, + * XMLTagInfoHoverProcessor, AnnotationHoverProcessor + */ +public class XMLBestMatchHoverProcessor extends AbstractBestMatchHoverProcessor { + XMLTagInfoHoverProcessor fTagInfoHover; + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.ui.structured.taginfo.AbstractBestMatchHoverProcessor#getTagInfoHover() + */ + protected ITextHover getTagInfoHover() { + if (fTagInfoHover == null) { + fTagInfoHover = new XMLTagInfoHoverProcessor(); + } + return fTagInfoHover; + } + +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/taginfo/XMLInformationProvider.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/taginfo/XMLInformationProvider.java new file mode 100644 index 0000000000..ae52fe9fe0 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/taginfo/XMLInformationProvider.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.taginfo; + + + +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.information.IInformationProvider; +import org.eclipse.jface.text.information.IInformationProviderExtension; + +/** + * Provides context information for XML tags (Shows tooltip description) + * + * @author amywu + */ +public class XMLInformationProvider implements IInformationProvider, IInformationProviderExtension { + + private XMLBestMatchHoverProcessor fTextHover = null; + + public XMLInformationProvider() { + fTextHover = new XMLBestMatchHoverProcessor(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.information.IInformationProvider#getInformation(org.eclipse.jface.text.ITextViewer, + * org.eclipse.jface.text.IRegion) + */ + public String getInformation(ITextViewer textViewer, IRegion subject) { + return (String) getInformation2(textViewer, subject); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.information.IInformationProviderExtension#getInformation2(org.eclipse.jface.text.ITextViewer, + * org.eclipse.jface.text.IRegion) + */ + public Object getInformation2(ITextViewer textViewer, IRegion subject) { + return fTextHover.getHoverInfo(textViewer, subject); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.information.IInformationProvider#getSubject(org.eclipse.jface.text.ITextViewer, + * int) + */ + public IRegion getSubject(ITextViewer textViewer, int offset) { + return fTextHover.getHoverRegion(textViewer, offset); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/taginfo/XMLTagInfoHoverProcessor.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/taginfo/XMLTagInfoHoverProcessor.java new file mode 100644 index 0000000000..7638c93698 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/taginfo/XMLTagInfoHoverProcessor.java @@ -0,0 +1,343 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.taginfo; + + + +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextHover; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.Region; +import org.eclipse.wst.common.contentmodel.CMAttributeDeclaration; +import org.eclipse.wst.common.contentmodel.CMElementDeclaration; +import org.eclipse.wst.common.contentmodel.CMNamedNodeMap; +import org.eclipse.wst.common.contentmodel.CMNode; +import org.eclipse.wst.common.contentmodel.modelquery.ModelQuery; +import org.eclipse.wst.common.contentmodel.util.DOMNamespaceHelper; +import org.eclipse.wst.sse.core.IndexedRegion; +import org.eclipse.wst.sse.core.text.IStructuredDocument; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.core.text.ITextRegionList; +import org.eclipse.wst.sse.core.util.Debug; +import org.eclipse.wst.sse.ui.Logger; +import org.eclipse.wst.sse.ui.StructuredTextViewer; +import org.eclipse.wst.sse.ui.internal.contentassist.ContentAssistUtils; +import org.eclipse.wst.xml.core.document.XMLNode; +import org.eclipse.wst.xml.core.modelquery.ModelQueryUtil; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + + +/** + * Provides hover help documentation for xml tags + * + * @author amywu + * @see org.eclipse.jface.text.ITextHover + */ +public class XMLTagInfoHoverProcessor implements ITextHover { + protected MarkupTagInfoProvider fInfoProvider = null; + + /** + * Constructor for XMLTextHoverProcessor. + */ + public XMLTagInfoHoverProcessor() { + } + + /** + * Retreives documentation to display in the hover help popup. + * + * @return String any documentation information to display + * <code>null</code> if there is nothing to display. + * + */ + protected String computeHoverHelp(ITextViewer textViewer, int documentPosition) { + String result = null; + + IndexedRegion treeNode = ContentAssistUtils.getNodeAt((StructuredTextViewer) textViewer, documentPosition); + if (treeNode == null) + return null; + Node node = (Node) treeNode; + + while (node != null && node.getNodeType() == Node.TEXT_NODE && node.getParentNode() != null) + node = node.getParentNode(); + XMLNode parentNode = (XMLNode) node; + + IStructuredDocumentRegion flatNode = ((IStructuredDocument) textViewer.getDocument()).getRegionAtCharacterOffset(documentPosition); + if (flatNode != null) { + ITextRegion region = flatNode.getRegionAtCharacterOffset(documentPosition); + if (region != null) { + result = computeRegionHelp(treeNode, parentNode, flatNode, region); + } + } + + return result; + } + + /** + * Computes the hoverhelp based on region + * + * @return String hoverhelp + */ + protected String computeRegionHelp(IndexedRegion treeNode, XMLNode parentNode, IStructuredDocumentRegion flatNode, ITextRegion region) { + String result = null; + if (region == null) + return null; + String regionType = region.getType(); + if (regionType == XMLRegionContext.XML_TAG_NAME) + result = computeTagNameHelp((XMLNode) treeNode, parentNode, flatNode, region); + else if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_NAME) + result = computeTagAttNameHelp((XMLNode) treeNode, parentNode, flatNode, region); + else if (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE) + result = computeTagAttValueHelp((XMLNode) treeNode, parentNode, flatNode, region); + return result; + } + + /** + * Computes the hover help for the attribute name + */ + protected String computeTagAttNameHelp(XMLNode xmlnode, XMLNode parentNode, IStructuredDocumentRegion flatNode, ITextRegion region) { + CMElementDeclaration elementDecl = getCMElementDeclaration(xmlnode); + String attName = flatNode.getText(region); + CMAttributeDeclaration attDecl = getCMAttributeDeclaration(elementDecl, attName); + return getAdditionalInfo(elementDecl, attDecl); + } + + /** + * Computes the hover help for the attribute value (this is the same as + * the attribute name's help) + */ + protected String computeTagAttValueHelp(XMLNode xmlnode, XMLNode parentNode, IStructuredDocumentRegion flatNode, ITextRegion region) { + CMElementDeclaration elementDecl = getCMElementDeclaration(xmlnode); + ITextRegion attrNameRegion = getAttrNameRegion(xmlnode, region); + + String attName = flatNode.getText(attrNameRegion); + CMAttributeDeclaration attDecl = getCMAttributeDeclaration(elementDecl, attName); + return getAdditionalInfo(elementDecl, attDecl); + } + + /** + * Computes the hover help for the tag name + */ + protected String computeTagNameHelp(XMLNode xmlnode, XMLNode parentNode, IStructuredDocumentRegion flatNode, ITextRegion region) { + CMElementDeclaration elementDecl = getCMElementDeclaration(xmlnode); + CMElementDeclaration pelementDecl = getCMElementDeclaration(parentNode); + return getAdditionalInfo(pelementDecl, elementDecl); + } + + /** + * Retreives cmnode's documentation to display in the hover help popup. If + * no documentation exists for cmnode, try displaying parentOrOwner's + * documentation + * + * @return String any documentation information to display for cmnode. + * <code>null</code> if there is nothing to display. + */ + protected String getAdditionalInfo(CMNode parentOrOwner, CMNode cmnode) { + String addlInfo = null; + + if (cmnode == null) { + if (Debug.displayWarnings) { + new IllegalArgumentException("Null declaration!").printStackTrace(); //$NON-NLS-1$ + } + return null; + } + + addlInfo = getInfoProvider().getInfo(cmnode); + if (addlInfo == null && parentOrOwner != null) + addlInfo = getInfoProvider().getInfo(parentOrOwner); + return addlInfo; + } + + /** + * Find the region of the attribute name for the given attribute value + * region + * + * @param XMLNode + * node - parent node + * @param ITextRegion + * region - region of attribute value + * + * @return region - attribute name region for given region + */ + protected ITextRegion getAttrNameRegion(XMLNode node, ITextRegion region) { + // Find the attribute name for which this position should have a value + IStructuredDocumentRegion open = node.getFirstStructuredDocumentRegion(); + ITextRegionList openRegions = open.getRegions(); + int i = openRegions.indexOf(region); + if (i < 0) + return null; + ITextRegion nameRegion = null; + while (i >= 0) { + nameRegion = openRegions.get(i--); + if (nameRegion.getType() == XMLRegionContext.XML_TAG_ATTRIBUTE_NAME) + break; + } + return nameRegion; + } + + /** + * Retreives CMAttributeDeclaration indicated by attribute name within + * elementDecl + */ + protected CMAttributeDeclaration getCMAttributeDeclaration(CMElementDeclaration elementDecl, String attName) { + CMAttributeDeclaration attrDecl = null; + + if (elementDecl != null) { + CMNamedNodeMap attributes = elementDecl.getAttributes(); + String noprefixName = DOMNamespaceHelper.getUnprefixedName(attName); + if (attributes != null) { + attrDecl = (CMAttributeDeclaration) attributes.getNamedItem(noprefixName); + if (attrDecl == null) { + attrDecl = (CMAttributeDeclaration) attributes.getNamedItem(attName); + } + } + } + return attrDecl; + } + + /** + * Retreives CMElementDeclaration for given node + * + * @param Node + * node + * + * @return CMElementDeclaration - CMElementDeclaration of node or + * <code>null</code> if not possible + */ + protected CMElementDeclaration getCMElementDeclaration(Node node) { + CMElementDeclaration result = null; + if (node.getNodeType() == Node.ELEMENT_NODE) { + ModelQuery modelQuery = ModelQueryUtil.getModelQuery(node.getOwnerDocument()); + if (modelQuery != null) + result = modelQuery.getCMElementDeclaration((Element) node); + } + return result; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.text.ITextHover#getHoverInfo(org.eclipse.jface.text.ITextViewer, + * org.eclipse.jface.text.IRegion) + */ + public String getHoverInfo(ITextViewer viewer, IRegion hoverRegion) { + if ((hoverRegion == null) || (viewer == null) || (viewer.getDocument() == null)) + return null; + + String displayText = null; + int documentOffset = hoverRegion.getOffset(); + displayText = computeHoverHelp(viewer, documentOffset); + + return displayText; + } + + /** + * Returns the region to hover the text over based on the offset. + * + * @param textViewer + * @param offset + * + * @return IRegion region to hover over if offset is within tag name, + * attribute name, or attribute value and if offset is not over + * invalid whitespace. otherwise, returns <code>null</code> + * + * @see ITextHover#getHoverRegion(ITextViewer, int) + */ + public IRegion getHoverRegion(ITextViewer textViewer, int offset) { + if ((textViewer == null) || (textViewer.getDocument() == null)) + return null; + + IStructuredDocumentRegion flatNode = ((IStructuredDocument) textViewer.getDocument()).getRegionAtCharacterOffset(offset); + ITextRegion region = null; + + if (flatNode != null) { + region = flatNode.getRegionAtCharacterOffset(offset); + } + + if (region != null) { + // only supply hoverhelp for tag name, attribute name, or + // attribute value + String regionType = region.getType(); + if ((regionType == XMLRegionContext.XML_TAG_NAME) || (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_NAME) || (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE)) { + try { + // check if we are at whitespace before or after line + IRegion line = textViewer.getDocument().getLineInformationOfOffset(offset); + if ((offset > (line.getOffset())) && (offset < (line.getOffset() + line.getLength()))) { + // check if we are in region's trailing whitespace + // (whitespace after relevant info) + if (offset < flatNode.getTextEndOffset(region)) { + return new Region(flatNode.getStartOffset(region), region.getTextLength()); + } + } + } catch (BadLocationException e) { + Logger.logException(e); + } + } + } + return null; + } + + /** + * @deprecated if enabled flag is false, dont call getHoverRegion in the + * first place if true, use getHoverRegion(ITextViewer, int) + */ + public IRegion getHoverRegion(ITextViewer textViewer, int offset, boolean enabled) { + if ((!enabled) || (textViewer == null) || (textViewer.getDocument() == null)) + return null; + + IStructuredDocumentRegion flatNode = ((IStructuredDocument) textViewer.getDocument()).getRegionAtCharacterOffset(offset); + ITextRegion region = null; + + if (flatNode != null) { + region = flatNode.getRegionAtCharacterOffset(offset); + } + + if (region != null) { + // only supply hoverhelp for tag name, attribute name, or + // attribute value + String regionType = region.getType(); + if ((regionType == XMLRegionContext.XML_TAG_NAME) || (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_NAME) || (regionType == XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE)) { + try { + // check if we are at whitespace before or after line + IRegion line = textViewer.getDocument().getLineInformationOfOffset(offset); + if ((offset > (line.getOffset())) && (offset < (line.getOffset() + line.getLength()))) { + // check if we are in region's trailing whitespace + // (whitespace after relevant info) + if (offset < flatNode.getTextEndOffset(region)) { + return new Region(flatNode.getStartOffset(region), region.getTextLength()); + } + } + } catch (BadLocationException e) { + Logger.logException(e); + } + } + } + return null; + } + + /** + * Gets the infoProvider. + * + * @return Returns fInfoProvider and if fInfoProvider was + * <code>null</code> set fInfoProvider to DefaultInfoProvider + */ + public MarkupTagInfoProvider getInfoProvider() { + if (fInfoProvider == null) { + fInfoProvider = new MarkupTagInfoProvider(); + } + return fInfoProvider; + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/templates/TemplateContextTypeIds.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/templates/TemplateContextTypeIds.java new file mode 100644 index 0000000000..38e9db7cd2 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/templates/TemplateContextTypeIds.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.templates; + +/** + * Contains a list of template context type ids + */ +public class TemplateContextTypeIds { + public static final String ALL = "all"; //$NON-NLS-1$ + public static final String ATTRIBUTE = "attribute"; //$NON-NLS-1$ + public static final String ATTRIBUTEVALUE = "attribute_value"; //$NON-NLS-1$ + public static final String TAG = "tag"; //$NON-NLS-1$ + +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/templates/TemplateContextTypeXML.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/templates/TemplateContextTypeXML.java new file mode 100644 index 0000000000..2174956774 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/templates/TemplateContextTypeXML.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.templates; + +import org.eclipse.jface.text.templates.GlobalTemplateVariables; +import org.eclipse.jface.text.templates.TemplateContextType; +import org.eclipse.wst.xml.ui.nls.ResourceHandler; + + +/** + * Base class for XML template context types. Templates of this context type + * apply to any place within XML content type. + */ +public class TemplateContextTypeXML extends TemplateContextType { + public static final String XML_PREFIX = "xml_"; //$NON-NLS-1$ + + /** + * Generate a context type id that includes content type + * + * @param base_contextTypeId + * @return String + */ + public static String generateContextTypeId(String base_contextTypeId) { + return XML_PREFIX + base_contextTypeId; + } + + public TemplateContextTypeXML() { + this(generateContextTypeId(TemplateContextTypeIds.ALL), ResourceHandler.getString("TemplateContextTypeXML.0")); //$NON-NLS-1$ + } + + /** + * @param id + * @param name + */ + public TemplateContextTypeXML(String id, String name) { + super(id, name); + addResolver(new GlobalTemplateVariables.Cursor()); + addResolver(new GlobalTemplateVariables.Date()); + addResolver(new GlobalTemplateVariables.Dollar()); + addResolver(new GlobalTemplateVariables.LineSelection()); + addResolver(new GlobalTemplateVariables.Time()); + addResolver(new GlobalTemplateVariables.User()); + addResolver(new GlobalTemplateVariables.WordSelection()); + addResolver(new GlobalTemplateVariables.Year()); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/templates/TemplateContextTypeXMLAttribute.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/templates/TemplateContextTypeXMLAttribute.java new file mode 100644 index 0000000000..faf4b6ef83 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/templates/TemplateContextTypeXMLAttribute.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.templates; + +import org.eclipse.wst.xml.ui.nls.ResourceHandler; + +/** + * Templates of this context type apply to any attributes within XML content + * type. + */ +public class TemplateContextTypeXMLAttribute extends TemplateContextTypeXML { + + public TemplateContextTypeXMLAttribute() { + super(generateContextTypeId(TemplateContextTypeIds.ATTRIBUTE), ResourceHandler.getString("TemplateContextTypeXMLAttribute.0")); //$NON-NLS-1$ + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/templates/TemplateContextTypeXMLAttributeValue.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/templates/TemplateContextTypeXMLAttributeValue.java new file mode 100644 index 0000000000..05d0708358 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/templates/TemplateContextTypeXMLAttributeValue.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.templates; + +import org.eclipse.wst.xml.ui.nls.ResourceHandler; + +/** + * Templates of this context type apply to any attribute values within XML + * content type. + */ +public class TemplateContextTypeXMLAttributeValue extends TemplateContextTypeXML { + + public TemplateContextTypeXMLAttributeValue() { + super(generateContextTypeId(TemplateContextTypeIds.ATTRIBUTEVALUE), ResourceHandler.getString("TemplateContextTypeXMLAttributeValue.0")); //$NON-NLS-1$ + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/templates/TemplateContextTypeXMLTag.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/templates/TemplateContextTypeXMLTag.java new file mode 100644 index 0000000000..4f6dbb9698 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/templates/TemplateContextTypeXMLTag.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.templates; + +import org.eclipse.wst.xml.ui.nls.ResourceHandler; + +/** + * Templates of this context type apply to any tags within XML content type. + */ +public class TemplateContextTypeXMLTag extends TemplateContextTypeXML { + + public TemplateContextTypeXMLTag() { + super(generateContextTypeId(TemplateContextTypeIds.TAG), ResourceHandler.getString("TemplateContextTypeXMLTag.0")); //$NON-NLS-1$ + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/text/XMLDocumentRegionEdgeMatcher.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/text/XMLDocumentRegionEdgeMatcher.java new file mode 100644 index 0000000000..bad82e93fc --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/text/XMLDocumentRegionEdgeMatcher.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.text; + +import org.eclipse.wst.sse.ui.text.DocumentRegionEdgeMatcher; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; + + +public class XMLDocumentRegionEdgeMatcher extends DocumentRegionEdgeMatcher { + + /** + * @param validContexts + * @param nextMatcher + */ + public XMLDocumentRegionEdgeMatcher() { + super(new String[]{XMLRegionContext.XML_TAG_NAME, XMLRegionContext.XML_COMMENT_TEXT, XMLRegionContext.XML_CDATA_TEXT, XMLRegionContext.XML_PI_OPEN, XMLRegionContext.XML_PI_CONTENT}, null); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/util/SharedXMLEditorPluginImageHelper.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/util/SharedXMLEditorPluginImageHelper.java new file mode 100644 index 0000000000..81c8a4440c --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/util/SharedXMLEditorPluginImageHelper.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.util; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.swt.graphics.Image; +import org.eclipse.wst.xml.ui.internal.editor.XMLEditorPluginImageHelper; +import org.eclipse.wst.xml.ui.internal.editor.XMLEditorPluginImages; + + +public class SharedXMLEditorPluginImageHelper { + public static final String IMG_DTOOL_CONSTRAINOFF = XMLEditorPluginImages.IMG_DTOOL_CONSTRAINOFF; + public static final String IMG_DTOOL_CONSTRAINON = XMLEditorPluginImages.IMG_DTOOL_CONSTRAINON; + public static final String IMG_DTOOL_RLDGRMR = XMLEditorPluginImages.IMG_DTOOL_RLDGRMR; + public static final String IMG_DTOOL_VALIDATE = XMLEditorPluginImages.IMG_DTOOL_VALIDATE; + public static final String IMG_ETOOL_CONSTRAINOFF = XMLEditorPluginImages.IMG_ETOOL_CONSTRAINOFF; + public static final String IMG_ETOOL_CONSTRAINON = XMLEditorPluginImages.IMG_ETOOL_CONSTRAINON; + public static final String IMG_ETOOL_RLDGRMR = XMLEditorPluginImages.IMG_ETOOL_RLDGRMR; + public static final String IMG_ETOOL_VALIDATE = XMLEditorPluginImages.IMG_ETOOL_VALIDATE; + public static final String IMG_OBJ_ATTRIBUTE = XMLEditorPluginImages.IMG_OBJ_ATTRIBUTE; + public static final String IMG_OBJ_CDATASECTION = XMLEditorPluginImages.IMG_OBJ_CDATASECTION; + public static final String IMG_OBJ_COMMENT = XMLEditorPluginImages.IMG_OBJ_COMMENT; + public static final String IMG_OBJ_DOCTYPE = XMLEditorPluginImages.IMG_OBJ_DOCTYPE; + public static final String IMG_OBJ_ELEMENT = XMLEditorPluginImages.IMG_OBJ_ELEMENT; + public static final String IMG_OBJ_ENTITY = XMLEditorPluginImages.IMG_OBJ_ENTITY; + public static final String IMG_OBJ_ENTITY_REFERENCE = XMLEditorPluginImages.IMG_OBJ_ENTITY_REFERENCE; + public static final String IMG_OBJ_NOTATION = XMLEditorPluginImages.IMG_OBJ_NOTATION; + public static final String IMG_OBJ_PROCESSINGINSTRUCTION = XMLEditorPluginImages.IMG_OBJ_PROCESSINGINSTRUCTION; + public static final String IMG_OBJ_TAG_GENERIC = XMLEditorPluginImages.IMG_OBJ_TAG_GENERIC; + public static final String IMG_OBJ_TAG_MACRO = XMLEditorPluginImages.IMG_OBJ_TAG_MACRO; + public static final String IMG_OBJ_TXTEXT = XMLEditorPluginImages.IMG_OBJ_TXTEXT; + + /** + * Retrieves the specified image from the xml source editor plugin's image + * registry. Note: The returned <code>Image</code> is managed by the + * workbench; clients must <b>not </b> dispose of the returned image. + * + * @param symbolicName + * the symbolic name of the image; there are constants declared + * in this class for build-in images that come with the xml + * source editor + * @return the image, or <code>null</code> if not found + */ + public static Image getImage(String symbolicName) { + return XMLEditorPluginImageHelper.getInstance().getImage(symbolicName); + } + + /** + * Retrieves the image descriptor for specified image from the xml source + * editor plugin's image registry. Unlike <code>Image</code>s, image + * descriptors themselves do not need to be disposed. + * + * @param symbolicName + * the symbolic name of the image; there are constants declared + * in this interface for build-in images that come with the xml + * source editor + * @return the image descriptor, or <code>null</code> if not found + */ + public static ImageDescriptor getImageDescriptor(String symbolicName) { + return XMLEditorPluginImageHelper.getInstance().getImageDescriptor(symbolicName); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/util/XMLCommonResources.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/util/XMLCommonResources.java new file mode 100644 index 0000000000..4cb406d196 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/util/XMLCommonResources.java @@ -0,0 +1,98 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ + + +package org.eclipse.wst.xml.ui.util; + + +import java.text.MessageFormat; +import java.util.ResourceBundle; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.eclipse.ui.views.markers.internal.ImageFactory; +import org.eclipse.wst.xml.ui.XMLEditorPlugin; + + + +/** + * This class exists temporarily until the properties files can be + * re-organized and the various resource references can be updated + */ +public class XMLCommonResources { + protected static XMLCommonResources instance; + + public synchronized static XMLCommonResources getInstance() { + if (instance == null) + instance = new XMLCommonResources(XMLEditorPlugin.getDefault()); + return instance; + } + + private XMLEditorPlugin editorPlugin; + + protected ImageFactory imageFactory; + private ResourceBundle resourceBundle; + + public XMLCommonResources(XMLEditorPlugin editorPlugin) { + instance = this; + this.editorPlugin = editorPlugin; + //imageFactory = new ImageFactory(); + try { + resourceBundle = ResourceBundle.getBundle("EditingXML"); //$NON-NLS-1$ + imageFactory = new ImageFactory(); + } catch (java.util.MissingResourceException exception) { + //TODO... log an error message + //B2BUtilPlugin.getPlugin().getMsgLogger().write(B2BUtilPlugin.getGUIString("_WARN_PLUGIN_PROPERTIES_MISSING") + // + descriptor.getLabel()); + resourceBundle = null; + } + } + + ImageDescriptor _getImageDescriptor(String iconName) { + return AbstractUIPlugin.imageDescriptorFromPlugin(XMLEditorPlugin.ID, iconName); + } + + + public ResourceBundle getResourceBundle() { + return resourceBundle; + } + + /** + * This gets the string resource. + */ + public String getString(String key) { + return getResourceBundle().getString(key); + } + + /** + * This gets the string resource and does one substitution. + */ + public String getString(String key, Object s1) { + return MessageFormat.format(getString(key), new Object[]{s1}); + } + + /** + * This gets the string resource and does two substitutions. + */ + public String getString(String key, Object s1, Object s2) { + return MessageFormat.format(getString(key), new Object[]{s1, s2}); + } + + public IWorkbench getWorkbench() { + return editorPlugin.getWorkbench(); + } + /* + * public ImageFactory getImageFactory() { return imageFactory; } + */ +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/util/XMLCommonUIContextIds.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/util/XMLCommonUIContextIds.java new file mode 100644 index 0000000000..e421f2289b --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/util/XMLCommonUIContextIds.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ + + +package org.eclipse.wst.xml.ui.util; + +/** + * Context help id constants. + */ +public interface XMLCommonUIContextIds { + public static final String PLUGIN_NAME = "com.ibm.etools.xml.common.ui"; //$NON-NLS-1$ + + + /* CONTEXT_IDs for "Assign an XSL Stylesheet To The XML File" dialog */ + /* CONTEXT_ID comn0010 for the dropdown menu. Follow comnxxxx */ + public static final String XCUI_ASSIGN_XSL_TO_XML_DROPDOWN = PLUGIN_NAME + ".xcui1000"; //$NON-NLS-1$ + /* CONTEXT_ID comn0030 for the import button. Follow comnxxxx */ + public static final String XCUI_ASSIGN_XSL_TO_XML_IMPORT = PLUGIN_NAME + ".xcui3000"; //$NON-NLS-1$ + /* CONTEXT_ID comn0020 for the workbench button. Follow comnxxxx */ + public static final String XCUI_ASSIGN_XSL_TO_XML_WORKBENCH = PLUGIN_NAME + ".xcui2000"; //$NON-NLS-1$ + + /* CONTEXT_ID xcui0500 for Edit Attribute Instruction Dialog */ + public static final String XCUI_ATTRIBUTE_DIALOG = PLUGIN_NAME + ".xcui0500"; //$NON-NLS-1$ + + /* CONTEXT_ID xcui0400 for Select XML Catalog ID Dialog */ + public static final String XCUI_CATALOG_DIALOG = PLUGIN_NAME + ".xcui0400"; //$NON-NLS-1$ + + /* CONTEXT_IDs for XML Common UI use xcuixxx context IDs */ + + /* CONTEXT_ID xcui0010 for Edit Doctype Dialog */ + public static final String XCUI_DOCTYPE_DIALOG = PLUGIN_NAME + ".xcui0010"; //$NON-NLS-1$ + /* CONTEXT_ID xcui0030 for Public ID Text Edit */ + public static final String XCUI_DOCTYPE_PUBLIC = PLUGIN_NAME + ".xcui0030"; //$NON-NLS-1$ + /* CONTEXT_ID xcui0030 for Public ID Browse Button */ + public static final String XCUI_DOCTYPE_PUBLIC_BROWSE = PLUGIN_NAME + ".xcui0040"; //$NON-NLS-1$ + /* CONTEXT_ID xcui0020 for Root Element Name Text Edit */ + public static final String XCUI_DOCTYPE_ROOT = PLUGIN_NAME + ".xcui0020"; //$NON-NLS-1$ + /* CONTEXT_ID xcui0040 for System ID Text Edit */ + public static final String XCUI_DOCTYPE_SYSTEM = PLUGIN_NAME + ".xcui0050"; //$NON-NLS-1$ + /* CONTEXT_ID xcui0030 for System ID Browse Button */ + public static final String XCUI_DOCTYPE_SYSTEM_BROWSE = PLUGIN_NAME + ".xcui0060"; //$NON-NLS-1$ + + /* CONTEXT_ID xcui0300 for Edit Element Instruction Dialog */ + public static final String XCUI_ELEMENT_DIALOG = PLUGIN_NAME + ".xcui0600"; //$NON-NLS-1$ + + /* CONTEXT_ID xcui0200 for Edit Namespace Dialog */ + public static final String XCUI_NAMESPACE_DIALOG = PLUGIN_NAME + ".xcui0200"; //$NON-NLS-1$ + + /* CONTEXT_ID xcui0300 for Edit Processing Instruction Dialog */ + public static final String XCUI_PROCESSING_DIALOG = PLUGIN_NAME + ".xcui0300"; //$NON-NLS-1$ + + /* CONTEXT_ID xcui0100 for Edit Schema Information Dialog */ + public static final String XCUI_SCHEMA_INFO_DIALOG = PLUGIN_NAME + ".xcui0100"; //$NON-NLS-1$ +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/views/contentoutline/JFaceNodeAdapter.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/views/contentoutline/JFaceNodeAdapter.java new file mode 100644 index 0000000000..b98a918459 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/views/contentoutline/JFaceNodeAdapter.java @@ -0,0 +1,345 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.views.contentoutline; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.core.runtime.Platform; +import org.eclipse.jface.resource.ImageRegistry; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.viewers.StructuredViewer; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.views.properties.PropertySheetPage; +import org.eclipse.wst.common.contentmodel.CMDocument; +import org.eclipse.wst.common.contentmodel.modelquery.CMDocumentManager; +import org.eclipse.wst.common.contentmodel.modelquery.CMDocumentManagerListener; +import org.eclipse.wst.common.contentmodel.util.CMDocumentCache; +import org.eclipse.wst.sse.core.AdapterFactory; +import org.eclipse.wst.sse.core.INodeNotifier; +import org.eclipse.wst.sse.ui.views.contentoutline.BufferedOutlineUpdater; +import org.eclipse.wst.sse.ui.views.contentoutline.IJFaceNodeAdapter; +import org.eclipse.wst.sse.ui.views.contentoutline.IJFaceNodeAdapterFactory; +import org.eclipse.wst.xml.ui.internal.editor.XMLEditorPluginImageHelper; +import org.eclipse.wst.xml.ui.internal.editor.XMLEditorPluginImages; +import org.eclipse.wst.xml.ui.nls.ResourceHandler; +import org.w3c.dom.Node; + + +/** + * Adapts a DOM node to a JFace viewer. + */ +public class JFaceNodeAdapter implements IJFaceNodeAdapter { + + public class CMDocumentManagerListenerImpl implements CMDocumentManagerListener { + + List beingRefreshed = Collections.synchronizedList(new ArrayList()); + + public void cacheCleared(org.eclipse.wst.common.contentmodel.util.CMDocumentCache cache) { + + } + + public void cacheUpdated(CMDocumentCache cache, final String uri, int oldStatus, int newStatus, CMDocument cmDocument) { + + if (newStatus == CMDocumentCache.STATUS_LOADED || newStatus == CMDocumentCache.STATUS_ERROR) { + refreshViewers(); + } + } + + private Display getDisplay() { + + return PlatformUI.getWorkbench().getDisplay(); + } + + public void propertyChanged(CMDocumentManager cmDocumentManager, String propertyName) { + + if (cmDocumentManager.getPropertyEnabled(CMDocumentManager.PROPERTY_AUTO_LOAD)) { + refreshViewers(); + } + } + + protected void refreshViewers() { + + // we're counting on getListers returning a "copy" of the + // listeners, so we'll be thread safe. + Collection listeners = ((IJFaceNodeAdapterFactory) adapterFactory).getListeners(); + Iterator iterator = listeners.iterator(); + while (iterator.hasNext()) { + Object listener = iterator.next(); + // now that we use aynchExec, we ourselves have to gaurd + // against + // agains adding some refreshes when its already being + // refreshed. + if (listener instanceof PropertySheetPage && (!beingRefreshed.contains(listener))) { + final PropertySheetPage propertySheetPage = (PropertySheetPage) listener; + beingRefreshed.add(propertySheetPage); + getDisplay().asyncExec(new Runnable() { + + public void run() { + + if (getDisplay().isDisposed()) { + return; + } + if (propertySheetPage.getControl() != null && !propertySheetPage.getControl().isDisposed()) { + propertySheetPage.refresh(); + beingRefreshed.remove(propertySheetPage); + } + } + }); + } + } + } + } + + final static Class ADAPTER_KEY = IJFaceNodeAdapter.class; + + // for debugging + private static final boolean DEBUG; + static { + String value = Platform.getDebugOption("org.eclipse.wst.sse.ui/debug/outline"); //$NON-NLS-1$ + DEBUG = value != null && value.equalsIgnoreCase("true"); //$NON-NLS-1$ + } + + protected AdapterFactory adapterFactory; + protected CMDocumentManagerListener cmDocumentManagerListener; + private BufferedOutlineUpdater fUpdater = null; + + public JFaceNodeAdapter(AdapterFactory adapterFactory) { + + super(); + this.adapterFactory = adapterFactory; + } + + protected Image createImage(Object object) { + + Image image = null; + Node node = (Node) object; + switch (node.getNodeType()) { + case Node.ELEMENT_NODE : { + image = createXMLImageDescriptor(XMLEditorPluginImages.IMG_OBJ_ELEMENT); + break; + } + case Node.ATTRIBUTE_NODE : { + image = createXMLImageDescriptor(XMLEditorPluginImages.IMG_OBJ_ATTRIBUTE); + break; + } + case Node.TEXT_NODE : { // actually, TEXT should never be seen in + // the tree + image = createXMLImageDescriptor(XMLEditorPluginImages.IMG_OBJ_ELEMENT); + break; + } + case Node.CDATA_SECTION_NODE : { + image = createXMLImageDescriptor(XMLEditorPluginImages.IMG_OBJ_CDATASECTION); + break; + } + case Node.ENTITY_REFERENCE_NODE : + case Node.ENTITY_NODE : { + image = createXMLImageDescriptor(XMLEditorPluginImages.IMG_OBJ_ENTITY); + break; + } + case Node.PROCESSING_INSTRUCTION_NODE : { + image = createXMLImageDescriptor(XMLEditorPluginImages.IMG_OBJ_PROCESSINGINSTRUCTION); + break; + } + case Node.COMMENT_NODE : { + image = createXMLImageDescriptor(XMLEditorPluginImages.IMG_OBJ_COMMENT); + break; + } + case Node.DOCUMENT_TYPE_NODE : { + image = createXMLImageDescriptor(XMLEditorPluginImages.IMG_OBJ_DOCTYPE); + break; + } + case Node.NOTATION_NODE : { + image = createXMLImageDescriptor(XMLEditorPluginImages.IMG_OBJ_NOTATION); + break; + } + default : { + image = createXMLImageDescriptor(XMLEditorPluginImages.IMG_OBJ_ELEMENT); + break; + } + } + return image; + } + + protected Image createXMLImageDescriptor(String imageResourceName) { + return XMLEditorPluginImageHelper.getInstance().getImage(imageResourceName); + } + + public Object[] getChildren(Object object) { + + // (pa) 20021217 + // cmvc defect 235554 + // performance enhancement: using child.getNextSibling() rather than + // nodeList(item) for O(n) vs. O(n*n) + // + Node node = (Node) object; + ArrayList v = new ArrayList(node.getChildNodes().getLength()); + for (Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) { + Node n = child; + if (n.getNodeType() != Node.TEXT_NODE) + v.add(n); + } + return v.toArray(); + } + + /** + * Returns a CMDocumentManagerListener that can update JFace views when + * notified of CMDocumentManager events + */ + public org.eclipse.wst.common.contentmodel.modelquery.CMDocumentManagerListener getCMDocumentManagerListener() { + + if (cmDocumentManagerListener == null) + cmDocumentManagerListener = new CMDocumentManagerListenerImpl(); + return cmDocumentManagerListener; + } + + Display getDisplay() { + + // Note: the workbench should always have a display + // (unless running headless), whereas Display.getCurrent() + // only returns the display if the currently executing thread + // has one. + if (PlatformUI.isWorkbenchRunning()) + return PlatformUI.getWorkbench().getDisplay(); + else + return null; + } + + /** + * Returns an enumeration with the elements belonging to the passed + * element. These are the top level items in a list, tree, table, etc... + */ + public Object[] getElements(Object node) { + + return getChildren(node); + } + + /** + * Fetches the label image specific to this object instance. + */ + public Image getLabelImage(Object node) { + + Image image = null; + if (JFaceResources.getImageRegistry() != null) { + ImageRegistry imageRegistry = JFaceResources.getImageRegistry(); + String nodeName = getNodeName(node); + image = imageRegistry.get(nodeName); + if (image == null) { + image = createImage(node); + if (image != null) + imageRegistry.put(nodeName, image); + } + } + return image; + } + + /** + * Fetches the label text specific to this object instance. + */ + public String getLabelText(Object node) { + + return getNodeName(node); + } + + private String getNodeName(Object object) { + + Node node = (Node) object; + String nodeName = node.getNodeName(); + if (node.getNodeType() == Node.DOCUMENT_TYPE_NODE) + nodeName = "DOCTYPE:" + nodeName; //$NON-NLS-1$ + return nodeName; + } + + private BufferedOutlineUpdater getOutlineUpdater() { + if (fUpdater == null) + fUpdater = new BufferedOutlineUpdater(); + return fUpdater; + } + + public Object getParent(Object object) { + + Node node = (Node) object; + return node.getParentNode(); + } + + public boolean hasChildren(Object object) { + + // (pa) 20021217 + // cmvc defect 235554 > use child.getNextSibling() instead of + // nodeList(item) for O(n) vs. O(n*n) + Node node = (Node) object; + for (Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) { + if (child.getNodeType() != Node.TEXT_NODE) + return true; + } + return false; + } + + /** + * Allowing the INodeAdapter to compare itself against the type allows it + * to return true in more than one case. + */ + public boolean isAdapterForType(Object type) { + + return type.equals(ADAPTER_KEY); + } + + /** + * Called by the object being adapter (the notifier) when something has + * changed. + */ + public void notifyChanged(INodeNotifier notifier, int eventType, Object changedFeature, Object oldValue, Object newValue, int pos) { + + // future_TODO: the 'uijobs' used in this method were added to solve + // threading problems when the dom + // is updated in the background while the editor is open. They may be + // a bit overkill and not that useful. + // (That is, may be be worthy of job manager management). If they are + // found to be important enough to leave in, + // there's probably some optimization that can be done. + Collection listeners = ((JFaceNodeAdapterFactory) adapterFactory).getListeners(); + Iterator iterator = listeners.iterator(); + + while (iterator.hasNext()) { + Object listener = iterator.next(); + if (notifier instanceof Node && (listener instanceof StructuredViewer) && (eventType == INodeNotifier.STRUCTURE_CHANGED || (eventType == INodeNotifier.CHANGE && changedFeature == null))) { + + if (DEBUG) + System.out.println("JFaceNodeAdapter notified on event type > " + eventType); + + // refresh on structural and "unknown" changes + StructuredViewer structuredViewer = (StructuredViewer) listener; + // https://w3.opensource.ibm.com/bugzilla/show_bug.cgi?id=5230 + if (structuredViewer.getControl() != null /* + * && + * structuredViewer.getControl().isVisible() + */) + getOutlineUpdater().processNode(structuredViewer, (Node) notifier); + } else if ((listener instanceof PropertySheetPage) && ((eventType == INodeNotifier.CHANGE) || (eventType == INodeNotifier.STRUCTURE_CHANGED))) { + PropertySheetPage propertySheetPage = (PropertySheetPage) listener; + if (propertySheetPage.getControl() != null /* + * && + * !propertySheetPage.getControl().isDisposed() + */) { + RefreshPropertySheetJob refreshPropertySheetJob = new RefreshPropertySheetJob(getDisplay(), ResourceHandler.getString("JFaceNodeAdapter.1"), propertySheetPage); //$NON-NLS-1$ + refreshPropertySheetJob.schedule(); + } + } + } + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/views/contentoutline/JFaceNodeAdapterFactory.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/views/contentoutline/JFaceNodeAdapterFactory.java new file mode 100644 index 0000000000..c13860683e --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/views/contentoutline/JFaceNodeAdapterFactory.java @@ -0,0 +1,104 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.views.contentoutline; + + + +import java.util.ArrayList; +import java.util.Collection; + +import org.eclipse.wst.common.contentmodel.modelquery.CMDocumentManager; +import org.eclipse.wst.common.contentmodel.modelquery.ModelQuery; +import org.eclipse.wst.sse.core.AbstractAdapterFactory; +import org.eclipse.wst.sse.core.AdapterFactory; +import org.eclipse.wst.sse.core.INodeAdapter; +import org.eclipse.wst.sse.core.INodeNotifier; +import org.eclipse.wst.sse.core.modelquery.ModelQueryAdapter; +import org.eclipse.wst.sse.ui.views.contentoutline.IJFaceNodeAdapter; +import org.eclipse.wst.sse.ui.views.contentoutline.IJFaceNodeAdapterFactory; + + +/** + * An adapter factory to create JFaceNodeAdapters. Use this adapter factory + * with a JFaceAdapterContentProvider to display DOM nodes in a tree. + */ +public class JFaceNodeAdapterFactory extends AbstractAdapterFactory implements IJFaceNodeAdapterFactory { + protected CMDocumentManager cmDocumentManager; + /** + * This keeps track of all the listeners. + */ + protected ArrayList fListeners = new ArrayList(); + + protected INodeAdapter singletonAdapter; + + public JFaceNodeAdapterFactory() { + this(IJFaceNodeAdapter.class, true); + } + + public JFaceNodeAdapterFactory(Object adapterKey, boolean registerAdapters) { + super(adapterKey, registerAdapters); + } + + public synchronized void addListener(Object listener) { + fListeners.add(listener); + } + + public AdapterFactory copy() { + + return new JFaceNodeAdapterFactory(this.adapterKey, this.shouldRegisterAdapter); + } + + /** + * Create a new JFace adapter for the DOM node passed in + */ + protected INodeAdapter createAdapter(INodeNotifier node) { + if (singletonAdapter == null) { + // create the JFaceNodeAdapter + singletonAdapter = new JFaceNodeAdapter(this); + initAdapter(singletonAdapter, node); + } + return singletonAdapter; + } + + /** + * returns "copy" so no one can modify our list. Its is a shallow copy. + */ + public synchronized Collection getListeners() { + return (Collection) fListeners.clone(); + } + + protected void initAdapter(INodeAdapter adapter, INodeNotifier node) { + // register for CMDocumentManager events + if (((JFaceNodeAdapter) adapter).getCMDocumentManagerListener() != null) { + ModelQueryAdapter mqadapter = (ModelQueryAdapter) node.getAdapterFor(ModelQueryAdapter.class); + if (mqadapter != null) { + ModelQuery mquery = mqadapter.getModelQuery(); + if (mquery != null && mquery.getCMDocumentManager() != null) { + cmDocumentManager = mquery.getCMDocumentManager(); + cmDocumentManager.addListener(((JFaceNodeAdapter) adapter).getCMDocumentManagerListener()); + } + } + } + } + + public void release() { + // deregister from CMDocumentManager events + if (cmDocumentManager != null && singletonAdapter != null && ((JFaceNodeAdapter) singletonAdapter).getCMDocumentManagerListener() != null) { + cmDocumentManager.removeListener(((JFaceNodeAdapter) singletonAdapter).getCMDocumentManagerListener()); + } + } + + public synchronized void removeListener(Object listener) { + fListeners.remove(listener); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/views/contentoutline/JFaceNodeContentProvider.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/views/contentoutline/JFaceNodeContentProvider.java new file mode 100644 index 0000000000..d6a121215f --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/views/contentoutline/JFaceNodeContentProvider.java @@ -0,0 +1,104 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.views.contentoutline; + +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.wst.sse.core.AdapterFactory; +import org.eclipse.wst.sse.core.INodeAdapter; +import org.eclipse.wst.sse.core.INodeNotifier; +import org.eclipse.wst.sse.ui.views.contentoutline.IJFaceNodeAdapter; +import org.eclipse.wst.xml.core.document.XMLModel; + + +/** + * An ITreeContentProvider for a TreeViewers used to display DOM nodes. This + * content provider takes an adapter factory to create JFace adapters for the + * nodes in the tree. + */ +public class JFaceNodeContentProvider implements ITreeContentProvider { + protected AdapterFactory adapterFactory; + + public JFaceNodeContentProvider(AdapterFactory jfaceAdapterFactory) { + super(); + this.adapterFactory = jfaceAdapterFactory; + } + + /** + * The visual part that is using this content provider is about to be + * disposed. Deallocate all allocated SWT resources. + */ + public void dispose() { + } + + /** + * Returns the JFace adapter for the specified object. + * + * @return com.ibm.sed.view.tree.DOMJFaceAdapter The JFace adapter + * @param adaptable + * java.lang.Object The object to get the adapter for + */ + protected IJFaceNodeAdapter getAdapter(Object adaptable) { + if (adaptable instanceof INodeNotifier) { + INodeAdapter adapter = adapterFactory.adapt((INodeNotifier) adaptable); + if (adapter instanceof IJFaceNodeAdapter) + return (IJFaceNodeAdapter) adapter; + } + return null; + } + + public Object[] getChildren(Object object) { + IJFaceNodeAdapter adapter = getAdapter(object); + + if (adapter != null) + return adapter.getChildren(object); + + return new Object[0]; + } + + public Object[] getElements(Object object) { + // The root is usually an instance of an XMLStructuredModel in + // which case we want to extract the document. + Object topNode = object; + if (object instanceof XMLModel) + topNode = ((XMLModel) object).getDocument(); + + IJFaceNodeAdapter adapter = getAdapter(topNode); + + if (adapter != null) + return adapter.getElements(topNode); + + return new Object[0]; + } + + public Object getParent(Object object) { + IJFaceNodeAdapter adapter = getAdapter(object); + + if (adapter != null) + return adapter.getParent(object); + + return null; + } + + public boolean hasChildren(Object object) { + IJFaceNodeAdapter adapter = getAdapter(object); + + if (adapter != null) + return adapter.hasChildren(object); + + return false; + } + + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/views/contentoutline/JFaceNodeLabelProvider.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/views/contentoutline/JFaceNodeLabelProvider.java new file mode 100644 index 0000000000..bd94407b49 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/views/contentoutline/JFaceNodeLabelProvider.java @@ -0,0 +1,140 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.views.contentoutline; + + + +import org.eclipse.jface.viewers.ILabelProvider; +import org.eclipse.jface.viewers.ILabelProviderListener; +import org.eclipse.swt.graphics.Image; +import org.eclipse.wst.sse.core.AdapterFactory; +import org.eclipse.wst.sse.core.INodeNotifier; +import org.eclipse.wst.sse.ui.views.contentoutline.IJFaceNodeAdapter; + + +/** + * A class that uses a JFaceNodeAdapterFactory to provide adapters to provide + * the labels and images for DOM nodes. + */ +public class JFaceNodeLabelProvider implements ILabelProvider { + + protected AdapterFactory adapterFactory; + + /** + * JFaceNodeLabelProvider constructor comment. + */ + public JFaceNodeLabelProvider(AdapterFactory adapterFactory) { + super(); + this.adapterFactory = adapterFactory; + } + + /** + * Adds a listener to the label provider. A label provider should inform + * its listener about state changes that enforces rendering of the visual + * part that uses this label provider. + */ + public void addListener(ILabelProviderListener listener) { + // The label provider state never changes so we do not have + // to implement this method. + } + + /** + * The visual part that is using this label provider is about to be + * disposed. Deallocate all allocated SWT resources. + */ + public void dispose() { + // Nothing to dispose + } + + /** + * Returns the JFace adapter for the specified object. + * + * @return com.ibm.sed.view.tree.DOMJFaceAdapter The JFace adapter + * @param adaptable + * java.lang.Object The object to get the adapter for + */ + protected IJFaceNodeAdapter getAdapter(Object adaptable) { + return (IJFaceNodeAdapter) adapterFactory.adapt((INodeNotifier) adaptable); + } + + /** + * Returns the image for the label of the given element, for use in the + * given viewer. + * + * @param viewer + * The viewer that displays the element. + * @param element + * The element for which to provide the label image. Element + * can be <code>null</code> indicating no input object is set + * to the viewer. + */ + public Image getImage(Object element) { + return getAdapter(element).getLabelImage(element); + } + + /** + * Returns the text for the label of the given element, for use in the + * given viewer. + * + * @param viewer + * The viewer that displays the element. + * @param element + * The element for which to provide the label text. Element can + * be <code>null</code> indicating no input object is set to + * the viewer. + */ + public java.lang.String getText(Object element) { + // This was returning null, on occasion ... probably should not be, + // but + // took the quick and easy way out for now. (dmw 3/8/01) + String result = getAdapter(element).getLabelText(element); + if (result == null) + result = "";//$NON-NLS-1$ + return result; + } + + /** + * Checks whether this label provider is affected by the given domain + * event. + */ + public boolean isAffected(Object dummy) {//DomainEvent event) { + //return event.isModifier(DomainEvent.NON_STRUCTURE_CHANGE); + return true; + + } + + /** + * Returns whether the label would be affected by a change to the given + * property of the given element. This can be used to optimize a + * non-structural viewer update. If the property mentioned in the update + * does not affect the label, then the viewer need not update the label. + * + * @param element + * the element + * @param property + * the property + * @return <code>true</code> if the label would be affected, and + * <code>false</code> if it would be unaffected + */ + public boolean isLabelProperty(Object element, String property) { + return false; + } + + /** + * Removes a listener from the label provider. + */ + public void removeListener(ILabelProviderListener listener) { + // The label provider state never changes so we do not have + // to implement this method. + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/views/contentoutline/RefreshOutlineJob.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/views/contentoutline/RefreshOutlineJob.java new file mode 100644 index 0000000000..570949a8ba --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/views/contentoutline/RefreshOutlineJob.java @@ -0,0 +1,90 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.views.contentoutline; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jface.viewers.StructuredViewer; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.progress.UIJob; +import org.eclipse.wst.sse.core.INodeNotifier; +import org.w3c.dom.Node; + + + +public class RefreshOutlineJob extends UIJob { + + + private INodeNotifier fNodeNotifier; + private StructuredViewer fStructuredViewer; + + /** + * @param jobDisplay + * @param name + */ + public RefreshOutlineJob(Display jobDisplay, String name, StructuredViewer structuredViewer, INodeNotifier nodeNotifier) { + super(jobDisplay, name); + setPriority(Job.SHORT); + + setStructuredViewer(structuredViewer); + setNodeNotifier(nodeNotifier); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor) + */ + public IStatus runInUIThread(IProgressMonitor monitor) { + IStatus result = Status.OK_STATUS; + try { + Control control = fStructuredViewer.getControl(); + // we should have check before even scheduling this, but even if + // ok then, need to check again, right before executing. + if (control != null && !control.isDisposed()) { + + if ((fNodeNotifier instanceof Node) && (((Node) fNodeNotifier).getParentNode() == null)) { + // refresh whole document + fStructuredViewer.refresh(); + } else { + // refresh only the node that's changed + fStructuredViewer.refresh(fNodeNotifier); + } + } + } catch (Exception e) { + result = errorStatus(e); + } finally { + monitor.done(); + } + return result; + } + + /** + * @param nodeNotifier + */ + private void setNodeNotifier(INodeNotifier nodeNotifier) { + fNodeNotifier = nodeNotifier; + + } + + /** + * @param structuredViewer + */ + private void setStructuredViewer(StructuredViewer structuredViewer) { + fStructuredViewer = structuredViewer; + + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/views/contentoutline/RefreshPropertySheetJob.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/views/contentoutline/RefreshPropertySheetJob.java new file mode 100644 index 0000000000..e20a28bd33 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/views/contentoutline/RefreshPropertySheetJob.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.views.contentoutline; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.progress.UIJob; +import org.eclipse.ui.views.properties.PropertySheetPage; + + +public class RefreshPropertySheetJob extends UIJob { + + + private PropertySheetPage fPropertySheetPage; + + /** + * @param jobDisplay + * @param name + */ + public RefreshPropertySheetJob(Display jobDisplay, String name, PropertySheetPage propertySheetPage) { + super(jobDisplay, name); + setPriority(Job.SHORT); + fPropertySheetPage = propertySheetPage; + } + + + /* + * (non-Javadoc) + * + * @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor) + */ + public IStatus runInUIThread(IProgressMonitor monitor) { + IStatus result = Status.OK_STATUS; + try { + Control control = fPropertySheetPage.getControl(); + // we should have check before even scheduling this, but even if + // ok then, need to check again, right before executing. + if (control != null && !control.isDisposed()) { + fPropertySheetPage.refresh(); + } + } catch (Exception e) { + result = errorStatus(e); + } finally { + monitor.done(); + } + return result; + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/views/contentoutline/XMLContentOutlineConfiguration.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/views/contentoutline/XMLContentOutlineConfiguration.java new file mode 100644 index 0000000000..123732f597 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/views/contentoutline/XMLContentOutlineConfiguration.java @@ -0,0 +1,232 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.views.contentoutline; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jface.action.IMenuListener; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.util.TransferDragSourceListener; +import org.eclipse.jface.util.TransferDropTargetListener; +import org.eclipse.jface.viewers.IContentProvider; +import org.eclipse.jface.viewers.ILabelProvider; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.swt.dnd.DragSourceEvent; +import org.eclipse.swt.dnd.DropTargetEvent; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.wst.sse.core.AdapterFactory; +import org.eclipse.wst.sse.ui.IReleasable; +import org.eclipse.wst.sse.ui.view.events.NodeSelectionChangedEvent; +import org.eclipse.wst.sse.ui.views.contentoutline.StructuredContentOutlineConfiguration; +import org.eclipse.wst.ui.dnd.ObjectTransfer; +import org.eclipse.wst.ui.dnd.ViewerDragAdapter; +import org.eclipse.wst.ui.dnd.ViewerDropAdapter; +import org.eclipse.wst.xml.ui.dnd.XMLDragAndDropManager; +import org.w3c.dom.Attr; +import org.w3c.dom.Node; + +public class XMLContentOutlineConfiguration extends StructuredContentOutlineConfiguration { + + protected class ActionManagerMenuListener implements IMenuListener, IReleasable { + private XMLNodeActionManager fActionManager; + private TreeViewer fTreeViewer; + + public ActionManagerMenuListener(TreeViewer viewer) { + fTreeViewer = viewer; + fActionManager = createNodeActionManager(fTreeViewer); + } + + public void menuAboutToShow(IMenuManager manager) { + if (fActionManager != null) + fActionManager.fillContextMenu(manager, fTreeViewer.getSelection()); + } + + public void release() { + fTreeViewer = null; + fActionManager.setModel(null); + } + } + + protected ActionManagerMenuListener fContextMenuFiller = null; + + private TransferDragSourceListener[] fTransferDragSourceListeners; + private TransferDropTargetListener[] fTransferDropTargetListeners; + + public XMLContentOutlineConfiguration() { + super(); + } + + protected XMLNodeActionManager createNodeActionManager(TreeViewer treeViewer) { + return new XMLNodeActionManager(getEditor().getModel(), treeViewer); + } + + /** + * @see org.eclipse.wst.sse.ui.views.contentoutline.ContentOutlineConfiguration#getTreeContentProvider(org.eclipse.jface.viewers.TreeViewer) + */ + public IContentProvider getContentProvider(TreeViewer viewer) { + if (fContentProvider == null) { + if (getFactory() != null) { + fContentProvider = new JFaceNodeContentProvider((AdapterFactory) getFactory()); + } else { + fContentProvider = super.getContentProvider(viewer); + } + } + return fContentProvider; + } + + /** + * @see org.eclipse.wst.sse.ui.views.contentoutline.ContentOutlineConfiguration#getLabelProvider(org.eclipse.jface.viewers.TreeViewer) + */ + public ILabelProvider getLabelProvider(TreeViewer viewer) { + if (fLabelProvider == null) { + if (getFactory() != null) { + fLabelProvider = new JFaceNodeLabelProvider((AdapterFactory) getFactory()); + } else { + fLabelProvider = super.getLabelProvider(viewer); + } + } + return fLabelProvider; + } + + /** + * @see org.eclipse.wst.sse.ui.views.contentoutline.ContentOutlineConfiguration#getMenuListener(org.eclipse.jface.viewers.TreeViewer) + */ + public IMenuListener getMenuListener(TreeViewer viewer) { + if (fContextMenuFiller == null) { + fContextMenuFiller = new ActionManagerMenuListener(viewer); + } + return fContextMenuFiller; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.ui.views.contentoutline.ContentOutlineConfiguration#getNodes(java.util.List) + */ + public List getNodes(List nodes) { + List filteredNodes = new ArrayList(super.getNodes(nodes)); + for (int i = 0; i < filteredNodes.size(); i++) { + Object selectedNode = filteredNodes.get(i); + if (selectedNode instanceof Node) { + Node eachNode = (Node) selectedNode; + // replace attribute node in selection with its parent + if (eachNode.getNodeType() == Node.ATTRIBUTE_NODE) + filteredNodes.set(i, ((Attr) eachNode).getOwnerElement()); + // replace TextNode in selection with its parent + else if (eachNode.getNodeType() == Node.TEXT_NODE) + filteredNodes.set(i, eachNode.getParentNode()); + } + } + return filteredNodes; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.ui.views.contentoutline.ContentOutlineConfiguration#getSelectedNodes(org.eclipse.wst.sse.ui.view.events.NodeSelectionChangedEvent) + */ + public List getSelectedNodes(NodeSelectionChangedEvent event) { + return getNodes(super.getSelectedNodes(event)); + } + + /** + * @see org.eclipse.wst.sse.ui.views.contentoutline.ContentOutlineConfiguration#getTransferDragSourceListeners(org.eclipse.jface.viewers.TreeViewer) + */ + public TransferDragSourceListener[] getTransferDragSourceListeners(TreeViewer treeViewer) { + if (fTransferDragSourceListeners == null) { + // emulate the XMLDragAndDropManager + final ViewerDragAdapter dragAdapter = new ViewerDragAdapter(treeViewer); + fTransferDragSourceListeners = new TransferDragSourceListener[]{new TransferDragSourceListener() { + public void dragFinished(DragSourceEvent event) { + dragAdapter.dragFinished(event); + } + + public void dragSetData(DragSourceEvent event) { + dragAdapter.dragSetData(event); + } + + public void dragStart(DragSourceEvent event) { + dragAdapter.dragStart(event); + } + + public Transfer getTransfer() { + return ObjectTransfer.getInstance(); + } + }}; + } + + return fTransferDragSourceListeners; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.wst.sse.ui.views.contentoutline.ContentOutlineConfiguration#getTransferDropTargetListeners(org.eclipse.jface.viewers.TreeViewer) + */ + public TransferDropTargetListener[] getTransferDropTargetListeners(TreeViewer treeViewer) { + if (fTransferDropTargetListeners == null) { + // emulate the XMLDragAnDropManager + final ViewerDropAdapter dropAdapter = new ViewerDropAdapter(treeViewer, new XMLDragAndDropManager()); + fTransferDropTargetListeners = new TransferDropTargetListener[]{new TransferDropTargetListener() { + public void dragEnter(DropTargetEvent event) { + dropAdapter.dragEnter(event); + } + + public void dragLeave(DropTargetEvent event) { + dropAdapter.dragLeave(event); + } + + public void dragOperationChanged(DropTargetEvent event) { + dropAdapter.dragOperationChanged(event); + } + + public void dragOver(DropTargetEvent event) { + dropAdapter.dragOver(event); + } + + public void drop(DropTargetEvent event) { + dropAdapter.drop(event); + } + + public void dropAccept(DropTargetEvent event) { + dropAdapter.dropAccept(event); + } + + public Transfer getTransfer() { + return ObjectTransfer.getInstance(); + } + + public boolean isEnabled(DropTargetEvent event) { + return getTransfer().isSupportedType(event.currentDataType); + } + }}; + } + return fTransferDropTargetListeners; + } + + /** + * @see org.eclipse.wst.sse.ui.views.contentoutline.StructuredContentOutlineConfiguration#unconfigure() + */ + public void unconfigure(TreeViewer viewer) { + super.unconfigure(viewer); + fTransferDragSourceListeners = null; + fTransferDropTargetListeners = null; + if (fContextMenuFiller != null) { + fContextMenuFiller.release(); + fContextMenuFiller = null; + } + // TODO: Add DnD support + // XMLDragAndDropManager.addDragAndDropSupport(fTreeViewer); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/views/contentoutline/XMLNodeActionManager.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/views/contentoutline/XMLNodeActionManager.java new file mode 100644 index 0000000000..9fe7c36c70 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/views/contentoutline/XMLNodeActionManager.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.views.contentoutline; + +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.wst.common.contentmodel.modelquery.ModelQuery; +import org.eclipse.wst.sse.core.IStructuredModel; +import org.eclipse.wst.sse.core.format.IStructuredFormatProcessor; +import org.eclipse.wst.xml.core.format.FormatProcessorXML; +import org.eclipse.wst.xml.core.modelquery.ModelQueryUtil; +import org.eclipse.wst.xml.ui.actions.AbstractNodeActionManager; +import org.w3c.dom.Node; + + +public class XMLNodeActionManager extends AbstractNodeActionManager { + public XMLNodeActionManager(IStructuredModel model, Viewer viewer) { + super(model, ModelQueryUtil.getModelQuery(model), viewer); + } + + public void reformat(Node newElement, boolean deep) { + try { + // tell the model that we are about to make a big model change + model.aboutToChangeModel(); + + // format selected node + IStructuredFormatProcessor formatProcessor = new FormatProcessorXML(); + formatProcessor.formatNode(newElement); + } finally { + // tell the model that we are done with the big model change + model.changedModel(); + } + } + + public void setModel(IStructuredModel newModel) { + model = newModel; + setModelQuery(ModelQueryUtil.getModelQuery(newModel)); + } + + protected void setModelQuery(ModelQuery newModelQuery) { + modelQuery = newModelQuery; + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/views/properties/ProcessingInstructionPropertySourceAdapter.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/views/properties/ProcessingInstructionPropertySourceAdapter.java new file mode 100644 index 0000000000..de4b996498 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/views/properties/ProcessingInstructionPropertySourceAdapter.java @@ -0,0 +1,167 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.views.properties; + +import org.eclipse.ui.views.properties.IPropertyDescriptor; +import org.eclipse.ui.views.properties.IPropertySource; +import org.eclipse.wst.sse.core.INodeAdapter; +import org.eclipse.wst.sse.core.INodeNotifier; +import org.eclipse.wst.sse.core.text.IStructuredDocumentRegion; +import org.eclipse.wst.sse.core.text.ITextRegion; +import org.eclipse.wst.sse.core.text.ITextRegionList; +import org.eclipse.wst.sse.core.util.StringUtils; +import org.eclipse.wst.sse.ui.util.Assert; +import org.eclipse.wst.sse.ui.views.properties.CustomPropertyDescriptor; +import org.eclipse.wst.sse.ui.views.properties.IPropertySourceExtension; +import org.eclipse.wst.xml.core.document.XMLNode; +import org.eclipse.wst.xml.core.parser.XMLRegionContext; +import org.w3c.dom.Node; +import org.w3c.dom.ProcessingInstruction; + + +/** + * An IPropertySource implementation for a JFace viewer used to display + * properties of DOM nodes. Requires an adapter factory to create JFace + * adapters for the nodes in the tree. + */ +public class ProcessingInstructionPropertySourceAdapter implements INodeAdapter, IPropertySource, IPropertySourceExtension { + protected final static String CATEGORY_ATTRIBUTES = "Instructions"; //$NON-NLS-1$ + + protected IPropertyDescriptor[] fDescriptors = null; + protected Node fNode = null; + + public ProcessingInstructionPropertySourceAdapter(INodeNotifier target) { + super(); + fNode = (Node) target; + Assert.isTrue(target instanceof XMLNode); + Assert.isTrue(fNode.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE); + } + + /** + * Returns the current collection of property descriptors. + * + * @return all valid descriptors. + */ + protected IPropertyDescriptor[] createPropertyDescriptors() { + boolean isXML = ((ProcessingInstruction) fNode).getTarget().equalsIgnoreCase("xml"); //$NON-NLS-1$ + if (!isXML) + return new IPropertyDescriptor[0]; + CustomPropertyDescriptor[] descriptors = new CustomPropertyDescriptor[2]; + descriptors[0] = new CustomPropertyDescriptor("version", "version", null); //$NON-NLS-1$ //$NON-NLS-2$ + descriptors[0].setCategory(CATEGORY_ATTRIBUTES); + descriptors[1] = new CustomPropertyDescriptor("encoding", "encoding", null); //$NON-NLS-1$ //$NON-NLS-2$ + descriptors[1].setCategory(CATEGORY_ATTRIBUTES); + return descriptors; + } + + /** + * Returns a value for this Node that can be editted in a property sheet. + * + * @return a value that can be editted + */ + public Object getEditableValue() { + return null; + } + + /** + * Returns the current collection of property descriptors. + * + * @return all valid descriptors. + */ + public IPropertyDescriptor[] getPropertyDescriptors() { + if (fDescriptors == null) { + fDescriptors = createPropertyDescriptors(); + } + return fDescriptors; + } + + /** + * Returns the current value for the named property. + * + * @param name + * the name of the property as named by its property descriptor + * @return the current value of the property + */ + public Object getPropertyValue(Object nameObject) { + XMLNode node = (XMLNode) fNode; + String value = null; + String name = null; + IStructuredDocumentRegion docRegion = node.getFirstStructuredDocumentRegion(); + if (docRegion == null) + return null; + ITextRegionList regions = docRegion.getRegions(); + ITextRegion region = null; + int i = 2; + while (value == null && i < regions.size()) { + region = regions.get(i); + if (region.getType().equals(XMLRegionContext.XML_TAG_ATTRIBUTE_NAME)) + name = docRegion.getText(region); + else if (region.getType().equals(XMLRegionContext.XML_TAG_ATTRIBUTE_VALUE) && name != null && name.equals(nameObject)) + value = docRegion.getText(region); + i++; + } + if (value != null) + value = StringUtils.strip(value); + return value; + } + + /** + * Allowing the INodeAdapter to compare itself against the type allows it + * to return true in more than one case. + */ + public boolean isAdapterForType(Object type) { + return type == IPropertySource.class; + } + + /** + * Returns whether the property value has changed from the default. + * + * @return <code>true</code> if the value of the specified property has + * changed from its original default value; <code>false</code> + * otherwise. + */ + public boolean isPropertySet(Object propertyObject) { + return false; + } + + public void notifyChanged(INodeNotifier notifier, int eventType, java.lang.Object changedFeature, java.lang.Object oldValue, java.lang.Object newValue, int pos) { + } + + /** + * Remove the given attribute from the Node + * + * @param propertyObject + */ + public void removeProperty(Object propertyObject) { + } + + /** + * Resets the specified property's value to its default value. + * + * @param property + * the property to reset + */ + public void resetPropertyValue(Object propertyObject) { + } + + /** + * Sets the named property to the given value. + * + * @param name + * the name of the property being set + * @param value + * the new value for the property + */ + public void setPropertyValue(Object nameObject, Object value) { + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/views/properties/XMLPropertySheetConfiguration.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/views/properties/XMLPropertySheetConfiguration.java new file mode 100644 index 0000000000..7ce0ff08a2 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/views/properties/XMLPropertySheetConfiguration.java @@ -0,0 +1,88 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.views.properties; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jface.text.ITextSelection; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.wst.sse.ui.views.properties.StructuredPropertySheetConfiguration; +import org.w3c.dom.Attr; +import org.w3c.dom.Node; + + +public class XMLPropertySheetConfiguration extends StructuredPropertySheetConfiguration { + + /** + * + */ + public XMLPropertySheetConfiguration() { + super(); + } + + /** + * @see org.eclipse.wst.sse.ui.views.properties.PropertySheetConfiguration#getSelection(org.eclipse.ui.IWorkbenchPart, + * org.eclipse.jface.viewers.ISelection) + */ + public ISelection getSelection(IWorkbenchPart selectingPart, ISelection selection) { + // On Attr nodes, select the owner Element. On Text nodes, select the + // parent Element. + ISelection preferredSelection = selection; + if (selection instanceof ITextSelection) { + // on text selection, find the appropriate Node + ITextSelection textSel = (ITextSelection) selection; + if (getModel() != null) { + Object inode = getModel().getIndexedRegion(textSel.getOffset()); + if (inode instanceof Node) { + Node node = (Node) inode; + // replace Attribute Node with its owner + if (node.getNodeType() == Node.ATTRIBUTE_NODE) + inode = ((Attr) node).getOwnerElement(); + // replace Text Node with its parent + else if ((node.getNodeType() == Node.TEXT_NODE || (node.getNodeType() == Node.CDATA_SECTION_NODE)) && node.getParentNode() != null) { + inode = node.getParentNode(); + } + } + if (inode != null) { + List inputList = new ArrayList(1); + inputList.add(inode); + preferredSelection = new StructuredSelection(inputList); + } + } + } else if (selection instanceof IStructuredSelection) { + IStructuredSelection structuredSel = (IStructuredSelection) selection; + if (getModel() != null) { + List inputList = new ArrayList(structuredSel.toList()); + for (int i = 0; i < inputList.size(); i++) { + Object inode = inputList.get(i); + if (inode instanceof Node) { + Node node = (Node) inputList.get(i); + // replace Attribute Node with its owner + if (node.getNodeType() == Node.ATTRIBUTE_NODE) + inputList.set(i, ((Attr) node).getOwnerElement()); + // replace Text Node with its parent + else if ((node.getNodeType() == Node.TEXT_NODE || (node.getNodeType() == Node.CDATA_SECTION_NODE)) && node.getParentNode() != null) { + inputList.set(i, node.getParentNode()); + } + } + } + preferredSelection = new StructuredSelection(inputList); + } + } + return preferredSelection; + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/views/properties/XMLPropertySourceAdapter.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/views/properties/XMLPropertySourceAdapter.java new file mode 100644 index 0000000000..b71904126f --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/views/properties/XMLPropertySourceAdapter.java @@ -0,0 +1,680 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.views.properties; + + + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Stack; + +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.views.properties.IPropertyDescriptor; +import org.eclipse.ui.views.properties.IPropertySheetEntry; +import org.eclipse.ui.views.properties.IPropertySource; +import org.eclipse.ui.views.properties.TextPropertyDescriptor; +import org.eclipse.wst.common.contentmodel.CMAttributeDeclaration; +import org.eclipse.wst.common.contentmodel.CMDataType; +import org.eclipse.wst.common.contentmodel.CMElementDeclaration; +import org.eclipse.wst.common.contentmodel.CMNamedNodeMap; +import org.eclipse.wst.common.contentmodel.modelquery.ModelQuery; +import org.eclipse.wst.sse.core.INodeAdapter; +import org.eclipse.wst.sse.core.INodeNotifier; +import org.eclipse.wst.sse.ui.Logger; +import org.eclipse.wst.sse.ui.views.properties.EnumeratedStringPropertyDescriptor; +import org.eclipse.wst.sse.ui.views.properties.IPropertySourceExtension; +import org.eclipse.wst.xml.core.document.DocumentTypeAdapter; +import org.eclipse.wst.xml.core.document.XMLNode; +import org.eclipse.wst.xml.core.modelquery.ModelQueryUtil; +import org.eclipse.wst.xml.ui.nls.ResourceHandler; +import org.w3c.dom.Attr; +import org.w3c.dom.DOMException; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + + +/** + * An IPropertySource implementation for a JFace viewer used to display + * properties of DOM nodes. Requires an adapter factory to create JFace + * adapters for the nodes in the tree. + */ +public class XMLPropertySourceAdapter implements INodeAdapter, IPropertySource, IPropertySourceExtension { + protected final static String CATEGORY_ATTRIBUTES = ResourceHandler.getString("XMLPropertySourceAdapter.0"); //$NON-NLS-1$ + + private static final boolean fSetExpertFilter = false; + + // derive categories from CMDataTypes; disabled until display strings can + // be planned + private final static boolean fShouldDeriveCategories = false; + + private final static boolean fSortEnumeratedValues = true; + protected boolean fCaseSensitive = true; + protected IPropertyDescriptor[] fDescriptors = null; + protected Node fNode = null; + + protected Stack fValuesBeingSet = new Stack(); + + public XMLPropertySourceAdapter(INodeNotifier target) { + super(); + fNode = (Node) target; + if (fNode instanceof XMLNode) { + Document ownerDocument = fNode.getOwnerDocument(); + if (ownerDocument == null) { + // if ownerDocument is null, then it must be the Document Node + ownerDocument = (Document) fNode; + } + DocumentTypeAdapter adapter = (DocumentTypeAdapter) ((INodeNotifier) ownerDocument).getAdapterFor(DocumentTypeAdapter.class); + if (adapter != null) + fCaseSensitive = adapter.getTagNameCase() == DocumentTypeAdapter.STRICT_CASE; + } + } + + private String[] _getValidFixedStrings(CMAttributeDeclaration attrDecl, CMDataType helper) { + String attributeName = attrDecl.getAttrName(); + List values = new ArrayList(1); + String impliedValue = helper.getImpliedValue(); + if (impliedValue != null) + values.add(impliedValue); + boolean checkIfCurrentValueIsIncluded = (fNode.getAttributes() != null && fNode.getAttributes().getNamedItem(attributeName) != null && fNode.getAttributes().getNamedItem(attributeName).getNodeValue() != null); + if (checkIfCurrentValueIsIncluded) { + String currentValue = null; + currentValue = fNode.getAttributes().getNamedItem(attributeName).getNodeValue(); + if (!currentValue.equals(impliedValue)) + values.add(currentValue); + } + String[] validStrings = new String[values.size()]; + validStrings = (String[]) values.toArray(validStrings); + return validStrings; + } + + private String[] _getValidStrings(CMAttributeDeclaration attrDecl, CMDataType valuesHelper) { + String attributeName = attrDecl.getAttrName(); + List values = new ArrayList(1); + boolean currentValueKnown = false; + boolean checkIfCurrentValueIsKnown = (fNode.getAttributes() != null && fNode.getAttributes().getNamedItem(attributeName) != null && fNode.getAttributes().getNamedItem(attributeName).getNodeValue() != null); + String currentValue = null; + if (checkIfCurrentValueIsKnown) + currentValue = fNode.getAttributes().getNamedItem(attributeName).getNodeValue(); + + if (valuesHelper.getImpliedValueKind() == CMDataType.IMPLIED_VALUE_FIXED && valuesHelper.getImpliedValue() != null) { + // FIXED value + currentValueKnown = currentValue != null && valuesHelper.getImpliedValue().equals(currentValue); + values.add(valuesHelper.getImpliedValue()); + } else { + // ENUMERATED values + String[] valueStrings = null; + // valueStrings = valuesHelper.getEnumeratedValues(); + ModelQuery modelQuery = ModelQueryUtil.getModelQuery(fNode.getOwnerDocument()); + if (modelQuery != null && fNode.getNodeType() == Node.ELEMENT_NODE) { + valueStrings = modelQuery.getPossibleDataTypeValues((Element) fNode, attrDecl); + } else { + valueStrings = attrDecl.getAttrType().getEnumeratedValues(); + } + if (valueStrings != null) { + for (int i = 0; i < valueStrings.length; i++) { + if (checkIfCurrentValueIsKnown && valueStrings[i].equals(currentValue)) + currentValueKnown = true; + values.add(valueStrings[i]); + } + } + } + if (valuesHelper.getImpliedValueKind() != CMDataType.IMPLIED_VALUE_NONE && valuesHelper.getImpliedValue() != null) { + if (!values.contains(valuesHelper.getImpliedValue())) + values.add(valuesHelper.getImpliedValue()); + } + + if (checkIfCurrentValueIsKnown && !currentValueKnown && currentValue != null && currentValue.length() > 0) + values.add(currentValue); + String[] validStrings = new String[values.size()]; + validStrings = (String[]) values.toArray(validStrings); + return validStrings; + } + + protected void clearDescriptors() { + fDescriptors = null; + } + + protected IPropertyDescriptor createDefaultPropertyDescriptor(String attributeName) { + return createDefaultPropertyDescriptor(attributeName, false); + } + + protected IPropertyDescriptor createDefaultPropertyDescriptor(String attributeName, boolean hideOnFilter) { + // The descriptor class used here is also used in + // updatePropertyDescriptors() + TextPropertyDescriptor descriptor = new TextPropertyDescriptor(attributeName, attributeName); + descriptor.setCategory(getCategory(null)); + descriptor.setDescription(attributeName); + if (hideOnFilter && fSetExpertFilter) + descriptor.setFilterFlags(new String[]{IPropertySheetEntry.FILTER_ID_EXPERT}); + return descriptor; + } + + /** + * Creates a property descriptor for an attribute with ENUMERATED values - + * if the value does not exist, an editable combo box is returned - if the + * value exists but is not one in the enumerated list of value, a combo + * box featuring the current and correct values is returned - if the value + * exists and it is a valid value, a combo box featuring the correct + * values with the current one visible is returned + */ + private IPropertyDescriptor createEnumeratedPropertyDescriptor(CMAttributeDeclaration attrDecl, CMDataType valuesHelper) { + // the displayName MUST be set + EnumeratedStringPropertyDescriptor descriptor = new EnumeratedStringPropertyDescriptor(attrDecl.getAttrName(), attrDecl.getAttrName(), _getValidStrings(attrDecl, valuesHelper)); + descriptor.setCategory(getCategory(attrDecl)); + descriptor.setDescription(attrDecl.getAttrName()); + if (attrDecl.getUsage() != CMAttributeDeclaration.REQUIRED && fSetExpertFilter) + descriptor.setFilterFlags(new String[]{IPropertySheetEntry.FILTER_ID_EXPERT}); + return descriptor; + } + + /** + * Creates a property descriptor for an attribute with a FIXED value - if + * the value does not exist, an editable combo box is returned - if the + * value exists but is not the fixed/default value, a combo box featuring + * the current and correct value is returned - if the value exists and it + * is the fixed/default value, no cell editor is provided "locking" the + * value in + */ + private IPropertyDescriptor createFixedPropertyDescriptor(CMAttributeDeclaration attrDecl, CMDataType helper) { + // the displayName MUST be set + EnumeratedStringPropertyDescriptor descriptor = new EnumeratedStringPropertyDescriptor(attrDecl.getNodeName(), attrDecl.getNodeName(), _getValidFixedStrings(attrDecl, helper)); + descriptor.setCategory(getCategory(attrDecl)); + descriptor.setDescription(attrDecl.getAttrName()); + return descriptor; + } + + protected IPropertyDescriptor createPropertyDescriptor(CMAttributeDeclaration attrDecl) { + IPropertyDescriptor descriptor = null; + CMDataType attrType = attrDecl.getAttrType(); + + if (attrType != null) { + // handle declarations that provide FIXED/ENUMERATED values + if (attrType.getEnumeratedValues() != null && attrType.getEnumeratedValues().length > 0) { + descriptor = createEnumeratedPropertyDescriptor(attrDecl, attrType); + } else if ((attrDecl.getUsage() == CMAttributeDeclaration.FIXED || attrType.getImpliedValueKind() == CMDataType.IMPLIED_VALUE_FIXED) && attrType.getImpliedValue() != null) { + descriptor = createFixedPropertyDescriptor(attrDecl, attrType); + } else { + // plain text + descriptor = createTextPropertyDescriptor(attrDecl); + } + } else { + // no extra information given + descriptor = createTextPropertyDescriptor(attrDecl); + } + return descriptor; + } + + /** + * Returns the current collection of property descriptors. + * + * @return all valid descriptors. + */ + protected IPropertyDescriptor[] createPropertyDescriptors() { + CMNamedNodeMap attrMap = null; + CMElementDeclaration ed = getDeclaration(); + if (ed != null) { + attrMap = ed.getAttributes(); + } + + List descriptorList = new ArrayList(); + List names = new ArrayList(); + IPropertyDescriptor descriptor; + + CMAttributeDeclaration attrDecl = null; + + // add descriptors for existing attributes + NamedNodeMap attributes = fNode.getAttributes(); + if (attributes != null) { + for (int i = 0; i < attributes.getLength(); i++) { + Attr attr = (Attr) attributes.item(i); + // if metainfo is present for this attribute, use the + // CMAttributeDeclaration to derive a descriptor + if (attrMap != null) { + String attrName = attr.getName(); + if (fCaseSensitive) + attrDecl = (CMAttributeDeclaration) attrMap.getNamedItem(attrName); + else { + for (int j = 0; j < attrMap.getLength(); j++) { + if (!fCaseSensitive && attrMap.item(j).getNodeName().equalsIgnoreCase(attrName)) { + attrDecl = (CMAttributeDeclaration) attrMap.item(j); + break; + } + } + } + } + // be consistent: if there's metainfo, use *that* as the + // descriptor ID + if (attrDecl != null) { + descriptor = createPropertyDescriptor(attrDecl); + if (descriptor != null) + names.add(attrDecl.getNodeName()); + } else { + descriptor = createDefaultPropertyDescriptor(attr.getName()); + if (descriptor != null) + names.add(attr.getName()); + } + if (descriptor != null) + descriptorList.add(descriptor); + } + } + + // add descriptors from the metainfo that are not yet listed + if (attrMap != null) { + for (int i = 0; i < attrMap.getLength(); i++) { + attrDecl = (CMAttributeDeclaration) attrMap.item(i); + if (!names.contains(attrDecl.getAttrName())) { + IPropertyDescriptor holdDescriptor = createPropertyDescriptor(attrDecl); + if (holdDescriptor != null) { + descriptorList.add(holdDescriptor); + } + } + } + } + + IPropertyDescriptor[] descriptors = new IPropertyDescriptor[descriptorList.size()]; + for (int i = 0; i < descriptors.length; i++) + descriptors[i] = (IPropertyDescriptor) descriptorList.get(i); + return descriptors; + } + + private IPropertyDescriptor createTextPropertyDescriptor(CMAttributeDeclaration attrDecl) { + TextPropertyDescriptor descriptor = new TextPropertyDescriptor(attrDecl.getAttrName(), attrDecl.getAttrName()); + descriptor.setCategory(getCategory(attrDecl)); + descriptor.setDescription(attrDecl.getAttrName()); + if (attrDecl.getUsage() != CMAttributeDeclaration.REQUIRED && fSetExpertFilter) + descriptor.setFilterFlags(new String[]{IPropertySheetEntry.FILTER_ID_EXPERT}); + return descriptor; + } + + protected String getCategory(CMAttributeDeclaration attrDecl) { + if (attrDecl != null) { + if (attrDecl.supports("category")) { //$NON-NLS-1$ + return (String) attrDecl.getProperty("category"); //$NON-NLS-1$ + } + if (fShouldDeriveCategories && attrDecl.getAttrType() != null && attrDecl.getAttrType().getNodeName() != null && attrDecl.getAttrType().getNodeName().length() > 0) { + return attrDecl.getAttrType().getDataTypeName(); + } + } + return CATEGORY_ATTRIBUTES; + } + + protected CMElementDeclaration getDeclaration() { + if (fNode == null || fNode.getNodeType() != Node.ELEMENT_NODE) + return null; + ModelQuery modelQuery = ModelQueryUtil.getModelQuery(fNode.getOwnerDocument()); + if (modelQuery != null) { + return modelQuery.getCMElementDeclaration((Element) fNode); + } + return null; + } + + private Display getDisplay() { + + return PlatformUI.getWorkbench().getDisplay(); + } + + /** + * Returns a value for this Node that can be editted in a property sheet. + * + * @return a value that can be editted + */ + public Object getEditableValue() { + return null; + } + + /** + * Returns the current collection of property descriptors. + * + * @return all valid descriptors. + */ + public IPropertyDescriptor[] getPropertyDescriptors() { + if (fDescriptors == null || fDescriptors.length == 0) { + fDescriptors = createPropertyDescriptors(); + } else { + updatePropertyDescriptors(); + } + return fDescriptors; + } + + /** + * Returns the current value for the named property. + * + * @param name + * the name of the property as named by its property descriptor + * @return the current value of the property + */ + public Object getPropertyValue(Object nameObject) { + String name = nameObject.toString(); + String returnedValue = null; + NamedNodeMap attrMap = fNode.getAttributes(); + if (attrMap != null) { + Node attribute = attrMap.getNamedItem(name); + if (attribute != null) { + if (attribute instanceof XMLNode) + returnedValue = ((XMLNode) attribute).getValueSource(); + else + returnedValue = attribute.getNodeValue(); + } + } + if (returnedValue == null) + returnedValue = ""; //$NON-NLS-1$ + return returnedValue; + } + + protected String[] getValidValues(CMAttributeDeclaration attrDecl) { + if (attrDecl == null) + return new String[0]; + + String[] validValues = null; + CMDataType attrType = attrDecl.getAttrType(); + if (attrType != null) { + validValues = _getValidStrings(attrDecl, attrType); + if (fSortEnumeratedValues) + Arrays.sort(validValues); + } + if (validValues == null) + validValues = new String[0]; + return validValues; + } + + /** + * Allowing the INodeAdapter to compare itself against the type allows it + * to return true in more than one case. + */ + public boolean isAdapterForType(Object type) { + return type == IPropertySource.class; + } + + protected boolean isFixedValue(CMAttributeDeclaration attrDecl) { + if (attrDecl == null) + return true; + + CMDataType attrType = attrDecl.getAttrType(); + if (attrType != null) { + return attrType.getImpliedValueKind() == CMDataType.IMPLIED_VALUE_FIXED || attrDecl.getUsage() == CMAttributeDeclaration.FIXED; + } + return false; + } + + /** + * Returns whether the property value has changed from the default. + * + * @return <code>true</code> if the value of the specified property has + * changed from its original default value; <code>false</code> + * otherwise. + */ + public boolean isPropertySet(Object propertyObject) { + String property = propertyObject.toString(); + + NamedNodeMap attrMap = fNode.getAttributes(); + if (attrMap != null) + return attrMap.getNamedItem(property) != null; + return false; + } + + public void notifyChanged(INodeNotifier notifier, int eventType, java.lang.Object changedFeature, java.lang.Object oldValue, java.lang.Object newValue, int pos) { + } + + /** + * Remove the given attribute from the Node + * + * @param propertyObject + */ + public void removeProperty(Object propertyObject) { + NamedNodeMap attrMap = fNode.getAttributes(); + if (attrMap != null) { + Node attribute = attrMap.getNamedItem(propertyObject.toString()); + if (attribute != null) { + try { + attrMap.removeNamedItem(propertyObject.toString()); + } catch (DOMException e) { + if (e.code != DOMException.INVALID_MODIFICATION_ERR) { + Logger.logException(e); + } + } + } + } + } + + /** + * Resets the specified property's value to its default value. + * + * @param property + * the property to reset + */ + public void resetPropertyValue(Object propertyObject) { + String property = propertyObject.toString(); + CMNamedNodeMap attrDecls = null; + + CMElementDeclaration ed = getDeclaration(); + if (ed != null) { + attrDecls = ed.getAttributes(); + } + + NamedNodeMap attrMap = fNode.getAttributes(); + if (attrDecls != null) { + CMAttributeDeclaration attrDecl = (CMAttributeDeclaration) attrDecls.getNamedItem(property); + String defValue = null; + if (attrDecl != null) { + if (attrDecl.getAttrType() != null) { + CMDataType helper = attrDecl.getAttrType(); + if (helper.getImpliedValueKind() != CMDataType.IMPLIED_VALUE_NONE && helper.getImpliedValue() != null) + defValue = helper.getImpliedValue(); + } + } + if (defValue != null && defValue.length() > 0) { + ((Attr) attrMap.getNamedItem(property)).setValue(defValue); + } else { + attrMap.removeNamedItem(property); + } + } else { + attrMap.removeNamedItem(property); + } + } + + /** + * Sets the named property to the given value. + * + * @param name + * the name of the property being set + * @param value + * the new value for the property + */ + public void setPropertyValue(Object nameObject, Object value) { + // Avoid cycling - can happen if a closing cell editor causes a + // refresh + // on the PropertySheet page and the setInput again asks the editor to + // close; besides, why apply the same value twice? + if (!fValuesBeingSet.isEmpty() && fValuesBeingSet.peek() == nameObject) + return; + fValuesBeingSet.push(nameObject); + String name = nameObject.toString(); + String valueString = null; + if (value != null) + valueString = value.toString(); + NamedNodeMap attrMap = fNode.getAttributes(); + try { + if (attrMap != null) { + Attr attr = (Attr) attrMap.getNamedItem(name); + if (attr != null) { + // EXISTING VALUE + // potential out of control loop if updating the value + // triggers a viewer update, forcing the + // active cell editor to save its value and causing the + // loop to continue + if (attr.getValue() == null || !attr.getValue().equals(valueString)) { + if (attr instanceof XMLNode) + ((XMLNode) attr).setValueSource(valueString); + else + attr.setValue(valueString); + } + } else { + // NEW(?) value + if (value != null) { // never create an empty attribute + Attr newAttr = fNode.getOwnerDocument().createAttribute(name); + if (newAttr instanceof XMLNode) + ((XMLNode) newAttr).setValueSource(valueString); + else + newAttr.setValue(valueString); + attrMap.setNamedItem(newAttr); + } + } + } else { + if (fNode instanceof Element) { + ((Element) fNode).setAttribute(name, valueString); + } + } + } catch (DOMException e) { + Display d = getDisplay(); + if (d != null) + d.beep(); + } + fValuesBeingSet.pop(); + } + + protected void updatePropertyDescriptors() { + if (fDescriptors == null || fDescriptors.length == 0) + // Nothing to update + return; + + // List of all names encountered in the tag and defined by the element + List declaredNames = new ArrayList(); + // New descriptor list that will become fDescriptors after all + // processing is done + List descriptors = new ArrayList(); + // Names of the descriptors in the above List + List descriptorNames = new ArrayList(); + + // Update any descriptors derived from the metainfo + CMElementDeclaration ed = getDeclaration(); + CMNamedNodeMap attrMap = null; + if (ed != null) { + attrMap = ed.getAttributes(); + } + // Update exiting descriptors; not added to the final list here + if (attrMap != null) { + // Update existing descriptor types based on metainfo + CMAttributeDeclaration attrDecl = null; + for (int i = 0; i < attrMap.getLength(); i++) { + attrDecl = (CMAttributeDeclaration) attrMap.item(i); + String attrName = attrDecl.getAttrName(); + if (!declaredNames.contains(attrName)) { + declaredNames.add(attrName); + } + for (int j = 0; j < fDescriptors.length; j++) { + boolean sameName = (fCaseSensitive && fDescriptors[j].getId().equals(attrDecl.getNodeName())) || (!fCaseSensitive && attrDecl.getNodeName().equals(fDescriptors[j].getId().toString())); + if (sameName) { + String[] validValues = getValidValues(attrDecl); + // Update the descriptor for this + // CMAttributeDeclaration (only enumerated values get + // updated for now) + if (fDescriptors[j] instanceof EnumeratedStringPropertyDescriptor) { + ((EnumeratedStringPropertyDescriptor) fDescriptors[j]).updateValues(validValues); + } + // Replace with better descriptor + else if (validValues != null && validValues.length > 0) { + fDescriptors[j] = createPropertyDescriptor(attrDecl); + } + } + } + } + } else { + // Update existing descriptors based on not having any metainfo + for (int j = 0; j < fDescriptors.length; j++) { + // Replace with basic descriptor + if (!(fDescriptors[j] instanceof TextPropertyDescriptor)) { + fDescriptors[j] = createDefaultPropertyDescriptor((String) fDescriptors[j].getId()); + } + } + } + + NamedNodeMap attributes = fNode.getAttributes(); + + // Remove descriptors for attributes that aren't present AND aren't + // known through metainfo, + // do this by only reusing existing descriptors for attributes that + // are present or declared + for (int i = 0; i < fDescriptors.length; i++) { + if (fDescriptors[i] != null) { + String descriptorName = fDescriptors[i].getId().toString(); + if ((declaredNames.contains(descriptorName) || (attributes.getNamedItem(descriptorName) != null)) && !descriptorNames.contains(descriptorName)) { + descriptorNames.add(descriptorName); + descriptors.add(fDescriptors[i]); + } + } + } + + // Add descriptors for declared attributes that don't already have one + if (attrMap != null) { + // Update existing descriptor types based on metainfo + CMAttributeDeclaration attrDecl = null; + for (int i = 0; i < attrMap.getLength(); i++) { + attrDecl = (CMAttributeDeclaration) attrMap.item(i); + String attrName = attrDecl.getAttrName(); + if (fCaseSensitive) { + if (!descriptorNames.contains(attrName)) { + IPropertyDescriptor descriptor = createPropertyDescriptor(attrDecl); + if (descriptor != null) { + descriptorNames.add(attrName); + descriptors.add(descriptor); + } + } + } else { + boolean exists = false; + for (int j = 0; j < descriptorNames.size(); j++) + exists = (descriptorNames.get(j).toString().equalsIgnoreCase(attrName)) || exists; + if (!exists) { + descriptorNames.add(attrName); + IPropertyDescriptor descriptor = createPropertyDescriptor(attrDecl); + if (descriptor != null) { + descriptorNames.add(attrName); + descriptors.add(descriptor); + } + } + } + } + } + + // Add descriptors for existing attributes that don't already have one + if (attributes != null) { + for (int i = 0; i < attributes.getLength(); i++) { + Attr attr = (Attr) attributes.item(i); + String attrName = attr.getName(); + if (fCaseSensitive) { + if (!descriptorNames.contains(attrName)) { + descriptorNames.add(attrName); + descriptors.add(createDefaultPropertyDescriptor(attrName)); + } + } else { + boolean exists = false; + for (int j = 0; j < descriptorNames.size(); j++) + exists = (descriptorNames.get(j).toString().equalsIgnoreCase(attrName)) || exists; + if (!exists) { + descriptorNames.add(attrName); + descriptors.add(createDefaultPropertyDescriptor(attrName)); + } + } + } + } + + // Update fDescriptors + IPropertyDescriptor[] newDescriptors = new IPropertyDescriptor[descriptors.size()]; + for (int i = 0; i < newDescriptors.length; i++) + newDescriptors[i] = (IPropertyDescriptor) descriptors.get(i); + fDescriptors = newDescriptors; + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/views/properties/XMLPropertySourceAdapterFactory.java b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/views/properties/XMLPropertySourceAdapterFactory.java new file mode 100644 index 0000000000..0d14000882 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/views/properties/XMLPropertySourceAdapterFactory.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2001, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + * Jens Lukowski/Innoopract - initial renaming/restructuring + * + *******************************************************************************/ +package org.eclipse.wst.xml.ui.views.properties; + +import org.eclipse.ui.views.properties.IPropertySource; +import org.eclipse.wst.sse.core.AbstractAdapterFactory; +import org.eclipse.wst.sse.core.AdapterFactory; +import org.eclipse.wst.sse.core.INodeAdapter; +import org.eclipse.wst.sse.core.INodeNotifier; +import org.w3c.dom.Node; + + +public class XMLPropertySourceAdapterFactory extends AbstractAdapterFactory { + + public XMLPropertySourceAdapterFactory() { + super(IPropertySource.class, true); + } + + public XMLPropertySourceAdapterFactory(Object adapterKey, boolean registerAdapters) { + super(adapterKey, registerAdapters); + } + + public AdapterFactory copy() { + return new XMLPropertySourceAdapterFactory(this.adapterKey, this.shouldRegisterAdapter); + } + + protected INodeAdapter createAdapter(INodeNotifier target) { + // at the moment, only one implementation exists + if (target != null && target instanceof Node && ((Node) target).getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) + return new ProcessingInstructionPropertySourceAdapter(target); + return new XMLPropertySourceAdapter(target); + } +} diff --git a/bundles/org.eclipse.wst.xml.ui/templates/xmldefault-templates.properties b/bundles/org.eclipse.wst.xml.ui/templates/xmldefault-templates.properties new file mode 100644 index 0000000000..4a178765c2 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/templates/xmldefault-templates.properties @@ -0,0 +1,14 @@ +############################################################################### +# Copyright (c) 2001, 2004 IBM Corporation and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# IBM Corporation - initial API and implementation +# Jens Lukowski/Innoopract - initial renaming/restructuring +# +############################################################################### +Templates.comment.name=comment +Templates.comment.desc=xml comment diff --git a/bundles/org.eclipse.wst.xml.ui/templates/xmldefault-templates.xml b/bundles/org.eclipse.wst.xml.ui/templates/xmldefault-templates.xml new file mode 100644 index 0000000000..1ba2929662 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/templates/xmldefault-templates.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8"?> +<templates> + +<template name="%Templates.comment.name" description="%Templates.comment.desc" id="org.eclipse.wst.xml.ui.templates.comment" context="xml_tag" enabled="true"><!-- ${cursor} --></template> +</templates> diff --git a/bundles/org.eclipse.wst.xml.ui/templates/xmldefault-templates_de.properties b/bundles/org.eclipse.wst.xml.ui/templates/xmldefault-templates_de.properties new file mode 100644 index 0000000000..9d5e20bf40 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/templates/xmldefault-templates_de.properties @@ -0,0 +1,14 @@ +############################################################################### +# Copyright (c) 2001, 2004 IBM Corporation and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# IBM Corporation - initial API and implementation +# Jens Lukowski/Innoopract - initial renaming/restructuring +# +############################################################################### +Templates.comment.name=Kommentar +Templates.comment.desc=XML-Kommentar diff --git a/bundles/org.eclipse.wst.xml.ui/templates/xmldefault-templates_es.properties b/bundles/org.eclipse.wst.xml.ui/templates/xmldefault-templates_es.properties new file mode 100644 index 0000000000..3a5d4a3114 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/templates/xmldefault-templates_es.properties @@ -0,0 +1,14 @@ +############################################################################### +# Copyright (c) 2001, 2004 IBM Corporation and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# IBM Corporation - initial API and implementation +# Jens Lukowski/Innoopract - initial renaming/restructuring +# +############################################################################### +Templates.comment.name=comment +Templates.comment.desc=Comentario xml diff --git a/bundles/org.eclipse.wst.xml.ui/templates/xmldefault-templates_fr.properties b/bundles/org.eclipse.wst.xml.ui/templates/xmldefault-templates_fr.properties new file mode 100644 index 0000000000..15246b2d68 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/templates/xmldefault-templates_fr.properties @@ -0,0 +1,14 @@ +############################################################################### +# Copyright (c) 2001, 2004 IBM Corporation and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# IBM Corporation - initial API and implementation +# Jens Lukowski/Innoopract - initial renaming/restructuring +# +############################################################################### +Templates.comment.name=commentaire +Templates.comment.desc=commentaire xml diff --git a/bundles/org.eclipse.wst.xml.ui/templates/xmldefault-templates_it.properties b/bundles/org.eclipse.wst.xml.ui/templates/xmldefault-templates_it.properties new file mode 100644 index 0000000000..7319bebc3d --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/templates/xmldefault-templates_it.properties @@ -0,0 +1,14 @@ +############################################################################### +# Copyright (c) 2001, 2004 IBM Corporation and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# IBM Corporation - initial API and implementation +# Jens Lukowski/Innoopract - initial renaming/restructuring +# +############################################################################### +Templates.comment.name=commento +Templates.comment.desc=commento xml diff --git a/bundles/org.eclipse.wst.xml.ui/templates/xmldefault-templates_ja.properties b/bundles/org.eclipse.wst.xml.ui/templates/xmldefault-templates_ja.properties new file mode 100644 index 0000000000..8c87bc80fa --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/templates/xmldefault-templates_ja.properties @@ -0,0 +1,14 @@ +############################################################################### +# Copyright (c) 2001, 2004 IBM Corporation and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# IBM Corporation - initial API and implementation +# Jens Lukowski/Innoopract - initial renaming/restructuring +# +############################################################################### +Templates.comment.name=\u30b3\u30e1\u30f3\u30c8 +Templates.comment.desc=xml \u30b3\u30e1\u30f3\u30c8 diff --git a/bundles/org.eclipse.wst.xml.ui/templates/xmldefault-templates_ko.properties b/bundles/org.eclipse.wst.xml.ui/templates/xmldefault-templates_ko.properties new file mode 100644 index 0000000000..8c61a284af --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/templates/xmldefault-templates_ko.properties @@ -0,0 +1,14 @@ +############################################################################### +# Copyright (c) 2001, 2004 IBM Corporation and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# IBM Corporation - initial API and implementation +# Jens Lukowski/Innoopract - initial renaming/restructuring +# +############################################################################### +Templates.comment.name=\uc8fc\uc11d +Templates.comment.desc=xml \uc8fc\uc11d diff --git a/bundles/org.eclipse.wst.xml.ui/templates/xmldefault-templates_pt_BR.properties b/bundles/org.eclipse.wst.xml.ui/templates/xmldefault-templates_pt_BR.properties new file mode 100644 index 0000000000..3fe1125463 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/templates/xmldefault-templates_pt_BR.properties @@ -0,0 +1,14 @@ +############################################################################### +# Copyright (c) 2001, 2004 IBM Corporation and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# IBM Corporation - initial API and implementation +# Jens Lukowski/Innoopract - initial renaming/restructuring +# +############################################################################### +Templates.comment.name=coment\u00e1rio +Templates.comment.desc=coment\u00e1rio xml diff --git a/bundles/org.eclipse.wst.xml.ui/templates/xmldefault-templates_zh_CN.properties b/bundles/org.eclipse.wst.xml.ui/templates/xmldefault-templates_zh_CN.properties new file mode 100644 index 0000000000..9bff0b4d3d --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/templates/xmldefault-templates_zh_CN.properties @@ -0,0 +1,14 @@ +############################################################################### +# Copyright (c) 2001, 2004 IBM Corporation and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# IBM Corporation - initial API and implementation +# Jens Lukowski/Innoopract - initial renaming/restructuring +# +############################################################################### +Templates.comment.name=\u6ce8\u91ca +Templates.comment.desc=xml \u6ce8\u91ca diff --git a/bundles/org.eclipse.wst.xml.ui/templates/xmldefault-templates_zh_TW.properties b/bundles/org.eclipse.wst.xml.ui/templates/xmldefault-templates_zh_TW.properties new file mode 100644 index 0000000000..b051523c64 --- /dev/null +++ b/bundles/org.eclipse.wst.xml.ui/templates/xmldefault-templates_zh_TW.properties @@ -0,0 +1,14 @@ +############################################################################### +# Copyright (c) 2001, 2004 IBM Corporation and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# IBM Corporation - initial API and implementation +# Jens Lukowski/Innoopract - initial renaming/restructuring +# +############################################################################### +Templates.comment.name=\u8a3b\u89e3 +Templates.comment.desc=xml \u8a3b\u89e3 |