1 /******************************************************************************* 2 * Copyright (c) 2005, 2010 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.pde.internal.ui.refactoring; 15 16 import org.eclipse.core.filebuffers.*; 17 import org.eclipse.core.resources.*; 18 import org.eclipse.core.runtime.*; 19 import org.eclipse.jdt.core.*; 20 import org.eclipse.jface.text.IDocument; 21 import org.eclipse.ltk.core.refactoring.*; 22 import org.eclipse.pde.core.plugin.*; 23 import org.eclipse.pde.internal.core.ICoreConstants; 24 import org.eclipse.pde.internal.core.PDECore; 25 import org.eclipse.pde.internal.core.ischema.*; 26 import org.eclipse.pde.internal.core.schema.SchemaRegistry; 27 import org.eclipse.pde.internal.core.text.IDocumentAttributeNode; 28 import org.eclipse.pde.internal.core.text.plugin.*; 29 import org.eclipse.pde.internal.ui.util.PDEModelUtility; 30 import org.eclipse.text.edits.*; 31 32 public class PluginManifestChange { 33 createRenameChange(IFile file, Object[] affectedElements, String[] newNames, TextChange textChange, IProgressMonitor monitor)34 public static Change createRenameChange(IFile file, Object[] affectedElements, String[] newNames, TextChange textChange, IProgressMonitor monitor) throws CoreException { 35 ITextFileBufferManager manager = FileBuffers.getTextFileBufferManager(); 36 try { 37 manager.connect(file.getFullPath(), LocationKind.NORMALIZE, monitor); 38 ITextFileBuffer buffer = manager.getTextFileBuffer(file.getFullPath(), LocationKind.NORMALIZE); 39 40 MultiTextEdit multiEdit = new MultiTextEdit(); 41 42 IDocument document = buffer.getDocument(); 43 44 try { 45 PluginModelBase model; 46 if (ICoreConstants.FRAGMENT_FILENAME_DESCRIPTOR.equals(file.getName())) 47 model = new FragmentModel(document, false); 48 else 49 model = new PluginModel(document, false); 50 51 model.load(); 52 if (!model.isLoaded()) 53 return null; 54 55 for (int i = 0; i < affectedElements.length; i++) { 56 if (model instanceof PluginModel && affectedElements[i] instanceof IJavaElement) { 57 PluginNode plugin = (PluginNode) model.getPluginBase(); 58 IDocumentAttributeNode attr = plugin.getDocumentAttribute("class"); //$NON-NLS-1$ 59 TextEdit edit = createTextEdit(attr, (IJavaElement) affectedElements[i], newNames[i]); 60 if (edit != null) 61 multiEdit.addChild(edit); 62 } 63 64 SchemaRegistry registry = PDECore.getDefault().getSchemaRegistry(); 65 IPluginExtension[] extensions = model.getPluginBase().getExtensions(); 66 for (IPluginExtension extension : extensions) { 67 ISchema schema = registry.getSchema(extension.getPoint()); 68 if (schema != null) 69 addExtensionAttributeEdit(schema, extension, multiEdit, affectedElements[i], newNames[i]); 70 } 71 } 72 73 if (multiEdit.hasChildren()) { 74 // add to existing text edits. If you create a new MultiText edit, the file will get corrupted since the edits are applied independently 75 if (textChange != null) { 76 TextEdit edit = textChange.getEdit(); 77 if (edit instanceof MultiTextEdit) { 78 ((MultiTextEdit) edit).addChild(multiEdit); 79 multiEdit = ((MultiTextEdit) edit); 80 } else 81 multiEdit.addChild(edit); 82 } 83 TextFileChange change = new TextFileChange("", file); //$NON-NLS-1$ 84 change.setEdit(multiEdit); 85 PDEModelUtility.setChangeTextType(change, file); 86 return change; 87 } 88 } catch (CoreException e) { 89 return null; 90 } 91 return null; 92 } finally { 93 manager.disconnect(file.getFullPath(), LocationKind.NORMALIZE, monitor); 94 } 95 } 96 addExtensionAttributeEdit(ISchema schema, IPluginParent parent, MultiTextEdit multi, Object element, String newName)97 private static void addExtensionAttributeEdit(ISchema schema, IPluginParent parent, MultiTextEdit multi, Object element, String newName) { 98 IPluginObject[] children = parent.getChildren(); 99 for (IPluginObject childObject : children) { 100 IPluginElement child = (IPluginElement) childObject; 101 ISchemaElement schemaElement = schema.findElement(child.getName()); 102 if (schemaElement != null) { 103 IPluginAttribute[] attributes = child.getAttributes(); 104 for (IPluginAttribute attr : attributes) { 105 ISchemaAttribute attInfo = schemaElement.getAttribute(attr.getName()); 106 if (attInfo != null) { 107 if (element instanceof IJavaElement && attInfo.getKind() == IMetaAttribute.JAVA) { 108 IDocumentAttributeNode docAttr = (IDocumentAttributeNode) attr; 109 TextEdit edit = createTextEdit(docAttr, (IJavaElement) element, newName); 110 if (edit != null) 111 multi.addChild(edit); 112 } else if (element instanceof IResource && attInfo.getKind() == IMetaAttribute.RESOURCE) { 113 IDocumentAttributeNode docAttr = (IDocumentAttributeNode) attr; 114 TextEdit edit = createTextEdit(docAttr, (IResource) element, newName); 115 if (edit != null) 116 multi.addChild(edit); 117 } 118 } 119 } 120 } 121 addExtensionAttributeEdit(schema, child, multi, element, newName); 122 } 123 } 124 createTextEdit(IDocumentAttributeNode attr, IJavaElement element, String newName)125 private static TextEdit createTextEdit(IDocumentAttributeNode attr, IJavaElement element, String newName) { 126 if (attr == null) 127 return null; 128 129 String oldName = (element instanceof IType) ? ((IType) element).getFullyQualifiedName('$') : element.getElementName(); 130 String value = attr.getAttributeValue(); 131 if (oldName.equals(value) || isGoodMatch(value, oldName, element instanceof IPackageFragment)) { 132 int offset = attr.getValueOffset(); 133 if (offset >= 0) 134 return new ReplaceEdit(offset, oldName.length(), newName); 135 } 136 return null; 137 } 138 createTextEdit(IDocumentAttributeNode attr, IResource resource, String newName)139 private static TextEdit createTextEdit(IDocumentAttributeNode attr, IResource resource, String newName) { 140 if (attr != null) { 141 String oldName = resource.getProjectRelativePath().toString(); 142 String value = attr.getAttributeValue(); 143 if (oldName.equals(value) || ((resource instanceof IContainer) && isGoodFolderMatch(value, oldName))) { 144 int offset = attr.getValueOffset(); 145 if (offset >= 0) 146 return new ReplaceEdit(offset, oldName.length(), newName); 147 } 148 } 149 return null; 150 } 151 isGoodMatch(String value, String oldName, boolean isPackage)152 private static boolean isGoodMatch(String value, String oldName, boolean isPackage) { 153 if (value == null || value.length() <= oldName.length()) 154 return false; 155 boolean goodLengthMatch = isPackage ? value.lastIndexOf('.') <= oldName.length() : value.charAt(oldName.length()) == '$'; 156 return value.startsWith(oldName) && goodLengthMatch; 157 } 158 isGoodFolderMatch(String value, String oldName)159 private static boolean isGoodFolderMatch(String value, String oldName) { 160 return new Path(oldName).isPrefixOf(new Path(value)); 161 } 162 } 163