001: /*******************************************************************************
002: * Copyright (c) 2005, 2007 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.nls;
011:
012: import java.lang.reflect.InvocationTargetException;
013: import java.util.HashMap;
014: import java.util.Iterator;
015:
016: import org.eclipse.core.filebuffers.FileBuffers;
017: import org.eclipse.core.filebuffers.ITextFileBuffer;
018: import org.eclipse.core.filebuffers.ITextFileBufferManager;
019: import org.eclipse.core.filebuffers.LocationKind;
020: import org.eclipse.core.resources.IFile;
021: import org.eclipse.core.runtime.CoreException;
022: import org.eclipse.core.runtime.IProgressMonitor;
023: import org.eclipse.jface.text.IDocument;
024: import org.eclipse.jface.text.TextUtilities;
025: import org.eclipse.ltk.core.refactoring.CompositeChange;
026: import org.eclipse.ltk.core.refactoring.TextFileChange;
027: import org.eclipse.osgi.util.NLS;
028: import org.eclipse.pde.core.IBaseModel;
029: import org.eclipse.pde.core.plugin.IPluginModelBase;
030: import org.eclipse.pde.internal.core.ibundle.IBundle;
031: import org.eclipse.pde.internal.core.ibundle.IBundlePluginModelBase;
032: import org.eclipse.pde.internal.ui.PDEUIMessages;
033: import org.eclipse.pde.internal.ui.util.ModelModification;
034: import org.eclipse.pde.internal.ui.util.PDEModelUtility;
035: import org.eclipse.text.edits.InsertEdit;
036: import org.eclipse.text.edits.MalformedTreeException;
037: import org.eclipse.text.edits.MultiTextEdit;
038: import org.eclipse.text.edits.ReplaceEdit;
039: import org.eclipse.text.edits.TextEditGroup;
040: import org.eclipse.ui.actions.WorkspaceModifyOperation;
041:
042: public class ExternalizeStringsOperation extends
043: WorkspaceModifyOperation {
044:
045: private Object[] fChangeFiles;
046: private CompositeChange fParentChange;
047: private HashMap fCompositeChanges;
048: private HashMap fFileChanges;
049:
050: public ExternalizeStringsOperation(Object[] changeFiles,
051: CompositeChange parentChange) {
052: fChangeFiles = changeFiles;
053: fParentChange = parentChange;
054: fCompositeChanges = new HashMap();
055: fFileChanges = new HashMap();
056: }
057:
058: protected void execute(IProgressMonitor monitor)
059: throws CoreException, InvocationTargetException,
060: InterruptedException {
061: for (int i = 0; i < fChangeFiles.length; i++) {
062: if (fChangeFiles[i] instanceof ModelChangeFile) {
063: ModelChangeFile changeFile = (ModelChangeFile) fChangeFiles[i];
064: CompositeChange pluginChange = getChangeForPlugin(changeFile
065: .getModel().getParentModel().getPluginBase()
066: .getId());
067: ModelChange change = changeFile.getModel();
068: IFile pFile = change.getPropertiesFile();
069: // if the properties file does not exist and we have not already made a TextFileChange
070: // for it create the Change and insert a comment
071: if (!pFile.exists() && !fFileChanges.containsKey(pFile)) {
072: TextFileChange fileChange = getChangeForFile(pFile,
073: pluginChange);
074: InsertEdit edit = new InsertEdit(0,
075: getPropertiesFileComment(pFile));
076: fileChange.getEdit().addChild(edit);
077: fileChange
078: .addTextEditGroup(new TextEditGroup(
079: PDEUIMessages.ExternalizeStringsOperation_editNames_addComment,
080: edit));
081: }
082: if (!change.localizationSet())
083: addBundleLocalization(change, monitor, pluginChange);
084:
085: ITextFileBufferManager pManager = FileBuffers
086: .getTextFileBufferManager();
087: try {
088: pManager.connect(pFile.getFullPath(),
089: LocationKind.IFILE, monitor);
090: ITextFileBuffer pBuffer = pManager
091: .getTextFileBuffer(pFile.getFullPath(),
092: LocationKind.IFILE);
093: IDocument pDoc = pBuffer.getDocument();
094: TextFileChange pChange = getChangeForFile(pFile,
095: pluginChange);
096:
097: doReplace(changeFile, pDoc, pChange, monitor,
098: pluginChange);
099:
100: } catch (MalformedTreeException e) {
101: } finally {
102: pManager.disconnect(pFile.getFullPath(),
103: LocationKind.IFILE, monitor);
104: }
105: }
106: }
107: }
108:
109: private CompositeChange getChangeForPlugin(String pluginName) {
110: if (fCompositeChanges.containsKey(pluginName))
111: return (CompositeChange) fCompositeChanges.get(pluginName);
112: CompositeChange result = new CompositeChange(
113: NLS
114: .bind(
115: PDEUIMessages.ExternalizeStringsOperation_pluginChangeName,
116: pluginName));
117: fCompositeChanges.put(pluginName, result);
118: fParentChange.add(result);
119: return result;
120: }
121:
122: private TextFileChange getChangeForFile(IFile file,
123: CompositeChange parentChange) {
124: if (fFileChanges.containsKey(file))
125: return (TextFileChange) fFileChanges.get(file);
126: MultiTextEdit edit = new MultiTextEdit();
127: TextFileChange change = new TextFileChange(file.getName(), file);
128: change.setEdit(edit);
129: // mark a plugin.xml or a fragment.xml as PLUGIN2 type so they will be compared
130: // with the PluginContentMergeViewer
131: String textType = file.getName().equals("plugin.xml") || //$NON-NLS-1$
132: file.getName().equals("fragment.xml") ? //$NON-NLS-1$
133: "PLUGIN2"
134: : file.getFileExtension(); //$NON-NLS-1$
135: change.setTextType(textType);
136: parentChange.add(change);
137: fFileChanges.put(file, change);
138: return change;
139: }
140:
141: private void doReplace(ModelChangeFile changeFile, IDocument pDoc,
142: TextFileChange pChange, IProgressMonitor monitor,
143: CompositeChange parentChange) throws CoreException {
144: IFile uFile = changeFile.getFile();
145: try {
146: TextFileChange uChange = getChangeForFile(uFile,
147: parentChange);
148:
149: Iterator iter = changeFile.getChanges().iterator();
150:
151: while (iter.hasNext()) {
152: ModelChangeElement changeElement = (ModelChangeElement) iter
153: .next();
154: if (changeElement.isExternalized()) {
155: ReplaceEdit uEdit = new ReplaceEdit(changeElement
156: .getOffset(), changeElement.getLength(),
157: changeElement.getExternKey());
158: uChange.getEdit().addChild(uEdit);
159: uChange
160: .addTextEditGroup(new TextEditGroup(
161: NLS
162: .bind(
163: PDEUIMessages.ExternalizeStringsOperation_editNames_replaceText,
164: changeElement
165: .getKey()),
166: uEdit));
167: InsertEdit pEdit = getPropertiesInsertEdit(pDoc,
168: changeElement);
169: pChange.getEdit().addChild(pEdit);
170: pChange
171: .addTextEditGroup(new TextEditGroup(
172: NLS
173: .bind(
174: PDEUIMessages.ExternalizeStringsOperation_editNames_insertProperty,
175: changeElement
176: .getKey()),
177: pEdit));
178: }
179: }
180: } catch (MalformedTreeException e) {
181: }
182: }
183:
184: private void addBundleLocalization(ModelChange change,
185: IProgressMonitor mon, CompositeChange parent) {
186: IPluginModelBase base = change.getParentModel();
187: IFile manifest = base.getUnderlyingResource().getProject()
188: .getFile(PDEModelUtility.F_MANIFEST_FP);
189: // if the edit for this manifest file is in the HashMap, then we must have added
190: // the localization already since it is checked first (this must be the second or subsequent
191: // change to the manifest for this plug-in)
192: if (fFileChanges.containsKey(manifest))
193: return;
194: final String localiz = change.getBundleLocalization();
195: TextFileChange[] result = PDEModelUtility
196: .changesForModelModication(new ModelModification(
197: manifest) {
198: protected void modifyModel(IBaseModel model,
199: IProgressMonitor monitor)
200: throws CoreException {
201: if (model instanceof IBundlePluginModelBase) {
202: IBundlePluginModelBase bundleModel = (IBundlePluginModelBase) model;
203: IBundle bundle = bundleModel
204: .getBundleModel().getBundle();
205: bundle.setLocalization(localiz);
206: }
207: }
208: }, mon);
209: // this model change just adds localization to the manifest, so we will only have one change
210: // with one edit
211: if (result.length > 0 && result[0] != null) {
212: // we know the manifest does not already have a change in the HashMap, so just add the resultant one
213: fFileChanges.put(manifest, result[0]);
214: parent.add(result[0]);
215: }
216: }
217:
218: public static InsertEdit getPropertiesInsertEdit(IDocument doc,
219: ModelChangeElement element) {
220: String nl = TextUtilities.getDefaultLineDelimiter(doc);
221: StringBuffer sb = new StringBuffer(nl);
222: sb.append(element.getKey());
223: sb.append(" = "); //$NON-NLS-1$
224: sb.append(StringHelper.preparePropertiesString(element
225: .getValue(), nl.toCharArray()));
226: return new InsertEdit(doc.getLength(), sb.toString());
227: }
228:
229: public static String getPropertiesFileComment(IFile file) {
230: return NLS
231: .bind(
232: "#Properties file for {0}", file.getProject().getName()); //$NON-NLS-1$
233: }
234: }
|