Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.m2e.editor.xml/src')
-rw-r--r--org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/InsertArtifactProposal.java340
-rw-r--r--org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/InsertExpressionProposal.java110
-rw-r--r--org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/MavenMarkerResolutionGenerator.java65
-rw-r--r--org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/MvnImages.java107
-rw-r--r--org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/MvnIndexPlugin.java99
-rw-r--r--org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomContentAssistProcessor.java579
-rw-r--r--org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomContentOutlineConfiguration.java358
-rw-r--r--org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomHyperlinkDetector.java729
-rw-r--r--org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomModelHandler.java133
-rw-r--r--org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomQuickAssistProcessor.java678
-rw-r--r--org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomStructuredTextViewConfiguration.java65
-rw-r--r--org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomTemplateContext.java764
-rw-r--r--org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomTemplateContextType.java32
-rw-r--r--org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomTemplateContextUtil.java105
-rw-r--r--org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomTextHover.java148
-rw-r--r--org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/XMLSchemaMarkerResolution.java75
-rw-r--r--org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/Messages.java156
-rw-r--r--org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/POMMarkerAnnotationModel.java34
-rw-r--r--org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/POMMarkerAnnotationModelFactory.java34
-rw-r--r--org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/messages.properties66
-rw-r--r--org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/preferences/PomTemplatesPreferencePage.java43
-rw-r--r--org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/template/.gitignore0
22 files changed, 4720 insertions, 0 deletions
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/InsertArtifactProposal.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/InsertArtifactProposal.java
new file mode 100644
index 00000000..27ddffb9
--- /dev/null
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/InsertArtifactProposal.java
@@ -0,0 +1,340 @@
+package org.eclipse.m2e.editor.xml;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.maven.model.Plugin;
+import org.apache.maven.model.PluginManagement;
+import org.apache.maven.project.MavenProject;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.Region;
+import org.eclipse.jface.text.contentassist.ICompletionProposal;
+import org.eclipse.jface.text.contentassist.ICompletionProposalExtension4;
+import org.eclipse.jface.text.contentassist.ICompletionProposalExtension5;
+import org.eclipse.jface.text.contentassist.IContextInformation;
+import org.eclipse.jface.text.formatter.IContentFormatter;
+import org.eclipse.jface.text.formatter.IContentFormatterExtension;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+import org.eclipse.m2e.core.index.IIndex;
+import org.eclipse.m2e.core.index.IndexedArtifactFile;
+import org.eclipse.m2e.core.internal.project.MavenMarkerManager;
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+import org.eclipse.m2e.core.ui.dialogs.MavenRepositorySearchDialog;
+import org.eclipse.m2e.editor.xml.InsertArtifactProposal.Configuration;
+import org.eclipse.m2e.editor.xml.internal.Messages;
+
+public class InsertArtifactProposal implements ICompletionProposal, ICompletionProposalExtension4, ICompletionProposalExtension5 {
+
+ private ISourceViewer sourceViewer;
+ private Region region;
+ private int generatedLength = 0;
+ private int generatedOffset;
+ private Configuration config;
+ private PomStructuredTextViewConfiguration textConfig;
+
+ public InsertArtifactProposal(ISourceViewer sourceViewer, Region region, Configuration config, PomStructuredTextViewConfiguration config2) {
+ this.sourceViewer = sourceViewer;
+ this.region = region;
+ generatedOffset = region.getOffset();
+ this.config = config;
+ this.textConfig = config2;
+ assert config.getType() != null;
+ }
+
+ public void apply(IDocument document) {
+ IProject prj = PomContentAssistProcessor.extractProject(sourceViewer);
+ Set<ArtifactKey> managedKeys = new HashSet<ArtifactKey>();
+ Set<ArtifactKey> usedKeys = new HashSet<ArtifactKey>();
+ if (prj != null) {
+ IMavenProjectFacade facade = MavenPlugin.getDefault().getMavenProjectManager().getProject(prj);
+ if (facade != null) {
+ MavenProject mp = facade.getMavenProject();
+ if (mp != null) {
+ PluginManagement pm = mp.getPluginManagement();
+ if (pm != null && pm.getPlugins() != null) {
+ for (Plugin plug : pm.getPlugins()) {
+ managedKeys.add(new ArtifactKey(plug.getGroupId(), plug.getArtifactId(), plug.getVersion(), null));
+ }
+ }
+ }
+ }
+ }
+ //TODO also collect the used plugin's list
+
+ MavenRepositorySearchDialog dialog = new MavenRepositorySearchDialog(sourceViewer.getTextWidget().getShell(),
+ config.getType().getWindowTitle(), config.getType().getIIndexType(),
+ usedKeys, managedKeys, false);
+ if (config.getInitiaSearchString() != null) {
+ dialog.setQuery(config.getInitiaSearchString());
+ }
+ if(dialog.open() == Window.OK) {
+ String lineDelim = document.getLegalLineDelimiters()[0];//do we care? or just append \n always?
+ IndexedArtifactFile af = (IndexedArtifactFile) dialog.getFirstResult();
+ int offset = region.getOffset();
+ if(af != null) {
+ if (config.getType() == SearchType.PARENT) {
+ try {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("<parent>").append(lineDelim); //$NON-NLS-1$
+ buffer.append("<groupId>").append(af.group).append("</groupId>").append(lineDelim); //$NON-NLS-1$ //$NON-NLS-2$
+ buffer.append("<artifactId>").append(af.artifact).append("</artifactId>").append(lineDelim); //$NON-NLS-1$ //$NON-NLS-2$
+ buffer.append("<version>").append(af.version).append("</version>").append(lineDelim); //$NON-NLS-1$ //$NON-NLS-2$
+ String relativePath = PomContentAssistProcessor.findRelativePath(sourceViewer, af.group, af.artifact, af.version);
+ if (relativePath != null) {
+ buffer.append("<relativePath>").append(relativePath).append("</relativePath>").append(lineDelim); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ buffer.append("</parent>").append(lineDelim); //$NON-NLS-1$
+ generatedLength = buffer.toString().length();
+ document.replace(offset, region.getLength(), buffer.toString());
+
+ IContentFormatter formatter = textConfig.getContentFormatter(sourceViewer);
+ Region resRegion = format(formatter, document, generatedOffset, generatedLength);
+ generatedOffset = resRegion.getOffset();
+ generatedLength = resRegion.getLength();
+ } catch(BadLocationException e) {
+ MavenLogger.log("Failed inserting parent element", e); //$NON-NLS-1$
+ }
+ }
+ if (config.getType() == SearchType.PLUGIN) {
+ Node current = config.getCurrentNode();
+ if ("project".equals(current.getNodeName())) { //$NON-NLS-1$
+ //in project section go with build/plugins.
+ Element build = MavenMarkerManager.findChildElement((Element)current, "build"); //$NON-NLS-1$
+ if (build == null) {
+ try {
+ StringBuffer buffer = new StringBuffer();
+ generateBuild(buffer, lineDelim, af, skipVersion(current, af, managedKeys));
+ generatedLength = buffer.toString().length();
+ document.replace(offset, 0, buffer.toString());
+
+ IContentFormatter formatter = textConfig.getContentFormatter(sourceViewer);
+ Region resRegion = format(formatter, document, generatedOffset, generatedLength);
+ generatedOffset = resRegion.getOffset();
+ generatedLength = resRegion.getLength();
+ } catch (BadLocationException e) {
+ MavenLogger.log("Failed inserting build element", e); //$NON-NLS-1$
+ }
+ return;
+ } else {
+ current = build;
+ IndexedRegion reg = (IndexedRegion)current;
+ //we need to update the offset to where we found the existing build element..
+ offset = reg.getEndOffset() - "</build>".length(); //$NON-NLS-1$
+ }
+ }
+ if ("build".equals(current.getNodeName()) || "pluginManagement".equals(current.getNodeName())) { //$NON-NLS-1$ //$NON-NLS-2$
+ Element plugins = MavenMarkerManager.findChildElement((Element)current, "plugins"); //$NON-NLS-1$
+ if (plugins == null) {
+ //we need to create it.
+ try {
+ StringBuffer buffer = new StringBuffer();
+ generatePlugins(buffer, lineDelim, af, skipVersion(current, af, managedKeys));
+ generatedLength = buffer.toString().length();
+ document.replace(offset, 0, buffer.toString());
+
+ IContentFormatter formatter = textConfig.getContentFormatter(sourceViewer);
+ Region resRegion = format(formatter, document, offset, generatedLength);
+ generatedOffset = resRegion.getOffset();
+ generatedLength = resRegion.getLength();
+ } catch (BadLocationException e) {
+ MavenLogger.log("Failed inserting plugins element", e); //$NON-NLS-1$
+ }
+ return;
+ } else {
+ current = plugins;
+ IndexedRegion reg = (IndexedRegion)current;
+ //we need to update the offset to where we found the existing plugins element..
+ offset = reg.getEndOffset() - "</plugins>".length(); //$NON-NLS-1$
+ }
+ }
+ if ("plugins".equals(current.getNodeName())) { //$NON-NLS-1$
+ //simple, just add the plugin here..
+ //TODO we might want to look if the plugin is already defined in this section or not..
+ try {
+ StringBuffer buffer = new StringBuffer();
+ generatePlugin(buffer, lineDelim, af, skipVersion(current, af, managedKeys));
+ generatedLength = buffer.toString().length();
+ document.replace(offset, 0, buffer.toString());
+ IContentFormatter formatter = textConfig.getContentFormatter(sourceViewer);
+ Region resRegion = format(formatter, document, offset, generatedLength);
+ generatedOffset = resRegion.getOffset();
+ generatedLength = resRegion.getLength();
+ } catch (BadLocationException e) {
+ MavenLogger.log("Failed inserting plugin element", e); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * decide if we want to generate the version element or not..
+ * @param currentNode
+ * @param af
+ * @param managedList
+ * @return
+ */
+ private boolean skipVersion(Node currentNode, IndexedArtifactFile af, Set<ArtifactKey> managedList) {
+ if ("pluginManagement".equals(currentNode.getNodeName()) || "pluginManagement".equals(currentNode.getParentNode().getNodeName())) {
+ return false;
+ }
+ ArtifactKey key = new ArtifactKey(af.group, af.artifact, af.version, null);
+ return managedList.contains(key);
+ }
+
+ private void generatePlugin(StringBuffer buffer, String lineDelim, IndexedArtifactFile af, boolean skipVersion) {
+ buffer.append("<plugin>").append(lineDelim); //$NON-NLS-1$
+ buffer.append("<groupId>").append(af.group).append("</groupId>").append(lineDelim); //$NON-NLS-1$ //$NON-NLS-2$
+ buffer.append("<artifactId>").append(af.artifact).append("</artifactId>").append(lineDelim); //$NON-NLS-1$ //$NON-NLS-2$
+ //for managed plugins (if version matches only?), don't add the version element
+ if (!skipVersion) {
+ buffer.append("<version>").append(af.version).append("</version>").append(lineDelim); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ buffer.append("</plugin>").append(lineDelim); //$NON-NLS-1$
+ }
+
+ private void generatePlugins(StringBuffer buffer, String lineDelim, IndexedArtifactFile af, boolean skipVersion) {
+ buffer.append("<plugins>").append(lineDelim); //$NON-NLS-1$
+ generatePlugin(buffer, lineDelim, af, skipVersion);
+ buffer.append("</plugins>").append(lineDelim); //$NON-NLS-1$
+ }
+
+ private void generateBuild(StringBuffer buffer, String lineDelim, IndexedArtifactFile af, boolean skipVersion) {
+ buffer.append("<build>").append(lineDelim); //$NON-NLS-1$
+ generatePlugins(buffer, lineDelim, af, skipVersion);
+ buffer.append("</build>").append(lineDelim); //$NON-NLS-1$
+ }
+
+ /**
+ * take the document and format the region specified by the supplied formatter.
+ * operates on whole line (determined by the region specified)
+ * returns the new region encompassing the original region after formatting
+ */
+ public static Region format(IContentFormatter formatter, IDocument document, int offset, int length) throws BadLocationException {
+ int startLine = document.getLineOfOffset(offset);
+ int endLine = document.getLineOfOffset(offset + length - 1); // -1 to make sure to be before the end of line char
+ int startLineOffset = document.getLineOffset(startLine);
+ formatter.format(document, new Region(startLineOffset, (document.getLineOffset(endLine) + document.getLineLength(endLine)) - startLineOffset));
+ startLineOffset = document.getLineOffset(startLine); //should be same, just being paranoid
+ return new Region (startLineOffset, (document.getLineOffset(endLine) + document.getLineLength(endLine)) - startLineOffset);
+ }
+
+ public Point getSelection(IDocument document) {
+ return new Point(generatedOffset, generatedLength);
+ }
+
+ public String getAdditionalProposalInfo() {
+ return null; //not to be used anymore
+ }
+
+ public String getDisplayString() {
+ return config.getType().getDisplayName();
+ }
+
+ public Image getImage() {
+ return config.getType().getImage();
+ }
+
+ public IContextInformation getContextInformation() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public boolean isAutoInsertable() {
+ return false;
+ }
+
+ public Object getAdditionalProposalInfo(IProgressMonitor monitor) {
+ return config.getType().getAdditionalInfo();
+ }
+
+ /**
+ * supported search types
+ * @author mkleint
+ *
+ */
+ public static enum SearchType {
+
+ PARENT(IIndex.SEARCH_PARENTS, Messages.InsertArtifactProposal_searchDialog_title, Messages.InsertArtifactProposal_display_name, MvnImages.IMG_OPEN_POM, Messages.InsertArtifactProposal_additionals),
+ PLUGIN(IIndex.SEARCH_PLUGIN, Messages.InsertArtifactProposal_insert_plugin_title, Messages.InsertArtifactProposal_insert_plugin_display_name, MvnImages.IMG_OPEN_POM, Messages.InsertArtifactProposal_insert_plugin_description);
+
+ private final String type;
+ private final String windowTitle;
+ private final String displayName;
+ private final Image image;
+ private final String additionalInfo;
+ private SearchType(String type, String windowTitle, String dn, Image img, String addInfo) {
+ this.type = type;
+ this.windowTitle = windowTitle;
+ this.displayName = dn;
+ this.image = img;
+ this.additionalInfo = addInfo;
+ }
+
+ String getIIndexType() {
+ return type;
+ }
+
+ public String getWindowTitle() {
+ return windowTitle;
+ }
+
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ public Image getImage() {
+ return image;
+ }
+
+ public String getAdditionalInfo() {
+ return additionalInfo;
+ }
+
+ }
+
+ public static class Configuration {
+ private final SearchType type;
+ private String initiaSearchString;
+ private Node node;
+
+ public Configuration(SearchType type) {
+ this.type = type;
+ }
+
+ public void setInitiaSearchString(String initiaSearchString) {
+ this.initiaSearchString = initiaSearchString;
+ }
+ public String getInitiaSearchString() {
+ return initiaSearchString;
+ }
+ public SearchType getType() {
+ return type;
+ }
+
+ public void setCurrentNode(Node node) {
+ this.node = node;
+ }
+
+ public Node getCurrentNode() {
+ return node;
+ }
+ }
+
+}
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/InsertExpressionProposal.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/InsertExpressionProposal.java
new file mode 100644
index 00000000..1424e7b6
--- /dev/null
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/InsertExpressionProposal.java
@@ -0,0 +1,110 @@
+package org.eclipse.m2e.editor.xml;
+
+import org.apache.maven.model.InputLocation;
+import org.apache.maven.model.InputSource;
+import org.apache.maven.model.Model;
+import org.apache.maven.project.MavenProject;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.Region;
+import org.eclipse.jface.text.contentassist.ICompletionProposal;
+import org.eclipse.jface.text.contentassist.ICompletionProposalExtension5;
+import org.eclipse.jface.text.contentassist.IContextInformation;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+import org.eclipse.m2e.editor.xml.internal.Messages;
+/**
+ * insertion proposal for ${ expressions
+ * @author mkleint
+ *
+ */
+public class InsertExpressionProposal implements ICompletionProposal, ICompletionProposalExtension5 {
+
+ private IMavenProjectFacade project;
+ private String key;
+ private Region region;
+ private ISourceViewer sourceViewer;
+ private int len = 0;
+
+ public InsertExpressionProposal(ISourceViewer sourceViewer, Region region, String key, IMavenProjectFacade mvnproject) {
+ assert project != null;
+ this.sourceViewer = sourceViewer;
+ this.region = region;
+ this.key = key;
+ this.project = mvnproject;
+ }
+
+ public Object getAdditionalProposalInfo(IProgressMonitor monitor) {
+ String value = PomTemplateContext.simpleInterpolate(project.getProject(), "${" + key + "}"); //$NON-NLS-1$ //$NON-NLS-2$
+ MavenProject mavprj = project.getMavenProject();
+ String loc = null;
+ if (mavprj != null) {
+ Model mdl = mavprj.getModel();
+ if (mdl.getProperties() != null && mdl.getProperties().containsKey(key)) {
+ if (mdl.getLocation("properties") != null) {
+ InputLocation location = mdl.getLocation("properties").getLocation(key); //$NON-NLS-1$
+ if (location != null) {
+ //MNGECLIPSE-2539 apparently you can have an InputLocation with null input source.
+ // check!
+ InputSource source = location.getSource();
+ if (source != null) {
+ loc = source.getModelId();
+ }
+ }
+ }
+ }
+ }
+ StringBuffer buff = new StringBuffer();
+ buff.append("<html>"); //$NON-NLS-1$
+ if (value != null) {
+ buff.append(NLS.bind(Messages.InsertExpressionProposal_hint1, value));
+ }
+ if (loc != null) {
+ buff.append(NLS.bind(Messages.InsertExpressionProposal_hint2, loc));
+ }
+ buff.append("</html>"); //$NON-NLS-1$
+ return buff.toString();
+ }
+
+ public void apply(IDocument document) {
+ int offset = region.getOffset();
+ String replace = "${" + key + "}"; //$NON-NLS-1$ //$NON-NLS-2$
+ try {
+ document.replace(offset, region.getLength(), replace);
+ len = replace.length();
+ } catch(BadLocationException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ }
+
+ public Point getSelection(IDocument document) {
+ return new Point(region.getOffset() + len, 0);
+ }
+
+ public String getAdditionalProposalInfo() {
+ //not used anymore
+ return null;
+ }
+
+ public String getDisplayString() {
+ return "${" + key + "}"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ public Image getImage() {
+ // TODO what kind of icon to use?
+ return null;
+ }
+
+ public IContextInformation getContextInformation() {
+ return null;
+ }
+
+}
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/MavenMarkerResolutionGenerator.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/MavenMarkerResolutionGenerator.java
new file mode 100644
index 00000000..351e8ec5
--- /dev/null
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/MavenMarkerResolutionGenerator.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.editor.xml;
+
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.ui.IMarkerResolution;
+import org.eclipse.ui.IMarkerResolutionGenerator;
+import org.eclipse.ui.IMarkerResolutionGenerator2;
+
+import org.eclipse.m2e.core.core.IMavenConstants;
+
+
+/**
+ * MavenMarkerResolutionGenerator
+ *
+ * @author dyocum
+ */
+public class MavenMarkerResolutionGenerator implements IMarkerResolutionGenerator, IMarkerResolutionGenerator2 {
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.IMarkerResolutionGenerator#getResolutions(org.eclipse.core.resources.IMarker)
+ */
+ public IMarkerResolution[] getResolutions(IMarker marker) {
+ String hint = marker.getAttribute(IMavenConstants.MARKER_ATTR_EDITOR_HINT, null);
+ if(hint != null) {
+ //only provide a quickfix for the schema marker
+ if(IMavenConstants.EDITOR_HINT_MISSING_SCHEMA.equals(hint)) {
+ return new IMarkerResolution[] {new XMLSchemaMarkerResolution()};
+ }
+ if(IMavenConstants.EDITOR_HINT_PARENT_VERSION.equals(hint)) {
+ return new IMarkerResolution[] {new PomQuickAssistProcessor.IdPartRemovalProposal(marker, true) };
+ }
+ if(IMavenConstants.EDITOR_HINT_PARENT_GROUP_ID.equals(hint)) {
+ return new IMarkerResolution[] {new PomQuickAssistProcessor.IdPartRemovalProposal(marker, false) };
+ }
+ if(hint.equals(IMavenConstants.EDITOR_HINT_MANAGED_DEPENDENCY_OVERRIDE)) {
+ return new IMarkerResolution[] {
+ new PomQuickAssistProcessor.ManagedVersionRemovalProposal(marker, true),
+ new PomQuickAssistProcessor.IgnoreWarningProposal(marker, IMavenConstants.MARKER_IGNORE_MANAGED)
+ };
+ }
+ if(hint.equals(IMavenConstants.EDITOR_HINT_MANAGED_PLUGIN_OVERRIDE)) {
+ return new IMarkerResolution[] {
+ new PomQuickAssistProcessor.ManagedVersionRemovalProposal(marker, false),
+ new PomQuickAssistProcessor.IgnoreWarningProposal(marker, IMavenConstants.MARKER_IGNORE_MANAGED)
+ };
+ }
+ }
+ return new IMarkerResolution[0];
+ }
+
+ public boolean hasResolutions(IMarker marker) {
+ String hint = marker.getAttribute(IMavenConstants.MARKER_ATTR_EDITOR_HINT, null); //$NON-NLS-1$
+ return !(hint == null);
+ }
+}
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/MvnImages.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/MvnImages.java
new file mode 100644
index 00000000..90ff8203
--- /dev/null
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/MvnImages.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.editor.xml;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.ImageRegistry;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+import org.eclipse.m2e.core.core.MavenLogger;
+
+/**
+ * @author Eugene Kuleshov
+ */
+public class MvnImages {
+
+ // object images
+
+ public static final Image IMG_JAR = createImage("jar_obj.gif"); //$NON-NLS-1$
+
+ public static final Image IMG_JARS = createImage("jars_obj.gif"); //$NON-NLS-1$
+
+ public static final Image IMG_REPOSITORY = createImage("repository_obj.gif"); //$NON-NLS-1$
+
+ public static final Image IMG_PLUGIN = createImage("plugin_obj.gif"); //$NON-NLS-1$
+
+ public static final Image IMG_PLUGINS = createImage("plugins_obj.gif"); //$NON-NLS-1$
+
+ public static final Image IMG_EXECUTION = createImage("execution_obj.gif"); //$NON-NLS-1$
+
+ public static final Image IMG_GOAL = createImage("goal_obj.gif"); //$NON-NLS-1$
+
+ public static final Image IMG_FILTER = createImage("filter_obj.gif"); //$NON-NLS-1$
+
+ public static final Image IMG_RESOURCE = createImage("resource_obj.gif"); //$NON-NLS-1$
+
+ public static final Image IMG_RESOURCES = createImage("resources_obj.gif"); //$NON-NLS-1$
+
+ public static final Image IMG_INCLUDE = createImage("include_obj.gif"); //$NON-NLS-1$
+
+ public static final Image IMG_EXCLUDE = createImage("exclude_obj.gif"); //$NON-NLS-1$
+
+ public static final Image IMG_PERSON = createImage("person_obj.gif"); //$NON-NLS-1$
+
+ public static final Image IMG_ROLE = createImage("role_obj.gif"); //$NON-NLS-1$
+
+ public static final Image IMG_PROPERTY = createImage("property_obj.gif"); //$NON-NLS-1$
+
+ public static final Image IMG_PROPERTIES = createImage("properties_obj.gif"); //$NON-NLS-1$
+
+ public static final Image IMG_REPORT = createImage("report_obj.gif"); //$NON-NLS-1$
+
+ public static final Image IMG_PROFILE = createImage("profile_obj.gif"); //$NON-NLS-1$
+
+ public static final Image IMG_PROFILES = createImage("profiles_obj.gif"); //$NON-NLS-1$
+
+ public static final Image IMG_PARAMETER = createImage("parameter_obj.gif"); //$NON-NLS-1$
+
+ public static final Image IMG_BUILD = createImage("build_obj.gif"); //$NON-NLS-1$
+
+ public static final Image IMG_ELEMENT = createImage("element_obj.gif"); //$NON-NLS-1$
+
+ public static final Image IMG_USER_TEMPLATE = createImage("template_obj.gif"); //$NON-NLS-1$
+
+ public static final Image IMG_OPEN_POM = createImage("open_pom.gif"); //$NON-NLS-1$
+
+ public static final Image IMG_CLOSE = createImage("close.gif"); //$NON-NLS-1$
+
+ private static ImageDescriptor create(String key) {
+ try {
+ ImageDescriptor imageDescriptor = createDescriptor(key);
+ ImageRegistry imageRegistry = getImageRegistry();
+ if(imageRegistry!=null) {
+ imageRegistry.put(key, imageDescriptor);
+ }
+ return imageDescriptor;
+ } catch (Exception ex) {
+ MavenLogger.log(key, ex);
+ return null;
+ }
+ }
+
+ private static Image createImage(String key) {
+ create(key);
+ ImageRegistry imageRegistry = getImageRegistry();
+ return imageRegistry==null ? null : imageRegistry.get(key);
+ }
+
+ private static ImageRegistry getImageRegistry() {
+ MvnIndexPlugin plugin = MvnIndexPlugin.getDefault();
+ return plugin==null ? null : plugin.getImageRegistry();
+ }
+
+ private static ImageDescriptor createDescriptor(String image) {
+ return AbstractUIPlugin.imageDescriptorFromPlugin(MvnIndexPlugin.PLUGIN_ID, "icons/" + image); //$NON-NLS-1$
+ }
+
+}
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/MvnIndexPlugin.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/MvnIndexPlugin.java
new file mode 100644
index 00000000..5e5812df
--- /dev/null
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/MvnIndexPlugin.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.editor.xml;
+
+import java.io.IOException;
+
+import org.osgi.framework.BundleContext;
+
+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.m2e.core.core.MavenLogger;
+
+
+/**
+ * @author Lukas Krecan
+ */
+public class MvnIndexPlugin extends AbstractUIPlugin {
+ public static final String PLUGIN_ID = "org.eclipse.m2e.editor.xml"; //$NON-NLS-1$
+
+ private static final String TEMPLATES_KEY = PLUGIN_ID + ".templates"; //$NON-NLS-1$
+
+ private static MvnIndexPlugin defaultInstance;
+
+ private TemplateStore templateStore;
+
+ private ContributionContextTypeRegistry contextTypeRegistry;
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ defaultInstance = this;
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ super.stop(context);
+ defaultInstance = null;
+ }
+
+ public static MvnIndexPlugin getDefault() {
+ return defaultInstance;
+ }
+
+ /**
+ * Returns the template store.
+ *
+ * @return the template store.
+ */
+ public TemplateStore getTemplateStore() {
+ if(templateStore == null) {
+ templateStore = new ContributionTemplateStore(getTemplateContextRegistry(), getPreferenceStore(), TEMPLATES_KEY);
+ try {
+ templateStore.load();
+ } catch(IOException ex) {
+ MavenLogger.log("Unable to load pom templates", ex); //$NON-NLS-1$
+ }
+ }
+ return templateStore;
+ }
+
+ /**
+ * Returns the template context type registry.
+ *
+ * @return the template context type registry
+ */
+ public ContextTypeRegistry getTemplateContextRegistry() {
+ if(contextTypeRegistry == null) {
+ ContributionContextTypeRegistry registry = new ContributionContextTypeRegistry();
+ for(PomTemplateContext contextType : PomTemplateContext.values()) {
+ registry.addContextType(contextType.getContextTypeId());
+ }
+ contextTypeRegistry = registry;
+ }
+ return contextTypeRegistry;
+ }
+
+ public ContextTypeRegistry getContextTypeRegistry() {
+ if(contextTypeRegistry == null) {
+ contextTypeRegistry = new ContributionContextTypeRegistry();
+ // TemplateContextType contextType = new TemplateContextType(CONTEXT_TYPE, "POM XML Editor");
+ PomTemplateContextType contextType = new PomTemplateContextType();
+ contextTypeRegistry.addContextType(contextType);
+ }
+ return contextTypeRegistry;
+ }
+}
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomContentAssistProcessor.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomContentAssistProcessor.java
new file mode 100644
index 00000000..6b010671
--- /dev/null
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomContentAssistProcessor.java
@@ -0,0 +1,579 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.editor.xml;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+import java.util.Stack;
+import java.util.TreeSet;
+
+import org.apache.maven.project.MavenProject;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+
+import org.eclipse.core.filebuffers.FileBuffers;
+import org.eclipse.core.filebuffers.ITextFileBuffer;
+import org.eclipse.core.filesystem.IFileStore;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+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.ITextViewer;
+import org.eclipse.jface.text.Region;
+import org.eclipse.jface.text.contentassist.CompletionProposal;
+import org.eclipse.jface.text.contentassist.ICompletionProposal;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.jface.text.templates.ContextTypeRegistry;
+import org.eclipse.jface.text.templates.DocumentTemplateContext;
+import org.eclipse.jface.text.templates.Template;
+import org.eclipse.jface.text.templates.TemplateContext;
+import org.eclipse.jface.text.templates.TemplateContextType;
+import org.eclipse.jface.text.templates.TemplateException;
+import org.eclipse.jface.text.templates.TemplateProposal;
+import org.eclipse.jface.text.templates.persistence.TemplateStore;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion;
+import org.eclipse.wst.sse.core.utils.StringUtils;
+import org.eclipse.wst.xml.ui.internal.contentassist.ContentAssistRequest;
+import org.eclipse.wst.xml.ui.internal.contentassist.XMLContentAssistProcessor;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.internal.project.MavenMarkerManager;
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+import org.eclipse.m2e.editor.xml.internal.Messages;
+
+/**
+ * @author Lukas Krecan
+ * @author Eugene Kuleshov
+ */
+@SuppressWarnings("restriction")
+public class PomContentAssistProcessor extends XMLContentAssistProcessor {
+
+ private static final ProposalComparator PROPOSAL_COMPARATOR = new ProposalComparator();
+
+ private ISourceViewer sourceViewer;
+
+ private PomStructuredTextViewConfiguration textConfig;
+
+ public PomContentAssistProcessor(ISourceViewer sourceViewer, PomStructuredTextViewConfiguration pomStructuredTextViewConfiguration) {
+ this.sourceViewer = sourceViewer;
+ textConfig = pomStructuredTextViewConfiguration;
+ }
+
+ //broken
+
+ protected void addTagNameProposals(ContentAssistRequest contentAssistRequest, int childPosition) {
+ String currentNodeName = getCurrentNode(contentAssistRequest).getNodeName();
+ PomTemplateContext context = PomTemplateContext.fromNodeName(currentNodeName);
+ if(PomTemplateContext.CONFIGURATION == context)
+ {
+ //this is sort of hack that makes sure the config proposals appear even
+ // when you type <prefix
+ // the downside is that additional typing hides the proposals popup
+ // there has to be a better way though. the xml element completions seems to be coping with it fine..
+ contentAssistRequest.setReplacementBeginPosition(contentAssistRequest.getReplacementBeginPosition() - 1);
+ contentAssistRequest.setReplacementLength(contentAssistRequest.getReplacementLength() + 1);
+ addProposals(contentAssistRequest, context, getCurrentNode(contentAssistRequest), contentAssistRequest.getMatchString());
+ }
+ if(PomTemplateContext.UNKNOWN == context)
+ {
+ context = PomTemplateContext.fromNodeName(getCurrentNode(contentAssistRequest).getParentNode().getNodeName());
+ if(PomTemplateContext.CONFIGURATION == context)
+ {
+ addProposals(contentAssistRequest, context, getCurrentNode(contentAssistRequest).getParentNode(), contentAssistRequest.getMatchString());
+ }
+ }
+ super.addTagNameProposals(contentAssistRequest, childPosition);
+ }
+
+
+ @Override
+ protected void addTagInsertionProposals(ContentAssistRequest contentAssistRequest, int childPosition) {
+ String currentNodeName = getCurrentNode(contentAssistRequest).getNodeName();
+
+ addProposals(contentAssistRequest, PomTemplateContext.fromNodeName(currentNodeName));
+ super.addTagInsertionProposals(contentAssistRequest, childPosition);
+ }
+
+ private Node getCurrentNode(ContentAssistRequest contentAssistRequest) {
+ Node currentNode = contentAssistRequest.getNode();
+ if(currentNode instanceof Text) {
+ currentNode = currentNode.getParentNode();
+ }
+ return currentNode;
+ }
+
+ private void addProposals(ContentAssistRequest request, PomTemplateContext context) {
+ ITextSelection selection = (ITextSelection) sourceViewer.getSelectionProvider().getSelection();
+ int offset = request.getReplacementBeginPosition();
+ // adjust offset to end of normalized selection
+ if(selection.getOffset() == offset) {
+ offset = selection.getOffset() + selection.getLength();
+ }
+
+ String prefix = extractPrefix(sourceViewer, offset);
+
+ addExpressionProposal(request, context, getCurrentNode(request), prefix);
+
+ addGenerateProposals(request, context, getCurrentNode(request), prefix);
+
+ addProposals(request, context, getCurrentNode(request), prefix);
+ }
+ /**
+ * this is a proposal method for adding expressions when ${ is typed..
+ * @param request
+ * @param context
+ * @param currentNode
+ * @param prefix
+ */
+ private void addExpressionProposal(ContentAssistRequest request, PomTemplateContext context, Node currentNode,
+ String prefix) {
+ int exprStart = prefix.lastIndexOf("${"); //$NON-NLS-1$
+ if (exprStart != -1) {
+ //the regular prefix is separated by whitespace and <> brackets only, we need to cut the last portion
+ String realExpressionPrefix = prefix.substring(exprStart);
+ if (realExpressionPrefix.contains("}")) { //$NON-NLS-1$
+ //the expression is not opened..
+ return;
+ }
+ if (expressionproposalContexts.contains(context)) {
+ //add all effective pom expressions
+ IProject prj = extractProject(sourceViewer);
+ Region region = new Region(request.getReplacementBeginPosition() - realExpressionPrefix.length(), realExpressionPrefix.length());
+ if (prj != null) {
+ IMavenProjectFacade mvnproject = MavenPlugin.getDefault().getMavenProjectManager().getProject(prj);
+ Set<String> collect = new TreeSet<String>();
+ if (mvnproject != null) {
+ MavenProject mp = mvnproject.getMavenProject();
+ if (mp != null) {
+ Properties props = mp.getProperties();
+ if (props != null) {
+ for (Object key : props.keySet()) {
+ String keyString = key.toString();
+ if (("${" + keyString).startsWith(realExpressionPrefix)) { //$NON-NLS-1$
+ collect.add(keyString);
+ }
+ }
+ }
+ }
+ //add a few hardwired values as well
+ if ("${basedir}".startsWith(realExpressionPrefix)) { //$NON-NLS-1$
+ collect.add("basedir"); //$NON-NLS-1$
+ }
+ if ("${project.version}".startsWith(realExpressionPrefix)) { //$NON-NLS-1$
+ collect.add("project.version"); //$NON-NLS-1$
+ }
+ if ("${project.groupId}".startsWith(realExpressionPrefix)) { //$NON-NLS-1$
+ collect.add("project.groupId"); //$NON-NLS-1$
+ }
+ if ("${project.artifactId}".startsWith(realExpressionPrefix)) { //$NON-NLS-1$
+ collect.add("project.artifactId"); //$NON-NLS-1$
+ }
+ if ("${project.build.directory}".startsWith(realExpressionPrefix)) { //$NON-NLS-1$
+ collect.add("project.build.directory"); //$NON-NLS-1$
+ }
+ for (String key : collect) {
+ ICompletionProposal proposal = new InsertExpressionProposal(sourceViewer, region, key, mvnproject);
+ if(request.shouldSeparate()) {
+ request.addMacro(proposal);
+ } else {
+ request.addProposal(proposal);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private static List<PomTemplateContext> expressionproposalContexts = Arrays.asList(new PomTemplateContext[] {
+ PomTemplateContext.ARTIFACT_ID,
+ PomTemplateContext.CLASSIFIER,
+// PomTemplateContext.CONFIGURATION,
+ PomTemplateContext.GOAL,
+ PomTemplateContext.GROUP_ID,
+ PomTemplateContext.MODULE,
+ PomTemplateContext.PACKAGING,
+ PomTemplateContext.PHASE,
+ PomTemplateContext.PROPERTIES, //??
+ PomTemplateContext.SCOPE,
+ PomTemplateContext.SYSTEM_PATH,
+ PomTemplateContext.TYPE,
+// PomTemplateContext.VERSION, version is intentionally not included as we have specialized handling there..
+ PomTemplateContext.UNKNOWN //this one is both important and troubling.. but having a context for everything is weird.
+ });
+
+ private void addGenerateProposals(ContentAssistRequest request, PomTemplateContext context, Node node, String prefix) {
+ if (prefix.trim().length() != 0) {
+ //only provide these generate proposals when there is no prefix.
+ return;
+ }
+ if (context == PomTemplateContext.PROJECT) {
+ //check if we have a parent defined..
+ Node project = node;
+ if (project != null && project instanceof Element) {
+ Element parent = MavenMarkerManager.findChildElement((Element)project, "parent"); //$NON-NLS-1$
+ if (parent == null) {
+ //now add the proposal for parent inclusion
+ Region region = new Region(request.getReplacementBeginPosition(), 0);
+ Element groupId = MavenMarkerManager.findChildElement((Element)project, "groupId"); //$NON-NLS-1$
+ String groupString = null;
+ if (groupId != null) {
+ groupString = MavenMarkerManager.getElementTextValue(groupId);
+ }
+ InsertArtifactProposal.Configuration config = new InsertArtifactProposal.Configuration(InsertArtifactProposal.SearchType.PARENT);
+ config.setInitiaSearchString(groupString);
+ ICompletionProposal proposal = new InsertArtifactProposal(sourceViewer, region, config, this.textConfig);
+ if(request.shouldSeparate()) {
+ request.addMacro(proposal);
+ } else {
+ request.addProposal(proposal);
+ }
+ }
+ }
+ }
+ if (context == PomTemplateContext.PARENT && node.getNodeName().equals("parent")) { //$NON-NLS-1$
+ Element parent = (Element)node;
+ Element relPath = MavenMarkerManager.findChildElement(parent, "relativePath"); //$NON-NLS-1$
+ if (relPath == null) {
+ //only show when no relpath already defined..
+ String relative = findRelativePath(sourceViewer, parent);
+ if (relative != null) {
+ Region region = new Region(request.getReplacementBeginPosition(), 0);
+ ICompletionProposal proposal = new CompletionProposal("<relativePath>" + relative + "</relativePath>", //$NON-NLS-1$ //$NON-NLS-2$
+ region.getOffset(), region.getLength(), 0,
+ WorkbenchPlugin.getDefault().getImageRegistry().get(org.eclipse.ui.internal.SharedImages.IMG_OBJ_ADD),
+ NLS.bind(Messages.PomContentAssistProcessor_insert_relPath_title, relative), null, null);
+ if (request.shouldSeparate()) {
+ request.addMacro(proposal);
+ } else {
+ request.addProposal(proposal);
+ }
+ }
+ }
+ }
+ if (context == PomTemplateContext.RELATIVE_PATH) {
+ //completion in the text portion of relative path
+ Element parent = (Element) node.getParentNode();
+ if (parent != null && "parent".equals(parent.getNodeName())) { //$NON-NLS-1$
+ String relative = findRelativePath(sourceViewer, parent);
+ String textContent = MavenMarkerManager.getElementTextValue(node);
+ if (relative != null && !relative.equals(textContent)) {
+ Region region = new Region(request.getReplacementBeginPosition() - prefix.length(), prefix.length());
+ if (request.getNode() instanceof IndexedRegion && request.getNode() instanceof Text) {
+ //for <relativePath>|</relativePath> the current node is the element node and not the text node
+ //only replace the text node content..
+ IndexedRegion index = (IndexedRegion)request.getNode();
+ region = new Region(index.getStartOffset(), index.getEndOffset() - index.getStartOffset());
+ }
+ ICompletionProposal proposal = new CompletionProposal(relative,
+ region.getOffset(), region.getLength(), 0,
+ WorkbenchPlugin.getDefault().getImageRegistry().get(org.eclipse.ui.internal.SharedImages.IMG_OBJ_ADD),
+ NLS.bind(Messages.PomContentAssistProcessor_set_relPath_title, relative), null, null);
+ if (request.shouldSeparate()) {
+ request.addMacro(proposal);
+ } else {
+ request.addProposal(proposal);
+ }
+ }
+ }
+ }
+ if (context == PomTemplateContext.PLUGINS || context == PomTemplateContext.BUILD
+ || context == PomTemplateContext.PLUGIN_MANAGEMENT || context == PomTemplateContext.PROJECT) {
+ //now add the proposal for plugin inclusion
+ Region region = new Region(request.getReplacementBeginPosition(), 0);
+ InsertArtifactProposal.Configuration config = new InsertArtifactProposal.Configuration(InsertArtifactProposal.SearchType.PLUGIN);
+ config.setCurrentNode(node);
+
+ ICompletionProposal proposal = new InsertArtifactProposal(sourceViewer, region, config, this.textConfig);
+ if(request.shouldSeparate()) {
+ request.addMacro(proposal);
+ } else {
+ request.addProposal(proposal);
+ }
+
+ }
+
+ }
+ /*
+ * calculates the path of the node up in the hierarchy, example of result is project/build/plugins/plugin
+ * level parameter designates the number of parents to climb eg. for level 2 the result would be plugins/plugin
+ * level -1 means all the way to the top.
+ */
+ static String pathUp(Node node, int level) {
+ StringBuffer buf = new StringBuffer();
+ int current = level;
+ while (node != null && level > 0) {
+ if (node instanceof Element) {
+ if (buf.length() > 0) {
+ buf.insert(0, "/");
+ }
+ buf.insert(0, node.getNodeName());
+ current = current -1;
+ }
+ node = node.getParentNode();
+ }
+ return buf.toString();
+ }
+
+ private static String findRelativePath(ISourceViewer viewer, Element parent) {
+ String groupId = MavenMarkerManager.getElementTextValue(MavenMarkerManager.findChildElement(parent, "groupId")); //$NON-NLS-1$
+ String artifactId = MavenMarkerManager.getElementTextValue(MavenMarkerManager.findChildElement(parent, "artifactId")); //$NON-NLS-1$
+ String version = MavenMarkerManager.getElementTextValue(MavenMarkerManager.findChildElement(parent, "version")); //$NON-NLS-1$
+ return findRelativePath(viewer, groupId, artifactId, version);
+ }
+
+ public static String findRelativePath(ISourceViewer viewer, String groupId, String artifactId, String version) {
+ if (groupId != null && artifactId != null && version != null) {
+ IMavenProjectFacade facade = MavenPlugin.getDefault().getMavenProjectManager().getMavenProject(groupId, artifactId, version);
+ if (facade != null) {
+ //now add the proposal for relativePath
+ IFile parentPomFile = facade.getPom();
+ IPath path = parentPomFile.getLocation();
+ IProject prj = extractProject(viewer);
+ if (prj != null && path != null) {
+ IPath path2 = prj.getLocation();
+ IPath relative = path.makeRelativeTo(path2);
+ if (relative != path) {
+ return relative.toString();
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+
+
+ private void addProposals(ContentAssistRequest request, PomTemplateContext context, Node currentNode, String prefix) {
+ if(request != null) {
+ IProject prj = extractProject(sourceViewer);
+
+ ICompletionProposal[] templateProposals = getTemplateProposals(prj, sourceViewer,
+ request.getReplacementBeginPosition(), context.getContextTypeId(), currentNode, prefix);
+ for(ICompletionProposal proposal : templateProposals) {
+ if(request.shouldSeparate()) {
+ request.addMacro(proposal);
+ } else {
+ request.addProposal(proposal);
+ }
+ }
+ }
+ }
+
+ /**
+ * what is this method supposed to do? for the sourceViewer find the associated file on disk and for
+ * that one find the IProject it belongs to. The required condition for the IProject instance is that
+ * project relative path of the file shall only be pom.xml (thus no nested, unopened maven pom).
+ * So that when MavenPlugin.getDefault().getMavenProjectManager().getProject(prj); is called later on
+ * the instance, it actually returns the maven model facade for the pom.xml backing the sourceViewer.
+ * @param sourceViewer
+ * @return
+ */
+ public static IProject extractProject(ITextViewer sourceViewer) {
+ ITextFileBuffer buf = FileBuffers.getTextFileBufferManager().getTextFileBuffer(sourceViewer.getDocument());
+ IFileStore folder = buf.getFileStore();
+ File file = new File(folder.toURI());
+ IPath path = Path.fromOSString(file.getAbsolutePath());
+ Stack<IResource> stack = new Stack<IResource>();
+ //here we need to find the most inner project to the path.
+ //we do so by shortening the path and remembering all the resources identified.
+ // at the end we pick the last one from the stack. is there a catch to it?
+ IResource ifile = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(path);
+ if (ifile != null) {
+ stack.push(ifile);
+ } else {
+ while(path.segmentCount() > 1) {
+ ResourcesPlugin.getWorkspace().getRoot().findMember(path);
+ if(ifile != null) {
+ stack.push(ifile);
+ }
+ path = path.removeFirstSegments(1);
+ }
+ }
+ IResource res = stack.empty() ? null : stack.pop();
+ if (res != null) {
+ IProject prj = res.getProject();
+ //the project returned is in a way unrelated to nested child poms that don't have an opened project,
+ //in that case we pass along a wrong parent/aggregator
+ if (res.getProjectRelativePath().segmentCount() != 1) {
+ //if the project were the pom's project, the relative path would be just "pom.xml", if it's not just throw it out of the window..
+ prj = null;
+ }
+ return prj;
+ }
+ return null;
+ }
+
+ private ICompletionProposal[] getTemplateProposals(IProject project, ITextViewer viewer, int offset, String contextTypeId, Node currentNode, String prefix) {
+ ITextSelection selection = (ITextSelection) viewer.getSelectionProvider().getSelection();
+
+ // adjust offset to end of normalized selection
+ if(selection.getOffset() == offset) {
+ offset = selection.getOffset() + selection.getLength();
+ }
+
+// String prefix = extractPrefix(viewer, offset);
+ Region region = new Region(offset - prefix.length(), prefix.length());
+ TemplateContext context = createContext(viewer, region, contextTypeId);
+ if(context == null) {
+ return new ICompletionProposal[0];
+ }
+
+ // name of the selection variables {line, word}_selection
+ context.setVariable("selection", selection.getText()); //$NON-NLS-1$
+
+ PomTemplateContext templateContext = PomTemplateContext.fromId(contextTypeId);
+
+ // add the user defined templates - separate them from the rest of the templates
+ // so that we know what they are and can assign proper icon to them.
+ Image image = MvnImages.IMG_USER_TEMPLATE;
+ List<TemplateProposal> matches = new ArrayList<TemplateProposal>();
+ TemplateStore store = MvnIndexPlugin.getDefault().getTemplateStore();
+ if(store != null) {
+ Template[] templates = store.getTemplates(contextTypeId);
+ for(Template template : templates) {
+ TemplateProposal proposal = createProposalForTemplate(prefix, region, context, image, template, true);
+ if (proposal != null) {
+ matches.add(proposal);
+ }
+ }
+ }
+ if (templateContext == PomTemplateContext.CONFIGURATION) {
+ image = MvnImages.IMG_PARAMETER;
+ } else {
+ //other suggestions from the templatecontext are to be text inside the element, not actual
+ //elements..
+ image = null;
+ }
+
+ Template[] templates = templateContext.getTemplates(project, currentNode, prefix);
+ for(Template template : templates) {
+ TemplateProposal proposal = createProposalForTemplate(prefix, region, context, image, template, false);
+ if (proposal != null) {
+ matches.add(proposal);
+ }
+ }
+
+
+ if (templateContext!=PomTemplateContext.VERSION) {
+ // versions are already sorted with o.a.m.artifact.versioning.ComparableVersion
+ Collections.sort(matches, PROPOSAL_COMPARATOR);
+ }
+
+ return (ICompletionProposal[]) matches.toArray(new ICompletionProposal[matches.size()]);
+
+ }
+
+ private TemplateProposal createProposalForTemplate(String prefix, Region region, TemplateContext context, Image image,
+ final Template template, boolean isUserTemplate) {
+ try {
+ context.getContextType().validate(template.getPattern());
+ if(template.matches(prefix, context.getContextType().getId())) {
+ if (isUserTemplate) {
+ //for templates defined by users, preserve the default behaviour..
+ return new TemplateProposal(template, context, region, image, getRelevance(template, prefix)) {
+ public String getAdditionalProposalInfo() {
+ return StringUtils.convertToHTMLContent(super.getAdditionalProposalInfo());
+ }
+ };
+ } else {
+ return new TemplateProposal(template, context, region, image, getRelevance(template, prefix)) {
+ public String getAdditionalProposalInfo() {
+ return getTemplate().getDescription();
+ }
+
+ public String getDisplayString() {
+ return template.getName();
+ }
+ };
+ }
+ }
+ } catch(TemplateException e) {
+ // ignore
+ }
+
+ return null;
+ }
+
+ protected TemplateContext createContext(ITextViewer viewer, IRegion region, String contextTypeId) {
+ TemplateContextType contextType= getContextType(viewer, region, contextTypeId);
+ if (contextType != null) {
+ IDocument document= viewer.getDocument();
+ return new DocumentTemplateContext(contextType, document, region.getOffset(), region.getLength());
+ }
+ return null;
+ }
+
+ //TODO we should have different relevance for user defined templates and generated proposals..
+ protected int getRelevance(Template template, String prefix) {
+ if (template.getName().startsWith(prefix))
+ return 90;
+ return 0;
+ }
+
+ protected TemplateContextType getContextType(ITextViewer viewer, IRegion region, String contextTypeId) {
+ ContextTypeRegistry registry = MvnIndexPlugin.getDefault().getTemplateContextRegistry();
+ if(registry != null) {
+ return registry.getContextType(contextTypeId);
+ }
+ return null;
+ }
+
+ public static final String extractPrefix(ITextViewer viewer, int offset) {
+ int i = offset;
+ IDocument document = viewer.getDocument();
+ if(i > document.getLength()) {
+ return ""; //$NON-NLS-1$
+ }
+
+ try {
+ while(i > 0) {
+ char ch = document.getChar(i - 1);
+ if(ch == '>' || ch == '<' || ch == ' ' || ch == '\n' || ch == '\t') {
+ break;
+ }
+ i-- ;
+ }
+ return document.get(i, offset - i);
+ } catch(BadLocationException e) {
+ return ""; //$NON-NLS-1$
+ }
+ }
+
+
+ static final class ProposalComparator implements Comparator<TemplateProposal> {
+ public int compare(TemplateProposal o1, TemplateProposal o2) {
+ int res = o2.getRelevance() - o1.getRelevance();
+ if(res == 0) {
+ res = o1.getDisplayString().compareTo(o2.getDisplayString());
+ }
+ return res;
+ }
+ }
+
+}
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomContentOutlineConfiguration.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomContentOutlineConfiguration.java
new file mode 100644
index 00000000..60b4b27a
--- /dev/null
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomContentOutlineConfiguration.java
@@ -0,0 +1,358 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.editor.xml;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.wst.xml.ui.views.contentoutline.XMLContentOutlineConfiguration;
+
+
+/**
+ * @author Eugene Kuleshov
+ */
+public class PomContentOutlineConfiguration extends XMLContentOutlineConfiguration {
+
+ public ILabelProvider getLabelProvider(TreeViewer viewer) {
+ return new PomLabelProvider(super.getLabelProvider(viewer));
+ }
+
+ /**
+ * POM label provider
+ */
+ private final class PomLabelProvider implements ILabelProvider {
+
+ private static final String TARGET_PATH = "targetPath"; //$NON-NLS-1$
+
+ private static final String DIRECTORY = "directory"; //$NON-NLS-1$
+
+ private static final String REPORT_SET = "reportSet"; //$NON-NLS-1$
+
+ private static final String PROPERTIES = "properties"; //$NON-NLS-1$
+
+ private static final String REPORTING = "reporting"; //$NON-NLS-1$
+
+ private static final String BUILD = "build"; //$NON-NLS-1$
+
+ private static final String EXCLUDE = "exclude"; //$NON-NLS-1$
+
+ private static final String INCLUDE = "include"; //$NON-NLS-1$
+
+ private static final String FILTER = "filter"; //$NON-NLS-1$
+
+ private static final String TEST_RESOURCE = "testResource"; //$NON-NLS-1$
+
+ private static final String RESOURCE = "resource"; //$NON-NLS-1$
+
+ private static final String TEST_RESOURCES = "testResources"; //$NON-NLS-1$
+
+ private static final String RESOURCES = "resources"; //$NON-NLS-1$
+
+ private static final String GOAL = "goal"; //$NON-NLS-1$
+
+ private static final String EXECUTION = "execution"; //$NON-NLS-1$
+
+ private static final String PLUGIN = "plugin"; //$NON-NLS-1$
+
+ private static final String PLUGINS = "plugins"; //$NON-NLS-1$
+
+ private static final String SNAPSHOT_REPOSITORY = "snapshotRepository"; //$NON-NLS-1$
+
+ private static final String PLUGIN_REPOSITORY = "pluginRepository"; //$NON-NLS-1$
+
+ private static final String REPOSITORY = "repository"; //$NON-NLS-1$
+
+ private static final String SITE = "site"; //$NON-NLS-1$
+
+ private static final String CONTRIBUTOR = "contributor"; //$NON-NLS-1$
+
+ private static final String DEVELOPER = "developer"; //$NON-NLS-1$
+
+ private static final String PROFILE = "profile"; //$NON-NLS-1$
+
+ private static final String PROFILES = "profiles"; //$NON-NLS-1$
+
+ private static final String MODULE = "module"; //$NON-NLS-1$
+
+ private static final String EXTENSION = "extension"; //$NON-NLS-1$
+
+ private static final String EXCLUSION = "exclusion"; //$NON-NLS-1$
+
+ private static final String MODULES = "modules"; //$NON-NLS-1$
+
+ private static final String EXTENSIONS = "extensions"; //$NON-NLS-1$
+
+ private static final String EXCLUSIONS = "exclusions"; //$NON-NLS-1$
+
+ private static final String DEPENDENCIES = "dependencies"; //$NON-NLS-1$
+
+ private static final String PARENT = "parent"; //$NON-NLS-1$
+
+ private static final String SCOPE = "scope"; //$NON-NLS-1$
+
+ private static final String TYPE = "type"; //$NON-NLS-1$
+
+ private static final String CLASSIFIER = "classifier"; //$NON-NLS-1$
+
+ private static final String DEPENDENCY = "dependency"; //$NON-NLS-1$
+
+ private static final String ID = "id"; //$NON-NLS-1$
+
+ private static final String EMAIL = "email"; //$NON-NLS-1$
+
+ private static final String NAME = "name"; //$NON-NLS-1$
+
+ private static final String VERSION = "version"; //$NON-NLS-1$
+
+ private static final String GROUP_ID = "groupId"; //$NON-NLS-1$
+
+ private static final String ARTIFACT_ID = "artifactId"; //$NON-NLS-1$
+
+ private static final String NAMESPACE_POM = "http://maven.apache.org/POM/4.0.0"; //$NON-NLS-1$
+
+ private static final int MAX_LABEL_LENGTH = 120;
+
+ private final ILabelProvider labelProvider;
+
+ private PomLabelProvider(ILabelProvider labelProvider) {
+ this.labelProvider = labelProvider;
+ }
+
+ public Image getImage(Object element) {
+ Node node = (Node) element;
+ String namespace = node.getNamespaceURI();
+ String nodeName = node.getNodeName();
+
+ if(node.getNodeType()==Node.COMMENT_NODE) {
+ return labelProvider.getImage(element);
+ }
+
+ if(NAMESPACE_POM.equals(namespace)) {
+ if(PARENT.equals(nodeName)) {
+ return MvnImages.IMG_JAR;
+
+ } else if(DEPENDENCIES.equals(nodeName) //
+ || EXCLUSIONS.equals(nodeName) //
+ || EXTENSIONS.equals(nodeName) //
+ || MODULES.equals(nodeName)) {
+ return MvnImages.IMG_JARS;
+
+ } else if(DEPENDENCY.equals(nodeName) //
+ || EXCLUSION.equals(nodeName) //
+ || EXTENSION.equals(nodeName) //
+ || MODULE.equals(nodeName)) {
+ // TODO show folder if module is in the workspace
+ return MvnImages.IMG_JAR;
+
+ } else if(REPOSITORY.equals(nodeName) || PLUGIN_REPOSITORY.equals(nodeName)
+ || SNAPSHOT_REPOSITORY.equals(nodeName) || SITE.equals(nodeName)) {
+ return MvnImages.IMG_REPOSITORY;
+
+ } else if(PROFILES.equals(nodeName)) {
+ return MvnImages.IMG_PROFILES;
+
+ } else if(PROFILE.equals(nodeName)) {
+ return MvnImages.IMG_PROFILE;
+
+ } else if(DEVELOPER.equals(nodeName) || CONTRIBUTOR.equals(nodeName)) {
+ return MvnImages.IMG_PERSON;
+
+ } else if(PLUGINS.equals(nodeName)) {
+ return MvnImages.IMG_PLUGINS;
+
+ } else if(PLUGIN.equals(nodeName)) {
+ return MvnImages.IMG_PLUGIN;
+
+ } else if(EXECUTION.equals(nodeName)) {
+ return MvnImages.IMG_EXECUTION;
+
+ } else if(GOAL.equals(nodeName)) {
+ return MvnImages.IMG_GOAL;
+
+ } else if(RESOURCES.equals(nodeName) //
+ || TEST_RESOURCES.equals(nodeName)) {
+ return MvnImages.IMG_RESOURCES;
+
+ } else if(RESOURCE.equals(nodeName) //
+ || TEST_RESOURCE.equals(nodeName)) {
+ return MvnImages.IMG_RESOURCE;
+
+ } else if(FILTER.equals(nodeName)) {
+ return MvnImages.IMG_FILTER;
+
+ } else if(INCLUDE.equals(nodeName)) {
+ return MvnImages.IMG_INCLUDE;
+
+ } else if(EXCLUDE.equals(nodeName)) {
+ return MvnImages.IMG_EXCLUDE;
+
+ } else if(BUILD.equals(nodeName)) {
+ return MvnImages.IMG_BUILD;
+
+ } else if(REPORTING.equals(nodeName)) {
+ return MvnImages.IMG_REPORT;
+
+ } else if(PROPERTIES.equals(nodeName)) {
+ return MvnImages.IMG_PROPERTIES;
+
+ } else if(PROPERTIES.equals(node.getParentNode().getNodeName())) {
+ return MvnImages.IMG_PROPERTY;
+
+ // } else if("mailingList".equals(nodeName)) {
+ // return MvnImages.IMG_MAIL;
+
+ }
+
+ return MvnImages.IMG_ELEMENT;
+ }
+
+ return labelProvider.getImage(element);
+ }
+
+ public String getText(Object element) {
+ String text = labelProvider.getText(element);
+
+ Node node = (Node) element;
+ String namespace = node.getNamespaceURI();
+ String nodeName = node.getNodeName();
+
+ if(node.getNodeType()==Node.COMMENT_NODE) {
+ return cleanText(node);
+ }
+
+ if(NAMESPACE_POM.equals(namespace)) {
+ if(PARENT.equals(nodeName)) {
+ return getLabel(text, node, GROUP_ID, ARTIFACT_ID, VERSION);
+
+ } else if(DEPENDENCY.equals(nodeName)) {
+ return getLabel(text, node, GROUP_ID, ARTIFACT_ID, VERSION, CLASSIFIER, TYPE, SCOPE);
+
+ } else if(EXCLUSION.equals(nodeName)) {
+ return getLabel(text, node, GROUP_ID, ARTIFACT_ID);
+
+ } else if(EXTENSION.equals(nodeName)) {
+ return getLabel(text, node, GROUP_ID, ARTIFACT_ID, VERSION);
+
+ } else if(REPOSITORY.equals(nodeName) || PLUGIN_REPOSITORY.equals(nodeName)
+ || SNAPSHOT_REPOSITORY.equals(nodeName) || SITE.equals(nodeName) || PROFILE.equals(nodeName)
+ || EXECUTION.equals(nodeName)) {
+ return getLabel(text, node, ID);
+
+ } else if("mailingList".equals(nodeName)) { //$NON-NLS-1$
+ return getLabel(text, node, NAME);
+
+ } else if(DEVELOPER.equals(nodeName)) {
+ return getLabel(text, node, ID, NAME, EMAIL);
+
+ } else if(CONTRIBUTOR.equals(nodeName)) {
+ return getLabel(text, node, NAME, EMAIL);
+
+ } else if(PLUGIN.equals(nodeName)) {
+ return getLabel(text, node, GROUP_ID, ARTIFACT_ID, VERSION);
+
+ } else if(RESOURCE.equals(nodeName) || TEST_RESOURCE.equals(nodeName)) {
+ return getLabel(text, node, DIRECTORY, TARGET_PATH);
+
+ } else if(REPORT_SET.equals(nodeName)) {
+ return getLabel(text, node, ID);
+
+ } else if(EXECUTION.equals(nodeName)) {
+ return getLabel(text, node, ID);
+
+ }
+
+ NodeList childNodes = node.getChildNodes();
+ if(childNodes.getLength()==1) {
+ Node item = childNodes.item(0);
+ short nodeType = item.getNodeType();
+ if(nodeType==Node.TEXT_NODE || nodeType==Node.COMMENT_NODE) {
+ String nodeText = item.getNodeValue();
+ if(nodeText.length()>0) {
+ return text + " " + cleanText(item); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+
+ return text;
+ }
+
+ public boolean isLabelProperty(Object element, String name) {
+ return labelProvider.isLabelProperty(element, name);
+ }
+
+ public void addListener(ILabelProviderListener listener) {
+ labelProvider.addListener(listener);
+ }
+
+ public void removeListener(ILabelProviderListener listener) {
+ labelProvider.removeListener(listener);
+ }
+
+ public void dispose() {
+ labelProvider.dispose();
+ }
+
+ private String getLabel(String text, Node node, String... names) {
+ StringBuilder sb = new StringBuilder(text).append(" "); //$NON-NLS-1$
+ String sep = ""; //$NON-NLS-1$
+ for(String name : names) {
+ String value = getValue(node, name);
+ if(value!=null) {
+ sb.append(sep).append(value);
+ sep = " : "; //$NON-NLS-1$
+ }
+ }
+
+ return sb.toString();
+ }
+
+ private String getValue(Node node, String name) {
+ NodeList childNodes = node.getChildNodes();
+ for(int i = 0; i < childNodes.getLength(); i++ ) {
+ Node item = childNodes.item(i);
+ if(item.getNodeType()==Node.ELEMENT_NODE && name.equals(item.getNodeName())) {
+ NodeList nodes = item.getChildNodes();
+ if(nodes.getLength()==1) {
+ String value = nodes.item(0).getNodeValue().trim();
+ if(value.length()>0) {
+ return value;
+ }
+ }
+ return null;
+ }
+ }
+ return null;
+ }
+
+ private String cleanText(Node node) {
+ String value = node.getNodeValue();
+ if (value==null) {
+ return ""; //$NON-NLS-1$
+ }
+
+ value = value.replaceAll("\\s", " ").replaceAll("(\\s){2,}", " ").trim(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ if (value.length() > MAX_LABEL_LENGTH) {
+ value = value.substring(0, 120) + Dialog.ELLIPSIS;
+ }
+
+ return value;
+ }
+ }
+
+}
+
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomHyperlinkDetector.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomHyperlinkDetector.java
new file mode 100644
index 00000000..25c71c7c
--- /dev/null
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomHyperlinkDetector.java
@@ -0,0 +1,729 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.editor.xml;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.maven.model.Build;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.model.DependencyManagement;
+import org.apache.maven.model.InputLocation;
+import org.apache.maven.model.InputSource;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.model.PluginManagement;
+import org.apache.maven.project.MavenProject;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Text;
+
+import org.eclipse.core.filebuffers.FileBuffers;
+import org.eclipse.core.filebuffers.ITextFileBuffer;
+import org.eclipse.core.filesystem.EFS;
+import org.eclipse.core.filesystem.IFileStore;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+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.dialogs.MessageDialog;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.Region;
+import org.eclipse.jface.text.hyperlink.IHyperlink;
+import org.eclipse.jface.text.hyperlink.IHyperlinkDetector;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.forms.editor.FormEditor;
+import org.eclipse.ui.ide.IDE;
+import org.eclipse.wst.sse.core.StructuredModelManager;
+import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
+import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion;
+import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
+import org.eclipse.wst.sse.ui.StructuredTextEditor;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.actions.OpenPomAction;
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+import org.eclipse.m2e.editor.xml.internal.Messages;
+
+
+/**
+ * @author Eugene Kuleshov
+ * @author Milos Kleint
+ */
+public class PomHyperlinkDetector implements IHyperlinkDetector {
+
+ private final String[] versioned = new String[] {
+ "dependency>", //$NON-NLS-1$
+ "parent>", //$NON-NLS-1$
+ "plugin>", //$NON-NLS-1$
+ "reportPlugin>", //$NON-NLS-1$
+ "extension>" //$NON-NLS-1$
+ };
+ public IHyperlink[] detectHyperlinks(ITextViewer textViewer, final IRegion region, boolean canShowMultipleHyperlinks) {
+ if(region == null || textViewer == null) {
+ return null;
+ }
+
+ IDocument document = textViewer.getDocument();
+ if(document == null) {
+ return null;
+ }
+
+ IRegion lineInfo;
+ String line;
+ try {
+ lineInfo = document.getLineInformationOfOffset(region.getOffset());
+ line = document.get(lineInfo.getOffset(), lineInfo.getLength());
+ } catch(BadLocationException ex) {
+ return null;
+ }
+
+ if(line.length() == 0) {
+ return null;
+ }
+ List<IHyperlink> hyperlinks = new ArrayList<IHyperlink>();
+ final int offset = region.getOffset();
+ final String text = document.get();
+ Node current = getCurrentNode(document, offset);
+ //check if we have a property expression at cursor
+ IHyperlink link = openPropertyDefinition(current, textViewer, offset);
+ if (link != null) {
+ hyperlinks.add(link);
+ }
+ //now check if the dependency/plugin has a version element or not, if not, try searching for it in DM/PM of effective pom
+ link = openDPManagement(current, textViewer, offset);
+ if (link != null) {
+ hyperlinks.add(link);
+ }
+
+ //first check all elements that have id (groupId+artifactId+version) combo
+ Fragment fragment = null;
+ //TODO rewrite to use Nodes
+ for (String el : versioned) {
+ fragment = getFragment(text, offset, "<" + el, "</" + el); //$NON-NLS-1$ //$NON-NLS-2$
+ if (fragment != null) break;
+ }
+
+ if (fragment != null) {
+ link = openPOMbyID(fragment, textViewer);
+ if (link != null) {
+ hyperlinks.add(link);
+ }
+ }
+ //check if <module> text is selected.
+ //TODO rewrite to use Nodes
+ fragment = getFragment(text, offset, "<module>", "</module>"); //$NON-NLS-1$ //$NON-NLS-2$
+ if (fragment != null) {
+ link = openModule(fragment, textViewer);
+ if (link != null) {
+ hyperlinks.add(link);
+ }
+ }
+ if (hyperlinks.size() > 0) {
+ return hyperlinks.toArray(new IHyperlink[0]);
+ }
+ return null;
+ }
+
+ static ManagedArtifactRegion findManagedArtifactRegion(Node current, ITextViewer textViewer, int offset) {
+ while (current != null && !( current instanceof Element)) {
+ current = current.getParentNode();
+ }
+ if (current != null) {
+ Node artNode = null;
+ Node groupNode = null;
+ if ("artifactId".equals(current.getNodeName())) { //$NON-NLS-1$
+ artNode = current;
+ }
+ if ("groupId".equals(current.getNodeName())) { //$NON-NLS-1$
+ groupNode = current;
+ }
+ //only on artifactid and groupid elements..
+ if (artNode == null && groupNode == null) {
+ return null;
+ }
+ Node root = current.getParentNode();
+ boolean isDependency = false;
+ boolean isPlugin = false;
+ if (root != null) {
+ String name = root.getNodeName();
+ if ("dependency".equals(name)) { //$NON-NLS-1$
+ isDependency = true;
+ }
+ if ("plugin".equals(name)) { //$NON-NLS-1$
+ isPlugin = true;
+ }
+ } else {
+ return null;
+ }
+ if (!isDependency && !isPlugin) {
+ //some kind of other identifier
+ return null;
+ }
+ //now see if version is missing
+ NodeList childs = root.getChildNodes();
+ for (int i = 0; i < childs.getLength(); i++) {
+ Node child = childs.item(i);
+ if (child instanceof Element) {
+ Element el = (Element) child;
+ if ("version".equals(el.getNodeName())) { //$NON-NLS-1$
+ return null;
+ }
+ if (artNode == null && "artifactId".equals(el.getNodeName())) { //$NON-NLS-1$
+ artNode = el;
+ }
+ if (groupNode == null && "groupId".equals(el.getNodeName())) { //$NON-NLS-1$
+ groupNode = el;
+ }
+ }
+ }
+ if (groupNode != null && artNode != null) {
+ assert groupNode instanceof IndexedRegion;
+ assert artNode instanceof IndexedRegion;
+
+ IndexedRegion groupReg = (IndexedRegion)groupNode;
+ IndexedRegion artReg = (IndexedRegion)artNode;
+ int startOffset = Math.min(groupReg.getStartOffset(), artReg.getStartOffset());
+ int length = Math.max(groupReg.getEndOffset(), artReg.getEndOffset()) - startOffset;
+ String groupId = getElementTextValue(groupNode);
+ String artifactId = getElementTextValue(artNode);
+ //TODO we shall rely on presence of a cached model, not project alone..
+ final IProject prj = PomContentAssistProcessor.extractProject(textViewer);
+ if (prj != null) {
+ //now we can create the region I guess,
+ return new ManagedArtifactRegion(startOffset, length, groupId, artifactId, isDependency, isPlugin, prj);
+ }
+ }
+ }
+ return null;
+ }
+
+ private IHyperlink openDPManagement(Node current, ITextViewer textViewer, int offset) {
+ final ManagedArtifactRegion region = findManagedArtifactRegion(current, textViewer, offset);
+ if (region != null) {
+ return new IHyperlink() {
+ public IRegion getHyperlinkRegion() {
+ return region;
+ }
+
+ public String getHyperlinkText() {
+ return NLS.bind(Messages.PomHyperlinkDetector_link_managed, "" + region.groupId + ":" + region.artifactId);
+ }
+
+ public String getTypeLabel() {
+ return "pom-dependency-plugin-management"; //$NON-NLS-1$
+ }
+
+ public void open() {
+ //see if we can find the plugin in plugin management of resolved project.
+ IMavenProjectFacade mvnproject = MavenPlugin.getDefault().getMavenProjectManager().getProject(region.project);
+ if (mvnproject != null) {
+ MavenProject mavprj = mvnproject.getMavenProject();
+ if (mavprj != null) {
+ InputLocation openLocation = findLocationForManagedArtifact(region, mavprj);
+ if (openLocation != null) {
+ File file = fileForInputLocation(openLocation);
+ if (file != null) {
+ IFileStore fileStore = EFS.getLocalFileSystem().getStore(file.toURI());
+ openXmlEditor(fileStore, openLocation.getLineNumber(), openLocation.getColumnNumber());
+ }
+ }
+ }
+ }
+ }
+ };
+ }
+ return null;
+ }
+
+
+ static InputLocation findLocationForManagedArtifact(final ManagedArtifactRegion region, MavenProject mavprj) {
+ Model mdl = mavprj.getModel();
+ InputLocation openLocation = null;
+ if (region.isDependency) {
+ DependencyManagement dm = mdl.getDependencyManagement();
+ if (dm != null) {
+ List<Dependency> list = dm.getDependencies();
+ String id = region.groupId + ":" + region.artifactId + ":"; //$NON-NLS-1$ //$NON-NLS-2$
+ if (list != null) {
+ for (Dependency dep : list) {
+ if (dep.getManagementKey().startsWith(id)) {
+ InputLocation location = dep.getLocation("artifactId"); //$NON-NLS-1$
+ //when would this be null?
+ if (location != null) {
+ openLocation = location;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ if (region.isPlugin) {
+ Build build = mdl.getBuild();
+ if (build != null) {
+ PluginManagement pm = build.getPluginManagement();
+ if (pm != null) {
+ List<Plugin> list = pm.getPlugins();
+ String id = Plugin.constructKey(region.groupId, region.artifactId);
+ if (list != null) {
+ for (Plugin plg : list) {
+ if (id.equals(plg.getKey())) {
+ InputLocation location = plg.getLocation("artifactId"); //$NON-NLS-1$
+ //when would this be null?
+ if (location != null) {
+ openLocation = location;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return openLocation;
+ }
+
+ static String getElementTextValue(Node element) {
+ if (element == null) return null;
+ StringBuffer buff = new StringBuffer();
+ NodeList list = element.getChildNodes();
+ for (int i = 0; i < list.getLength(); i++) {
+ Node child = list.item(i);
+ if (child instanceof Text) {
+ Text text = (Text)child;
+ buff.append(text.getData());
+ }
+ }
+ return buff.toString();
+ }
+
+ static ExpressionRegion findExpressionRegion(Node current, ITextViewer viewer, int offset) {
+ if (current != null && current instanceof Text) {
+ Text node = (Text)current;
+ String value = node.getNodeValue();
+ if (value != null) {
+ assert node instanceof IndexedRegion;
+ IndexedRegion reg = (IndexedRegion)node;
+ int index = offset - reg.getStartOffset();
+ String before = value.substring(0, Math.min (index + 1, value.length()));
+ String after = value.substring(Math.min (index + 1, value.length()));
+ int start = before.lastIndexOf("${"); //$NON-NLS-1$
+ if (before.lastIndexOf("}") > start) {//$NON-NLS-1$
+ //we might be in between two expressions..
+ start = -1;
+ }
+ int end = after.indexOf("}"); //$NON-NLS-1$
+ if (after.indexOf("${") != -1 && after.indexOf("${") < end) {//$NON-NLS-1$
+ //we might be in between two expressions..
+ end = -1;
+ }
+ if (start > -1 && end > -1) {
+ final int startOffset = reg.getStartOffset() + start;
+ final String expr = before.substring(start) + after.substring(0, end + 1);
+ final int length = expr.length();
+ final String prop = before.substring(start + 2) + after.substring(0, end);
+// there are often properties that start with project. eg. project.build.sourceEncoding
+// if (prop.startsWith("project.") || prop.startsWith("pom.")) { //$NON-NLS-1$ //$NON-NLS-2$
+// return null; //ignore these, not in properties section.
+// }
+ final IProject prj = PomContentAssistProcessor.extractProject(viewer);
+ //TODO we shall rely on presence of a cached model, not project alone.. ]MNGECLIPSE-2540
+ if (prj != null) {
+ return new ExpressionRegion(startOffset, length, prop, prj);
+ }
+ }
+ }
+ }
+ return null;
+ }
+ /**
+ * converts an InputLocation to a file path on the local disk, null if not available.
+ * still the input source's model value can be used further..
+ * @param location
+ * @return
+ */
+ static File fileForInputLocation(InputLocation location) {
+ InputSource source = location.getSource();
+ if (source != null) {
+ //MNGECLIPSE-2539 apparently if maven can't resolve the model from local storage,
+ //the location will be empty. not only applicable to local repo models but
+ //apparently also to models in workspace not reachable by relativePath
+ String loc = source.getLocation();
+ File file = null;
+ if (loc != null) {
+ file = new File(loc);
+ } else {
+ //try to find pom by coordinates..
+ String modelId = source.getModelId();
+ String[] splitStrings = modelId.split(":");
+ assert splitStrings.length == 3;
+ IMavenProjectFacade facade = MavenPlugin.getDefault().getMavenProjectManager().getMavenProject(splitStrings[0], splitStrings[1], splitStrings[2]);
+ if (facade != null) {
+ file = facade.getPomFile();
+ }
+ }
+ return file;
+ }
+ return null;
+ }
+
+
+ private IHyperlink openPropertyDefinition(Node current, ITextViewer viewer, int offset) {
+ final ExpressionRegion region = findExpressionRegion(current, viewer, offset);
+ if (region != null) {
+ return new IHyperlink() {
+ public IRegion getHyperlinkRegion() {
+ return region;
+ }
+
+ public String getHyperlinkText() {
+ return NLS.bind(Messages.PomHyperlinkDetector_open_property, region.property);
+ }
+
+ public String getTypeLabel() {
+ return "pom-property-expression"; //$NON-NLS-1$
+ }
+
+ public void open() {
+ //see if we can find the plugin in plugin management of resolved project.
+ IMavenProjectFacade mvnproject = MavenPlugin.getDefault().getMavenProjectManager().getProject(region.project);
+ if(mvnproject != null) {
+ MavenProject mavprj = mvnproject.getMavenProject();
+ if(mavprj != null) {
+ Model mdl = mavprj.getModel();
+ if (mdl.getProperties().containsKey(region.property)) {
+ InputLocation location = mdl.getLocation( "properties" ).getLocation( region.property ); //$NON-NLS-1$
+ if (location != null) {
+ File file = fileForInputLocation(location);
+ if (file != null) {
+ IFileStore fileStore = EFS.getLocalFileSystem().getStore(file.toURI());
+ openXmlEditor(fileStore, location.getLineNumber(), location.getColumnNumber());
+ }
+ }
+ }
+ }
+ }
+ }
+ };
+ }
+ return null;
+ }
+
+ private IHyperlink openModule(Fragment fragment, ITextViewer textViewer) {
+ final Fragment module = getValue(fragment, "<module>", "</module>"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ ITextFileBuffer buf = FileBuffers.getTextFileBufferManager().getTextFileBuffer(textViewer.getDocument());
+ IFileStore folder = buf.getFileStore().getParent();
+
+ String path = module.text;
+ //construct IPath for the child pom file, handle relative paths..
+ while(folder != null && path.startsWith("../")) { //NOI18N //$NON-NLS-1$
+ folder = folder.getParent();
+ path = path.substring("../".length());//NOI18N //$NON-NLS-1$
+ }
+ if(folder == null) {
+ return null;
+ }
+ IFileStore modulePom = folder.getChild(path);
+ if(!modulePom.getName().endsWith("xml")) {//NOI18N //$NON-NLS-1$
+ modulePom = modulePom.getChild("pom.xml");//NOI18N //$NON-NLS-1$
+ }
+ final IFileStore fileStore = modulePom;
+ if (!fileStore.fetchInfo().exists()) {
+ return null;
+ }
+
+ IHyperlink pomHyperlink = new IHyperlink() {
+ public IRegion getHyperlinkRegion() {
+ return new Region(module.offset, module.length);
+ }
+
+ public String getHyperlinkText() {
+ return NLS.bind(Messages.PomHyperlinkDetector_open_module, module.text);
+ }
+
+ public String getTypeLabel() {
+ return "pom-module"; //$NON-NLS-1$
+ }
+
+ public void open() {
+ openXmlEditor(fileStore);
+ }
+ };
+
+ return pomHyperlink;
+
+ }
+
+ private IHyperlink openPOMbyID(Fragment fragment, final ITextViewer viewer) {
+ final Fragment groupId = getValue(fragment, "<groupId>", "</groupId>"); //$NON-NLS-1$ //$NON-NLS-2$
+ final Fragment artifactId = getValue(fragment, "<artifactId>", Messages.PomHyperlinkDetector_23); //$NON-NLS-1$
+ final Fragment version = getValue(fragment, "<version>", "</version>"); //$NON-NLS-1$ //$NON-NLS-2$
+ final IProject prj = PomContentAssistProcessor.extractProject(viewer);
+
+ IHyperlink pomHyperlink = new IHyperlink() {
+ public IRegion getHyperlinkRegion() {
+ //the goal here is to have the groupid/artifactid/version combo underscored by the link.
+ //that will prevent underscoring big portions (like plugin config) underscored and
+ // will also handle cases like dependencies within plugins.
+ int max = groupId != null ? groupId.offset + groupId.length : Integer.MIN_VALUE;
+ int min = groupId != null ? groupId.offset : Integer.MAX_VALUE;
+ max = Math.max(max, artifactId != null ? artifactId.offset + artifactId.length : Integer.MIN_VALUE);
+ min = Math.min(min, artifactId != null ? artifactId.offset : Integer.MAX_VALUE);
+ max = Math.max(max, version != null ? version.offset + version.length : Integer.MIN_VALUE);
+ min = Math.min(min, version != null ? version.offset : Integer.MAX_VALUE);
+ return new Region(min, max - min);
+ }
+
+ public String getHyperlinkText() {
+ return NLS.bind(Messages.PomHyperlinkDetector_hyperlink_pattern, groupId, artifactId);
+ }
+
+ public String getTypeLabel() {
+ return "pom"; //$NON-NLS-1$
+ }
+
+ public void open() {
+ new Job(Messages.PomHyperlinkDetector_job_name) {
+ protected IStatus run(IProgressMonitor monitor) {
+ // TODO resolve groupId if groupId==null
+ String gridString = groupId == null ? "org.apache.maven.plugins" : groupId.text; //$NON-NLS-1$
+ String artidString = artifactId == null ? null : artifactId.text;
+ String versionString = version == null ? null : version.text;
+ if (prj != null && gridString != null && artidString != null && (version == null || version.text.contains("${"))) { //$NON-NLS-1$
+ try {
+ //TODO how do we decide here if the hyperlink is a dependency or a plugin
+ // hyperlink??
+ versionString = PomTemplateContext.extractVersion(prj, versionString, gridString, artidString, PomTemplateContext.EXTRACT_STRATEGY_DEPENDENCY);
+
+ } catch(CoreException e) {
+ versionString = null;
+ }
+ }
+ if (versionString == null) {
+ return Status.OK_STATUS;
+ }
+ OpenPomAction.openEditor(gridString,
+ artidString,
+ versionString, monitor);
+ return Status.OK_STATUS;
+ }
+ }.schedule();
+ }
+
+ };
+
+ return pomHyperlink;
+ }
+
+ /**
+ * fragment offset returned contains the xml elements
+ * while the text only includes the element text value
+ */
+ private Fragment getValue(Fragment section, String startTag, String endTag) {
+ int start = section.text.indexOf(startTag);
+ if(start == -1) {
+ return null;
+ }
+ int end = section.text.indexOf(endTag);
+ if(end == -1) {
+ return null;
+ }
+
+ return new Fragment(section.text.substring(start + startTag.length(), end).trim(), section.offset + start, end + endTag.length() - start);
+ }
+
+ /**
+ * returns the text, offset and length of the xml element. text includes the xml tags.
+ */
+ private Fragment getFragment(String text, int offset, String startTag, String endTag) {
+ int start = text.substring(0, offset).lastIndexOf(startTag);
+ if(start == -1) {
+ return null;
+ }
+
+ int end = text.indexOf(endTag, start);
+ if(end == -1 || end <= offset) {
+ return null;
+ }
+ end = end + endTag.length();
+ return new Fragment(text.substring(start, end), start, end - start);
+ }
+
+ private static class Fragment {
+ final int length;
+ final int offset;
+ final String text;
+
+ Fragment(String text, int start, int len) {
+ this.text = text;
+ this.offset = start;
+
+ this.length = len;
+
+ }
+
+ @Override
+ public String toString() {
+ return text;
+ }
+ }
+
+
+ /**
+ * copied from org.eclipse.wst.xml.ui.internal.hyperlink.XMLHyperlinkDetector
+ * Returns the node the cursor is currently on in the document. null if no
+ * node is selected
+ *
+ * returned value is also an instance of IndexedRegion
+ *
+ * @param offset
+ * @return Node either element, doctype, text, or null
+ */
+ static Node getCurrentNode(IDocument document, int offset) {
+ // get the current node at the offset (returns either: element,
+ // doctype, text)
+ IndexedRegion inode = null;
+ IStructuredModel sModel = null;
+ try {
+ sModel = StructuredModelManager.getModelManager().getExistingModelForRead(document);
+ if (sModel != null) {
+ inode = sModel.getIndexedRegion(offset);
+ if (inode == null) {
+ inode = sModel.getIndexedRegion(offset - 1);
+ }
+ }
+ }
+ finally {
+ if (sModel != null) {
+ sModel.releaseFromRead();
+ }
+ }
+
+ if (inode instanceof Node) {
+ return (Node) inode;
+ }
+ return null;
+ }
+
+ private void openXmlEditor(final IFileStore fileStore) {
+ openXmlEditor(fileStore, -1, -1);
+ }
+
+ private void openXmlEditor(final IFileStore fileStore, int line, int column) {
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ if(window != null) {
+ IWorkbenchPage page = window.getActivePage();
+ if(page != null) {
+ try {
+ IEditorPart part = IDE.openEditorOnFileStore(page, fileStore);
+ if(part instanceof FormEditor) {
+ FormEditor ed = (FormEditor) part;
+ ed.setActivePage(null); //null means source, always or just in the case of MavenPomEditor?
+ if(line != -1) {
+ if(ed.getActiveEditor() instanceof StructuredTextEditor) {
+ StructuredTextEditor structured = (StructuredTextEditor) ed.getActiveEditor();
+ // convert the line and Column numbers to an offset:
+ IDocument doc = structured.getTextViewer().getDocument();
+ if (doc instanceof IStructuredDocument) {
+ IStructuredDocument document = (IStructuredDocument) doc;
+ try {
+ int offset = document.getLineOffset(line - 1);
+ structured.selectAndReveal(offset + column - 1, 0);
+ } catch(BadLocationException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ }
+ } catch(PartInitException e) {
+ MessageDialog.openInformation(
+ Display.getDefault().getActiveShell(), //
+ Messages.PomHyperlinkDetector_error_title,
+ NLS.bind(Messages.PomHyperlinkDetector_error_message, fileStore, e.toString()));
+
+ }
+ }
+ }
+ }
+
+
+ static class ExpressionRegion implements IRegion {
+
+ final String property;
+ private int length;
+ private int offset;
+ final IProject project;
+
+ public ExpressionRegion(int startOffset, int length, String prop, IProject project) {
+ this.offset = startOffset;
+ this.length = length;
+ this.property = prop;
+ this.project = project;
+ }
+
+ public int getLength() {
+ return length;
+ }
+
+ public int getOffset() {
+ return offset;
+ }
+ }
+
+ static class ManagedArtifactRegion implements IRegion {
+
+ private int length;
+ private int offset;
+ final IProject project;
+ final String groupId;
+ final String artifactId;
+ final boolean isPlugin;
+ final boolean isDependency;
+
+ public ManagedArtifactRegion(int startOffset, int length, String groupId, String artifactId, boolean isDependency, boolean isPlugin, IProject project) {
+ this.offset = startOffset;
+ this.length = length;
+ this.project = project;
+ this.artifactId = artifactId;
+ this.groupId = groupId;
+ this.isDependency = isDependency;
+ this.isPlugin = isPlugin;
+ }
+
+ public int getLength() {
+ return length;
+ }
+
+ public int getOffset() {
+ return offset;
+ }
+ }
+
+
+}
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomModelHandler.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomModelHandler.java
new file mode 100644
index 00000000..cd68f514
--- /dev/null
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomModelHandler.java
@@ -0,0 +1,133 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.editor.xml;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.w3c.dom.Element;
+
+import org.eclipse.wst.common.uriresolver.internal.provisional.URIResolver;
+import org.eclipse.wst.sse.core.internal.provisional.IModelLoader;
+import org.eclipse.wst.sse.core.internal.provisional.INodeAdapter;
+import org.eclipse.wst.sse.core.internal.provisional.INodeAdapterFactory;
+import org.eclipse.wst.sse.core.internal.provisional.INodeNotifier;
+import org.eclipse.wst.xml.core.internal.contentmodel.CMDocument;
+import org.eclipse.wst.xml.core.internal.contentmodel.CMElementDeclaration;
+import org.eclipse.wst.xml.core.internal.contentmodel.modelquery.CMDocumentManager;
+import org.eclipse.wst.xml.core.internal.contentmodel.modelqueryimpl.ModelQueryImpl;
+import org.eclipse.wst.xml.core.internal.contentmodel.util.CMDocumentCache;
+import org.eclipse.wst.xml.core.internal.contentmodel.util.NamespaceTable;
+import org.eclipse.wst.xml.core.internal.modelhandler.ModelHandlerForXML;
+import org.eclipse.wst.xml.core.internal.modelhandler.XMLModelLoader;
+import org.eclipse.wst.xml.core.internal.modelquery.ModelQueryAdapterFactoryForXML;
+import org.eclipse.wst.xml.core.internal.modelquery.XMLModelQueryAssociationProvider;
+import org.eclipse.wst.xml.core.internal.ssemodelquery.ModelQueryAdapter;
+import org.eclipse.wst.xml.core.internal.ssemodelquery.ModelQueryAdapterImpl;
+
+
+
+@SuppressWarnings("restriction")
+public class PomModelHandler extends ModelHandlerForXML {
+
+ private static final String ASSOCIATED_CONTENT_TYPE_ID = "org.eclipse.m2e.pomFile"; //$NON-NLS-1$
+
+ private static final String POM_NAMESPACE = "http://maven.apache.org/POM/4.0.0"; //$NON-NLS-1$
+
+ private static final String POM_XSD = "http://maven.apache.org/xsd/maven-4.0.0.xsd"; //$NON-NLS-1$
+
+ public PomModelHandler() {
+ super();
+ setAssociatedContentTypeId(ASSOCIATED_CONTENT_TYPE_ID);
+ }
+
+ @Override
+ public IModelLoader getModelLoader() {
+ return new PomModelLoader();
+ }
+
+ private static class PomModelLoader extends XMLModelLoader {
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public List getAdapterFactories() {
+ List result = new ArrayList();
+ INodeAdapterFactory factory = new ModelQueryAdapterFactoryForPom();
+ result.add(factory);
+ return result;
+ }
+
+ }
+
+ static class ModelQueryAdapterFactoryForPom extends ModelQueryAdapterFactoryForXML {
+
+ protected ModelQueryAdapterImpl modelQueryAdapterImpl;
+
+ @Override
+ protected INodeAdapter createAdapter(INodeNotifier target) {
+ if(modelQueryAdapterImpl == null) {
+ ModelQueryAdapter mqa = (ModelQueryAdapter) super.createAdapter(target);
+ modelQueryAdapterImpl = new ModelQueryAdapterImpl(mqa.getCMDocumentCache(), new PomModelQueryImpl(mqa
+ .getCMDocumentCache(), mqa.getIdResolver()), mqa.getIdResolver());
+ }
+ return modelQueryAdapterImpl;
+ }
+
+ }
+
+ static class PomModelQueryImpl extends ModelQueryImpl {
+
+ public PomModelQueryImpl(CMDocumentCache cache, URIResolver idResolver) {
+ super(new PomModelQueryAssociationProvider(cache, idResolver));
+ }
+
+ }
+
+ static class PomModelQueryAssociationProvider extends XMLModelQueryAssociationProvider {
+
+ public PomModelQueryAssociationProvider(CMDocumentCache cache, URIResolver idResolver) {
+ super(cache, idResolver);
+ }
+
+ @Override
+ public CMDocument getCMDocument(String publicId, String systemId, String type) {
+ if("".equals(publicId) && "".equals(systemId)) { //$NON-NLS-1$ //$NON-NLS-2$
+ return null;
+ }
+
+ return super.getCMDocument(publicId, systemId, type);
+ }
+
+ @Override
+ public CMElementDeclaration getCMElementDeclaration(Element element) {
+ CMElementDeclaration result = super.getCMElementDeclaration(element);
+
+ if(result == null) {
+ NamespaceTable namespaceTable = new NamespaceTable(element.getOwnerDocument());
+ List list = NamespaceTable.getElementLineage(element);
+ Element rootElement = (Element) list.get(0);
+ namespaceTable.addElement(rootElement);
+
+ documentManager.setPropertyEnabled(CMDocumentManager.PROPERTY_ASYNC_LOAD, false);
+ documentManager.addCMDocumentReference(POM_NAMESPACE, POM_XSD, "XSD"); //$NON-NLS-1$
+ namespaceTable.addNamespaceInfo("", POM_NAMESPACE, ""); //$NON-NLS-1$ //$NON-NLS-2$
+
+ if(namespaceTable.isNamespaceEncountered()) {
+ result = getCMElementDeclaration(element, list, namespaceTable);
+ }
+ }
+
+ return result;
+ }
+ }
+
+}
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomQuickAssistProcessor.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomQuickAssistProcessor.java
new file mode 100644
index 00000000..b12153c1
--- /dev/null
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomQuickAssistProcessor.java
@@ -0,0 +1,678 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.editor.xml;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.Position;
+import org.eclipse.jface.text.contentassist.ICompletionProposal;
+import org.eclipse.jface.text.contentassist.ICompletionProposalExtension5;
+import org.eclipse.jface.text.contentassist.IContextInformation;
+import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext;
+import org.eclipse.jface.text.quickassist.IQuickAssistProcessor;
+import org.eclipse.jface.text.source.Annotation;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.text.edits.DeleteEdit;
+import org.eclipse.text.edits.InsertEdit;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IMarkerResolution;
+import org.eclipse.ui.internal.WorkbenchPlugin;
+import org.eclipse.ui.texteditor.MarkerAnnotation;
+import org.eclipse.wst.sse.core.StructuredModelManager;
+import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion;
+import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
+import org.eclipse.wst.sse.core.utils.StringUtils;
+import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel;
+
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.internal.project.MavenMarkerManager;
+import org.eclipse.m2e.editor.xml.internal.Messages;
+
+public class PomQuickAssistProcessor implements IQuickAssistProcessor {
+ private static final String GROUP_ID_NODE = "groupId"; //$NON-NLS-1$
+ private static final String ARTIFACT_ID_NODE = "artifactId"; //$NON-NLS-1$
+ private static final String VERSION_NODE = "version"; //$NON-NLS-1$
+
+ public static final String PROJECT_NODE = "project"; //$NON-NLS-1$
+ public static final String XSI_VALUE = " xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"+ //$NON-NLS-1$
+ "xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\""; //$NON-NLS-1$
+
+ public boolean canAssist(IQuickAssistInvocationContext arg0) {
+ return true;
+ }
+
+ public boolean canFix(Annotation an) {
+ if(an instanceof MarkerAnnotation) {
+ MarkerAnnotation mark = (MarkerAnnotation) an;
+ String hint = mark.getMarker().getAttribute(IMavenConstants.MARKER_ATTR_EDITOR_HINT, null);
+ if(hint != null) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public ICompletionProposal[] computeQuickAssistProposals(IQuickAssistInvocationContext context) {
+ List<ICompletionProposal> proposals = new ArrayList<ICompletionProposal>();
+ Iterator<Annotation> annotationIterator = context.getSourceViewer().getAnnotationModel().getAnnotationIterator();
+ while(annotationIterator.hasNext()) {
+ Annotation annotation = annotationIterator.next();
+ if(annotation instanceof MarkerAnnotation) {
+ MarkerAnnotation mark = (MarkerAnnotation) annotation;
+ try {
+ Position position = context.getSourceViewer().getAnnotationModel().getPosition(annotation);
+ int lineNum = context.getSourceViewer().getDocument().getLineOfOffset(position.getOffset()) + 1;
+ int currentLineNum = context.getSourceViewer().getDocument().getLineOfOffset(context.getOffset()) + 1;
+ if(currentLineNum == lineNum) {
+ String hint = mark.getMarker().getAttribute(IMavenConstants.MARKER_ATTR_EDITOR_HINT, null);
+ if(hint != null) {
+ if(hint.equals(IMavenConstants.EDITOR_HINT_PARENT_GROUP_ID)) {
+ proposals.add(new IdPartRemovalProposal(context, false, mark));
+ } else if(hint.equals(IMavenConstants.EDITOR_HINT_PARENT_VERSION)) {
+ proposals.add(new IdPartRemovalProposal(context, true, mark));
+ } else if(hint.equals(IMavenConstants.EDITOR_HINT_MANAGED_DEPENDENCY_OVERRIDE)) {
+ proposals.add(new ManagedVersionRemovalProposal(context, true, mark));
+ //add a proposal to ignore the marker
+ proposals.add(new IgnoreWarningProposal(context, mark, IMavenConstants.MARKER_IGNORE_MANAGED));
+ } else if(hint.equals(IMavenConstants.EDITOR_HINT_MANAGED_PLUGIN_OVERRIDE)) {
+ proposals.add(new ManagedVersionRemovalProposal(context, false, mark));
+ //add a proposal to ignore the marker
+ proposals.add(new IgnoreWarningProposal(context, mark, IMavenConstants.MARKER_IGNORE_MANAGED));
+ } else if(hint.equals(IMavenConstants.EDITOR_HINT_MISSING_SCHEMA)) {
+ proposals.add(new SchemaCompletionProposal(context, mark));
+ }
+ }
+ }
+ } catch(Exception e) {
+ MvnIndexPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, MvnIndexPlugin.PLUGIN_ID, "Exception in pom quick assist.", e));
+ }
+ }
+ }
+
+ if(proposals.size() > 0) {
+ return proposals.toArray(new ICompletionProposal[0]);
+ }
+ return null;
+ }
+
+ public String getErrorMessage() {
+ return null;
+ }
+
+ static Element getRootElement(IDocument doc) {
+ IDOMModel domModel = null;
+ try {
+ domModel = (IDOMModel) StructuredModelManager.getModelManager().getExistingModelForRead(doc);
+ IStructuredDocument document = domModel.getStructuredDocument();
+ Element root = domModel.getDocument().getDocumentElement();
+ return root;
+ } finally {
+ if (domModel != null) {
+ domModel.releaseFromRead();
+ }
+ }
+ }
+
+ static IStructuredDocument getDocument(IMarker marker) {
+ if (marker.getResource().getType() == IResource.FILE)
+ {
+ IDOMModel domModel = null;
+ try {
+ domModel = (IDOMModel)StructuredModelManager.getModelManager().getModelForEdit((IFile)marker.getResource());
+ return domModel.getStructuredDocument();
+ } catch(Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } finally {
+ if (domModel != null) {
+ domModel.releaseFromRead();
+ }
+ }
+ }
+ return null;
+ }
+
+ static String previewForRemovedElement(IDocument doc, Element removed) {
+ if (removed != null && removed instanceof IndexedRegion) {
+ IndexedRegion reg = (IndexedRegion)removed;
+ try {
+ int line = doc.getLineOfOffset(reg.getStartOffset());
+ int startLine = doc.getLineOffset(line);
+ int prev2 = doc.getLineOffset(Math.max(line - 2, 0));
+ String prevString = StringUtils.convertToHTMLContent(doc.get(prev2, startLine - prev2));
+ String currentLine = doc.get(startLine, doc.getLineLength(line));
+ int nextLine = Math.min(line + 2, doc.getNumberOfLines() - 1);
+ int next2End = doc.getLineOffset(nextLine) + doc.getLineLength(nextLine);
+ int next2Start = startLine + doc.getLineLength( line ) + 1;
+ String nextString = StringUtils.convertToHTMLContent(doc.get(next2Start, next2End - next2Start));
+ return "<html>...<br>" + prevString + /**"<del>" + currentLine + "</del>" +*/ nextString + "...<html>"; //$NON-NLS-1$ //$NON-NLS-2$
+ } catch(BadLocationException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ return null;
+ }
+
+class SchemaCompletionProposal implements ICompletionProposal, ICompletionProposalExtension5 {
+
+ IQuickAssistInvocationContext context;
+ private MarkerAnnotation annotation;
+ public SchemaCompletionProposal(IQuickAssistInvocationContext context, MarkerAnnotation mark){
+ this.context = context;
+ annotation = mark;
+ }
+
+ public void apply(IDocument doc) {
+ IDOMModel domModel = null;
+ try {
+ domModel = (IDOMModel) StructuredModelManager.getModelManager().getExistingModelForRead(doc);
+ IStructuredDocument document = domModel.getStructuredDocument();
+ Element root = domModel.getDocument().getDocumentElement();
+
+ //now check parent version and groupid against the current project's ones..
+ if (root.getNodeName().equals(PomQuickAssistProcessor.PROJECT_NODE)) { //$NON-NLS-1$
+ if (root instanceof IndexedRegion) {
+ IndexedRegion off = (IndexedRegion) root;
+
+ int offset = off.getStartOffset() + PomQuickAssistProcessor.PROJECT_NODE.length() + 1;
+ if (offset <= 0) {
+ return;
+ }
+ InsertEdit edit = new InsertEdit(offset, PomQuickAssistProcessor.XSI_VALUE);
+ try {
+ edit.apply(doc);
+ annotation.getMarker().delete();
+ Display.getDefault().asyncExec(new Runnable() {
+ public void run() {
+ IEditorPart activeEditor = MvnIndexPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow()
+ .getActivePage().getActiveEditor();
+ MvnIndexPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow().getActivePage()
+ .saveEditor(activeEditor, false);
+ }
+ });
+ } catch(Exception e) {
+ MavenLogger.log("Unable to insert schema info", e); //$NON-NLS-1$
+ }
+ }
+ }
+ } finally {
+ if (domModel != null) {
+ domModel.releaseFromRead();
+ }
+ }
+ }
+
+ public String getAdditionalProposalInfo() {
+ //NOT TO BE REALLY IMPLEMENTED, we have the other method
+ return null;
+ }
+
+ public IContextInformation getContextInformation() {
+ return null;
+ }
+
+ public String getDisplayString() {
+ return Messages.PomQuickAssistProcessor_name;
+ }
+
+ public Image getImage() {
+ return WorkbenchPlugin.getDefault().getImageRegistry().get(org.eclipse.ui.internal.SharedImages.IMG_OBJ_ADD);
+ }
+
+ public Point getSelection(IDocument arg0) {
+ return null;
+ }
+
+ public Object getAdditionalProposalInfo(IProgressMonitor monitor) {
+ // TODO Auto-generated method stub
+ return "<html>...<br>&lt;project <b>" + PomQuickAssistProcessor.XSI_VALUE + "</b>&gt;<br>...</html>"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+}
+
+
+static class IdPartRemovalProposal implements ICompletionProposal, ICompletionProposalExtension5, IMarkerResolution {
+
+ private IQuickAssistInvocationContext context;
+ private final boolean isVersion;
+ private final IMarker marker;
+ public IdPartRemovalProposal(IQuickAssistInvocationContext context, boolean version, MarkerAnnotation mark) {
+ this.context = context;
+ isVersion = version;
+ marker = mark.getMarker();
+ }
+
+ public IdPartRemovalProposal(IMarker marker, boolean version) {
+ this.marker = marker;
+ isVersion = version;
+ }
+
+ public void apply(IDocument doc) {
+ Element root = getRootElement(doc);
+ processFix(doc, root, isVersion, marker);
+ }
+
+ private void processFix(IDocument doc, Element root, boolean isversion, IMarker marker) {
+ //now check parent version and groupid against the current project's ones..
+ if (root.getNodeName().equals(PomQuickAssistProcessor.PROJECT_NODE)) { //$NON-NLS-1$
+ Element value = MavenMarkerManager.findChildElement(root, isversion ? VERSION_NODE : GROUP_ID_NODE); //$NON-NLS-1$ //$NON-NLS-2$
+ if (value != null && value instanceof IndexedRegion) {
+ IndexedRegion off = (IndexedRegion) value;
+
+ int offset = off.getStartOffset();
+ if (offset <= 0) {
+ return;
+ }
+ Node prev = value.getNextSibling();
+ if (prev instanceof Text) {
+ //check the content as well??
+ off = ((IndexedRegion) prev);
+ }
+ DeleteEdit edit = new DeleteEdit(offset, off.getEndOffset() - offset);
+ try {
+ edit.apply(doc);
+ marker.delete();
+ } catch(Exception e) {
+ MavenLogger.log("Unable to remove the element", e); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+
+ public String getAdditionalProposalInfo() {
+ return null;
+ }
+
+ public IContextInformation getContextInformation() {
+ return null;
+ }
+
+ public String getDisplayString() {
+ return isVersion ? Messages.PomQuickAssistProcessor_title_version : Messages.PomQuickAssistProcessor_title_groupId;
+ }
+
+ public Image getImage() {
+ return WorkbenchPlugin.getDefault().getImageRegistry().get(org.eclipse.ui.internal.SharedImages.IMG_TOOL_DELETE);
+ }
+
+ public Point getSelection(IDocument arg0) {
+ return null;
+ }
+
+ public Object getAdditionalProposalInfo(IProgressMonitor monitor) {
+ if (context == null) {
+ //no context in markerresolution, just to be sure..
+ return null;
+ }
+ IDocument doc = context.getSourceViewer().getDocument();
+ IDOMModel domModel = null;
+ try {
+ domModel = (IDOMModel) StructuredModelManager.getModelManager().getExistingModelForRead(doc);
+// IStructuredDocument document = domModel.getStructuredDocument();
+ Element root = domModel.getDocument().getDocumentElement();
+
+ //now check parent version and groupid against the current project's ones..
+ if (root.getNodeName().equals(PomQuickAssistProcessor.PROJECT_NODE)) { //$NON-NLS-1$
+ Element value = MavenMarkerManager.findChildElement(root, isVersion ? VERSION_NODE : GROUP_ID_NODE); //$NON-NLS-1$ //$NON-NLS-2$
+ String toRet = previewForRemovedElement(doc, value);
+ if (toRet != null) {
+ return toRet;
+ }
+ }
+ } finally {
+ if (domModel != null) {
+ domModel.releaseFromRead();
+ }
+ }
+ return Messages.PomQuickAssistProcessor_remove_hint;
+ }
+
+ public String getLabel() {
+ return getDisplayString();
+ }
+
+ public void run(IMarker marker) {
+ IStructuredDocument doc = getDocument(marker);
+ if (doc != null) {
+ Element root = getRootElement(doc);
+ processFix(doc, root, isVersion, marker);
+ }
+ }
+}
+
+static class ManagedVersionRemovalProposal implements ICompletionProposal, ICompletionProposalExtension5, IMarkerResolution {
+
+ private IQuickAssistInvocationContext context;
+ private final boolean isDependency;
+ private final IMarker marker;
+ public ManagedVersionRemovalProposal(IQuickAssistInvocationContext context, boolean dependency, MarkerAnnotation mark) {
+ this.context = context;
+ isDependency = dependency;
+ marker = mark.getMarker();
+ }
+
+ public ManagedVersionRemovalProposal(IMarker marker, boolean dependency) {
+ this.marker = marker;
+ isDependency = dependency;
+ }
+
+
+
+ public void apply(IDocument doc) {
+ Element root = getRootElement(doc);
+ processFix(doc, root, isDependency, marker);
+
+ }
+
+ private void processFix(IDocument doc, Element root, boolean isdep, IMarker marker) {
+ if (root.getNodeName().equals(PomQuickAssistProcessor.PROJECT_NODE)) {
+ Element artifact = findArtifactElement(root, isdep, marker);
+ if (artifact == null) {
+ //TODO report somehow?
+ MavenLogger.log("Unable to find the marked element"); //$NON-NLS-1$
+ return;
+ }
+ Element value = MavenMarkerManager.findChildElement(artifact, VERSION_NODE); //$NON-NLS-1$ //$NON-NLS-2$
+ if (value != null && value instanceof IndexedRegion) {
+ IndexedRegion off = (IndexedRegion) value;
+
+ int offset = off.getStartOffset();
+ if (offset <= 0) {
+ return;
+ }
+ Node prev = value.getNextSibling();
+ if (prev instanceof Text) {
+ //check the content as well??
+ off = ((IndexedRegion) prev);
+ }
+ DeleteEdit edit = new DeleteEdit(offset, off.getEndOffset() - offset);
+ try {
+ edit.apply(doc);
+ marker.delete();
+ } catch(Exception e) {
+ MavenLogger.log("Unable to remove the element", e); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+
+ private Element findArtifactElement(Element root, boolean isdep, IMarker marker) {
+ if (root == null) {
+ return null;
+ }
+ String groupId = marker.getAttribute("groupId", null);
+ String artifactId = marker.getAttribute("artifactId", null);
+ assert groupId != null;
+ assert artifactId != null;
+
+ String profile = marker.getAttribute("profile", null);
+ Element artifactParent = root;
+ if (profile != null) {
+ Element profileRoot = MavenMarkerManager.findChildElement(root, "profiles");
+ if (profileRoot != null) {
+ for (Element prf : MavenMarkerManager.findChildElements(profileRoot, "profile")) {
+ if (profile.equals(MavenMarkerManager.getElementTextValue(MavenMarkerManager.findChildElement(prf, "id")))) {
+ artifactParent = prf;
+ break;
+ }
+ }
+ }
+ }
+ if (!isdep) {
+ //we have plugins now, need to go one level down to build
+ artifactParent = MavenMarkerManager.findChildElement(artifactParent, "build");
+ }
+ if (artifactParent == null) {
+ return null;
+ }
+ Element list = MavenMarkerManager.findChildElement(artifactParent, isdep ? "dependencies" : "plugins");
+ if (list == null) {
+ return null;
+ }
+ Element artifact = null;
+ for (Element art : MavenMarkerManager.findChildElements(list, isdep ? "dependency" : "plugin")) {
+ String grpString = MavenMarkerManager.getElementTextValue(MavenMarkerManager.findChildElement(art, GROUP_ID_NODE));
+ String artString = MavenMarkerManager.getElementTextValue(MavenMarkerManager.findChildElement(art, ARTIFACT_ID_NODE));
+ if (groupId.equals(grpString) && artifactId.equals(artString)) {
+ artifact = art;
+ break;
+ }
+ }
+ return artifact;
+ }
+
+ public String getAdditionalProposalInfo() {
+ return null;
+ }
+
+ public IContextInformation getContextInformation() {
+ return null;
+ }
+
+ public String getDisplayString() {
+ return Messages.PomQuickAssistProcessor_title_version;
+ }
+
+ public Image getImage() {
+ return WorkbenchPlugin.getDefault().getImageRegistry().get(org.eclipse.ui.internal.SharedImages.IMG_TOOL_DELETE);
+ }
+
+ public Point getSelection(IDocument arg0) {
+ return null;
+ }
+
+ public Object getAdditionalProposalInfo(IProgressMonitor monitor) {
+ if (context == null) {
+ //no context in markerresolution, just to be sure..
+ return null;
+ }
+ IDocument doc = context.getSourceViewer().getDocument();
+ IDOMModel domModel = null;
+ try {
+ domModel = (IDOMModel) StructuredModelManager.getModelManager().getExistingModelForRead(doc);
+ Element root = domModel.getDocument().getDocumentElement();
+ Element artifact = findArtifactElement(root, isDependency, marker);
+ if (artifact != null) {
+ Element value = MavenMarkerManager.findChildElement(artifact, VERSION_NODE);
+ String toRet = previewForRemovedElement(doc, value);
+ if (toRet != null) {
+ return toRet;
+ }
+ }
+ } finally {
+ if (domModel != null) {
+ domModel.releaseFromRead();
+ }
+ }
+ return Messages.PomQuickAssistProcessor_remove_hint;
+ }
+
+ public String getLabel() {
+ return getDisplayString();
+ }
+
+ public void run(IMarker marker) {
+ IStructuredDocument doc = getDocument(marker);
+ if (doc != null) {
+ Element root = getRootElement(doc);
+ processFix(doc, root, isDependency, marker);
+ }
+ }
+}
+
+static class IgnoreWarningProposal implements ICompletionProposal, ICompletionProposalExtension5, IMarkerResolution {
+
+ private IQuickAssistInvocationContext context;
+ private final IMarker marker;
+ private final String markupText;
+ public IgnoreWarningProposal(IQuickAssistInvocationContext context, MarkerAnnotation mark, String markupText) {
+ this.context = context;
+ marker = mark.getMarker();
+ this.markupText = markupText;
+ }
+
+ public IgnoreWarningProposal(IMarker marker, String markupText) {
+ this.marker = marker;
+ this.markupText = markupText;
+ }
+
+ public void apply(IDocument doc) {
+ if (doc instanceof IStructuredDocument) {
+ processFix((IStructuredDocument) doc, marker);
+ } else {
+ IStructuredDocument strdoc = getDocument(marker);
+ if (strdoc != null) {
+ processFix(strdoc, marker);
+ }
+ }
+ }
+
+ private void processFix(IStructuredDocument doc, IMarker marker) {
+ IDOMModel domModel = null;
+ try {
+ domModel = (IDOMModel) StructuredModelManager.getModelManager().getExistingModelForRead(doc);
+ int line;
+ if (context != null) {
+ line = doc.getLineOfOffset(context.getOffset());
+ } else {
+ line = marker.getAttribute(IMarker.LINE_NUMBER, -1);
+ assert line != -1;
+ line = line - 1;
+ }
+ try {
+ int linestart = doc.getLineOffset(line);
+ int lineend = linestart + doc.getLineLength(line);
+ int start = linestart;
+ IndexedRegion reg = domModel.getIndexedRegion(start);
+ while (reg != null && !(reg instanceof Element) && start < lineend) {
+ reg = domModel.getIndexedRegion(reg.getEndOffset() + 1);
+ if (reg != null) {
+ start = reg.getStartOffset();
+ }
+ }
+ if (reg != null && reg instanceof Element) {
+ InsertEdit edit = new InsertEdit(reg.getEndOffset(), "<!--" + markupText + "-->");
+ try {
+ edit.apply(doc);
+ marker.delete();
+ } catch(Exception e) {
+ MavenLogger.log("Unable to insert", e); //$NON-NLS-1$
+ }
+ }
+ } catch(BadLocationException e1) {
+ // TODO Auto-generated catch block
+ e1.printStackTrace();
+ }
+ } finally {
+ if (domModel != null) {
+ domModel.releaseFromRead();
+ }
+ }
+ }
+
+ public String getAdditionalProposalInfo() {
+ return null;
+ }
+
+ public IContextInformation getContextInformation() {
+ return null;
+ }
+
+ public String getDisplayString() {
+ return "Ignore this warning";
+ }
+
+ public Image getImage() {
+ return MvnImages.IMG_CLOSE;
+ }
+
+ public Point getSelection(IDocument arg0) {
+ return null;
+ }
+
+ public Object getAdditionalProposalInfo(IProgressMonitor monitor) {
+ if (context == null) {
+ //no context in markerresolution, just to be sure..
+ return null;
+ }
+ IDOMModel domModel = null;
+ try {
+ IDocument doc = context.getSourceViewer().getDocument();
+ domModel = (IDOMModel) StructuredModelManager.getModelManager().getExistingModelForRead(doc);
+ try {
+ //the offset of context is important here, not the offset of the marker!!!
+ //line/offset of marker only gets updated hen file gets saved.
+ //we need the proper handling also for unsaved documents..
+ int line = doc.getLineOfOffset(context.getOffset());
+ int linestart = doc.getLineOffset(line);
+ int lineend = linestart + doc.getLineLength(line);
+ int start = linestart;
+ IndexedRegion reg = domModel.getIndexedRegion(start);
+ while (reg != null && !(reg instanceof Element) && start < lineend) {
+ reg = domModel.getIndexedRegion(reg.getEndOffset() + 1);
+ if (reg != null) {
+ start = reg.getStartOffset();
+ }
+ }
+ if (reg != null && reg instanceof Element) { //just a simple guard against moved marker
+ try {
+ int startLine = doc.getLineOffset(line);
+ String currentLine = StringUtils.convertToHTMLContent(doc.get(reg.getStartOffset(), reg.getEndOffset() - reg.getStartOffset()));
+ String insert = StringUtils.convertToHTMLContent("<!--" + markupText + "-->");
+ return "<html>...<br>" + currentLine + "<b>" + insert + "</b><br>...<html>"; //$NON-NLS-1$ //$NON-NLS-2$
+ } catch(BadLocationException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ } catch(BadLocationException e1) {
+ MavenLogger.log("Error while computing completion proposal", e1);
+ }
+ } finally {
+ if (domModel != null) {
+ domModel.releaseFromRead();
+ }
+ }
+ return Messages.PomQuickAssistProcessor_remove_hint;
+ }
+
+ public String getLabel() {
+ return getDisplayString();
+ }
+
+ public void run(IMarker marker) {
+ IStructuredDocument doc = getDocument(marker);
+ if (doc != null) {
+ processFix(doc, marker);
+ }
+ }
+}
+
+}
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomStructuredTextViewConfiguration.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomStructuredTextViewConfiguration.java
new file mode 100644
index 00000000..5f5b26b1
--- /dev/null
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomStructuredTextViewConfiguration.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.editor.xml;
+
+import org.eclipse.jface.text.ITextHover;
+import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
+import org.eclipse.jface.text.hyperlink.IHyperlinkDetector;
+import org.eclipse.jface.text.quickassist.IQuickAssistAssistant;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.wst.sse.core.text.IStructuredPartitions;
+import org.eclipse.wst.xml.core.text.IXMLPartitions;
+import org.eclipse.wst.xml.ui.StructuredTextViewerConfigurationXML;
+
+/**
+ * @author Lukas Krecan
+ */
+public class PomStructuredTextViewConfiguration extends StructuredTextViewerConfigurationXML {
+
+ @Override
+ public IContentAssistProcessor[] getContentAssistProcessors(ISourceViewer sourceViewer, String partitionType) {
+ if(partitionType == IStructuredPartitions.DEFAULT_PARTITION || partitionType == IXMLPartitions.XML_DEFAULT) {
+ return new IContentAssistProcessor[] {new PomContentAssistProcessor(sourceViewer, this)};
+ }
+ return super.getContentAssistProcessors(sourceViewer, partitionType);
+ }
+
+ @Override
+ public ITextHover getTextHover(ISourceViewer sourceViewer, String contentType, int stateMask) {
+ return new PomTextHover(sourceViewer, contentType, stateMask);
+ }
+
+ @Override
+ public IHyperlinkDetector[] getHyperlinkDetectors(ISourceViewer sourceViewer) {
+ IHyperlinkDetector[] detectors = super.getHyperlinkDetectors(sourceViewer);
+ if(detectors==null) {
+ detectors = new IHyperlinkDetector[0];
+ }
+
+ IHyperlinkDetector[] pomDetectors = new IHyperlinkDetector[detectors.length + 1];
+ pomDetectors[0] = new PomHyperlinkDetector();
+ System.arraycopy(detectors, 0, pomDetectors, 1, detectors.length);
+
+ return pomDetectors;
+ }
+
+ public IQuickAssistAssistant getQuickAssistAssistant(ISourceViewer sourceViewer) {
+ //not explicitly setting processor results in having a bunch of generic quick fixes around..
+ //also see org.eclipse.wst.sse.ui.quickFixProcessor extension point regarding the way to declaratively
+ //register the pomquickassistprocessor
+ IQuickAssistAssistant quickAssistAssistant = super.getQuickAssistAssistant(sourceViewer);
+ quickAssistAssistant.setQuickAssistProcessor(new PomQuickAssistProcessor());
+ return quickAssistAssistant;
+ }
+
+}
+
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomTemplateContext.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomTemplateContext.java
new file mode 100644
index 00000000..0738befd
--- /dev/null
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomTemplateContext.java
@@ -0,0 +1,764 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.editor.xml;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.maven.model.Dependency;
+import org.apache.maven.model.DependencyManagement;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.model.PluginManagement;
+import org.apache.maven.plugin.descriptor.MojoDescriptor;
+import org.apache.maven.plugin.descriptor.Parameter;
+import org.apache.maven.plugin.descriptor.PluginDescriptor;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.interpolation.InterpolationException;
+import org.codehaus.plexus.interpolation.PrefixedObjectValueSource;
+import org.codehaus.plexus.interpolation.PropertiesBasedValueSource;
+import org.codehaus.plexus.interpolation.RegexBasedInterpolator;
+import org.codehaus.plexus.util.StringUtils;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Text;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.jface.text.templates.Template;
+import org.eclipse.osgi.util.NLS;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.internal.project.MavenMarkerManager;
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+import org.eclipse.m2e.core.util.search.ArtifactInfo;
+import org.eclipse.m2e.core.util.search.Packaging;
+import org.eclipse.m2e.core.util.search.SearchEngine;
+import org.eclipse.m2e.editor.xml.internal.Messages;
+
+
+/**
+ * Context types.
+ *
+ * @author Lukas Krecan
+ * @author Eugene Kuleshov
+ */
+public enum PomTemplateContext {
+
+ UNKNOWN("unknown"), // //$NON-NLS-1$
+
+ DOCUMENT("#document"), // //$NON-NLS-1$
+
+ PROJECT("project"), // //$NON-NLS-1$
+
+ BUILD("build"), // //$NON-NLS-1$
+
+ PARENT("parent"), // //$NON-NLS-1$
+
+ RELATIVE_PATH("relativePath"), // //$NON-NLS-1$
+
+ MODULES("modules"), // //$NON-NLS-1$
+
+ PROPERTIES("properties"), // //$NON-NLS-1$
+
+ DEPENDENCIES("dependencies"), // //$NON-NLS-1$
+
+ EXCLUSIONS("exclusions"), // //$NON-NLS-1$
+
+ PLUGINS("plugins"), // //$NON-NLS-1$
+
+ PLUGIN("plugin"), // //$NON-NLS-1$
+
+ PLUGIN_MANAGEMENT("pluginManagement"), // //$NON-NLS-1$
+
+ EXECUTIONS("executions"), // //$NON-NLS-1$
+
+ PROFILES("profiles"), // //$NON-NLS-1$
+
+ REPOSITORIES("repositories"), // //$NON-NLS-1$
+
+ CONFIGURATION("configuration") { //$NON-NLS-1$
+
+ @Override
+ protected void addTemplates(IProject project, Collection<Template> proposals, Node node, String prefix) throws CoreException {
+ if("execution".equals(node.getParentNode().getNodeName()) //$NON-NLS-1$
+ || "reportSet".equals(node.getParentNode().getNodeName())) { //$NON-NLS-1$
+ node = node.getParentNode().getParentNode();
+ }
+ String groupId = getGroupId(node);
+ if(groupId==null) {
+ groupId = "org.apache.maven.plugins"; // TODO support other default groups //$NON-NLS-1$
+ }
+ String artifactId = getArtifactId(node);
+ String version = extractVersion(project, getVersion(node), groupId, artifactId, EXTRACT_STRATEGY_PLUGIN | EXTRACT_STRATEGY_SEARCH);
+ if (version == null) {
+ return;
+ }
+ PluginDescriptor descriptor = PomTemplateContextUtil.INSTANCE.getPluginDescriptor(groupId, artifactId, version);
+ if(descriptor!=null) {
+ List<MojoDescriptor> mojos = descriptor.getMojos();
+ HashSet<String> params = new HashSet<String>();
+ for(MojoDescriptor mojo : mojos) {
+ List<Parameter> parameters = (List<Parameter>) mojo.getParameters();
+ for(Parameter parameter : parameters) {
+ boolean editable = parameter.isEditable();
+ if(editable) {
+ String name = parameter.getName();
+ if(!params.contains(name) && name.startsWith(prefix)) {
+ params.add(name);
+
+ String text = NLS.bind(Messages.PomTemplateContext_param, parameter.isRequired(), parameter.getType());
+
+ String expression = parameter.getExpression();
+ if(expression!=null) {
+ text += NLS.bind(Messages.PomTemplateContext_param_expr, expression);
+ }
+
+ String defaultValue = parameter.getDefaultValue();
+ if(defaultValue!=null) {
+ text += NLS.bind(Messages.PomTemplateContext_param_def, defaultValue);
+ }
+
+ String desc = parameter.getDescription().trim();
+ text += desc.startsWith("<p>") ? desc : "<br>" + desc; //$NON-NLS-1$ //$NON-NLS-2$
+
+ proposals.add(new Template(name, text, getContextTypeId(), //
+ "<" + name + ">${cursor}</" + name + ">", false)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+
+ GROUP_ID("groupId") { //$NON-NLS-1$
+ @Override
+ public void addTemplates(IProject project, Collection<Template> proposals, Node node, String prefix) throws CoreException {
+ String contextTypeId = getContextTypeId();
+ for(String groupId : getSearchEngine(project).findGroupIds(prefix, getPackaging(node), getContainingArtifact(node))) {
+ add(proposals, contextTypeId, groupId);
+ }
+ }
+ },
+
+ ARTIFACT_ID("artifactId") { //$NON-NLS-1$
+ @Override
+ public void addTemplates(IProject project, Collection<Template> proposals, Node node, String prefix) throws CoreException {
+ String groupId = getGroupId(node);
+ //#MNGECLIPSE-1832
+ if((groupId == null || groupId.trim().length() == 0) && "plugin".equals(node.getParentNode().getNodeName())) {
+ groupId = "org.apache.maven.plugins"; //$NON-NLS-1$
+ }
+ if(groupId != null) {
+ String contextTypeId = getContextTypeId();
+ for(String artifactId : getSearchEngine(project).findArtifactIds(groupId, prefix, getPackaging(node),
+ getContainingArtifact(node))) {
+ add(proposals, contextTypeId, artifactId, groupId + ":" + artifactId);
+ }
+ }
+ }
+ },
+
+ VERSION("version") { //$NON-NLS-1$
+ @Override
+ public void addTemplates(IProject project, Collection<Template> proposals, Node node, String prefix) throws CoreException {
+ String groupId = getGroupId(node);
+ //#MNGECLIPSE-1832
+ if((groupId == null || groupId.trim().length() == 0) && "plugin".equals(node.getParentNode().getNodeName())) {
+ groupId = "org.apache.maven.plugins"; //$NON-NLS-1$
+ }
+ String artifactId = getArtifactId(node);
+ if(groupId != null && artifactId != null) {
+ String contextTypeId = getContextTypeId();
+ for(String version : getSearchEngine(project).findVersions(groupId, artifactId, prefix, getPackaging(node))) {
+ add(proposals, contextTypeId, version, groupId + ":" + artifactId + ":" + version);
+ }
+ }
+ //mkleint: this concept that all versions out there are equal is questionable..
+ if (project != null && "dependency".equals(node.getParentNode().getNodeName())) { //$NON-NLS-1$
+ //see if we can complete the properties ending with .version
+
+ IMavenProjectFacade mvnproject = MavenPlugin.getDefault().getMavenProjectManager().getProject(project);
+ List<String> keys = new ArrayList<String>();
+ String contextTypeId = getContextTypeId();
+ if(mvnproject != null) {
+ MavenProject mvn = mvnproject.getMavenProject();
+ if (mvn != null) {
+ //if groupid is the same, suggest ${project.version}
+ if (groupId.equals(mvn.getGroupId())) {
+ proposals.add(new Template("${project.version}", Messages.PomTemplateContext_project_version_hint, contextTypeId, "$${project.version}", false)); //$NON-NLS-1$ //$NON-NLS-3$
+ }
+ Properties props = mvn.getProperties();
+ if (props != null) {
+ for (Object key : props.keySet()) {
+ //only add the properties following the .version convention
+ if (key.toString().endsWith(".version") || key.toString().endsWith("Version")) { //$NON-NLS-1$ //$NON-NLS-2$
+ keys.add(key.toString());
+ }
+ }
+ //sort just properties
+ Collections.sort(keys);
+ if (keys.size() > 0) {
+ for (String key : keys) {
+ String expr = "${" + key + "}"; //$NON-NLS-1$ //$NON-NLS-2$
+ proposals.add(new Template(expr, Messages.PomTemplateContext_expression_description, contextTypeId, "$" + expr, false)); //$NON-NLS-2$ //$NON-NLS-1$
+ }
+ }
+ }
+ }
+ } else {
+ //if we don't have the maven facade, it means the pom is probably broken.
+ //all we can do is to try guess the groupid and come up with the project.version proposal eventually
+ Element root = node.getOwnerDocument().getDocumentElement();
+ if (root != null && "project".equals(root.getNodeName())) {//$NON-NLS-1$
+ String currentgroupid = MavenMarkerManager.getElementTextValue(MavenMarkerManager.findChildElement(root, "groupId"));//$NON-NLS-1$
+ if (currentgroupid == null) {
+ Element parEl = MavenMarkerManager.findChildElement(root, "parent");//$NON-NLS-1$
+ if (parEl != null) {
+ currentgroupid = MavenMarkerManager.getElementTextValue(MavenMarkerManager.findChildElement(parEl, "groupId"));//$NON-NLS-1$
+ }
+ }
+ if (groupId.equals(currentgroupid)) {
+ proposals.add(new Template("${project.version}", Messages.PomTemplateContext_project_version_hint, contextTypeId, "$${project.version}", false)); //$NON-NLS-1$ //$NON-NLS-3$
+ }
+ }
+ }
+ }
+ }
+ },
+
+ CLASSIFIER("classifier") { //$NON-NLS-1$
+ @Override
+ public void addTemplates(IProject project, Collection<Template> proposals, Node node, String prefix) throws CoreException {
+ String groupId = getGroupId(node);
+ String artifactId = getArtifactId(node);
+ String version = getVersion(node);
+ if(groupId != null && artifactId != null && version != null) {
+ String contextTypeId = getContextTypeId();
+ for(String classifier : getSearchEngine(project).findClassifiers(groupId, artifactId, version, prefix,
+ getPackaging(node))) {
+ add(proposals, contextTypeId, classifier, groupId + ":" + artifactId + ":" + version + ":" + classifier);
+ }
+ }
+ }
+ },
+
+ TYPE("type") { //$NON-NLS-1$
+ @Override
+ public void addTemplates(IProject project, Collection<Template> proposals, Node node, String prefix) throws CoreException {
+ String groupId = getGroupId(node);
+ String artifactId = getArtifactId(node);
+ String version = getVersion(node);
+ String contextTypeId = getContextTypeId();
+ if(groupId != null && artifactId != null && version != null) {
+ for(String type : getSearchEngine(project).findTypes(groupId, artifactId, version, prefix, getPackaging(node))) {
+ add(proposals, contextTypeId, type, groupId + ":" + artifactId + ":" + version + ":" + type);
+ }
+ }
+ }
+ },
+
+ PACKAGING("packaging") { //$NON-NLS-1$
+ @Override
+ public void addTemplates(IProject project, Collection<Template> proposals, Node node, String prefix) {
+ String contextTypeId = getContextTypeId();
+ // TODO only show "pom" packaging in root section
+ add(proposals, contextTypeId, "pom"); //$NON-NLS-1$
+ add(proposals, contextTypeId, "jar"); //$NON-NLS-1$
+ add(proposals, contextTypeId, "war"); //$NON-NLS-1$
+ add(proposals, contextTypeId, "ear"); //$NON-NLS-1$
+ add(proposals, contextTypeId, "ejb"); //$NON-NLS-1$
+ add(proposals, contextTypeId, "eclipse-plugin"); //$NON-NLS-1$
+ add(proposals, contextTypeId, "eclipse-feature"); //$NON-NLS-1$
+ add(proposals, contextTypeId, "eclipse-update-site"); //$NON-NLS-1$
+ add(proposals, contextTypeId, "maven-plugin"); //$NON-NLS-1$
+ add(proposals, contextTypeId, "maven-archetype"); //$NON-NLS-1$
+ }
+ },
+
+ SCOPE("scope") { //$NON-NLS-1$
+ @Override
+ public void addTemplates(IProject project, Collection<Template> proposals, Node node, String prefix) {
+ String contextTypeId = getContextTypeId();
+ add(proposals, contextTypeId, "compile"); //$NON-NLS-1$
+ add(proposals, contextTypeId, "test"); //$NON-NLS-1$
+ add(proposals, contextTypeId, "provided"); //$NON-NLS-1$
+ add(proposals, contextTypeId, "runtime"); //$NON-NLS-1$
+ add(proposals, contextTypeId, "system"); //$NON-NLS-1$
+ // TODO only show "import" scope in <dependencyManagement>
+ add(proposals, contextTypeId, "import"); //$NON-NLS-1$
+ }
+ },
+
+ SYSTEM_PATH("systemPath"), //$NON-NLS-1$
+
+ PHASE("phase") { //$NON-NLS-1$
+ @Override
+ public void addTemplates(IProject project, Collection<Template> proposals, Node node, String prefix) {
+ String contextTypeId = getContextTypeId();
+ // TODO the following list should be derived from the packaging handler (the actual lifecycle)
+
+ // Clean Lifecycle
+ add(proposals, contextTypeId, "pre-clean", Messages.PomTemplateContext_preclean); //$NON-NLS-1$
+ add(proposals, contextTypeId, "clean", Messages.PomTemplateContext_clean); //$NON-NLS-1$
+ add(proposals, contextTypeId, "post-clean", Messages.PomTemplateContext_postclean); //$NON-NLS-1$
+
+ // Default Lifecycle
+ add(proposals, contextTypeId, "validate", Messages.PomTemplateContext_validate); //$NON-NLS-1$
+ add(proposals, contextTypeId, "generate-sources", Messages.PomTemplateContext_generatesources); //$NON-NLS-1$
+ add(proposals, contextTypeId, "process-sources", Messages.PomTemplateContext_processsources); //$NON-NLS-1$
+ add(proposals, contextTypeId, "generate-resources", Messages.PomTemplateContext_generateresources); //$NON-NLS-1$
+ add(proposals, contextTypeId, "process-resources", Messages.PomTemplateContext_processresources); //$NON-NLS-1$
+ add(proposals, contextTypeId, "compile", Messages.PomTemplateContext_compile); //$NON-NLS-1$
+ add(proposals, contextTypeId, "process-classes", Messages.PomTemplateContext_processclasses); //$NON-NLS-1$
+ add(proposals, contextTypeId, "generate-test-sources", Messages.PomTemplateContext_generatetestsources); //$NON-NLS-1$
+ add(proposals, contextTypeId, "process-test-sources", Messages.PomTemplateContext_processtestsources); //$NON-NLS-1$
+ add(proposals, contextTypeId, "generate-test-resources", Messages.PomTemplateContext_generatetestresources); //$NON-NLS-1$
+ add(proposals, contextTypeId, "process-test-resources", Messages.PomTemplateContext_processtestresources); //$NON-NLS-1$
+ add(proposals, contextTypeId, "test-compile", Messages.PomTemplateContext_testcompile); //$NON-NLS-1$
+ add(proposals, contextTypeId, "process-test-classes", Messages.PomTemplateContext_processtestclasses); //$NON-NLS-1$
+ add(proposals, contextTypeId, "test", Messages.PomTemplateContext_test); //$NON-NLS-1$
+ add(proposals, contextTypeId, "prepare-package", Messages.PomTemplateContext_preparepackage); //$NON-NLS-1$
+ add(proposals, contextTypeId, "package", Messages.PomTemplateContext_package); //$NON-NLS-1$
+ add(proposals, contextTypeId, "pre-integration-test", Messages.PomTemplateContext_preintegrationtest); //$NON-NLS-1$
+ add(proposals, contextTypeId, "integration-test", Messages.PomTemplateContext_integrationtest); //$NON-NLS-1$
+ add(proposals, contextTypeId, "post-integration-test", Messages.PomTemplateContext_postintegrationtest); //$NON-NLS-1$
+ add(proposals, contextTypeId, "verify", Messages.PomTemplateContext_verify); //$NON-NLS-1$
+ add(proposals, contextTypeId, "install", Messages.PomTemplateContext_install); //$NON-NLS-1$
+ add(proposals, contextTypeId, "deploy", Messages.PomTemplateContext_deploy); //$NON-NLS-1$
+
+ // Site Lifecycle
+ add(proposals, contextTypeId, "pre-site", Messages.PomTemplateContext_presite); //$NON-NLS-1$
+ add(proposals, contextTypeId, "site", Messages.PomTemplateContext_site); //$NON-NLS-1$
+ add(proposals, contextTypeId, "post-site", Messages.PomTemplateContext_postsite); //$NON-NLS-1$
+ add(proposals, contextTypeId, "site-deploy", Messages.PomTemplateContext_sitedeploy); //$NON-NLS-1$
+ }
+ },
+
+ GOAL("goal") { //$NON-NLS-1$
+ @Override
+ public void addTemplates(IProject project, Collection<Template> proposals, Node node, String prefix) throws CoreException {
+ if(!"goals".equals(node.getParentNode().getNodeName())) { //$NON-NLS-1$
+ return;
+ }
+ node = node.getParentNode();
+ if(!"execution".equals(node.getParentNode().getNodeName())) { //$NON-NLS-1$
+ return;
+ }
+ node = node.getParentNode();
+ if(!"executions".equals(node.getParentNode().getNodeName())) { //$NON-NLS-1$
+ return;
+ }
+ node = node.getParentNode();
+
+ String groupId = getGroupId(node);
+ if(groupId==null) {
+ groupId = "org.apache.maven.plugins"; //$NON-NLS-1$
+ }
+ String artifactId = getArtifactId(node);
+
+ String version = extractVersion(project, getVersion(node), groupId, artifactId, EXTRACT_STRATEGY_PLUGIN | EXTRACT_STRATEGY_SEARCH);
+ if(version==null) {
+ return;
+ }
+
+ PluginDescriptor descriptor = PomTemplateContextUtil.INSTANCE.getPluginDescriptor(groupId, artifactId, version);
+ if (descriptor != null) {
+ List<MojoDescriptor> mojos = descriptor.getMojos();
+ if (mojos != null) {
+ String contextTypeId = getContextTypeId();
+ for (MojoDescriptor mojo : mojos) {
+ add(proposals, contextTypeId, mojo.getGoal(), mojo.getDescription());
+ }
+ }
+ }
+ }
+ },
+
+ MODULE("module") { //$NON-NLS-1$
+ @Override
+ public void addTemplates(IProject project, Collection<Template> proposals, Node node, String prefix)
+ throws CoreException {
+ if(project == null) {
+ //shall not happen just double check.
+ return;
+ }
+ //MNGECLIPSE-2204 collect the existing values from the surrounding xml content only..
+ List<String> existings = new ArrayList<String>();
+ Node moduleNode = node;
+ if (moduleNode != null) {
+ Node modulesNode = moduleNode.getParentNode();
+ if (modulesNode != null) {
+ for (Element el : MavenMarkerManager.findChildElements((Element)modulesNode, "module")) {
+ if (el != moduleNode) {
+ String val = MavenMarkerManager.getElementTextValue(el);
+ if (val != null) {
+ existings.add(val);
+ }
+ }
+ }
+ }
+ }
+
+ File directory = new File(project.getLocationURI());
+ final File currentPom = new File(directory, "pom.xml");
+ String path = prefix;
+ boolean endingSlash = path.endsWith("/"); //$NON-NLS-1$
+ String[] elems = StringUtils.split(path, "/"); //$NON-NLS-1$
+ String lastElement = null;
+ for(int i = 0; i < elems.length; i++ ) {
+ if("..".equals(elems[i])) { //$NON-NLS-1$
+ directory = directory != null ? directory.getParentFile() : null;
+ } else if(i < elems.length - (endingSlash ? 0 : 1)) {
+ directory = directory != null ? new File(directory, elems[i]) : null;
+ } else {
+ lastElement = elems[i];
+ }
+ }
+ path = lastElement != null ? path.substring(0, path.length() - lastElement.length()) : path;
+ FileFilter filter = new FileFilter() {
+ public boolean accept(File pathname) {
+ if (pathname.isDirectory()) {
+ File pom = new File(pathname, "pom.xml"); //$NON-NLS-1$
+ //TODO shall also handle polyglot maven :)
+ return pom.exists() && pom.isFile() && !pom.equals(currentPom);
+ }
+ return false;
+ }
+ };
+ if (directory != null && directory.exists() && directory.isDirectory()) {
+ File[] offerings = directory.listFiles(filter);
+ for (File candidate : offerings) {
+ if(lastElement == null || candidate.getName().startsWith(lastElement) ) {
+ String val = path + candidate.getName();
+ if (!existings.contains(val)) { //only those not already being added in the surrounding area
+ add(proposals, getContextTypeId(), val, NLS.bind(Messages.PomTemplateContext_candidate, candidate));
+ }
+ }
+ }
+ if (path.length() == 0 && directory.equals(currentPom.getParentFile())) {
+ //for the empty value, when searching in current directory, propose also stuff one level up.
+ File currentParent = directory.getParentFile();
+ if (currentParent != null && currentParent.exists()) {
+ offerings = currentParent.listFiles(filter);
+ for (File candidate : offerings) {
+ String val = "../" + candidate.getName();
+ if (!existings.contains(val)) { //only those not already being added in the surrounding area
+ add(proposals, getContextTypeId(), val, NLS.bind(Messages.PomTemplateContext_candidate, candidate));
+ }
+ }
+ }
+ }
+ }
+ }
+ };
+
+ private static final String PREFIX = MvnIndexPlugin.PLUGIN_ID + ".templates.contextType."; //$NON-NLS-1$
+
+ private final String nodeName;
+
+ private PomTemplateContext(String nodeName) {
+ this.nodeName = nodeName;
+ }
+
+ /**
+ * Return templates depending on the context type.
+ */
+ public Template[] getTemplates(IProject project, Node node, String prefix) {
+ Collection<Template> templates = new ArrayList<Template>();
+ try {
+ addTemplates(project, templates, node, prefix);
+ } catch (CoreException e) {
+ MavenLogger.log(e);
+ }
+ return templates.toArray(new Template[templates.size()]);
+ }
+
+ protected void addTemplates(IProject project, Collection<Template> templates, Node currentNode, String prefix) throws CoreException {
+ }
+
+ protected String getNodeName() {
+ return nodeName;
+ }
+
+ public String getContextTypeId() {
+ return PREFIX + nodeName;
+ }
+
+ public static PomTemplateContext fromId(String contextTypeId) {
+ for(PomTemplateContext context : values()) {
+ if(context.getContextTypeId().equals(contextTypeId)) {
+ return context;
+ }
+ }
+ return UNKNOWN;
+ }
+
+ public static PomTemplateContext fromNodeName(String idSuffix) {
+ for(PomTemplateContext context : values()) {
+ if(context.getNodeName().equals(idSuffix)) {
+ return context;
+ }
+ }
+ return UNKNOWN;
+ }
+
+ private static SearchEngine getSearchEngine(IProject project) throws CoreException {
+ if(searchEngineForTests != null) {
+ return searchEngineForTests;
+ }
+ return MavenPlugin.getDefault().getSearchEngine(project);
+ }
+
+
+ private static SearchEngine searchEngineForTests;
+
+ public static void setSearchEngineForTests(SearchEngine _searchEngineForTests) {
+ searchEngineForTests = _searchEngineForTests;
+ }
+
+ /**
+ * Returns containing artifactInfo for exclusions. Otherwise returns null.
+ */
+ protected ArtifactInfo getContainingArtifact(Node currentNode) {
+ if(isExclusion(currentNode)) {
+ Node node = currentNode.getParentNode().getParentNode();
+ return getArtifactInfo(node);
+ }
+ return null;
+ }
+
+ /**
+ * Returns artifact info from siblings of given node.
+ */
+ private ArtifactInfo getArtifactInfo(Node node) {
+ return new ArtifactInfo(getGroupId(node), getArtifactId(node), getVersion(node), //
+ getSiblingTextValue(node, "classifier"), getSiblingTextValue(node, "type")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /**
+ * Returns required packaging.
+ */
+ protected Packaging getPackaging(Node currentNode) {
+ if(isPlugin(currentNode)) {
+ return Packaging.PLUGIN;
+ } else if(isParent(currentNode)) {
+ return Packaging.POM;
+ }
+ return Packaging.ALL;
+ }
+
+ /**
+ * Returns true if user is editing plugin dependency.
+ */
+ private boolean isPlugin(Node currentNode) {
+ return "plugin".equals(currentNode.getParentNode().getNodeName()); //$NON-NLS-1$
+ }
+
+ /**
+ * Returns true if user is editing plugin dependency exclusion.
+ */
+ private boolean isExclusion(Node currentNode) {
+ return "exclusion".equals(currentNode.getParentNode().getNodeName()); //$NON-NLS-1$
+ }
+
+ /**
+ * Returns true if user is editing parent dependency.
+ */
+ private boolean isParent(Node currentNode) {
+ return "parent".equals(currentNode.getParentNode().getNodeName()); //$NON-NLS-1$
+ }
+
+ protected String getGroupId(Node currentNode) {
+ return getSiblingTextValue(currentNode, "groupId"); //$NON-NLS-1$
+ }
+
+ /**
+ *
+ * @param project
+ * @param version
+ * @param groupId
+ * @param artifactId
+ * @return
+ * @throws CoreException
+ */
+
+ static int EXTRACT_STRATEGY_PLUGIN = 1;
+ static int EXTRACT_STRATEGY_DEPENDENCY = 2;
+ static int EXTRACT_STRATEGY_SEARCH = 4;
+
+ static String extractVersion(IProject project, String version, String groupId, String artifactId, int strategy)
+ throws CoreException {
+ //interpolate the version found to get rid of expressions
+ version = simpleInterpolate(project, version);
+
+ if (version==null) {
+ Packaging pack = Packaging.ALL;
+ if ( (strategy & EXTRACT_STRATEGY_PLUGIN) != 0) {
+ version = searchPM(project, groupId, artifactId);
+ pack = Packaging.PLUGIN;
+ }
+ if ( (strategy & EXTRACT_STRATEGY_DEPENDENCY) != 0) {
+ version = searchDM(project, groupId, artifactId);
+ }
+ if (version == null && (strategy & EXTRACT_STRATEGY_SEARCH) != 0) {
+ Collection<String> versions = getSearchEngine(project).findVersions(groupId, artifactId, "", pack); //$NON-NLS-1$
+ if(versions.isEmpty()) {
+ return null;
+ }
+ version = versions.iterator().next();
+ }
+ }
+ return version;
+ }
+
+ //TODO MNGECLIPSE-2540 change project parameter to MavenProject I guess..
+ static String simpleInterpolate(IProject project, String text) {
+ if (text != null && text.contains("${")) { //$NON-NLS-1$
+ //when expression is in the version but no project instance around
+ // just give up.
+ if(project == null) {
+ return null;
+ }
+ IMavenProjectFacade mvnproject = MavenPlugin.getDefault().getMavenProjectManager().getProject(project);
+ if (mvnproject != null) {
+ MavenProject prj = mvnproject.getMavenProject();
+ if (prj != null) {
+ Properties props = prj.getProperties();
+ RegexBasedInterpolator inter = new RegexBasedInterpolator();
+ if (props != null) {
+ inter.addValueSource(new PropertiesBasedValueSource(props));
+ }
+ inter.addValueSource(new PrefixedObjectValueSource(Arrays.asList( new String[]{ "pom.", "project." } ), prj.getModel(), false)); //$NON-NLS-1$ //$NON-NLS-2$
+ try {
+ text = inter.interpolate(text);
+ } catch(InterpolationException e) {
+ text = null;
+ }
+
+ }
+ }
+ }
+ return text;
+ }
+
+ private static String searchPM(IProject project, String groupId, String artifactId) {
+ if (project == null) {
+ return null;
+ }
+ String version = null;
+ //see if we can find the plugin in plugin management of resolved project.
+ IMavenProjectFacade mvnproject = MavenPlugin.getDefault().getMavenProjectManager().getProject(project);
+ if(mvnproject != null) {
+ String id = Plugin.constructKey(groupId, artifactId);
+ MavenProject prj = mvnproject.getMavenProject();
+ if(prj != null) {
+ PluginManagement pm = prj.getPluginManagement();
+ if(pm != null) {
+ for(Plugin pl : pm.getPlugins()) {
+ if(id.equals(pl.getKey())) {
+ version = pl.getVersion();
+ break;
+ }
+ }
+ }
+ }
+ }
+ return version;
+ }
+
+ private static String searchDM(IProject project, String groupId, String artifactId) {
+ if (project == null) {
+ return null;
+ }
+ String version = null;
+ //see if we can find the dependency is in dependency management of resolved project.
+ IMavenProjectFacade mvnproject = MavenPlugin.getDefault().getMavenProjectManager().getProject(project);
+ if(mvnproject != null) {
+ String id = groupId + ":" + artifactId + ":";
+ MavenProject prj = mvnproject.getMavenProject();
+ if(prj != null) {
+ DependencyManagement dm = prj.getDependencyManagement();
+ if(dm != null) {
+ for(Dependency dep : dm.getDependencies()) {
+ if(dep.getManagementKey().startsWith(id)) {
+ version = dep.getVersion();
+ break;
+ }
+ }
+ }
+ }
+ }
+ return version;
+ }
+
+ protected static String getArtifactId(Node currentNode) {
+ return getSiblingTextValue(currentNode, "artifactId"); //$NON-NLS-1$
+ }
+
+ protected static String getVersion(Node currentNode) {
+ return getSiblingTextValue(currentNode, "version"); //$NON-NLS-1$
+ }
+
+ private static String getSiblingTextValue(Node sibling, String name) {
+ Node node = getSiblingWithName(sibling, name);
+ return getNodeTextValue(node);
+ }
+
+ /**
+ * Returns sibling with given name.
+ */
+ private static Node getSiblingWithName(Node node, String name) {
+ NodeList nodeList = node.getParentNode().getChildNodes();
+ for(int i = 0; i < nodeList.getLength(); i++ ) {
+ if(name.equals(nodeList.item(i).getNodeName())) {
+ return nodeList.item(i);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns text value of the node.
+ */
+ private static String getNodeTextValue(Node node) {
+ if(node != null && hasOneNode(node.getChildNodes())) {
+ return ((Text) node.getChildNodes().item(0)).getData().trim();
+ }
+ return null;
+ }
+
+ /**
+ * Returns true if there is only one node in the nodeList.
+ */
+ private static boolean hasOneNode(NodeList nodeList) {
+ return nodeList != null && nodeList.getLength() == 1;
+ }
+
+ private static void add(Collection<Template> proposals, String contextTypeId, String name) {
+ add(proposals, contextTypeId, name, name);
+ }
+
+ private static void add(Collection<Template> proposals, String contextTypeId, String name, String description) {
+ proposals.add(new Template(name, description, contextTypeId, name, false));
+ }
+
+}
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomTemplateContextType.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomTemplateContextType.java
new file mode 100644
index 00000000..597219e4
--- /dev/null
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomTemplateContextType.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.editor.xml;
+
+import org.eclipse.jface.text.templates.GlobalTemplateVariables;
+import org.eclipse.jface.text.templates.TemplateContextType;
+
+
+/**
+ * @author Lukas Krecan
+ */
+public class PomTemplateContextType extends TemplateContextType {
+ public PomTemplateContextType() {
+ 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/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomTemplateContextUtil.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomTemplateContextUtil.java
new file mode 100644
index 00000000..c140d2ba
--- /dev/null
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomTemplateContextUtil.java
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.editor.xml;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.plugin.descriptor.PluginDescriptor;
+import org.apache.maven.plugin.descriptor.PluginDescriptorBuilder;
+import org.codehaus.plexus.util.IOUtil;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.MavenConsole;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.embedder.IMaven;
+
+class PomTemplateContextUtil {
+
+ public static final PomTemplateContextUtil INSTANCE = new PomTemplateContextUtil();
+
+ private final Map<String, PluginDescriptor> descriptors = new HashMap<String, PluginDescriptor>();
+
+ public PluginDescriptor getPluginDescriptor(String groupId, String artifactId, String version) {
+ String name = groupId + ":" + artifactId + ":" + version;
+ PluginDescriptor descriptor = descriptors.get(name);
+ if(descriptor!=null) {
+ return descriptor;
+ }
+
+ MavenPlugin plugin = MavenPlugin.getDefault();
+ MavenConsole console = plugin.getConsole();
+ try {
+ IMaven embedder = MavenPlugin.getDefault().getMaven();
+
+ List<ArtifactRepository> repositories = embedder.getArtifactRepositories();
+
+ Artifact artifact = embedder.resolve(groupId, artifactId, version, "maven-plugin", null, repositories, null); //$NON-NLS-1$
+
+ File file = artifact.getFile();
+ if(file == null) {
+ String msg = "Can't resolve plugin " + name; //$NON-NLS-1$
+ console.logError(msg);
+ } else {
+ InputStream is = null;
+ ZipFile zf = null;
+ try {
+ zf = new ZipFile(file);
+ ZipEntry entry = zf.getEntry("META-INF/maven/plugin.xml"); //$NON-NLS-1$
+ if(entry != null) {
+ is = zf.getInputStream(entry);
+ PluginDescriptorBuilder builder = new PluginDescriptorBuilder();
+ descriptor = builder.build(new InputStreamReader(is));
+ descriptors.put(name, descriptor);
+ return descriptor;
+ }
+
+ } catch(Exception ex) {
+ String msg = "Can't read configuration for " + name; //$NON-NLS-1$
+ console.logError(msg);
+ MavenLogger.log(msg, ex);
+
+ } finally {
+ IOUtil.close(is);
+ try {
+ zf.close();
+ } catch(IOException ex) {
+ // ignore
+ }
+ }
+ }
+
+ } catch(CoreException ex) {
+ IStatus status = ex.getStatus();
+ if(status.getException() != null) {
+ console.logError(status.getMessage() + "; " + status.getException().getMessage());
+ } else {
+ console.logError(status.getMessage());
+ }
+ MavenLogger.log(ex);
+ }
+ return null;
+ }
+
+}
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomTextHover.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomTextHover.java
new file mode 100644
index 00000000..c0322877
--- /dev/null
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/PomTextHover.java
@@ -0,0 +1,148 @@
+package org.eclipse.m2e.editor.xml;
+
+import java.util.List;
+
+import org.apache.maven.model.Dependency;
+import org.apache.maven.model.DependencyManagement;
+import org.apache.maven.model.InputLocation;
+import org.apache.maven.model.InputSource;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.model.PluginManagement;
+import org.apache.maven.project.MavenProject;
+import org.w3c.dom.Node;
+
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.ITextHover;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.osgi.util.NLS;
+
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+import org.eclipse.m2e.editor.xml.PomHyperlinkDetector.ExpressionRegion;
+import org.eclipse.m2e.editor.xml.PomHyperlinkDetector.ManagedArtifactRegion;
+import org.eclipse.m2e.editor.xml.internal.Messages;
+
+public class PomTextHover implements ITextHover {
+
+ public PomTextHover(ISourceViewer sourceViewer, String contentType, int stateMask) {
+ }
+
+ public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) {
+ if (hoverRegion instanceof ExpressionRegion) {
+ ExpressionRegion region = (ExpressionRegion) hoverRegion;
+ IMavenProjectFacade mvnproject = MavenPlugin.getDefault().getMavenProjectManager().getProject(region.project);
+ if (mvnproject != null) {
+ MavenProject mavprj = mvnproject.getMavenProject();
+ if (mavprj != null) {
+ String value = PomTemplateContext.simpleInterpolate(region.project, "${" + region.property + "}"); //$NON-NLS-1$ //$NON-NLS-2$
+ String loc = null;
+ Model mdl = mavprj.getModel();
+ if (mdl.getProperties() != null && mdl.getProperties().containsKey(region.property)) {
+ if (mdl.getLocation("properties") != null) {
+ InputLocation location = mdl.getLocation("properties").getLocation(region.property); //$NON-NLS-1$
+ if (location != null) {
+ //MNGECLIPSE-2539 apparently you can have an InputLocation with null input source.
+ // check!
+ InputSource source = location.getSource();
+ if (source != null) {
+ loc = source.getModelId();
+ }
+ }
+ }
+ }
+ String ret = NLS.bind(Messages.PomTextHover_eval1,
+ value, loc != null ? NLS.bind(Messages.PomTextHover_eval2, loc) : ""); //$NON-NLS-2$ //$NON-NLS-1$
+ return ret;
+ }
+ }
+ } else if (hoverRegion instanceof ManagedArtifactRegion) {
+ ManagedArtifactRegion region = (ManagedArtifactRegion) hoverRegion;
+ IMavenProjectFacade mvnproject = MavenPlugin.getDefault().getMavenProjectManager().getProject(region.project);
+ if (mvnproject != null) {
+ MavenProject mavprj = mvnproject.getMavenProject();
+ if (mavprj != null) {
+ String version = null;
+ if (region.isDependency) {
+ DependencyManagement dm = mavprj.getDependencyManagement();
+ if (dm != null) {
+ List<Dependency> list = dm.getDependencies();
+ String id = region.groupId + ":" + region.artifactId + ":"; //$NON-NLS-1$ //$NON-NLS-2$
+ if (list != null) {
+ for (Dependency dep : list) {
+ if (dep.getManagementKey().startsWith(id)) {
+ version = dep.getVersion();
+ }
+ }
+ }
+ }
+ }
+
+ if (region.isPlugin) {
+ PluginManagement pm = mavprj.getPluginManagement();
+ if (pm != null) {
+ List<Plugin> list = pm.getPlugins();
+ String id = Plugin.constructKey(region.groupId, region.artifactId);
+ if (list != null) {
+ for (Plugin plg : list) {
+ if (id.equals(plg.getKey())) {
+ version = plg.getVersion();
+ }
+ }
+ }
+
+ }
+ }
+ StringBuffer ret = new StringBuffer();
+ ret.append("<html>"); //$NON-NLS-1$
+ if (version != null) {
+ ret.append(NLS.bind(Messages.PomTextHover_managed_version, version));
+ } else {
+ ret.append(Messages.PomTextHover_managed_version_missing);
+ }
+ ret.append("<br>"); //$NON-NLS-1$
+ InputLocation openLocation = PomHyperlinkDetector.findLocationForManagedArtifact(region, mavprj);
+ if (openLocation != null) {
+ //MNGECLIPSE-2539 apparently you can have an InputLocation with null input source.
+ // check!
+ InputSource source = openLocation.getSource();
+ if (source != null) {
+ ret.append(NLS.bind(Messages.PomTextHover_managed_location, source.getModelId()));
+ }
+ } else {
+ ret.append(Messages.PomTextHover_managed_location_missing);
+ }
+ ret.append("</html>"); //$NON-NLS-1$
+ return ret.toString();
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public IRegion getHoverRegion(ITextViewer textViewer, int offset) {
+ IDocument document = textViewer.getDocument();
+ if(document == null) {
+ return null;
+ }
+
+ Node current = PomHyperlinkDetector.getCurrentNode(document, offset);
+ if (current != null) {
+ ExpressionRegion region = PomHyperlinkDetector.findExpressionRegion(current, textViewer, offset);
+ if (region != null) {
+ return region;
+ }
+ ManagedArtifactRegion manReg = PomHyperlinkDetector.findManagedArtifactRegion(current, textViewer, offset);
+ if (manReg != null) {
+ return manReg;
+ }
+ }
+ return null;
+ }
+
+
+
+}
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/XMLSchemaMarkerResolution.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/XMLSchemaMarkerResolution.java
new file mode 100644
index 00000000..f35edc3d
--- /dev/null
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/XMLSchemaMarkerResolution.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.editor.xml;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.text.edits.InsertEdit;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IMarkerResolution;
+import org.eclipse.ui.ide.IDE;
+import org.eclipse.wst.sse.core.StructuredModelManager;
+import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion;
+import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel;
+
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.editor.xml.internal.Messages;
+
+/**
+ * MavenMarkerResolution
+ * TODO mkleint: this class shall be eventually merged with the class doing the same in POMQuickAssistProcessor
+ * @author dyocum
+ */
+public class XMLSchemaMarkerResolution implements IMarkerResolution {
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.IMarkerResolution#getLabel()
+ */
+ public String getLabel() {
+ return Messages.MavenMarkerResolution_schema_label;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.IMarkerResolution#run(org.eclipse.core.resources.IMarker)
+ */
+ public void run(final IMarker marker) {
+ if(marker.getResource().getType() == IResource.FILE){
+ try {
+ IDOMModel domModel = (IDOMModel)StructuredModelManager.getModelManager().getModelForEdit((IFile)marker.getResource());
+ int offset = ((Integer)marker.getAttribute("offset")); //$NON-NLS-1$
+ IStructuredDocumentRegion regionAtCharacterOffset = domModel.getStructuredDocument().getRegionAtCharacterOffset(offset);
+ if(regionAtCharacterOffset != null && regionAtCharacterOffset.getText() != null &&
+ regionAtCharacterOffset.getText().lastIndexOf("<project") >=0){ //$NON-NLS-1$
+ //in case there are unsaved changes, find the current offset of the <project> node before inserting
+ offset = regionAtCharacterOffset.getStartOffset();
+ IDE.openEditor(MvnIndexPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow().getActivePage(), (IFile)marker.getResource());
+ InsertEdit edit = new InsertEdit(offset+8, PomQuickAssistProcessor.XSI_VALUE);
+ try {
+ edit.apply(domModel.getStructuredDocument());
+ IEditorPart activeEditor = MvnIndexPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor();
+ MvnIndexPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow().getActivePage().saveEditor(activeEditor, false);
+ } catch(Exception e){
+ MavenLogger.log("Unable to insert schema info", e); //$NON-NLS-1$
+ }
+ } else {
+ String msg = Messages.MavenMarkerResolution_error;
+ MessageDialog.openError(MvnIndexPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow().getShell(), Messages.MavenMarkerResolution_error_title, msg);
+ }
+ } catch(Exception e) {
+ MavenLogger.log("Unable to run quick fix for maven marker", e); //$NON-NLS-1$
+ }
+ }
+ }
+
+}
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/Messages.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/Messages.java
new file mode 100644
index 00000000..aa74c0cb
--- /dev/null
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/Messages.java
@@ -0,0 +1,156 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+
+package org.eclipse.m2e.editor.xml.internal;
+
+import org.eclipse.osgi.util.NLS;
+
+
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.m2e.editor.xml.internal.messages"; //$NON-NLS-1$
+
+ public static String InsertArtifactProposal_additionals;
+
+ public static String InsertArtifactProposal_display_name;
+
+ public static String InsertArtifactProposal_insert_plugin_description;
+
+ public static String InsertArtifactProposal_insert_plugin_display_name;
+
+ public static String InsertArtifactProposal_insert_plugin_title;
+
+ public static String InsertArtifactProposal_searchDialog_title;
+
+ public static String InsertExpressionProposal_hint1;
+
+ public static String InsertExpressionProposal_hint2;
+
+ public static String MavenMarkerResolution_error;
+
+ public static String MavenMarkerResolution_error_title;
+
+ public static String MavenMarkerResolution_schema_label;
+ public static String PomContentAssistProcessor_insert_relPath_title;
+
+ public static String PomContentAssistProcessor_set_relPath_title;
+
+ public static String PomHyperlinkDetector_23;
+
+ public static String PomHyperlinkDetector_error_message;
+
+ public static String PomHyperlinkDetector_error_title;
+
+ public static String PomHyperlinkDetector_hyperlink_pattern;
+
+ public static String PomHyperlinkDetector_job_name;
+
+ public static String PomHyperlinkDetector_link_managed;
+
+ public static String PomHyperlinkDetector_open_module;
+
+ public static String PomHyperlinkDetector_open_property;
+
+ public static String PomQuickAssistProcessor_name;
+
+ public static String PomQuickAssistProcessor_remove_hint;
+ public static String PomQuickAssistProcessor_title_groupId;
+
+ public static String PomQuickAssistProcessor_title_version;
+
+ public static String PomTemplateContext_candidate;
+
+ public static String PomTemplateContext_clean;
+
+ public static String PomTemplateContext_compile;
+
+ public static String PomTemplateContext_deploy;
+
+ public static String PomTemplateContext_expression_description;
+
+ public static String PomTemplateContext_generateresources;
+
+ public static String PomTemplateContext_generatesources;
+
+ public static String PomTemplateContext_generatetestresources;
+
+ public static String PomTemplateContext_generatetestsources;
+
+ public static String PomTemplateContext_install;
+
+ public static String PomTemplateContext_integrationtest;
+
+ public static String PomTemplateContext_package;
+
+ public static String PomTemplateContext_param;
+
+ public static String PomTemplateContext_param_def;
+
+ public static String PomTemplateContext_param_expr;
+
+ public static String PomTemplateContext_postclean;
+
+ public static String PomTemplateContext_postintegrationtest;
+
+ public static String PomTemplateContext_postsite;
+
+ public static String PomTemplateContext_preclean;
+
+ public static String PomTemplateContext_preintegrationtest;
+
+ public static String PomTemplateContext_preparepackage;
+
+ public static String PomTemplateContext_presite;
+
+ public static String PomTemplateContext_processclasses;
+
+ public static String PomTemplateContext_processresources;
+
+ public static String PomTemplateContext_processsources;
+
+ public static String PomTemplateContext_processtestclasses;
+
+ public static String PomTemplateContext_processtestresources;
+
+ public static String PomTemplateContext_processtestsources;
+
+ public static String PomTemplateContext_project_version_hint;
+
+ public static String PomTemplateContext_site;
+
+ public static String PomTemplateContext_sitedeploy;
+
+ public static String PomTemplateContext_test;
+
+ public static String PomTemplateContext_testcompile;
+
+ public static String PomTemplateContext_validate;
+
+ public static String PomTemplateContext_verify;
+
+ public static String PomTextHover_eval1;
+
+ public static String PomTextHover_eval2;
+ public static String PomTextHover_managed_location;
+
+ public static String PomTextHover_managed_location_missing;
+
+ public static String PomTextHover_managed_version;
+
+ public static String PomTextHover_managed_version_missing;
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/POMMarkerAnnotationModel.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/POMMarkerAnnotationModel.java
new file mode 100644
index 00000000..5a7bc121
--- /dev/null
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/POMMarkerAnnotationModel.java
@@ -0,0 +1,34 @@
+package org.eclipse.m2e.editor.xml.internal;
+
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.ui.texteditor.MarkerAnnotation;
+import org.eclipse.wst.sse.ui.internal.StructuredResourceMarkerAnnotationModel;
+
+import org.eclipse.m2e.core.core.IMavenConstants;
+
+/**
+ * created this file to get the proper lightbulb icon for the warnings with hint
+ * @author mkleint
+ */
+public class POMMarkerAnnotationModel extends StructuredResourceMarkerAnnotationModel {
+
+ public POMMarkerAnnotationModel(IResource resource) {
+ super(resource);
+ }
+
+ public POMMarkerAnnotationModel(IResource resource, String secondaryID) {
+ super(resource, secondaryID);
+ }
+
+ @Override
+ protected MarkerAnnotation createMarkerAnnotation(IMarker marker) {
+ String hint = marker.getAttribute(IMavenConstants.MARKER_ATTR_EDITOR_HINT, null);
+ if(hint != null) {
+ MarkerAnnotation ann = new MarkerAnnotation(marker);
+ ann.setQuickFixable(true);
+ return ann;
+ }
+ return super.createMarkerAnnotation(marker);
+ }
+}
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/POMMarkerAnnotationModelFactory.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/POMMarkerAnnotationModelFactory.java
new file mode 100644
index 00000000..026f359a
--- /dev/null
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/POMMarkerAnnotationModelFactory.java
@@ -0,0 +1,34 @@
+package org.eclipse.m2e.editor.xml.internal;
+
+import org.eclipse.core.filebuffers.FileBuffers;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.jface.text.source.IAnnotationModel;
+import org.eclipse.ui.texteditor.ResourceMarkerAnnotationModelFactory;
+
+/**
+ * created this file to get the proper lightbulb icon for the warnings with hint
+ * is almost exact copy of the wst one..
+ * @author mkleint
+ */
+public class POMMarkerAnnotationModelFactory extends ResourceMarkerAnnotationModelFactory {
+ public POMMarkerAnnotationModelFactory() {
+ super();
+ }
+
+ /*
+ * @see org.eclipse.core.filebuffers.IAnnotationModelFactory#createAnnotationModel(org.eclipse.core.runtime.IPath)
+ */
+ public IAnnotationModel createAnnotationModel(IPath location) {
+ IAnnotationModel model = null;
+ IFile file = FileBuffers.getWorkspaceFileAtLocation(location);
+ if (file != null) {
+ model = new POMMarkerAnnotationModel(file);
+ }
+ else {
+ model = new POMMarkerAnnotationModel(ResourcesPlugin.getWorkspace().getRoot(), location.toString());
+ }
+ return model;
+ }
+}
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/messages.properties b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/messages.properties
new file mode 100644
index 00000000..169707c9
--- /dev/null
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/internal/messages.properties
@@ -0,0 +1,66 @@
+InsertArtifactProposal_additionals=Opens a search dialog where you can select the parent pom for this project.
+InsertArtifactProposal_display_name=Insert reference to parent POM
+InsertArtifactProposal_insert_plugin_description=Opens a search dialog where you can select a Maven plugin to add to this project
+InsertArtifactProposal_insert_plugin_display_name=Insert plugin
+InsertArtifactProposal_insert_plugin_title=Select Plugin
+InsertArtifactProposal_searchDialog_title=Select Parent
+InsertExpressionProposal_hint1=The expression evaluates to <b>{0}</b> in the current effective pom.
+InsertExpressionProposal_hint2=<br>It is based on property defined in <b>{0}</b>
+MavenMarkerResolution_error=Unable to apply the quick fix. The file may have unsaved changes that invalidate the current quick fix.
+MavenMarkerResolution_error_title=Error
+MavenMarkerResolution_schema_label=Add Schema information to the specified pom.xml
+PomContentAssistProcessor_insert_relPath_title=Insert relativePath pointing to {0}
+PomContentAssistProcessor_set_relPath_title=Set relativePath to {0}
+PomHyperlinkDetector_23=</artifactId>
+PomHyperlinkDetector_error_message=Can't open editor for {0}\n{1}
+PomHyperlinkDetector_error_title=Open Maven POM
+PomHyperlinkDetector_hyperlink_pattern=Open pom.xml for {0}:{1}
+PomHyperlinkDetector_job_name=Opening POM
+PomHyperlinkDetector_link_managed=Open managed location for {0}
+PomHyperlinkDetector_open_module=Open module project pom.xml at {0}
+PomHyperlinkDetector_open_property=Open definition of property {0}
+PomQuickAssistProcessor_name=Add Maven XML Schema declaration
+PomQuickAssistProcessor_remove_hint=It removes the current definition to rely on value inherited from parent
+PomQuickAssistProcessor_title_groupId=Remove groupId declaration
+PomQuickAssistProcessor_title_version=Remove version declaration
+PomTemplateContext_candidate=Maven project at {0}
+PomTemplateContext_clean=Removes all files generated by the previous build
+PomTemplateContext_compile=Compile the source code of the project
+PomTemplateContext_deploy=Done in an integration or release environment, copies the final package to the remote repository for sharing with other developers and projects
+PomTemplateContext_expression_description=Property defined in effective pom.
+PomTemplateContext_generateresources=Generate resources for inclusion in the package
+PomTemplateContext_generatesources=Generate any source code for inclusion in compilation
+PomTemplateContext_generatetestresources=Create resources for testing
+PomTemplateContext_generatetestsources=Generate any test source code for inclusion in compilation
+PomTemplateContext_install=Install the package into the local repository, for use as a dependency in other projects locally
+PomTemplateContext_integrationtest=Process and deploy the package if necessary into an environment where integration tests can be run
+PomTemplateContext_package=Take the compiled code and package it in its distributable format, such as a JAR
+PomTemplateContext_param=<b>required:</b> {0}<br><b>type:</b> {1}<br>
+PomTemplateContext_param_def=default: {0}<br>
+PomTemplateContext_param_expr=expression: {0}<br>
+PomTemplateContext_postclean=Executes processes needed to finalize the project cleaning
+PomTemplateContext_postintegrationtest=Perform actions required after integration tests have been executed. This may including cleaning up the environment
+PomTemplateContext_postsite=Executes processes needed to finalize the site generation, and to prepare for site deployment
+PomTemplateContext_preclean=Executes processes needed prior to the actual project cleaning
+PomTemplateContext_preintegrationtest=Perform actions required before integration tests are executed. This may involve things such as setting up the required environment
+PomTemplateContext_preparepackage=Perform any operations necessary to prepare a package before the actual packaging. This often results in an unpacked, processed version of the package. (Maven 2.1 and above)
+PomTemplateContext_presite=Executes processes needed prior to the actual project site generation
+PomTemplateContext_processclasses=Post-process the generated files from compilation, for example to do bytecode enhancement on Java classes
+PomTemplateContext_processresources=Copy and process the resources into the destination directory, ready for packaging
+PomTemplateContext_processsources=Process the source code, for example to filter any values
+PomTemplateContext_processtestclasses=Post-process the generated files from test compilation, for example to do bytecode enhancement on Java classes. For Maven 2.0.5 and above
+PomTemplateContext_processtestresources=Copy and process the resources into the test destination directory
+PomTemplateContext_processtestsources=Process the test source code, for example to filter any values
+PomTemplateContext_project_version_hint=For projects developed in sync only.
+PomTemplateContext_site=Generates the project's site documentation
+PomTemplateContext_sitedeploy=Deploys the generated site documentation to the specified web server
+PomTemplateContext_test=Run tests using a suitable unit testing framework. These tests should not require the code be packaged or deployed
+PomTemplateContext_testcompile=Compile the test source code into the test destination directory
+PomTemplateContext_validate=Validate the project is correct and all necessary information is available
+PomTemplateContext_verify=Run any checks to verify the package is valid and meets quality criteria
+PomTextHover_eval1=<html>This expression evaluates to <b>{0}</b>{1}</html>
+PomTextHover_eval2=<br>The property is defined in {0}
+PomTextHover_managed_location=The artifact is managed in {0}
+PomTextHover_managed_location_missing=The managed artifact's location could not be determined.
+PomTextHover_managed_version=The managed version is <b>{0}</b>
+PomTextHover_managed_version_missing=The managed version could not be determined
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/preferences/PomTemplatesPreferencePage.java b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/preferences/PomTemplatesPreferencePage.java
new file mode 100644
index 00000000..67022b62
--- /dev/null
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/preferences/PomTemplatesPreferencePage.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.editor.xml.preferences;
+
+import org.eclipse.ui.texteditor.templates.TemplatePreferencePage;
+
+import org.eclipse.m2e.editor.xml.MvnIndexPlugin;
+
+
+
+/**
+ * @author Eugene Kuleshov
+ */
+public class PomTemplatesPreferencePage extends TemplatePreferencePage {
+
+ public PomTemplatesPreferencePage() {
+ setPreferenceStore(MvnIndexPlugin.getDefault().getPreferenceStore());
+ setTemplateStore(MvnIndexPlugin.getDefault().getTemplateStore());
+ setContextTypeRegistry(MvnIndexPlugin.getDefault().getContextTypeRegistry());
+ }
+
+ @Override
+ public boolean performOk() {
+ boolean ok = super.performOk();
+ MvnIndexPlugin.getDefault().savePluginPreferences();
+ return ok;
+ }
+
+ @Override
+ protected boolean isShowFormatterSetting() {
+ return false;
+ }
+
+}
diff --git a/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/template/.gitignore b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/template/.gitignore
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/org.eclipse.m2e.editor.xml/src/main/java/org/eclipse/m2e/editor/xml/template/.gitignore

Back to the top