Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 5a239fdb280677a5fb944936182cffdca444acc1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
/*******************************************************************************
 * Copyright (c) 2000, 2008 QNX Software Systems and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     QNX Software Systems - Initial API and implementation
 *******************************************************************************/

package org.eclipse.cdt.internal.core.model;

import org.eclipse.cdt.core.CConventions;
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.IBuffer;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ICModelStatus;
import org.eclipse.cdt.core.model.ICModelStatusConstants;
import org.eclipse.cdt.core.model.ISourceRange;
import org.eclipse.cdt.core.model.ISourceReference;
import org.eclipse.cdt.core.model.ITranslationUnit;

/**
 * <p>This abstract class implements behavior common to <code>CreateElementInTUOperations</code>.
 * To create a compilation unit, or an element contained in a compilation unit, the
 * source code for the entire compilation unit is updated and saved.
 *
 * <p>The element being created can be positioned relative to an existing
 * element in the compilation unit via the methods <code>#createAfter</code>
 * and <code>#createBefore</code>. By default, the new element is positioned
 * as the last child of its parent element.
 *
 */
public abstract class CreateElementInTUOperation extends CModelOperation {

	/**
	 * A constant meaning to position the new element
	 * as the last child of its parent element.
	 */
	protected static final int INSERT_LAST = 1;

	/**
	 * A constant meaning to position the new element
	 * after the element defined by <code>fAnchorElement</code>.
	 */
	protected static final int INSERT_AFTER = 2;

	/**
	 * A constant meaning to position the new element
	 * before the element defined by <code>fAnchorElement</code>.
	 */
	protected static final int INSERT_BEFORE = 3;

	/**
	 * One of the position constants, describing where
	 * to position the newly created element.
	 */
	protected int fInsertionPolicy = INSERT_LAST;

	/**
	 * The element that is being created.
	 */
	protected String fCreatedElement = null;

	/**
	 * The element that the newly created element is
	 * positioned relative to, as described by
	 * <code>fInsertPosition</code>, or <code>null</code>
	 * if the newly created element will be positioned
	 * last.
	 */
	protected ICElement fAnchorElement = null;

	/**
	 * A flag indicating whether creation of a new element occurred.
	 * A request for creating a duplicate element would request in this
	 * flag being set to <code>false</code>. Ensures that no deltas are generated
	 * when creation does not occur.
	 */
	protected boolean fCreationOccurred = true;

	/**
	 * The position of the element that is being created.
	 */
	protected int fInsertionPosition = -1;

	/**
	 * The number of characters the new element replaces,
	 * or 0 if the new element is inserted,
	 * or -1 if the new element is append to the end of the CU.
	 */
	protected int fReplacementLength = -1;

	/**
	 * Constructs an operation that creates a C Language Element with
	 * the specified parent, contained within a translation unit.
	 */
	public CreateElementInTUOperation(ICElement parentElement) {
		super(null, new ICElement[]{parentElement});
		initializeDefaultPosition();
	}

	/**
	 * Only allow cancelling if this operation is not nested.
	 */
	@Override
	protected void checkCanceled() {
		if (!fNested) {
			super.checkCanceled();
		}
	}

	/**
	 * Instructs this operation to position the new element after
	 * the given sibling, or to add the new element as the last child
	 * of its parent if <code>null</code>.
	 */
	public void createAfter(ICElement sibling) {
		setRelativePosition(sibling, INSERT_AFTER);
	}

	/**
	 * Instructs this operation to position the new element before
	 * the given sibling, or to add the new element as the last child
	 * of its parent if <code>null</code>.
	 */
	public void createBefore(ICElement sibling) {
		setRelativePosition(sibling, INSERT_BEFORE);
	}

	protected abstract String generateElement(ITranslationUnit unit) throws CModelException;
	
	/**
	 * Execute the operation - generate new source for the compilation unit
	 * and save the results.
	 *
	 * @exception CModelException if the operation is unable to complete
	 */
	@Override
	protected void executeOperation() throws CModelException {
		beginTask(getMainTaskName(), getMainAmountOfWork());
		CElementDelta delta = newCElementDelta();
		ITranslationUnit unit = getTranslationUnit();
		fCreatedElement = generateElement(unit);
		insertElement();
		if (fCreationOccurred) {
			//a change has really occurred
			IBuffer buffer = unit.getBuffer();
			if (buffer == null) return;
			char[] bufferContents = buffer.getCharacters();
			if (bufferContents == null) return;
			char[] elementContents = Util.normalizeCRs(getCreatedElementCharacters(), bufferContents);
			switch (fReplacementLength) {
				case -1 : 
					// element is append at the end
					buffer.append(elementContents);
					break;

				case 0 :
					// element is inserted
					buffer.replace(fInsertionPosition, 0, elementContents);
					break;

				default :
					// element is replacing the previous one
					buffer.replace(fInsertionPosition, fReplacementLength, elementContents);
			}
			unit.save(null, false);
			boolean isWorkingCopy = unit.isWorkingCopy();
			//if (isWorkingCopy) {
			//	this.setAttributes(...);
			//}
			worked(1);
			fResultElements = generateResultHandles();
			if (!isWorkingCopy) { // if unit is working copy, then save will have already fired the delta
				if (unit.getParent().exists()) {
					for (ICElement resultElement : fResultElements) {
						delta.added(resultElement);
					}
					addDelta(delta);
				} // else unit is created outside classpath
				  // non-java resource delta will be notified by delta processor
			}
		}
		done();
	}

