001: /*******************************************************************************
002: * Copyright (c) 2005, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.pde.internal.ui.refactoring;
011:
012: import org.eclipse.core.filebuffers.FileBuffers;
013: import org.eclipse.core.filebuffers.ITextFileBuffer;
014: import org.eclipse.core.filebuffers.ITextFileBufferManager;
015: import org.eclipse.core.filebuffers.LocationKind;
016: import org.eclipse.core.resources.IContainer;
017: import org.eclipse.core.resources.IFile;
018: import org.eclipse.core.resources.IResource;
019: import org.eclipse.core.runtime.CoreException;
020: import org.eclipse.core.runtime.IProgressMonitor;
021: import org.eclipse.core.runtime.Path;
022: import org.eclipse.jdt.core.IJavaElement;
023: import org.eclipse.jdt.core.IPackageFragment;
024: import org.eclipse.jdt.core.IType;
025: import org.eclipse.jface.text.IDocument;
026: import org.eclipse.ltk.core.refactoring.Change;
027: import org.eclipse.ltk.core.refactoring.TextChange;
028: import org.eclipse.ltk.core.refactoring.TextFileChange;
029: import org.eclipse.pde.core.plugin.IPluginAttribute;
030: import org.eclipse.pde.core.plugin.IPluginElement;
031: import org.eclipse.pde.core.plugin.IPluginExtension;
032: import org.eclipse.pde.core.plugin.IPluginObject;
033: import org.eclipse.pde.core.plugin.IPluginParent;
034: import org.eclipse.pde.internal.core.PDECore;
035: import org.eclipse.pde.internal.core.ischema.IMetaAttribute;
036: import org.eclipse.pde.internal.core.ischema.ISchema;
037: import org.eclipse.pde.internal.core.ischema.ISchemaAttribute;
038: import org.eclipse.pde.internal.core.ischema.ISchemaElement;
039: import org.eclipse.pde.internal.core.schema.SchemaRegistry;
040: import org.eclipse.pde.internal.core.text.IDocumentAttributeNode;
041: import org.eclipse.pde.internal.core.text.plugin.FragmentModel;
042: import org.eclipse.pde.internal.core.text.plugin.PluginModel;
043: import org.eclipse.pde.internal.core.text.plugin.PluginModelBase;
044: import org.eclipse.pde.internal.core.text.plugin.PluginNode;
045: import org.eclipse.pde.internal.ui.util.PDEModelUtility;
046: import org.eclipse.text.edits.MultiTextEdit;
047: import org.eclipse.text.edits.ReplaceEdit;
048: import org.eclipse.text.edits.TextEdit;
049:
050: public class PluginManifestChange {
051:
052: public static Change createRenameChange(IFile file,
053: Object[] affectedElements, String[] newNames,
054: TextChange textChange, IProgressMonitor monitor)
055: throws CoreException {
056: ITextFileBufferManager manager = FileBuffers
057: .getTextFileBufferManager();
058: try {
059: manager.connect(file.getFullPath(), LocationKind.NORMALIZE,
060: monitor);
061: ITextFileBuffer buffer = manager.getTextFileBuffer(file
062: .getFullPath(), LocationKind.NORMALIZE);
063:
064: MultiTextEdit multiEdit = new MultiTextEdit();
065:
066: IDocument document = buffer.getDocument();
067:
068: try {
069: PluginModelBase model;
070: if ("fragment.xml".equals(file.getName())) //$NON-NLS-1$
071: model = new FragmentModel(document, false);
072: else
073: model = new PluginModel(document, false);
074:
075: model.load();
076: if (!model.isLoaded())
077: return null;
078:
079: for (int i = 0; i < affectedElements.length; i++) {
080: if (model instanceof PluginModel
081: && affectedElements[i] instanceof IJavaElement) {
082: PluginNode plugin = (PluginNode) model
083: .getPluginBase();
084: IDocumentAttributeNode attr = plugin
085: .getDocumentAttribute("class"); //$NON-NLS-1$
086: TextEdit edit = createTextEdit(attr,
087: (IJavaElement) affectedElements[i],
088: newNames[i]);
089: if (edit != null)
090: multiEdit.addChild(edit);
091: }
092:
093: SchemaRegistry registry = PDECore.getDefault()
094: .getSchemaRegistry();
095: IPluginExtension[] extensions = model
096: .getPluginBase().getExtensions();
097: for (int j = 0; j < extensions.length; j++) {
098: ISchema schema = registry
099: .getSchema(extensions[j].getPoint());
100: if (schema != null)
101: addExtensionAttributeEdit(schema,
102: extensions[j], multiEdit,
103: affectedElements[i], newNames[i]);
104: }
105: }
106:
107: if (multiEdit.hasChildren()) {
108: // add to existing text edits. If you create a new MultiText edit, the file will get corrupted since the edits are applied independently
109: if (textChange != null) {
110: TextEdit edit = textChange.getEdit();
111: if (edit instanceof MultiTextEdit) {
112: ((MultiTextEdit) edit).addChild(multiEdit);
113: multiEdit = ((MultiTextEdit) edit);
114: } else
115: multiEdit.addChild(edit);
116: }
117: TextFileChange change = new TextFileChange("", file); //$NON-NLS-1$
118: change.setEdit(multiEdit);
119: PDEModelUtility.setChangeTextType(change, file);
120: return change;
121: }
122: } catch (CoreException e) {
123: return null;
124: }
125: return null;
126: } finally {
127: manager.disconnect(file.getFullPath(),
128: LocationKind.NORMALIZE, monitor);
129: }
130: }
131:
132: private static void addExtensionAttributeEdit(ISchema schema,
133: IPluginParent parent, MultiTextEdit multi, Object element,
134: String newName) {
135: IPluginObject[] children = parent.getChildren();
136: for (int i = 0; i < children.length; i++) {
137: IPluginElement child = (IPluginElement) children[i];
138: ISchemaElement schemaElement = schema.findElement(child
139: .getName());
140: if (schemaElement != null) {
141: IPluginAttribute[] attributes = child.getAttributes();
142: for (int j = 0; j < attributes.length; j++) {
143: IPluginAttribute attr = attributes[j];
144: ISchemaAttribute attInfo = schemaElement
145: .getAttribute(attr.getName());
146: if (attInfo != null) {
147: if (element instanceof IJavaElement
148: && attInfo.getKind() == IMetaAttribute.JAVA) {
149: IDocumentAttributeNode docAttr = (IDocumentAttributeNode) attr;
150: TextEdit edit = createTextEdit(docAttr,
151: (IJavaElement) element, newName);
152: if (edit != null)
153: multi.addChild(edit);
154: } else if (element instanceof IResource
155: && attInfo.getKind() == IMetaAttribute.RESOURCE) {
156: IDocumentAttributeNode docAttr = (IDocumentAttributeNode) attr;
157: TextEdit edit = createTextEdit(docAttr,
158: (IResource) element, newName);
159: if (edit != null)
160: multi.addChild(edit);
161: }
162: }
163: }
164: }
165: addExtensionAttributeEdit(schema, child, multi, element,
166: newName);
167: }
168: }
169:
170: private static TextEdit createTextEdit(IDocumentAttributeNode attr,
171: IJavaElement element, String newName) {
172: if (attr == null)
173: return null;
174:
175: String oldName = (element instanceof IType) ? ((IType) element)
176: .getFullyQualifiedName('$') : element.getElementName();
177: String value = attr.getAttributeValue();
178: if (oldName.equals(value)
179: || isGoodMatch(value, oldName,
180: element instanceof IPackageFragment)) {
181: int offset = attr.getValueOffset();
182: if (offset >= 0)
183: return new ReplaceEdit(offset, oldName.length(),
184: newName);
185: }
186: return null;
187: }
188:
189: private static TextEdit createTextEdit(IDocumentAttributeNode attr,
190: IResource resource, String newName) {
191: if (attr != null) {
192: String oldName = resource.getProjectRelativePath()
193: .toString();
194: String value = attr.getAttributeValue();
195: if (oldName.equals(value)
196: || ((resource instanceof IContainer) && isGoodFolderMatch(
197: value, oldName))) {
198: int offset = attr.getValueOffset();
199: if (offset >= 0)
200: return new ReplaceEdit(offset, oldName.length(),
201: newName);
202: }
203: }
204: return null;
205: }
206:
207: private static boolean isGoodMatch(String value, String oldName,
208: boolean isPackage) {
209: if (value == null || value.length() <= oldName.length())
210: return false;
211: boolean goodLengthMatch = isPackage ? value.lastIndexOf('.') <= oldName
212: .length()
213: : value.charAt(oldName.length()) == '$';
214: return value.startsWith(oldName) && goodLengthMatch;
215: }
216:
217: private static boolean isGoodFolderMatch(String value,
218: String oldName) {
219: return new Path(oldName).isPrefixOf(new Path(value));
220: }
221: }
|