1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Eclipse Public License, Version 1.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.eclipse.org/org/documents/epl-v10.php 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.ide.eclipse.adt.internal.editors; 18 19 20 import com.android.ide.eclipse.adt.internal.editors.formatting.AndroidXmlFormatter; 21 import com.android.ide.eclipse.adt.internal.editors.formatting.AndroidXmlFormattingStrategy; 22 23 import org.eclipse.jface.text.DefaultAutoIndentStrategy; 24 import org.eclipse.jface.text.IAutoEditStrategy; 25 import org.eclipse.jface.text.ITextHover; 26 import org.eclipse.jface.text.ITextViewer; 27 import org.eclipse.jface.text.contentassist.ICompletionProposal; 28 import org.eclipse.jface.text.contentassist.IContentAssistProcessor; 29 import org.eclipse.jface.text.contentassist.IContentAssistant; 30 import org.eclipse.jface.text.contentassist.IContextInformation; 31 import org.eclipse.jface.text.contentassist.IContextInformationValidator; 32 import org.eclipse.jface.text.formatter.IContentFormatter; 33 import org.eclipse.jface.text.formatter.MultiPassContentFormatter; 34 import org.eclipse.jface.text.source.ISourceViewer; 35 import org.eclipse.wst.sse.core.text.IStructuredPartitions; 36 import org.eclipse.wst.xml.core.text.IXMLPartitions; 37 import org.eclipse.wst.xml.ui.StructuredTextViewerConfigurationXML; 38 import org.eclipse.wst.xml.ui.internal.contentassist.XMLContentAssistProcessor; 39 40 import java.util.ArrayList; 41 import java.util.List; 42 import java.util.Map; 43 44 /** 45 * Base Source Viewer Configuration for Android resources. 46 */ 47 @SuppressWarnings({"restriction", "deprecation"}) // XMLContentAssistProcessor etc 48 public abstract class AndroidSourceViewerConfig extends StructuredTextViewerConfigurationXML { 49 50 public AndroidSourceViewerConfig() { 51 super(); 52 } 53 54 @Override 55 public IContentAssistant getContentAssistant(ISourceViewer sourceViewer) { 56 return super.getContentAssistant(sourceViewer); 57 } 58 59 /** 60 * Returns the IContentAssistProcessor that 61 * {@link #getContentAssistProcessors(ISourceViewer, String)} should use 62 * for XML and default/unknown partitions. 63 * 64 * @return An {@link IContentAssistProcessor} or null. 65 */ 66 public abstract IContentAssistProcessor getAndroidContentAssistProcessor( 67 ISourceViewer sourceViewer, 68 String partitionType); 69 70 /** 71 * Returns the content assist processors that will be used for content 72 * assist in the given source viewer and for the given partition type. 73 * 74 * @param sourceViewer the source viewer to be configured by this 75 * configuration 76 * @param partitionType the partition type for which the content assist 77 * processors are applicable 78 * @return IContentAssistProcessors or null if should not be supported 79 */ 80 @Override 81 protected IContentAssistProcessor[] getContentAssistProcessors( 82 ISourceViewer sourceViewer, String partitionType) { 83 ArrayList<IContentAssistProcessor> processors = new ArrayList<IContentAssistProcessor>(); 84 if (partitionType == IStructuredPartitions.UNKNOWN_PARTITION || 85 partitionType == IStructuredPartitions.DEFAULT_PARTITION || 86 partitionType == IXMLPartitions.XML_DEFAULT) { 87 88 IContentAssistProcessor processor = 89 getAndroidContentAssistProcessor(sourceViewer, partitionType); 90 91 if (processor != null) { 92 processors.add(processor); 93 } 94 } 95 96 IContentAssistProcessor[] others = super.getContentAssistProcessors(sourceViewer, 97 partitionType); 98 if (others != null && others.length > 0) { 99 for (IContentAssistProcessor p : others) { 100 // Builtin Eclipse WTP code completion assistant? If so, 101 // wrap it with our own filter which hides some unwanted completions. 102 if (p instanceof XMLContentAssistProcessor 103 // On Eclipse 3.7, XMLContentAssistProcessor is no longer used, 104 // and instead org.eclipse.wst.xml.ui.internal.contentassist. 105 // XMLStructuredContentAssistProcessor is used - which isn't available 106 // at compile time in 3.5. 107 || p.getClass().getSimpleName().equals( 108 "XMLStructuredContentAssistProcessor")) { //$NON-NLS-1$ 109 processors.add(new FilteringContentAssistProcessor(p)); 110 } else { 111 processors.add(p); 112 } 113 } 114 } 115 116 if (processors.size() > 0) { 117 return processors.toArray(new IContentAssistProcessor[processors.size()]); 118 } else { 119 return null; 120 } 121 } 122 123 @Override 124 public ITextHover getTextHover(ISourceViewer sourceViewer, String contentType) { 125 // TODO text hover for android xml 126 return super.getTextHover(sourceViewer, contentType); 127 } 128 129 @Override 130 public IAutoEditStrategy[] getAutoEditStrategies( 131 ISourceViewer sourceViewer, String contentType) { 132 IAutoEditStrategy[] strategies = super.getAutoEditStrategies(sourceViewer, contentType); 133 List<IAutoEditStrategy> s = new ArrayList<IAutoEditStrategy>(strategies.length + 1); 134 s.add(new AndroidXmlAutoEditStrategy()); 135 136 // Add other registered strategies, except the builtin indentation strategy which is 137 // now handled by the above AndroidXmlAutoEditStrategy 138 for (IAutoEditStrategy strategy : strategies) { 139 if (strategy instanceof DefaultAutoIndentStrategy) { 140 continue; 141 } 142 s.add(strategy); 143 } 144 145 return s.toArray(new IAutoEditStrategy[s.size()]); 146 } 147 148 @Override 149 public IContentFormatter getContentFormatter(ISourceViewer sourceViewer) { 150 IContentFormatter formatter = super.getContentFormatter(sourceViewer); 151 152 if (formatter instanceof MultiPassContentFormatter) { 153 ((MultiPassContentFormatter) formatter).setMasterStrategy( 154 new AndroidXmlFormattingStrategy()); 155 return formatter; 156 } else { 157 return new AndroidXmlFormatter(); 158 } 159 } 160 161 @Override 162 protected Map<String, ?> getHyperlinkDetectorTargets(final ISourceViewer sourceViewer) { 163 @SuppressWarnings("unchecked") 164 Map<String, ?> targets = super.getHyperlinkDetectorTargets(sourceViewer); 165 // If we want to look up more context in our HyperlinkDetector via the 166 // getAdapter method, we should place an IAdaptable object into the map here. 167 targets.put("com.android.ide.eclipse.xmlCode", null); //$NON-NLS-1$ 168 return targets; 169 } 170 171 /** 172 * A delegating {@link IContentAssistProcessor} whose purpose is to filter out some 173 * default Eclipse XML completions which are distracting in Android XML files 174 */ 175 private static class FilteringContentAssistProcessor implements IContentAssistProcessor { 176 private IContentAssistProcessor mDelegate; 177 178 public FilteringContentAssistProcessor(IContentAssistProcessor delegate) { 179 super(); 180 mDelegate = delegate; 181 } 182 183 @Override 184 public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) { 185 ICompletionProposal[] result = mDelegate.computeCompletionProposals(viewer, offset); 186 if (result == null) { 187 return null; 188 } 189 190 List<ICompletionProposal> proposals = 191 new ArrayList<ICompletionProposal>(result.length); 192 for (ICompletionProposal proposal : result) { 193 String replacement = proposal.getDisplayString(); 194 if (replacement.charAt(0) == '"' && 195 replacement.charAt(replacement.length() - 1) == '"') { 196 // Filter out attribute values. In Android XML files (where there is no DTD 197 // etc) the default Eclipse XML code completion simply provides the 198 // existing value as a completion. This is often misleading, since if you 199 // for example have a typo, completion will show your current (wrong) 200 // value as a valid completion. 201 } else if (replacement.contains("Namespace") //$NON-NLS-1$ 202 || replacement.startsWith("XSL ") //$NON-NLS-1$ 203 || replacement.contains("Schema")) { //$NON-NLS-1$ 204 // Eclipse adds in a number of namespace and schema related completions which 205 // are not usually applicable in our files. 206 } else { 207 proposals.add(proposal); 208 } 209 } 210 211 if (proposals.size() == result.length) { 212 return result; 213 } else { 214 return proposals.toArray(new ICompletionProposal[proposals.size()]); 215 } 216 } 217 218 @Override 219 public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) { 220 return mDelegate.computeContextInformation(viewer, offset); 221 } 222 223 @Override 224 public char[] getCompletionProposalAutoActivationCharacters() { 225 return mDelegate.getCompletionProposalAutoActivationCharacters(); 226 } 227 228 @Override 229 public char[] getContextInformationAutoActivationCharacters() { 230 return mDelegate.getContextInformationAutoActivationCharacters(); 231 } 232 233 @Override 234 public IContextInformationValidator getContextInformationValidator() { 235 return mDelegate.getContextInformationValidator(); 236 } 237 238 @Override 239 public String getErrorMessage() { 240 return mDelegate.getErrorMessage(); 241 } 242 } 243 } 244