	private char[] getCreatedElementCharacters() {
		return fCreatedElement.toCharArray();
	}

	/**
	 * Creates and returns the handle for the element this operation created.
	 */
	protected abstract ICElement generateResultHandle();

	/**
	 * Creates and returns the handles for the elements this operation created.
	 */
	protected ICElement[] generateResultHandles() throws CModelException {
		return new ICElement[]{generateResultHandle()};
	}

	/**
	 * Returns the compilation unit in which the new element is being created.
	 */
	protected ITranslationUnit getTranslationUnit() {
		return ((ISourceReference)getParentElement()).getTranslationUnit();
	}

	/**
	 * Returns the amount of work for the main task of this operation for
	 * progress reporting.
	 * @see #executeOperation()
	 */
	protected int getMainAmountOfWork(){
		return 2;
	}

	/**
	 * Returns the name of the main task of this operation for
	 * progress reporting.
	 * @see #executeOperation()
	 */
	protected abstract String getMainTaskName();

	/**
	 * Returns the elements created by this operation.
	 */
	@Override
	public ICElement[] getResultElements() {
		return fResultElements;
	}

	/**
	 * Sets the default position in which to create the new type
	 * member. By default, the new element is positioned as the
	 * last child of the parent element in which it is created.
	 * Operations that require a different default position must
	 * override this method.
	 */
	protected void initializeDefaultPosition() {
	}

	/**
	 * Inserts the given child into the given JDOM, 
	 * based on the position settings of this operation.
	 *
	 * @see #createAfter(ICElement)
	 * @see #createBefore(ICElement)
	 */
	protected void insertElement() throws CModelException {
		if (fInsertionPolicy != INSERT_LAST) {
			ISourceRange range = ((ISourceReference)fAnchorElement).getSourceRange();
			switch (fInsertionPolicy) {
				case INSERT_AFTER:
					fReplacementLength = 0;
					fInsertionPosition = range.getStartPos() + range.getLength();
				break;

				case INSERT_BEFORE:
					fReplacementLength = 0;
					fInsertionPosition = range.getStartPos();
				break;

				default:
					fReplacementLength = range.getStartPos() + range.getLength();
					fInsertionPosition = range.getStartPos();
			}
			return;
		}
		//add as the last element of the parent
		fReplacementLength = -1;
	}

	/**
	 * Sets the name of the <code>DOMNode</code> that will be used to
	 * create this new element.
	 * Used by the <code>CopyElementsOperation</code> for renaming.
	 * Only used for <code>CreateTypeMemberOperation</code>
	 */
	protected void setAlteredName(String newName) {
	}

	/**
	 * Instructs this operation to position the new element relative
	 * to the given sibling, or to add the new element as the last child
	 * of its parent if <code>null</code>. The <code>position</code>
	 * must be one of the position constants.
	 */
	protected void setRelativePosition(ICElement sibling, int policy) throws IllegalArgumentException {
		if (sibling == null) {
			fAnchorElement = null;
			fInsertionPolicy = INSERT_LAST;
		} else {
			fAnchorElement = sibling;
			fInsertionPolicy = policy;
		}
	}

	/**
	 * Possible failures: <ul>
	 *  <li>NO_ELEMENTS_TO_PROCESS - the compilation unit supplied to the operation is
	 * 		<code>null</code>.
	 *  <li>INVALID_NAME - no name, a name was null or not a valid
	 * 		import declaration name.
	 *  <li>INVALID_SIBLING - the sibling provided for positioning is not valid.
	 * </ul>
	 * @see ICModelStatus
	 * @see CConventions
	 */
	@Override
	public ICModelStatus verify() {
		if (getParentElement() == null) {
			return new CModelStatus(ICModelStatusConstants.NO_ELEMENTS_TO_PROCESS);
		}
		if (fAnchorElement != null) {
			ICElement domPresentParent = fAnchorElement.getParent();
			if (!domPresentParent.equals(getParentElement())) {
				return new CModelStatus(ICModelStatusConstants.INVALID_SIBLING, fAnchorElement);
			}
		}
		return CModelStatus.VERIFIED_OK;
	}

}

Back to the top