1) Added missing strings for italic, underline and strike through.
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / core / CreateElementInCUOperation.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2003 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.internal.core;
12
13 import net.sourceforge.phpdt.core.IBuffer;
14 import net.sourceforge.phpdt.core.ICompilationUnit;
15 import net.sourceforge.phpdt.core.IJavaElement;
16 import net.sourceforge.phpdt.core.IJavaModelStatus;
17 import net.sourceforge.phpdt.core.IJavaModelStatusConstants;
18 import net.sourceforge.phpdt.core.JavaConventions;
19 import net.sourceforge.phpdt.core.JavaModelException;
20 import net.sourceforge.phpdt.core.jdom.DOMFactory;
21 import net.sourceforge.phpdt.core.jdom.IDOMCompilationUnit;
22 import net.sourceforge.phpdt.core.jdom.IDOMNode;
23 import net.sourceforge.phpdt.internal.core.jdom.DOMNode;
24 import net.sourceforge.phpdt.internal.core.util.Util;
25
26 import org.eclipse.core.resources.IResource;
27 import org.eclipse.core.resources.IWorkspace;
28 import org.eclipse.core.runtime.jobs.ISchedulingRule;
29
30 /**
31  * <p>
32  * This abstract class implements behavior common to
33  * <code>CreateElementInCUOperations</code>. To create a compilation unit, or
34  * an element contained in a compilation unit, the source code for the entire
35  * compilation unit is updated and saved.
36  * 
37  * <p>
38  * The element being created can be positioned relative to an existing element
39  * in the compilation unit via the methods <code>#createAfter</code> and
40  * <code>#createBefore</code>. By default, the new element is positioned as
41  * the last child of its parent element.
42  * 
43  */
44 public abstract class CreateElementInCUOperation extends JavaModelOperation {
45         /**
46          * The compilation unit DOM used for this operation
47          */
48         protected IDOMCompilationUnit fCUDOM;
49
50         /**
51          * A constant meaning to position the new element as the last child of its
52          * parent element.
53          */
54         protected static final int INSERT_LAST = 1;
55
56         /**
57          * A constant meaning to position the new element after the element defined
58          * by <code>fAnchorElement</code>.
59          */
60         protected static final int INSERT_AFTER = 2;
61
62         /**
63          * A constant meaning to position the new element before the element defined
64          * by <code>fAnchorElement</code>.
65          */
66         protected static final int INSERT_BEFORE = 3;
67
68         /**
69          * One of the position constants, describing where to position the newly
70          * created element.
71          */
72         protected int fInsertionPolicy = INSERT_LAST;
73
74         /**
75          * The element that the newly created element is positioned relative to, as
76          * described by <code>fInsertPosition</code>, or <code>null</code> if
77          * the newly created element will be positioned last.
78          */
79         protected IJavaElement fAnchorElement = null;
80
81         /**
82          * A flag indicating whether creation of a new element occurred. A request
83          * for creating a duplicate element would request in this flag being set to
84          * <code>false</code>. Ensures that no deltas are generated when creation
85          * does not occur.
86          */
87         protected boolean fCreationOccurred = true;
88
89         /**
90          * The element that is being created.
91          */
92         protected DOMNode fCreatedElement;
93
94         /**
95          * The position of the element that is being created.
96          */
97         protected int fInsertionPosition = -1;
98
99         /**
100          * The number of characters the new element replaces, or 0 if the new
101          * element is inserted, or -1 if the new element is append to the end of the
102          * CU.
103          */
104         protected int fReplacementLength = -1;
105
106         /**
107          * Constructs an operation that creates a Java Language Element with the
108          * specified parent, contained within a compilation unit.
109          */
110         public CreateElementInCUOperation(IJavaElement parentElement) {
111                 super(null, new IJavaElement[] { parentElement });
112                 initializeDefaultPosition();
113         }
114
115         /**
116          * Only allow cancelling if this operation is not nested.
117          */
118         protected void checkCanceled() {
119                 if (!isNested) {
120                         super.checkCanceled();
121                 }
122         }
123
124         /**
125          * Instructs this operation to position the new element after the given
126          * sibling, or to add the new element as the last child of its parent if
127          * <code>null</code>.
128          */
129         public void createAfter(IJavaElement sibling) {
130                 setRelativePosition(sibling, INSERT_AFTER);
131         }
132
133         /**
134          * Instructs this operation to position the new element before the given
135          * sibling, or to add the new element as the last child of its parent if
136          * <code>null</code>.
137          */
138         public void createBefore(IJavaElement sibling) {
139                 setRelativePosition(sibling, INSERT_BEFORE);
140         }
141
142         /**
143          * Execute the operation - generate new source for the compilation unit and
144          * save the results.
145          * 
146          * @exception JavaModelException
147          *                if the operation is unable to complete
148          */
149         protected void executeOperation() throws JavaModelException {
150                 try {
151                         beginTask(getMainTaskName(), getMainAmountOfWork());
152                         JavaElementDelta delta = newJavaElementDelta();
153                         ICompilationUnit unit = getCompilationUnit();
154                         generateNewCompilationUnitDOM(unit);
155                         if (fCreationOccurred) {
156                                 // a change has really occurred
157                                 IBuffer buffer = unit.getBuffer();
158                                 if (buffer == null)
159                                         return;
160                                 char[] bufferContents = buffer.getCharacters();
161                                 if (bufferContents == null)
162                                         return;
163                                 char[] elementContents = net.sourceforge.phpdt.internal.core.util.Util
164                                                 .normalizeCRs(fCreatedElement.getCharacters(),
165                                                                 bufferContents);
166                                 switch (fReplacementLength) {
167                                 case -1:
168                                         // element is append at the end
169                                         buffer.append(elementContents);
170                                         break;
171                                 case 0:
172                                         // element is inserted
173                                         buffer.replace(fInsertionPosition, 0, elementContents);
174                                         break;
175                                 default:
176                                         // element is replacing the previous one
177                                         buffer.replace(fInsertionPosition, fReplacementLength,
178                                                         elementContents);
179                                 }
180                                 unit.save(null, false);
181                                 boolean isWorkingCopy = unit.isWorkingCopy();
182                                 if (!isWorkingCopy)
183                                         this.setAttribute(HAS_MODIFIED_RESOURCE_ATTR, TRUE);
184                                 worked(1);
185                                 resultElements = generateResultHandles();
186                                 if (!isWorkingCopy // if unit is working copy, then save will
187                                                                         // have already fired the delta
188                                                 && !Util.isExcluded(unit) && unit.getParent().exists()) {
189                                         for (int i = 0; i < resultElements.length; i++) {
190                                                 delta.added(resultElements[i]);
191                                         }
192                                         addDelta(delta);
193                                 } // else unit is created outside classpath
194                                 // non-java resource delta will be notified by delta processor
195                         }
196                 } finally {
197                         done();
198                 }
199         }
200
201         /**
202          * Returns a JDOM document fragment for the element being created.
203          */
204         protected abstract IDOMNode generateElementDOM() throws JavaModelException;
205
206         /**
207          * Returns the DOM with the new source to use for the given compilation
208          * unit.
209          */
210         protected void generateNewCompilationUnitDOM(ICompilationUnit cu)
211                         throws JavaModelException {
212                 IBuffer buffer = cu.getBuffer();
213                 if (buffer == null)
214                         return;
215                 char[] prevSource = buffer.getCharacters();
216                 if (prevSource == null)
217                         return;
218
219                 // create a JDOM for the compilation unit
220                 fCUDOM = (new DOMFactory()).createCompilationUnit(prevSource, cu
221                                 .getElementName());
222                 IDOMNode child = generateElementDOM();
223                 if (child != null) {
224                         insertDOMNode(fCUDOM, child);
225                 }
226                 worked(1);
227         }
228
229         /**
230          * Creates and returns the handle for the element this operation created.
231          */
232         protected abstract IJavaElement generateResultHandle();
233
234         /**
235          * Creates and returns the handles for the elements this operation created.
236          */
237         protected IJavaElement[] generateResultHandles() throws JavaModelException {
238                 return new IJavaElement[] { generateResultHandle() };
239         }
240
241         /**
242          * Returns the compilation unit in which the new element is being created.
243          */
244         protected ICompilationUnit getCompilationUnit() {
245                 return getCompilationUnitFor(getParentElement());
246         }
247
248         /**
249          * Returns the amount of work for the main task of this operation for
250          * progress reporting.
251          */
252         protected int getMainAmountOfWork() {
253                 return 2;
254         }
255
256         /**
257          * Returns the name of the main task of this operation for progress
258          * reporting.
259          */
260         public abstract String getMainTaskName();
261
262         protected ISchedulingRule getSchedulingRule() {
263                 IResource resource = getCompilationUnit().getResource();
264                 IWorkspace workspace = resource.getWorkspace();
265                 return workspace.getRuleFactory().modifyRule(resource);
266         }
267
268         /**
269          * Returns the elements created by this operation.
270          */
271         public IJavaElement[] getResultElements() {
272                 return resultElements;
273         }
274
275         /**
276          * Sets the default position in which to create the new type member. By
277          * default, the new element is positioned as the last child of the parent
278          * element in which it is created. Operations that require a different
279          * default position must override this method.
280          */
281         protected void initializeDefaultPosition() {
282
283         }
284
285         /**
286          * Inserts the given child into the given JDOM, based on the position
287          * settings of this operation.
288          * 
289          * @see createAfter(IJavaElement)
290          * @see createBefore(IJavaElement);
291          */
292         protected void insertDOMNode(IDOMNode parent, IDOMNode child) {
293                 if (fInsertionPolicy != INSERT_LAST) {
294                         IDOMNode sibling = ((JavaElement) fAnchorElement).findNode(fCUDOM);
295                         if (sibling != null && fInsertionPolicy == INSERT_AFTER) {
296                                 sibling = sibling.getNextNode();
297                         }
298                         if (sibling != null) {
299                                 sibling.insertSibling(child);
300                                 fCreatedElement = (DOMNode) child;
301                                 fInsertionPosition = ((DOMNode) sibling).getStartPosition();
302                                 fReplacementLength = 0;
303                                 return;
304                         }
305                 }
306                 // add as the last element of the parent
307                 parent.addChild(child);
308                 fCreatedElement = (DOMNode) child;
309                 fInsertionPosition = ((DOMNode) parent).getInsertionPosition();
310                 // fInsertionPosition = lastChild == null ?
311                 // ((DOMNode)parent).getInsertionPosition() :
312                 // lastChild.getInsertionPosition();
313                 fReplacementLength = parent.getParent() == null ? -1 : 0;
314         }
315
316         /**
317          * Sets the name of the <code>DOMNode</code> that will be used to create
318          * this new element. Used by the <code>CopyElementsOperation</code> for
319          * renaming. Only used for <code>CreateTypeMemberOperation</code>
320          */
321         protected void setAlteredName(String newName) {
322         }
323
324         /**
325          * Instructs this operation to position the new element relative to the
326          * given sibling, or to add the new element as the last child of its parent
327          * if <code>null</code>. The <code>position</code> must be one of the
328          * position constants.
329          */
330         protected void setRelativePosition(IJavaElement sibling, int policy)
331                         throws IllegalArgumentException {
332                 if (sibling == null) {
333                         fAnchorElement = null;
334                         fInsertionPolicy = INSERT_LAST;
335                 } else {
336                         fAnchorElement = sibling;
337                         fInsertionPolicy = policy;
338                 }
339         }
340
341         /**
342          * Possible failures:
343          * <ul>
344          * <li>NO_ELEMENTS_TO_PROCESS - the compilation unit supplied to the
345          * operation is <code>null</code>.
346          * <li>INVALID_NAME - no name, a name was null or not a valid import
347          * declaration name.
348          * <li>INVALID_SIBLING - the sibling provided for positioning is not valid.
349          * </ul>
350          * 
351          * @see IJavaModelStatus
352          * @see JavaConventions
353          */
354         public IJavaModelStatus verify() {
355                 if (getParentElement() == null) {
356                         return new JavaModelStatus(
357                                         IJavaModelStatusConstants.NO_ELEMENTS_TO_PROCESS);
358                 }
359                 if (fAnchorElement != null) {
360                         IJavaElement domPresentParent = fAnchorElement.getParent();
361                         if (domPresentParent.getElementType() == IJavaElement.IMPORT_CONTAINER) {
362                                 domPresentParent = domPresentParent.getParent();
363                         }
364                         if (!domPresentParent.equals(getParentElement())) {
365                                 return new JavaModelStatus(
366                                                 IJavaModelStatusConstants.INVALID_SIBLING,
367                                                 fAnchorElement);
368                         }
369                 }
370                 return JavaModelStatus.VERIFIED_OK;
371         }
372 }