1 /******************************************************************************* 2 * Copyright (c) 2005, 2008 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 *******************************************************************************/ 14 package org.eclipse.ui.texteditor.rulers; 15 16 import java.net.URL; 17 18 import org.eclipse.core.runtime.Assert; 19 import org.eclipse.core.runtime.CoreException; 20 import org.eclipse.core.runtime.IConfigurationElement; 21 import org.eclipse.core.runtime.InvalidRegistryObjectException; 22 import org.eclipse.core.runtime.content.IContentType; 23 24 import org.eclipse.jface.resource.ImageDescriptor; 25 26 import org.eclipse.ui.IEditorInput; 27 import org.eclipse.ui.IWorkbenchPartSite; 28 import org.eclipse.ui.internal.texteditor.rulers.ExtensionPointHelper; 29 import org.eclipse.ui.internal.texteditor.rulers.RulerColumnMessages; 30 import org.eclipse.ui.internal.texteditor.rulers.RulerColumnPlacement; 31 import org.eclipse.ui.internal.texteditor.rulers.RulerColumnTarget; 32 33 import org.eclipse.ui.texteditor.IDocumentProvider; 34 import org.eclipse.ui.texteditor.IDocumentProviderExtension4; 35 import org.eclipse.ui.texteditor.ITextEditor; 36 37 38 /** 39 * The description of an extension to the 40 * <code>org.eclipse.ui.workbench.texteditor.rulerColumns</code> extension point. Instances are 41 * immutable. Instances can be obtained from a {@link RulerColumnRegistry}. 42 * 43 * @since 3.3 44 * @noinstantiate This class is not intended to be instantiated by clients. 45 */ 46 public final class RulerColumnDescriptor { 47 /** The extension schema name of the class attribute. */ 48 private static final String CLASS= "class"; //$NON-NLS-1$ 49 /** The extension schema name of the id attribute. */ 50 private static final String ID= "id"; //$NON-NLS-1$ 51 /** The extension schema name of the optional name attribute. */ 52 private static final String NAME= "name"; //$NON-NLS-1$ 53 /** The extension schema name of the optional enabled attribute. */ 54 private static final String ENABLED= "enabled"; //$NON-NLS-1$ 55 /** The extension schema name of the optional icon attribute. */ 56 private static final String ICON= "icon"; //$NON-NLS-1$ 57 /** The extension schema name of the optional global attribute. */ 58 private static final String GLOBAL= "global"; //$NON-NLS-1$ 59 /** The extension schema name of the optional menu inclusion attribute. */ 60 private static final String INCLUDE_IN_MENU= "includeInMenu"; //$NON-NLS-1$ 61 /** The extension schema name of the targetEditor element. */ 62 private static final String TARGET_EDITOR= "targetEditor"; //$NON-NLS-1$ 63 /** The extension schema name of the targetContentType element. */ 64 private static final String TARGET_CONTENT_TYPE= "targetContentType"; //$NON-NLS-1$ 65 /** The extension schema name of the targetClass element. */ 66 private static final String TARGET_CLASS= "targetClass"; //$NON-NLS-1$ 67 /** The extension schema name of the placement element. */ 68 private static final String PLACEMENT= "placement"; //$NON-NLS-1$ 69 70 /** The identifier of the extension. */ 71 private final String fId; 72 /** The name of the extension, equal to the id if no name is given. */ 73 private final String fName; 74 /** The icon descriptor. */ 75 private final ImageDescriptor fIcon; 76 /** The configuration element of this extension. */ 77 private final IConfigurationElement fElement; 78 /** The target specification of the ruler column contribution. */ 79 private final RulerColumnTarget fTarget; 80 /** The placement specification of the ruler column contribution. */ 81 private final RulerColumnPlacement fRulerColumnPlacement; 82 /** The default enablement setting of the ruler column contribution. */ 83 private final boolean fDefaultEnablement; 84 /** The global setting of the ruler column contribution. */ 85 private final boolean fIsGlobal; 86 /** The menu inclusion setting of the ruler column contribution. */ 87 private final boolean fIncludeInMenu; 88 89 /** 90 * Creates a new descriptor. 91 * 92 * @param element the configuration element to read 93 * @param registry the computer registry creating this descriptor 94 * @throws InvalidRegistryObjectException if the configuration element is no longer valid 95 * @throws CoreException if the configuration element does not conform to the extension point spec 96 */ RulerColumnDescriptor(IConfigurationElement element, RulerColumnRegistry registry)97 RulerColumnDescriptor(IConfigurationElement element, RulerColumnRegistry registry) throws InvalidRegistryObjectException, CoreException { 98 Assert.isLegal(registry != null); 99 Assert.isLegal(element != null); 100 fElement= element; 101 102 ExtensionPointHelper helper= new ExtensionPointHelper(element); 103 104 fId= helper.getNonNullAttribute(ID); 105 fName= helper.getDefaultAttribute(NAME, fId); 106 helper.getNonNullAttribute(CLASS); // just check validity 107 URL iconURL= helper.getDefaultResourceURL(ICON, null); 108 fIcon= iconURL == null ? null : ImageDescriptor.createFromURL(iconURL); 109 fDefaultEnablement= helper.getDefaultAttribute(ENABLED, true); 110 fIsGlobal= helper.getDefaultAttribute(GLOBAL, true); 111 fIncludeInMenu= helper.getDefaultAttribute(INCLUDE_IN_MENU, true); 112 113 IConfigurationElement[] targetEditors= element.getChildren(TARGET_EDITOR); 114 IConfigurationElement[] targetContentTypes= element.getChildren(TARGET_CONTENT_TYPE); 115 IConfigurationElement[] targetClasses= element.getChildren(TARGET_CLASS); 116 117 if (targetContentTypes.length + targetEditors.length + targetClasses.length == 0) { 118 helper.fail(RulerColumnMessages.RulerColumnDescriptor_missing_target_msg); 119 fTarget= null; // dummy 120 } else { 121 RulerColumnTarget combined= null; 122 for (IConfigurationElement targetEditor : targetEditors) { 123 RulerColumnTarget target= RulerColumnTarget.createEditorIdTarget(new ExtensionPointHelper(targetEditor).getNonNullAttribute(ID)); 124 combined= RulerColumnTarget.createOrTarget(combined, target); 125 } 126 for (IConfigurationElement targetContentType : targetContentTypes) { 127 RulerColumnTarget target= RulerColumnTarget.createContentTypeTarget(new ExtensionPointHelper(targetContentType).getNonNullAttribute(ID)); 128 combined= RulerColumnTarget.createOrTarget(combined, target); 129 } 130 for (IConfigurationElement targetClass : targetClasses) { 131 RulerColumnTarget target= RulerColumnTarget.createClassTarget(new ExtensionPointHelper(targetClass).getNonNullAttribute(CLASS)); 132 combined= RulerColumnTarget.createOrTarget(combined, target); 133 } 134 fTarget= combined; 135 } 136 137 IConfigurationElement[] placements= element.getChildren(PLACEMENT); 138 switch (placements.length) { 139 case 0: 140 fRulerColumnPlacement= new RulerColumnPlacement(); 141 break; 142 case 1: 143 fRulerColumnPlacement= new RulerColumnPlacement(placements[0]); 144 break; 145 default: 146 helper.fail(RulerColumnMessages.RulerColumnDescriptor_invalid_placement_msg); 147 fRulerColumnPlacement= null; // dummy 148 break; 149 } 150 151 Assert.isTrue(fTarget != null); 152 Assert.isTrue(fRulerColumnPlacement != null); 153 } 154 155 /** 156 * Returns the identifier of the described extension. 157 * 158 * @return the identifier of the described extension 159 */ getId()160 public String getId() { 161 return fId; 162 } 163 164 /** 165 * Returns the name of the described extension. 166 * 167 * @return the name of the described extension 168 */ getName()169 public String getName() { 170 return fName; 171 } 172 173 /** 174 * Returns the image descriptor of the described extension, <code>null</code> if it does not 175 * have an image. 176 * 177 * @return the image descriptor of the described extension or <code>null</code> for no image 178 */ getIcon()179 public ImageDescriptor getIcon() { 180 return fIcon; 181 } 182 getTarget()183 RulerColumnTarget getTarget() { 184 return fTarget; 185 } 186 getPlacement()187 RulerColumnPlacement getPlacement() { 188 return fRulerColumnPlacement; 189 } 190 191 /** 192 * Returns the default enablement of the described extension. Editors that support this 193 * contribution should typically enable the column by default. 194 * 195 * @return the default enablement of the described extension 196 */ getDefaultEnablement()197 public boolean getDefaultEnablement() { 198 return fDefaultEnablement; 199 } 200 201 /** 202 * Returns the global property of the described extension. Changing the visibility of a column 203 * with the global property set to <code>true</code> should typically affect all matching 204 * editors. Changing the visibility of a column with the global property set to 205 * <code>false</code> should only affect the current editor. 206 * 207 * @return the global property of the described extension 208 */ isGlobal()209 public boolean isGlobal() { 210 return fIsGlobal; 211 } 212 213 /** 214 * Returns the menu inclusion property of the described extension. A toggle menu entry should be 215 * inluded in the ruler context menu for columns with this property set to <code>true</code>. 216 * 217 * @return the menu inclusion property of the described extension 218 */ isIncludedInMenu()219 public boolean isIncludedInMenu() { 220 return fIncludeInMenu; 221 } 222 223 /** 224 * Returns <code>true</code> if this contribution matches the passed editor, <code>false</code> if not. 225 * 226 * @param editor the editor to check 227 * @return <code>true</code> if this contribution targets the passed editor 228 */ matchesEditor(ITextEditor editor)229 public boolean matchesEditor(ITextEditor editor) { 230 Assert.isLegal(editor != null); 231 RulerColumnTarget target= getTarget(); 232 233 IWorkbenchPartSite site= editor.getSite(); 234 if (site != null && target.matchesEditorId(site.getId())) 235 return true; 236 237 if (target.matchesClass(editor.getClass())) 238 return true; 239 240 IContentType contentType= getContentType(editor); 241 return contentType != null && target.matchesContentType(contentType); 242 243 } 244 245 /** 246 * Creates a {@link IContributedRulerColumn} instance as described by the receiver. This may load the contributing plug-in. 247 * 248 * @param editor the editor that loads the contributed column 249 * @return the instantiated column 250 * @throws CoreException as thrown by {@link IConfigurationElement#createExecutableExtension(String)} 251 * @throws InvalidRegistryObjectException as thrown by {@link IConfigurationElement#createExecutableExtension(String)} 252 */ createColumn(ITextEditor editor)253 public IContributedRulerColumn createColumn(ITextEditor editor) throws CoreException, InvalidRegistryObjectException { 254 Assert.isLegal(editor != null); 255 IContributedRulerColumn column= (IContributedRulerColumn)fElement.createExecutableExtension(CLASS); 256 column.setDescriptor(this); 257 column.setEditor(editor); 258 column.columnCreated(); 259 return column; 260 } 261 262 @Override toString()263 public String toString() { 264 return "RulerColumnDescriptor[name=" + getName() + "]"; //$NON-NLS-1$ //$NON-NLS-2$ 265 } 266 getConfigurationElement()267 IConfigurationElement getConfigurationElement() { 268 return fElement; 269 } 270 271 @Override hashCode()272 public int hashCode() { 273 final int prime= 31; 274 int result= 1; 275 result= prime * result + ((fId == null) ? 0 : fId.hashCode()); 276 return result; 277 } 278 279 @Override equals(Object obj)280 public boolean equals(Object obj) { 281 if (this == obj) 282 return true; 283 if (obj == null) 284 return false; 285 if (getClass() != obj.getClass()) 286 return false; 287 final RulerColumnDescriptor other= (RulerColumnDescriptor) obj; 288 if (fId == null) { 289 if (other.fId != null) 290 return false; 291 } else if (!fId.equals(other.fId)) 292 return false; 293 return true; 294 } 295 296 /** 297 * Returns the content type of the editor's input, <code>null</code> if the editor input or 298 * the document provider is <code>null</code> or the content type cannot be determined. 299 * 300 * @param editor the editor to get the content type from 301 * @return the content type of the editor's input, <code>null</code> if it cannot be 302 * determined 303 */ getContentType(ITextEditor editor)304 private IContentType getContentType(ITextEditor editor) { 305 IEditorInput input= editor.getEditorInput(); 306 if (input == null) 307 return null; 308 IDocumentProvider provider= editor.getDocumentProvider(); 309 if (provider instanceof IDocumentProviderExtension4) { 310 IDocumentProviderExtension4 ext= (IDocumentProviderExtension4) provider; 311 try { 312 return ext.getContentType(input); 313 } catch (CoreException x) { 314 // ignore and return null; 315 } 316 } 317 return null; 318 } 319 getContributor()320 String getContributor() { 321 try { 322 return fElement.getContributor().getName(); 323 } catch (InvalidRegistryObjectException e) { 324 return "unknown"; //$NON-NLS-1$ 325 } 326 } 327 } 328