trace/tracebuilder/com.nokia.tracebuilder/src/com/nokia/tracebuilder/source/SourceEditor.java
changeset 10 ed1c9f64298a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/trace/tracebuilder/com.nokia.tracebuilder/src/com/nokia/tracebuilder/source/SourceEditor.java	Wed Jun 23 14:35:40 2010 +0300
@@ -0,0 +1,206 @@
+/*
+* Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies). 
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+* Extends the SourceParser with support for data changes
+*
+*/
+package com.nokia.tracebuilder.source;
+
+import java.util.Iterator;
+
+/**
+ * Extends the SourceParser with support for data changes
+ * 
+ */
+public class SourceEditor extends SourceParser {
+
+	/**
+	 * Full sync needed flag
+	 */
+	private boolean fullSync;
+
+	/**
+	 * End of the area affected by the change
+	 */
+	private int affectedAreaEnd;
+
+	/**
+	 * Constructor
+	 * 
+	 * @param framework
+	 *            the document framework
+	 * @param sourceData
+	 *            the source document data
+	 */
+	public SourceEditor(SourceDocumentFactory framework, String sourceData) {
+		super(framework, sourceData);
+	}
+
+	/**
+	 * Constructor
+	 * 
+	 * @param documentFramework
+	 *            the document framework
+	 * @param source
+	 *            the source
+	 */
+	public SourceEditor(SourceDocumentFactory documentFramework,
+			SourceDocumentInterface source) {
+		super(documentFramework, source);
+	}
+
+	/**
+	 * Updates the source file.
+	 * 
+	 * @param offset
+	 *            the offset to removed data
+	 * @param length
+	 *            the length of removed data
+	 * @param newText
+	 *            the data inserted at offset
+	 * @throws SourceParserException
+	 *             if update fails
+	 */
+	public void updateSource(int offset, int length, String newText)
+			throws SourceParserException {
+		getSource().replace(offset, length, newText);
+	}
+
+	/**
+	 * Prepares document update
+	 * 
+	 * @param offset
+	 *            the offset to removed data
+	 * @param length
+	 *            the length of removed data
+	 * @param newText
+	 *            the data inserted at offset
+	 * @throws SourceParserException
+	 *             if update fails
+	 */
+	public void prepareUpdateSource(int offset, int length, String newText)
+			throws SourceParserException {
+		// If the modified data contains characters used in building the
+		// excluded areas, the results might propagate to
+		// other parts of the source code. For example, removing the '*'
+		// from end-of-comment causes the comment to continue past the
+		// modified area to the next */. In that case a full re-sync needs
+		// to be done. One extra character is examined from both sides of the
+		// removed area. For example, introducing ' ' between '/' and '*' would
+		// remove the comment and affect rest of the code. Also if
+		// the new text introduces characters used in excluded areas, a full
+		// sync is done. For example, if '*' is inserted into a code, it might
+		// terminate an existing comment and thus affect the rest of the source.
+		// \n also needs to be processed, since it affects the line comments
+		// -> That should be the first one to be optimized away
+		fullSync = false;
+		SourceDocumentInterface source = getSource();
+		int start = offset == 0 ? offset : offset - 1;
+		int end = (offset + length) >= source.getLength() - 1 ? (offset + length)
+				: offset + length + 1;
+		for (int i = start; i < end && !fullSync; i++) {
+			char c = source.getChar(i);
+			if (c == '/' || c == '*' || c == '"' || c == '\n' || c == '\'') {
+				fullSync = true;
+			}
+		}
+		if (!fullSync && newText != null) {
+			int len = newText.length();
+			for (int i = 0; i < len && !fullSync; i++) {
+				char c = newText.charAt(i);
+				if (c == '/' || c == '*' || c == '"' || c == '\n' || c == '\'') {
+					fullSync = true;
+				}
+			}
+		}
+	}
+
+	/**
+	 * Sets the full sync flag. This needs to be called if there have been
+	 * multiple changes without prepareUpdateSource / sourceUpdated calls
+	 */
+	public void prepareFullSync() {
+		fullSync = true;
+	}
+
+	/**
+	 * Updates all excluded areas that follow the change offset
+	 * 
+	 * @param offset
+	 *            the offset to removed data
+	 * @param length
+	 *            the length of removed data
+	 * @param newText
+	 *            the data inserted at offset
+	 * @return end of the area where the change might affect
+	 * @throws SourceParserException
+	 *             if offset is not valid
+	 */
+	public int sourceUpdated(int offset, int length, String newText)
+			throws SourceParserException {
+		if (newText == null) {
+			newText = ""; //$NON-NLS-1$
+		}
+		// Full sync flag was calculated in prepareUpdateSource
+		if (fullSync) {
+			findExcludedAreas();
+			affectedAreaEnd = getSource().getLength();
+		} else {
+			// If the change was within an excluded area, the length of the
+			// area is updated. The offset of the areas following the change
+			// are updated.
+			int diff = newText.length() - length;
+			if (diff != 0) {
+				int index = findExcludedAreaIndex(offset);
+				if (index >= 0) {
+					SourceLocationBase p = getExcludedAreas().get(index);
+					p.setLength(p.getLength() + diff);
+					index++;
+				} else {
+					index = -1 - index;
+				}
+				for (; index < getExcludedAreas().size(); index++) {
+					SourceLocationBase p = getExcludedAreas().get(index);
+					p.setOffset(p.getOffset() + diff);
+				}
+			}
+			affectedAreaEnd = getSource().getLength();
+		}
+		// Contexts and preprocessor definitions are updated when needed for
+		// the next time
+		resetContexts();
+		resetPreprocessor();
+		return affectedAreaEnd;
+	}
+
+	/**
+	 * Sends update notifications to location listeners of modified and deleted
+	 * locations
+	 */
+	public void notifyLocationUpdates() {
+		// Posts delete notifications to location listeners
+		Iterator<SourceLocation> itr = getLocations();
+		while (itr.hasNext()) {
+			SourceLocation location = itr.next();
+			if (location.isDeleted()) {
+				location.notifyLocationDeleted();
+				itr.remove();
+			} else {
+				location.notifyLocationChanged();
+			}
+		}
+	}
+
+}