mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-07-29 20:05:35 +02:00
Changes from Oda introducing LRUCaching
and the notion of WorkingCopy in the mode.
This commit is contained in:
parent
305ae53cf5
commit
31945e2ce6
30 changed files with 3018 additions and 99 deletions
|
@ -15,6 +15,9 @@ import java.util.EventObject;
|
|||
* @see ICElementDelta
|
||||
*/
|
||||
public class ElementChangedEvent extends EventObject {
|
||||
public static final int POST_CHANGE = 1;
|
||||
public static final int PRE_AUTO_BUILD = 2;
|
||||
public static final int POST_RECONCILE = 4;
|
||||
/**
|
||||
* Creates an new element changed event (based on a <code>ICElementDelta</code>).
|
||||
*
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
package org.eclipse.cdt.core.model;
|
||||
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2002,2003 Rational Software Corporation and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Common Public License v0.5
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/cpl-v05.html
|
||||
*
|
||||
* Contributors:
|
||||
* Rational Software - Initial API and implementation
|
||||
***********************************************************************/
|
||||
|
||||
import org.eclipse.cdt.internal.core.model.IBuffer;
|
||||
import org.eclipse.cdt.internal.core.model.IBufferChangedListener;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
|
||||
/**
|
||||
* An openable is an element that can be opened, saved, and closed.
|
||||
* An openable might or might not have an associated buffer.
|
||||
*/
|
||||
public interface ICOpenable extends IBufferChangedListener{
|
||||
/**
|
||||
* Closes this element and its buffer (if any).
|
||||
*/
|
||||
public void close() throws CModelException;
|
||||
/**
|
||||
* Returns the buffer opened for this element, or <code>null</code>
|
||||
* if this element does not have a buffer.
|
||||
*/
|
||||
public IBuffer getBuffer() throws CModelException;
|
||||
/**
|
||||
* returns true if the associated buffer has some unsaved changes
|
||||
*/
|
||||
boolean hasUnsavedChanges() throws CModelException;
|
||||
/**
|
||||
* Returns whether the element is consistent with its underlying resource or buffer.
|
||||
* The element is consistent when opened, and is consistent if the underlying resource
|
||||
* or buffer has not been modified since it was last consistent.
|
||||
*/
|
||||
boolean isConsistent() throws CModelException;
|
||||
|
||||
/**
|
||||
* Returns whether this CFile is open.
|
||||
*/
|
||||
boolean isOpen();
|
||||
|
||||
/**
|
||||
* Makes this element consistent with its underlying resource or buffer
|
||||
* by updating the element's structure and properties as necessary.
|
||||
*/
|
||||
void makeConsistent(IProgressMonitor progress) throws CModelException;
|
||||
|
||||
/**
|
||||
* Opens this element and all parent elements that are not already open.
|
||||
* For translation units, a buffer is opened on the contents of the
|
||||
* underlying resource.
|
||||
*/
|
||||
public void open(IProgressMonitor progress) throws CModelException;
|
||||
|
||||
/**
|
||||
* Saves any changes in this element's buffer to its underlying resource
|
||||
* via a workspace resource operation.
|
||||
* <p>
|
||||
* The <code>force</code> parameter controls how this method deals with
|
||||
* cases where the workbench is not completely in sync with the local file system.
|
||||
*/
|
||||
public void save(IProgressMonitor progress, boolean force) throws CModelException;
|
||||
|
||||
}
|
|
@ -6,5 +6,5 @@
|
|||
package org.eclipse.cdt.core.model;
|
||||
|
||||
|
||||
public interface ICResource extends IParent, ICElement {
|
||||
public interface ICResource extends IParent, ICElement, ICOpenable {
|
||||
}
|
||||
|
|
|
@ -4,8 +4,9 @@ package org.eclipse.cdt.core.model;
|
|||
* (c) Copyright IBM Corp. 2000, 2001.
|
||||
* All Rights Reserved.
|
||||
*/
|
||||
import org.eclipse.cdt.internal.core.model.IBufferFactory;
|
||||
import org.eclipse.cdt.internal.core.model.IWorkingCopy;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
|
||||
/**
|
||||
* Represents an entire C translation unit (<code>.c</code> source file).
|
||||
* The children are of type <code>IStructureElement</code>,
|
||||
|
@ -64,6 +65,26 @@ public interface ITranslationUnit extends ICFile , ISourceReference, ISourceMani
|
|||
*/
|
||||
IUsing createUsing (String name, IProgressMonitor monitor) throws CModelException;
|
||||
|
||||
/**
|
||||
* Finds the shared working copy for this element, given a <code>IBuffer</code> factory.
|
||||
* If no working copy has been created for this element associated with this
|
||||
* buffer factory, returns <code>null</code>.
|
||||
* <p>
|
||||
* Users of this method must not destroy the resulting working copy.
|
||||
*
|
||||
* @param bufferFactory the given <code>IBuffer</code> factory
|
||||
* @return the found shared working copy for this element, <code>null</code> if none
|
||||
* @see IBufferFactory
|
||||
* @since 2.0
|
||||
*/
|
||||
IWorkingCopy findSharedWorkingCopy(IBufferFactory bufferFactory);
|
||||
|
||||
/**
|
||||
* Returns the contents of a translation unit as a char[]
|
||||
* @return char[]
|
||||
*/
|
||||
char[] getContents();
|
||||
|
||||
/**
|
||||
* Returns the smallest element within this translation unit that
|
||||
* includes the given source position (that is, a method, field, etc.), or
|
||||
|
@ -99,6 +120,55 @@ public interface ITranslationUnit extends ICFile , ISourceReference, ISourceMani
|
|||
*/
|
||||
IInclude[] getIncludes() throws CModelException;
|
||||
|
||||
/**
|
||||
* Returns a shared working copy on this element using the given factory to create
|
||||
* the buffer, or this element if this element is already a working copy.
|
||||
* This API can only answer an already existing working copy if it is based on the same
|
||||
* original translation unit AND was using the same buffer factory (i.e. as
|
||||
* defined by <code>Object#equals</code>).
|
||||
* <p>
|
||||
* The life time of a shared working copy is as follows:
|
||||
* <ul>
|
||||
* <li>The first call to <code>getSharedWorkingCopy(...)</code> creates a new working copy for this
|
||||
* element</li>
|
||||
* <li>Subsequent calls increment an internal counter.</li>
|
||||
* <li>A call to <code>destroy()</code> decrements the internal counter.</li>
|
||||
* <li>When this counter is 0, the working copy is destroyed.
|
||||
* </ul>
|
||||
* So users of this method must destroy exactly once the working copy.
|
||||
* <p>
|
||||
* Note that the buffer factory will be used for the life time of this working copy, i.e. if the
|
||||
* working copy is closed then reopened, this factory will be used.
|
||||
* The buffer will be automatically initialized with the original's compilation unit content
|
||||
* upon creation.
|
||||
* <p>
|
||||
* When the shared working copy instance is created, an ADDED ICElementDelta is reported on this
|
||||
* working copy.
|
||||
*
|
||||
* @param monitor a progress monitor used to report progress while opening this compilation unit
|
||||
* or <code>null</code> if no progress should be reported
|
||||
* @param factory the factory that creates a buffer that is used to get the content of the working copy
|
||||
* or <code>null</code> if the internal factory should be used
|
||||
* @param problemRequestor a requestor which will get notified of problems detected during
|
||||
* reconciling as they are discovered. The requestor can be set to <code>null</code> indicating
|
||||
* that the client is not interested in problems.
|
||||
* @exception CModelException if the contents of this element can not be
|
||||
* determined. Reasons include:
|
||||
* <ul>
|
||||
* <li> This C element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
|
||||
* </ul>
|
||||
* @return a shared working copy on this element using the given factory to create
|
||||
* the buffer, or this element if this element is already a working copy
|
||||
* @see IBufferFactory
|
||||
* @see IProblemRequestor
|
||||
* @since 2.0
|
||||
*/
|
||||
|
||||
IWorkingCopy getSharedWorkingCopy(
|
||||
IProgressMonitor monitor,
|
||||
IBufferFactory factory)
|
||||
throws CModelException;
|
||||
|
||||
/**
|
||||
* Returns the first namespace declaration in this translation unit with the given package name
|
||||
* This is a handle-only method. The namespace declaration may or may not exist.
|
||||
|
@ -117,4 +187,21 @@ public interface ITranslationUnit extends ICFile , ISourceReference, ISourceMani
|
|||
* exception occurs while accessing its corresponding resource
|
||||
*/
|
||||
IUsing[] getUsings() throws CModelException;
|
||||
/**
|
||||
* Returns a new working copy for the Translation Unit.
|
||||
* @return IWorkingCopy
|
||||
*/
|
||||
IWorkingCopy getWorkingCopy() throws CModelException;
|
||||
|
||||
/**
|
||||
* Returns a new working copy for the Translation Unit.
|
||||
* @return IWorkingCopy
|
||||
*/
|
||||
IWorkingCopy getWorkingCopy(IProgressMonitor monitor, IBufferFactory factory) throws CModelException;
|
||||
|
||||
/**
|
||||
* Checks if this is a working copy.
|
||||
* @return boolean
|
||||
*/
|
||||
boolean isWorkingCopy();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,443 @@
|
|||
package org.eclipse.cdt.internal.core.model;
|
||||
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2002,2003 Rational Software Corporation and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Common Public License v0.5
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/cpl-v05.html
|
||||
*
|
||||
* Contributors:
|
||||
* Rational Software - Initial API and implementation
|
||||
***********************************************************************/
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.eclipse.cdt.core.model.CModelException;
|
||||
import org.eclipse.cdt.core.model.ICOpenable;
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.ISafeRunnable;
|
||||
import org.eclipse.core.runtime.Platform;
|
||||
|
||||
/**
|
||||
* @see IBuffer
|
||||
* This class is similar to the JDT Buffer class.
|
||||
*/
|
||||
public class Buffer implements IBuffer {
|
||||
protected IFile file;
|
||||
protected int flags;
|
||||
protected char[] contents;
|
||||
protected ArrayList changeListeners;
|
||||
protected ICOpenable owner;
|
||||
protected int gapStart= -1;
|
||||
protected int gapEnd= -1;
|
||||
|
||||
protected Object lock= new Object();
|
||||
|
||||
protected static final int F_HAS_UNSAVED_CHANGES= 1;
|
||||
protected static final int F_IS_READ_ONLY= 2;
|
||||
protected static final int F_IS_CLOSED= 4;
|
||||
/**
|
||||
* Creates a new buffer on an underlying resource.
|
||||
*/
|
||||
protected Buffer(IFile file, ICOpenable owner, boolean readOnly) {
|
||||
this.file = file;
|
||||
this.owner = owner;
|
||||
if (file == null) {
|
||||
setReadOnly(readOnly);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see IBuffer
|
||||
*/
|
||||
public void addBufferChangedListener(IBufferChangedListener listener) {
|
||||
if (this.changeListeners == null) {
|
||||
this.changeListeners = new ArrayList(5);
|
||||
}
|
||||
if (!this.changeListeners.contains(listener)) {
|
||||
this.changeListeners.add(listener);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @see org.eclipse.cdt.internal.core.model.IBuffer#append(char)
|
||||
*/
|
||||
public void append(char[] text) {
|
||||
if (!isReadOnly()) {
|
||||
if (text == null || text.length == 0) {
|
||||
return;
|
||||
}
|
||||
int length = getLength();
|
||||
moveAndResizeGap(length, text.length);
|
||||
System.arraycopy(text, 0, this.contents, length, text.length);
|
||||
this.gapStart += text.length;
|
||||
this.flags |= F_HAS_UNSAVED_CHANGES;
|
||||
notifyChanged(new BufferChangedEvent(this, length, 0, new String(text)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.cdt.internal.core.model.IBuffer#append(java.lang.String)
|
||||
*/
|
||||
public void append(String text) {
|
||||
if (text == null) {
|
||||
return;
|
||||
}
|
||||
this.append(text.toCharArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.cdt.internal.core.model.IBuffer#close()
|
||||
*/
|
||||
public void close() {
|
||||
BufferChangedEvent event = null;
|
||||
synchronized (this.lock) {
|
||||
if (isClosed())
|
||||
return;
|
||||
event = new BufferChangedEvent(this, 0, 0, null);
|
||||
this.contents = null;
|
||||
this.flags |= F_IS_CLOSED;
|
||||
}
|
||||
notifyChanged(event); // notify outside of synchronized block
|
||||
this.changeListeners = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.cdt.internal.core.model.IBuffer#getChar(int)
|
||||
*/
|
||||
public char getChar(int position) {
|
||||
synchronized (this.lock) {
|
||||
if (position < this.gapStart) {
|
||||
return this.contents[position];
|
||||
}
|
||||
int gapLength = this.gapEnd - this.gapStart;
|
||||
return this.contents[position + gapLength];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.cdt.internal.core.model.IBuffer#getCharacters()
|
||||
*/
|
||||
public char[] getCharacters() {
|
||||
if (this.contents == null) return null;
|
||||
synchronized (this.lock) {
|
||||
if (this.gapStart < 0) {
|
||||
return this.contents;
|
||||
}
|
||||
int length = this.contents.length;
|
||||
char[] newContents = new char[length - this.gapEnd + this.gapStart];
|
||||
System.arraycopy(this.contents, 0, newContents, 0, this.gapStart);
|
||||
System.arraycopy(this.contents, this.gapEnd, newContents, this.gapStart, length - this.gapEnd);
|
||||
return newContents;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.cdt.internal.core.model.IBuffer#getContents()
|
||||
*/
|
||||
public String getContents() {
|
||||
if (this.contents == null) return null;
|
||||
return new String(this.getCharacters());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.cdt.internal.core.model.IBuffer#getLength()
|
||||
*/
|
||||
public int getLength() {
|
||||
synchronized (this.lock) {
|
||||
int length = this.gapEnd - this.gapStart;
|
||||
return (this.contents.length - length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.cdt.internal.core.model.IBuffer#getOwner()
|
||||
*/
|
||||
public ICOpenable getOwner() {
|
||||
return this.owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.cdt.internal.core.model.IBuffer#getText(int, int)
|
||||
*/
|
||||
public String getText(int offset, int length) {
|
||||
if (this.contents == null)
|
||||
return ""; //$NON-NLS-1$
|
||||
synchronized (this.lock) {
|
||||
if (offset + length < this.gapStart)
|
||||
return new String(this.contents, offset, length);
|
||||
if (this.gapStart < offset) {
|
||||
int gapLength = this.gapEnd - this.gapStart;
|
||||
return new String(this.contents, offset + gapLength, length);
|
||||
}
|
||||
StringBuffer buf = new StringBuffer();
|
||||
buf.append(this.contents, offset, this.gapStart - offset);
|
||||
buf.append(this.contents, this.gapEnd, offset + length - this.gapStart);
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.cdt.internal.core.model.IBuffer#getUnderlyingResource()
|
||||
*/
|
||||
public IResource getUnderlyingResource() {
|
||||
return this.file;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.cdt.internal.core.model.IBuffer#hasUnsavedChanges()
|
||||
*/
|
||||
public boolean hasUnsavedChanges() {
|
||||
return (this.flags & F_HAS_UNSAVED_CHANGES) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.cdt.internal.core.model.IBuffer#isClosed()
|
||||
*/
|
||||
public boolean isClosed() {
|
||||
return (this.flags & F_IS_CLOSED) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.cdt.internal.core.model.IBuffer#isReadOnly()
|
||||
*/
|
||||
public boolean isReadOnly() {
|
||||
if (this.file == null) {
|
||||
return (this.flags & F_IS_READ_ONLY) != 0;
|
||||
} else {
|
||||
return this.file.isReadOnly();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the listeners that this buffer has changed.
|
||||
* To avoid deadlock, this should not be called in a synchronized block.
|
||||
*/
|
||||
protected void notifyChanged(final BufferChangedEvent event) {
|
||||
if (this.changeListeners != null) {
|
||||
for (int i = 0, size = this.changeListeners.size(); i < size; ++i) {
|
||||
final IBufferChangedListener listener = (IBufferChangedListener) this.changeListeners.get(i);
|
||||
Platform.run(new ISafeRunnable() {
|
||||
public void handleException(Throwable exception) {
|
||||
Util.log(exception, "Exception occurred in listener of buffer change notification"); //$NON-NLS-1$
|
||||
}
|
||||
public void run() throws Exception {
|
||||
listener.bufferChanged(event);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @see IBuffer
|
||||
*/
|
||||
public void removeBufferChangedListener(IBufferChangedListener listener) {
|
||||
if (this.changeListeners != null) {
|
||||
this.changeListeners.remove(listener);
|
||||
if (this.changeListeners.size() == 0) {
|
||||
this.changeListeners = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @see org.eclipse.cdt.internal.core.model.IBuffer#replace(int, int, char)
|
||||
*/
|
||||
public void replace(int position, int length, char[] text) {
|
||||
if (!isReadOnly()) {
|
||||
int textLength = text == null ? 0 : text.length;
|
||||
synchronized (this.lock) {
|
||||
// move gap
|
||||
moveAndResizeGap(position + length, textLength - length);
|
||||
|
||||
// overwrite
|
||||
int min = Math.min(textLength, length);
|
||||
if (min > 0) {
|
||||
System.arraycopy(text, 0, this.contents, position, min);
|
||||
}
|
||||
if (length > textLength) {
|
||||
// enlarge the gap
|
||||
this.gapStart -= length - textLength;
|
||||
} else if (textLength > length) {
|
||||
// shrink gap
|
||||
this.gapStart += textLength - length;
|
||||
System.arraycopy(text, 0, this.contents, position, textLength);
|
||||
}
|
||||
}
|
||||
this.flags |= F_HAS_UNSAVED_CHANGES;
|
||||
String string = null;
|
||||
if (textLength > 0) {
|
||||
string = new String(text);
|
||||
}
|
||||
notifyChanged(new BufferChangedEvent(this, position, length, string));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.cdt.internal.core.model.IBuffer#replace(int, int, java.lang.String)
|
||||
*/
|
||||
public void replace(int position, int length, String text) {
|
||||
this.replace(position, length, text == null ? null : text.toCharArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.cdt.internal.core.model.IBuffer#save(org.eclipse.core.runtime.IProgressMonitor, boolean)
|
||||
*/
|
||||
public void save(IProgressMonitor progress, boolean force)
|
||||
throws CModelException {
|
||||
// determine if saving is required
|
||||
if (isReadOnly() || this.file == null) {
|
||||
return;
|
||||
}
|
||||
synchronized (this.lock) {
|
||||
if (!hasUnsavedChanges())
|
||||
return;
|
||||
|
||||
// use a platform operation to update the resource contents
|
||||
try {
|
||||
String contents = this.getContents();
|
||||
if (contents == null) return;
|
||||
byte[] bytes = contents.getBytes();
|
||||
ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
|
||||
|
||||
this.file.setContents(
|
||||
stream,
|
||||
force ? IResource.FORCE | IResource.KEEP_HISTORY : IResource.KEEP_HISTORY,
|
||||
null);
|
||||
}
|
||||
catch (CoreException e) {
|
||||
throw new CModelException(e);
|
||||
}
|
||||
|
||||
// the resource no longer has unsaved changes
|
||||
this.flags &= ~ (F_HAS_UNSAVED_CHANGES);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.cdt.internal.core.model.IBuffer#setContents(char)
|
||||
*/
|
||||
public void setContents(char[] newContents) {
|
||||
// allow special case for first initialization
|
||||
// after creation by buffer factory
|
||||
if (this.contents == null) {
|
||||
this.contents = newContents;
|
||||
this.flags &= ~ (F_HAS_UNSAVED_CHANGES);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isReadOnly()) {
|
||||
String string = null;
|
||||
if (newContents != null) {
|
||||
string = new String(newContents);
|
||||
}
|
||||
BufferChangedEvent event = new BufferChangedEvent(this, 0, this.getLength(), string);
|
||||
synchronized (this.lock) {
|
||||
this.contents = newContents;
|
||||
this.flags |= F_HAS_UNSAVED_CHANGES;
|
||||
this.gapStart = -1;
|
||||
this.gapEnd = -1;
|
||||
}
|
||||
notifyChanged(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.cdt.internal.core.model.IBuffer#setContents(java.lang.String)
|
||||
*/
|
||||
public void setContents(String newContents) {
|
||||
this.setContents(newContents.toCharArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the gap to location and adjust its size to the
|
||||
* anticipated change size. The size represents the expected
|
||||
* range of the gap that will be filled after the gap has been moved.
|
||||
* Thus the gap is resized to actual size + the specified size and
|
||||
* moved to the given position.
|
||||
*/
|
||||
protected void moveAndResizeGap(int position, int size) {
|
||||
char[] content = null;
|
||||
int oldSize = this.gapEnd - this.gapStart;
|
||||
if (size < 0) {
|
||||
if (oldSize > 0) {
|
||||
content = new char[this.contents.length - oldSize];
|
||||
System.arraycopy(this.contents, 0, content, 0, this.gapStart);
|
||||
System.arraycopy(this.contents, this.gapEnd, content, this.gapStart, content.length - this.gapStart);
|
||||
this.contents = content;
|
||||
}
|
||||
this.gapStart = this.gapEnd = position;
|
||||
return;
|
||||
}
|
||||
content = new char[this.contents.length + (size - oldSize)];
|
||||
int newGapStart = position;
|
||||
int newGapEnd = newGapStart + size;
|
||||
if (oldSize == 0) {
|
||||
System.arraycopy(this.contents, 0, content, 0, newGapStart);
|
||||
System.arraycopy(this.contents, newGapStart, content, newGapEnd, content.length - newGapEnd);
|
||||
} else
|
||||
if (newGapStart < this.gapStart) {
|
||||
int delta = this.gapStart - newGapStart;
|
||||
System.arraycopy(this.contents, 0, content, 0, newGapStart);
|
||||
System.arraycopy(this.contents, newGapStart, content, newGapEnd, delta);
|
||||
System.arraycopy(this.contents, this.gapEnd, content, newGapEnd + delta, this.contents.length - this.gapEnd);
|
||||
} else {
|
||||
int delta = newGapStart - this.gapStart;
|
||||
System.arraycopy(this.contents, 0, content, 0, this.gapStart);
|
||||
System.arraycopy(this.contents, this.gapEnd, content, this.gapStart, delta);
|
||||
System.arraycopy(this.contents, this.gapEnd + delta, content, newGapEnd, content.length - newGapEnd);
|
||||
}
|
||||
this.contents = content;
|
||||
this.gapStart = newGapStart;
|
||||
this.gapEnd = newGapEnd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this <code>Buffer</code> to be read only.
|
||||
*/
|
||||
protected void setReadOnly(boolean readOnly) {
|
||||
if (readOnly) {
|
||||
this.flags |= F_IS_READ_ONLY;
|
||||
} else {
|
||||
this.flags &= ~(F_IS_READ_ONLY);
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
buffer.append("Owner: " + ((CElement)this.owner).toString()); //$NON-NLS-1$
|
||||
buffer.append("\nHas unsaved changes: " + this.hasUnsavedChanges()); //$NON-NLS-1$
|
||||
buffer.append("\nIs readonly: " + this.isReadOnly()); //$NON-NLS-1$
|
||||
buffer.append("\nIs closed: " + this.isClosed()); //$NON-NLS-1$
|
||||
buffer.append("\nContents:\n"); //$NON-NLS-1$
|
||||
char[] contents = this.getCharacters();
|
||||
if (contents == null) {
|
||||
buffer.append("<null>"); //$NON-NLS-1$
|
||||
} else {
|
||||
int length = contents.length;
|
||||
for (int i = 0; i < length; i++) {
|
||||
char car = contents[i];
|
||||
switch (car) {
|
||||
case '\n':
|
||||
buffer.append("\\n\n"); //$NON-NLS-1$
|
||||
break;
|
||||
case '\r':
|
||||
if (i < length-1 && this.contents[i+1] == '\n') {
|
||||
buffer.append("\\r\\n\n"); //$NON-NLS-1$
|
||||
i++;
|
||||
} else {
|
||||
buffer.append("\\r\n"); //$NON-NLS-1$
|
||||
}
|
||||
break;
|
||||
default:
|
||||
buffer.append(car);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
package org.eclipse.cdt.internal.core.model;
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2002,2003 Rational Software Corporation and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Common Public License v0.5
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/cpl-v05.html
|
||||
*
|
||||
* Contributors:
|
||||
* Rational Software - Initial API and implementation
|
||||
***********************************************************************/
|
||||
|
||||
import java.util.EventObject;
|
||||
|
||||
/**
|
||||
* A buffer changed event describes how a buffer has changed. These events are
|
||||
* used in <code>IBufferChangedListener</code> notifications.
|
||||
* <p>
|
||||
* For text insertions, <code>getOffset</code> is the offset
|
||||
* of the first inserted character, <code>getText</code> is the
|
||||
* inserted text, and <code>getLength</code> is 0.
|
||||
* </p>
|
||||
* <p>
|
||||
* For text removals, <code>getOffset</code> is the offset
|
||||
* of the first removed character, <code>getText</code> is <code>null</code>,
|
||||
* and <code>getLength</code> is the length of the text that was removed.
|
||||
* </p>
|
||||
* <p>
|
||||
* For replacements (including <code>IBuffer.setContents</code>),
|
||||
* <code>getOffset</code> is the offset
|
||||
* of the first replaced character, <code>getText</code> is the replacement
|
||||
* text, and <code>getLength</code> is the length of the original text
|
||||
* that was replaced.
|
||||
* </p>
|
||||
* <p>
|
||||
* When a buffer is closed, <code>getOffset</code> is 0, <code>getLength</code>
|
||||
* is 0, and <code>getText</code> is <code>null</code>.
|
||||
* </p>
|
||||
* <p>
|
||||
* This class is not intended to be instantiated or subclassed by clients.
|
||||
* Instances of this class are automatically created by the C model.
|
||||
* </p>
|
||||
*
|
||||
* @see IBuffer
|
||||
* This class is similar to the JDT BufferChangedEvent class.
|
||||
*/
|
||||
|
||||
public class BufferChangedEvent extends EventObject {
|
||||
/**
|
||||
* The length of text that has been modified in the buffer.
|
||||
*/
|
||||
private int length;
|
||||
|
||||
/**
|
||||
* The offset into the buffer where the modification took place.
|
||||
*/
|
||||
private int offset;
|
||||
|
||||
/**
|
||||
* The text that was modified.
|
||||
*/
|
||||
private String text;
|
||||
|
||||
/**
|
||||
* Creates a new buffer changed event indicating that the given buffer has changed.
|
||||
*/
|
||||
public BufferChangedEvent(IBuffer buffer, int offset, int length, String text) {
|
||||
super(buffer);
|
||||
this.offset = offset;
|
||||
this.length = length;
|
||||
this.text = text;
|
||||
}
|
||||
/**
|
||||
* Returns the buffer which has changed.
|
||||
*
|
||||
* @return the buffer affected by the change
|
||||
*/
|
||||
public IBuffer getBuffer() {
|
||||
return (IBuffer) source;
|
||||
}
|
||||
/**
|
||||
* Returns the length of text removed or replaced in the buffer, or
|
||||
* 0 if text has been inserted into the buffer.
|
||||
*
|
||||
* @return the length of the original text fragment modified by the
|
||||
* buffer change (<code> 0 </code> in case of insertion).
|
||||
*/
|
||||
public int getLength() {
|
||||
return this.length;
|
||||
}
|
||||
/**
|
||||
* Returns the index of the first character inserted, removed, or replaced
|
||||
* in the buffer.
|
||||
*
|
||||
* @return the source offset of the textual manipulation in the buffer
|
||||
*/
|
||||
public int getOffset() {
|
||||
return this.offset;
|
||||
}
|
||||
/**
|
||||
* Returns the text that was inserted, the replacement text,
|
||||
* or <code>null</code> if text has been removed.
|
||||
*
|
||||
* @return the text corresponding to the buffer change (<code> null </code>
|
||||
* in case of deletion).
|
||||
*/
|
||||
public String getText() {
|
||||
return this.text;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
package org.eclipse.cdt.internal.core.model;
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2002,2003 Rational Software Corporation and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Common Public License v0.5
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/cpl-v05.html
|
||||
*
|
||||
* Contributors:
|
||||
* Rational Software - Initial API and implementation
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
import java.util.Enumeration;
|
||||
|
||||
import org.eclipse.cdt.core.model.CModelException;
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.core.model.ICOpenable;
|
||||
import org.eclipse.cdt.internal.core.util.LRUCache;
|
||||
import org.eclipse.cdt.internal.core.util.OverflowingLRUCache;
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
/**
|
||||
* The buffer manager manages the set of open buffers.
|
||||
* It implements an LRU cache of buffers.
|
||||
*
|
||||
* This class is similar to the JDT BufferManager class
|
||||
*/
|
||||
|
||||
public class BufferManager implements IBufferFactory {
|
||||
|
||||
/**
|
||||
* An LRU cache of <code>IBuffers</code>.
|
||||
*/
|
||||
public class BufferCache extends OverflowingLRUCache {
|
||||
/**
|
||||
* Constructs a new buffer cache of the given size.
|
||||
*/
|
||||
public BufferCache(int size) {
|
||||
super(size);
|
||||
}
|
||||
/**
|
||||
* Constructs a new buffer cache of the given size.
|
||||
*/
|
||||
public BufferCache(int size, int overflow) {
|
||||
super(size, overflow);
|
||||
}
|
||||
/**
|
||||
* Returns true if the buffer is successfully closed and
|
||||
* removed from the cache, otherwise false.
|
||||
*
|
||||
* <p>NOTE: this triggers an external removal of this buffer
|
||||
* by closing the buffer.
|
||||
*/
|
||||
protected boolean close(LRUCacheEntry entry) {
|
||||
IBuffer buffer= (IBuffer) entry._fValue;
|
||||
if (buffer.hasUnsavedChanges()) {
|
||||
return false;
|
||||
} else {
|
||||
buffer.close();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Returns a new instance of the reciever.
|
||||
*/
|
||||
protected LRUCache newInstance(int size, int overflow) {
|
||||
return new BufferCache(size, overflow);
|
||||
}
|
||||
}
|
||||
|
||||
protected static BufferManager DEFAULT_BUFFER_MANAGER;
|
||||
|
||||
/**
|
||||
* LRU cache of buffers. The key and value for an entry
|
||||
* in the table is the identical buffer.
|
||||
*/
|
||||
protected OverflowingLRUCache openBuffers = new BufferCache(60);
|
||||
|
||||
/**
|
||||
* Creates a new buffer manager.
|
||||
*/
|
||||
public BufferManager() {
|
||||
}
|
||||
/**
|
||||
* Adds a buffer to the table of open buffers.
|
||||
*/
|
||||
protected void addBuffer(IBuffer buffer) {
|
||||
openBuffers.put(buffer.getOwner(), buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.cdt.internal.core.model.IBufferFactory#createBuffer(org.eclipse.cdt.core.model.IOpenable)
|
||||
*/
|
||||
public IBuffer createBuffer(ICOpenable owner) {
|
||||
ICElement element = (ICElement)owner;
|
||||
try{
|
||||
IResource resource = element.getResource();
|
||||
return
|
||||
new Buffer(
|
||||
resource instanceof IFile ? (IFile)resource : null,
|
||||
owner,
|
||||
element.isReadOnly());
|
||||
}
|
||||
catch (CModelException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the open buffer associated with the given owner,
|
||||
* or <code>null</code> if the owner does not have an open
|
||||
* buffer associated with it.
|
||||
*/
|
||||
public IBuffer getBuffer(ICOpenable owner) {
|
||||
return (IBuffer)openBuffers.get(owner);
|
||||
}
|
||||
/**
|
||||
* Returns the default buffer factory.
|
||||
*/
|
||||
public IBufferFactory getDefaultBufferFactory() {
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Returns the default buffer manager.
|
||||
*/
|
||||
public synchronized static BufferManager getDefaultBufferManager() {
|
||||
if (DEFAULT_BUFFER_MANAGER == null) {
|
||||
DEFAULT_BUFFER_MANAGER = new BufferManager();
|
||||
}
|
||||
return DEFAULT_BUFFER_MANAGER;
|
||||
}
|
||||
/**
|
||||
* Returns an enumeration of all open buffers.
|
||||
* <p>
|
||||
* The <code>Enumeration</code> answered is thread safe.
|
||||
*
|
||||
* @see OverflowingLRUCache
|
||||
* @return Enumeration of IBuffer
|
||||
*/
|
||||
public Enumeration getOpenBuffers() {
|
||||
synchronized (openBuffers) {
|
||||
openBuffers.shrink();
|
||||
return openBuffers.elements();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes a buffer from the table of open buffers.
|
||||
*/
|
||||
protected void removeBuffer(IBuffer buffer) {
|
||||
openBuffers.remove(buffer.getOwner());
|
||||
}
|
||||
|
||||
}
|
|
@ -4,15 +4,17 @@ package org.eclipse.cdt.internal.core.model;
|
|||
* All Rights Reserved.
|
||||
*/
|
||||
|
||||
import org.eclipse.cdt.core.model.CModelException;
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.core.model.ICModelStatusConstants;
|
||||
import org.eclipse.cdt.core.model.ICOpenable;
|
||||
import org.eclipse.cdt.core.model.ICProject;
|
||||
import org.eclipse.cdt.core.model.ICRoot;
|
||||
import org.eclipse.cdt.core.model.IParent;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
import org.eclipse.core.runtime.IPath;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.PlatformObject;
|
||||
import org.eclipse.core.runtime.IPath;
|
||||
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.core.model.ICRoot;
|
||||
import org.eclipse.cdt.core.model.ICProject;
|
||||
import org.eclipse.cdt.core.model.CModelException;
|
||||
|
||||
public abstract class CElement extends PlatformObject implements ICElement {
|
||||
|
||||
|
@ -20,8 +22,6 @@ public abstract class CElement extends PlatformObject implements ICElement {
|
|||
|
||||
protected ICElement fParent;
|
||||
|
||||
protected CElementInfo fCElementInfo;
|
||||
|
||||
protected String fName;
|
||||
|
||||
protected int fStartPos;
|
||||
|
@ -37,7 +37,6 @@ public abstract class CElement extends PlatformObject implements ICElement {
|
|||
fParent= parent;
|
||||
fName= name;
|
||||
fType= type;
|
||||
fCElementInfo = null;
|
||||
}
|
||||
|
||||
// setters
|
||||
|
@ -89,7 +88,14 @@ public abstract class CElement extends PlatformObject implements ICElement {
|
|||
}
|
||||
|
||||
public boolean isReadOnly () {
|
||||
return getElementInfo().isReadOnly();
|
||||
try {
|
||||
IResource r = getUnderlyingResource();
|
||||
if (r != null) {
|
||||
return r.isReadOnly();
|
||||
}
|
||||
} catch (CModelException e) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isStructureKnown() throws CModelException {
|
||||
|
@ -206,10 +212,22 @@ public abstract class CElement extends PlatformObject implements ICElement {
|
|||
}
|
||||
|
||||
public CElementInfo getElementInfo () {
|
||||
if (fCElementInfo == null) {
|
||||
fCElementInfo = createElementInfo();
|
||||
try {
|
||||
CModelManager manager;
|
||||
synchronized(manager = CModelManager.getDefault()){
|
||||
Object info = manager.getInfo(this);
|
||||
if (info == null) {
|
||||
openHierarchy();
|
||||
info= manager.getInfo(this);
|
||||
if (info == null) {
|
||||
throw newNotPresentException();
|
||||
}
|
||||
}
|
||||
return (CElementInfo)info;
|
||||
}
|
||||
} catch(CModelException e) {
|
||||
return null;
|
||||
}
|
||||
return fCElementInfo;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
|
@ -264,4 +282,116 @@ public abstract class CElement extends PlatformObject implements ICElement {
|
|||
protected void runOperation(CModelOperation operation, IProgressMonitor monitor) throws CModelException {
|
||||
CModelManager.getDefault().runOperation(operation, monitor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the C Element
|
||||
* @throws CModelException
|
||||
*/
|
||||
public void close() throws CModelException {
|
||||
Object info = CModelManager.getDefault().peekAtInfo(this);
|
||||
if (info != null) {
|
||||
if (this instanceof IParent) {
|
||||
ICElement[] children = ((CElementInfo) info).getChildren();
|
||||
for (int i = 0, size = children.length; i < size; ++i) {
|
||||
CElement child = (CElement) children[i];
|
||||
child.close();
|
||||
}
|
||||
}
|
||||
closing(info);
|
||||
CModelManager.getDefault().removeInfo(this);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* This element is being closed. Do any necessary cleanup.
|
||||
*/
|
||||
protected void closing(Object info) throws CModelException {
|
||||
}
|
||||
|
||||
/**
|
||||
* This element has just been opened. Do any necessary setup.
|
||||
*/
|
||||
protected void opening(Object info) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the first instance of IOpenable in the parent
|
||||
* hierarchy of this element.
|
||||
*
|
||||
* <p>Subclasses that are not IOpenable's must override this method.
|
||||
*/
|
||||
public ICOpenable getOpenableParent() {
|
||||
|
||||
return (ICOpenable)fParent;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Opens this element and all parents that are not already open.
|
||||
*
|
||||
* @exception CModelException this element is not present or accessible
|
||||
*/
|
||||
protected void openHierarchy() throws CModelException {
|
||||
if (this instanceof ICOpenable) {
|
||||
((CResource) this).openWhenClosed(null);
|
||||
} else {
|
||||
CResource openableParent = (CResource)getOpenableParent();
|
||||
if (openableParent != null) {
|
||||
CElementInfo openableParentInfo = (CElementInfo) CModelManager.getDefault().getInfo((ICElement) openableParent);
|
||||
if (openableParentInfo == null) {
|
||||
openableParent.openWhenClosed(null);
|
||||
} else {
|
||||
CModelManager.getDefault().putInfo( this, createElementInfo());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Returns true if this element is an ancestor of the given element,
|
||||
* otherwise false.
|
||||
*/
|
||||
protected boolean isAncestorOf(ICElement e) {
|
||||
ICElement parent= e.getParent();
|
||||
while (parent != null && !parent.equals(this)) {
|
||||
parent= parent.getParent();
|
||||
}
|
||||
return parent != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns and not present exception for this element.
|
||||
*/
|
||||
protected CModelException newNotPresentException() {
|
||||
return new CModelException(new CModelStatus(ICModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
|
||||
}
|
||||
/**
|
||||
* Removes all cached info from the C Model, including all children,
|
||||
* but does not close this element.
|
||||
*/
|
||||
protected void removeInfo() {
|
||||
Object info = CModelManager.getDefault().peekAtInfo(this);
|
||||
if (info != null) {
|
||||
if (this instanceof IParent) {
|
||||
ICElement[] children = ((CElementInfo)info).getChildren();
|
||||
for (int i = 0, size = children.length; i < size; ++i) {
|
||||
CElement child = (CElement) children[i];
|
||||
child.removeInfo();
|
||||
}
|
||||
}
|
||||
CModelManager.getDefault().removeInfo(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hash code for this Java element. By default,
|
||||
* the hash code for an element is a combination of its name
|
||||
* and parent's hash code. Elements with other requirements must
|
||||
* override this method.
|
||||
*/
|
||||
// CHECKPOINT: making not equal objects seem equal
|
||||
// What elements should override this?
|
||||
public int hashCode() {
|
||||
if (fParent == null) return super.hashCode();
|
||||
return Util.combineHashCodes(fName.hashCode(), fParent.hashCode());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
package org.eclipse.cdt.internal.core.model;
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2002,2003 Rational Software Corporation and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Common Public License v0.5
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/cpl-v05.html
|
||||
*
|
||||
* Contributors:
|
||||
* Rational Software - Initial API and implementation
|
||||
***********************************************************************/
|
||||
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
|
||||
/**
|
||||
* A C element delta biulder creates a C element delta on a C element between
|
||||
* the version of the C element at the time the comparator was created and the
|
||||
* current version of the C element.
|
||||
*
|
||||
* It performs this operation by locally caching the contents of
|
||||
* the C element when it is created. When the method buildDeltas() is called, it
|
||||
* creates a delta over the cached contents and the new contents.
|
||||
*
|
||||
* This class is similar to the JDT CElementDeltaBuilder class.
|
||||
*/
|
||||
|
||||
public class CElementDeltaBuilder {
|
||||
|
||||
CElementDelta delta;
|
||||
|
||||
public CElementDeltaBuilder(ICElement cElement) {
|
||||
|
||||
}
|
||||
|
||||
public void buildDeltas() {
|
||||
}
|
||||
}
|
|
@ -94,20 +94,6 @@ class CElementInfo {
|
|||
return fIsStructureKnown;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ICElement.isStructureKnown()
|
||||
*/
|
||||
public boolean isReadOnly () {
|
||||
try {
|
||||
IResource r = getElement().getUnderlyingResource();
|
||||
if (r != null) {
|
||||
return r.isReadOnly();
|
||||
}
|
||||
} catch (CModelException e) {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array with all the same elements as the specified array except for
|
||||
* the element to remove. Assumes that the deletion is contained in the array.
|
||||
|
|
|
@ -4,15 +4,13 @@ package org.eclipse.cdt.internal.core.model;
|
|||
* All Rights Reserved.
|
||||
*/
|
||||
|
||||
import org.eclipse.cdt.core.model.CModelException;
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.core.model.ICFile;
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
import org.eclipse.core.resources.ResourcesPlugin;
|
||||
import org.eclipse.core.runtime.IPath;
|
||||
//import org.eclipse.core.runtime.CoreException;
|
||||
|
||||
import org.eclipse.cdt.core.model.CModelException;
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.core.model.ICFile;
|
||||
|
||||
public class CFile extends CResource implements ICFile {
|
||||
|
||||
|
|
|
@ -5,11 +5,11 @@ package org.eclipse.cdt.internal.core.model;
|
|||
* All Rights Reserved.
|
||||
*/
|
||||
|
||||
import org.eclipse.core.resources.IFolder;
|
||||
|
||||
import org.eclipse.cdt.core.model.CModelException;
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.core.model.ICFolder;
|
||||
import org.eclipse.cdt.core.model.CModelException;
|
||||
import org.eclipse.core.resources.IFolder;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
|
||||
public class CFolder extends CResource implements ICFolder {
|
||||
|
||||
|
@ -29,4 +29,10 @@ public class CFolder extends CResource implements ICFolder {
|
|||
protected CElementInfo createElementInfo () {
|
||||
return new CFolderInfo(this);
|
||||
}
|
||||
|
||||
// CHECKPOINT: folders will return the hash code of their path
|
||||
public int hashCode() {
|
||||
return getPath().hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,138 @@
|
|||
package org.eclipse.cdt.internal.core.model;
|
||||
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2002,2003 Rational Software Corporation and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Common Public License v0.5
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/cpl-v05.html
|
||||
*
|
||||
* Contributors:
|
||||
* Rational Software - Initial API and implementation
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.internal.core.util.OverflowingLRUCache;
|
||||
|
||||
|
||||
/**
|
||||
* The cache of C elements to their respective info.
|
||||
*
|
||||
* This class is similar to the JDT CModelCache class.
|
||||
*/
|
||||
public class CModelCache {
|
||||
public static final int PROJ_CACHE_SIZE = 50;
|
||||
public static final int FOLDER_CACHE_SIZE = 500;
|
||||
public static final int FILE_CACHE_SIZE = 2000;
|
||||
public static final int CHILDREN_CACHE_SIZE = FILE_CACHE_SIZE * 20;
|
||||
|
||||
/**
|
||||
* Cache of open projects and roots.
|
||||
*/
|
||||
protected Map projectAndRootCache;
|
||||
|
||||
/**
|
||||
* Cache of open containers
|
||||
*/
|
||||
protected Map folderCache;
|
||||
|
||||
/**
|
||||
* Cache of open translation unit files
|
||||
*/
|
||||
protected OverflowingLRUCache fileCache;
|
||||
|
||||
/**
|
||||
* Cache of children of C elements
|
||||
*/
|
||||
protected Map childrenCache;
|
||||
|
||||
public CModelCache() {
|
||||
this.projectAndRootCache = new HashMap(PROJ_CACHE_SIZE);
|
||||
this.folderCache = new HashMap(FOLDER_CACHE_SIZE);
|
||||
this.fileCache = new ElementCache(FILE_CACHE_SIZE);
|
||||
this.childrenCache = new HashMap(CHILDREN_CACHE_SIZE); // average 20 children per openable
|
||||
}
|
||||
|
||||
public double openableFillingRatio() {
|
||||
return this.fileCache.fillingRatio();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the info for the element.
|
||||
*/
|
||||
public Object getInfo(ICElement element) {
|
||||
switch (element.getElementType()) {
|
||||
case ICElement.C_PROJECT:
|
||||
case ICElement.C_ROOT:
|
||||
return this.projectAndRootCache.get(element);
|
||||
case ICElement.C_FOLDER:
|
||||
return this.folderCache.get(element);
|
||||
case ICElement.C_FILE:
|
||||
return this.fileCache.get(element);
|
||||
default:
|
||||
return this.childrenCache.get(element);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the info for this element without
|
||||
* disturbing the cache ordering.
|
||||
*/
|
||||
protected Object peekAtInfo(ICElement element) {
|
||||
switch (element.getElementType()) {
|
||||
case ICElement.C_PROJECT:
|
||||
case ICElement.C_ROOT:
|
||||
return this.projectAndRootCache.get(element);
|
||||
case ICElement.C_FOLDER:
|
||||
return this.folderCache.get(element);
|
||||
case ICElement.C_FILE:
|
||||
return this.fileCache.peek(element);
|
||||
default:
|
||||
return this.childrenCache.get(element);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remember the info for the element.
|
||||
*/
|
||||
protected void putInfo(ICElement element, Object info) {
|
||||
switch (element.getElementType()) {
|
||||
case ICElement.C_PROJECT:
|
||||
case ICElement.C_ROOT:
|
||||
this.projectAndRootCache.put(element, info);
|
||||
break;
|
||||
case ICElement.C_FOLDER:
|
||||
this.folderCache.put(element, info);
|
||||
break;
|
||||
case ICElement.C_FILE:
|
||||
this.fileCache.put(element, info);
|
||||
break;
|
||||
default:
|
||||
this.childrenCache.put(element, info);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Removes the info of the element from the cache.
|
||||
*/
|
||||
protected void removeInfo(ICElement element) {
|
||||
switch (element.getElementType()) {
|
||||
case ICElement.C_PROJECT:
|
||||
case ICElement.C_ROOT:
|
||||
this.projectAndRootCache.remove(element);
|
||||
break;
|
||||
case ICElement.C_FOLDER:
|
||||
this.folderCache.remove(element);
|
||||
break;
|
||||
case ICElement.C_FILE:
|
||||
this.fileCache.remove(element);
|
||||
break;
|
||||
default:
|
||||
this.childrenCache.remove(element);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -53,7 +53,7 @@ public class CModelManager implements IResourceChangeListener {
|
|||
//private static HashMap fParsers = new HashMap();
|
||||
|
||||
/**
|
||||
* Used to convert <code>IResourceDelta</code>s into <code>IJavaElementDelta</code>s.
|
||||
* Used to convert <code>IResourceDelta</code>s into <code>ICElementDelta</code>s.
|
||||
*/
|
||||
protected DeltaProcessor fDeltaProcessor= new DeltaProcessor();
|
||||
|
||||
|
@ -73,6 +73,25 @@ public class CModelManager implements IResourceChangeListener {
|
|||
*/
|
||||
protected ArrayList fElementChangedListeners= new ArrayList();
|
||||
|
||||
/**
|
||||
* A map from ITranslationUnit to IWorkingCopy of the shared working copies.
|
||||
*/
|
||||
public Map sharedWorkingCopies = new HashMap();
|
||||
/**
|
||||
* Set of elements which are out of sync with their buffers.
|
||||
*/
|
||||
protected Map elementsOutOfSynchWithBuffers = new HashMap(11);
|
||||
|
||||
/**
|
||||
* Infos cache.
|
||||
*/
|
||||
protected CModelCache cache = new CModelCache();
|
||||
|
||||
/**
|
||||
* This is a cache of the projects before any project addition/deletion has started.
|
||||
*/
|
||||
public ICProject[] cProjectsCache;
|
||||
|
||||
public static final String [] sourceExtensions = {"c", "cxx", "cc", "C", "cpp"};
|
||||
|
||||
public static final String [] headerExtensions = {"h", "hh", "hpp"};
|
||||
|
@ -658,11 +677,14 @@ public class CModelManager implements IResourceChangeListener {
|
|||
|
||||
case IResourceChangeEvent.PRE_AUTO_BUILD :
|
||||
// No need now.
|
||||
if(delta != null) {
|
||||
this.checkProjectsBeingAddedOrRemoved(delta);
|
||||
}
|
||||
break;
|
||||
|
||||
case IResourceChangeEvent.POST_CHANGE :
|
||||
if (delta != null) {
|
||||
try {
|
||||
try {
|
||||
if (delta != null) {
|
||||
ICElementDelta[] translatedDeltas = fDeltaProcessor.processResourceDelta(delta);
|
||||
if (translatedDeltas.length > 0) {
|
||||
for (int i= 0; i < translatedDeltas.length; i++) {
|
||||
|
@ -670,10 +692,10 @@ public class CModelManager implements IResourceChangeListener {
|
|||
}
|
||||
}
|
||||
fire();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -795,4 +817,62 @@ public class CModelManager implements IResourceChangeListener {
|
|||
} // else deltas are fired while processing the resource delta
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the given delta and look for projects being added, opened,
|
||||
* or closed
|
||||
*/
|
||||
public void checkProjectsBeingAddedOrRemoved(IResourceDelta delta) {
|
||||
IResource resource = delta.getResource();
|
||||
switch (resource.getType()) {
|
||||
case IResource.ROOT :
|
||||
if (this.cProjectsCache == null) {
|
||||
this.cProjectsCache = this.getCRoot().getCProjects();
|
||||
}
|
||||
|
||||
IResourceDelta[] children = delta.getAffectedChildren();
|
||||
for (int i = 0, length = children.length; i < length; i++) {
|
||||
this.checkProjectsBeingAddedOrRemoved(children[i]);
|
||||
}
|
||||
break;
|
||||
case IResource.PROJECT :
|
||||
// TO BE COMPLETED ...
|
||||
break;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Returns the set of elements which are out of synch with their buffers.
|
||||
*/
|
||||
protected Map getElementsOutOfSynchWithBuffers() {
|
||||
return this.elementsOutOfSynchWithBuffers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the info for the element.
|
||||
*/
|
||||
public Object getInfo(ICElement element) {
|
||||
return this.cache.getInfo(element);
|
||||
}
|
||||
/**
|
||||
* Returns the info for this element without
|
||||
* disturbing the cache ordering.
|
||||
*/
|
||||
protected Object peekAtInfo(ICElement element) {
|
||||
return this.cache.peekAtInfo(element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the info for a C Model Element
|
||||
*/
|
||||
protected void putInfo(ICElement element, Object info) {
|
||||
this.cache.putInfo(element, info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the info of this model element.
|
||||
*/
|
||||
protected void removeInfo(ICElement element) {
|
||||
this.cache.removeInfo(element);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -77,4 +77,10 @@ public class CProject extends CResource implements ICProject {
|
|||
protected CElementInfo createElementInfo() {
|
||||
return new CProjectInfo(this);
|
||||
}
|
||||
|
||||
// CHECKPOINT: CProjects will return the hash code of their underlying IProject
|
||||
public int hashCode() {
|
||||
return getProject().hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,13 +5,19 @@ package org.eclipse.cdt.internal.core.model;
|
|||
* All Rights Reserved.
|
||||
*/
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.cdt.core.model.CModelException;
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.core.model.ICModelStatusConstants;
|
||||
import org.eclipse.cdt.core.model.ICResource;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
import org.eclipse.core.resources.ResourcesPlugin;
|
||||
import org.eclipse.core.runtime.IPath;
|
||||
|
||||
import org.eclipse.cdt.core.model.*;
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.core.model.CModelException;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
|
||||
public abstract class CResource extends Parent implements ICResource {
|
||||
|
||||
|
@ -38,4 +44,246 @@ public abstract class CResource extends Parent implements ICResource {
|
|||
}
|
||||
|
||||
protected abstract CElementInfo createElementInfo ();
|
||||
/**
|
||||
* The buffer associated with this element has changed. Registers
|
||||
* this element as being out of synch with its buffer's contents.
|
||||
* If the buffer has been closed, this element is set as NOT out of
|
||||
* synch with the contents.
|
||||
*
|
||||
* @see IBufferChangedListener
|
||||
*/
|
||||
public void bufferChanged(BufferChangedEvent event) {
|
||||
if (event.getBuffer().isClosed()) {
|
||||
CModelManager.getDefault().getElementsOutOfSynchWithBuffers().remove(this);
|
||||
getBufferManager().removeBuffer(event.getBuffer());
|
||||
} else {
|
||||
CModelManager.getDefault().getElementsOutOfSynchWithBuffers().put(this, this);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Updates the info objects for this element and all of its children by
|
||||
* removing the current infos, generating new infos, and then placing
|
||||
* the new infos into the C Model cache tables.
|
||||
*/
|
||||
protected void buildStructure(CResourceInfo info, IProgressMonitor monitor) throws CModelException {
|
||||
|
||||
if (monitor != null && monitor.isCanceled()) return;
|
||||
|
||||
// remove existing (old) infos
|
||||
removeInfo();
|
||||
HashMap newElements = new HashMap(11);
|
||||
info.setIsStructureKnown(generateInfos(info, monitor, newElements, getResource()));
|
||||
CModelManager.getDefault().getElementsOutOfSynchWithBuffers().remove(this);
|
||||
for (Iterator iter = newElements.keySet().iterator(); iter.hasNext();) {
|
||||
ICElement key = (ICElement) iter.next();
|
||||
Object value = newElements.get(key);
|
||||
CModelManager.getDefault().putInfo(key, value);
|
||||
}
|
||||
|
||||
// add the info for this at the end, to ensure that a getInfo cannot reply null in case the LRU cache needs
|
||||
// to be flushed. Might lead to performance issues.
|
||||
CModelManager.getDefault().putInfo(this, info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the buffer associated with this element, if any.
|
||||
*/
|
||||
protected void closeBuffer(CFileInfo info) {
|
||||
if (!hasBuffer()) return; // nothing to do
|
||||
IBuffer buffer = null;
|
||||
buffer = getBufferManager().getBuffer(this);
|
||||
if (buffer != null) {
|
||||
buffer.close();
|
||||
buffer.removeBufferChangedListener(this);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Derived classes may override.
|
||||
*/
|
||||
protected boolean generateInfos(CResourceInfo info, IProgressMonitor pm, Map newElements, IResource underlyingResource) throws CModelException{
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* @see org.eclipse.cdt.core.model.ICOpenable#getBuffer()
|
||||
*/
|
||||
public IBuffer getBuffer() throws CModelException {
|
||||
if (hasBuffer()) {
|
||||
// ensure element is open
|
||||
if (!isOpen()) {
|
||||
getElementInfo();
|
||||
}
|
||||
IBuffer buffer = getBufferManager().getBuffer(this);
|
||||
if (buffer == null) {
|
||||
// try to (re)open a buffer
|
||||
buffer = openBuffer(null);
|
||||
}
|
||||
return buffer;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Answers the buffer factory to use for creating new buffers
|
||||
*/
|
||||
public IBufferFactory getBufferFactory(){
|
||||
return getBufferManager().getDefaultBufferFactory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the buffer manager for this element.
|
||||
*/
|
||||
protected BufferManager getBufferManager() {
|
||||
return BufferManager.getDefaultBufferManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this element may have an associated source buffer,
|
||||
* otherwise false. Subclasses must override as required.
|
||||
*/
|
||||
protected boolean hasBuffer() {
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* @see org.eclipse.cdt.core.model.ICOpenable#hasUnsavedChanges()
|
||||
*/
|
||||
public boolean hasUnsavedChanges() throws CModelException{
|
||||
|
||||
if (isReadOnly() || !isOpen()) {
|
||||
return false;
|
||||
}
|
||||
IBuffer buf = this.getBuffer();
|
||||
if (buf != null && buf.hasUnsavedChanges()) {
|
||||
return true;
|
||||
}
|
||||
// for roots and projects must check open buffers
|
||||
// to see if they have an child with unsaved changes
|
||||
if (fType == C_ROOT ||
|
||||
fType == C_PROJECT) {
|
||||
Enumeration openBuffers= getBufferManager().getOpenBuffers();
|
||||
while (openBuffers.hasMoreElements()) {
|
||||
IBuffer buffer= (IBuffer)openBuffers.nextElement();
|
||||
if (buffer.hasUnsavedChanges()) {
|
||||
ICElement owner= (ICElement)buffer.getOwner();
|
||||
if (isAncestorOf(owner)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Subclasses must override as required.
|
||||
*
|
||||
* @see org.eclipse.cdt.core.model.ICOpenable#isConsistent()
|
||||
*/
|
||||
public boolean isConsistent() throws CModelException {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.cdt.core.model.ICOpenable#isOpen()
|
||||
*/
|
||||
public boolean isOpen() {
|
||||
synchronized(CModelManager.getDefault()){
|
||||
return CModelManager.getDefault().getInfo(this) != null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this represents a source element.
|
||||
* Openable source elements have an associated buffer created
|
||||
* when they are opened.
|
||||
*/
|
||||
protected boolean isSourceElement() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.cdt.core.model.ICOpenable#makeConsistent(IProgressMonitor)
|
||||
*/
|
||||
public void makeConsistent(IProgressMonitor pm) throws CModelException {
|
||||
if (!isConsistent()) {
|
||||
buildStructure((CFileInfo)getElementInfo(), pm);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.cdt.core.model.ICOpenable#open(IProgressMonitor)
|
||||
*/
|
||||
public void open(IProgressMonitor pm) throws CModelException {
|
||||
if (!isOpen()) {
|
||||
this.openWhenClosed(pm);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a buffer on the contents of this element, and returns
|
||||
* the buffer, or returns <code>null</code> if opening fails.
|
||||
* By default, do nothing - subclasses that have buffers
|
||||
* must override as required.
|
||||
*/
|
||||
protected IBuffer openBuffer(IProgressMonitor pm) throws CModelException {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the parent element if necessary
|
||||
*
|
||||
*/
|
||||
protected void openParent(IProgressMonitor pm) throws CModelException {
|
||||
|
||||
CResource openableParent = (CResource)getOpenableParent();
|
||||
if (openableParent != null) {
|
||||
if (!openableParent.isOpen()){
|
||||
openableParent.openWhenClosed(pm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a <code>IOpenable</code> that is known to be closed (no check for
|
||||
* <code>isOpen()</code>).
|
||||
*/
|
||||
protected void openWhenClosed(IProgressMonitor pm) throws CModelException {
|
||||
try {
|
||||
|
||||
// 1) Parent must be open - open the parent if necessary
|
||||
openParent(pm);
|
||||
|
||||
// 2) create the new element info and open a buffer if needed
|
||||
CResourceInfo info = (CResourceInfo) createElementInfo();
|
||||
IResource resource = getResource();
|
||||
if (resource != null && isSourceElement()) {
|
||||
this.openBuffer(pm);
|
||||
}
|
||||
|
||||
// 3) build the structure of the openable
|
||||
buildStructure(info, pm);
|
||||
|
||||
// if any problems occuring openning the element, ensure that it's info
|
||||
// does not remain in the cache (some elements, pre-cache their info
|
||||
// as they are being opened).
|
||||
} catch (CModelException e) {
|
||||
CModelManager.getDefault().removeInfo(this);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.cdt.core.model.ICOpenable#save(IProgressMonitor, boolean)
|
||||
*/
|
||||
public void save(IProgressMonitor pm, boolean force) throws CModelException {
|
||||
if (isReadOnly() || this.getResource().isReadOnly()) {
|
||||
throw new CModelException(new CModelStatus(ICModelStatusConstants.READ_ONLY, this));
|
||||
}
|
||||
IBuffer buf = getBuffer();
|
||||
if (buf != null) {
|
||||
buf.save(pm, force);
|
||||
this.makeConsistent(pm); // update the element info of this element
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@ package org.eclipse.cdt.internal.core.model;
|
|||
* All Rights Reserved.
|
||||
*/
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.eclipse.cdt.core.model.CModelException;
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.core.model.ICProject;
|
||||
|
@ -29,10 +31,10 @@ public class CRoot extends CResource implements ICRoot {
|
|||
}
|
||||
|
||||
public ICProject[] getCProjects() {
|
||||
ICElement[] e = getChildren();
|
||||
ICProject[] p = new ICProject[e.length];
|
||||
System.arraycopy(e, 0, p, 0, e.length);
|
||||
return p;
|
||||
ArrayList list = getChildrenOfType(C_PROJECT);
|
||||
ICProject[] array= new ICProject[list.size()];
|
||||
list.toArray(array);
|
||||
return array;
|
||||
}
|
||||
|
||||
public IWorkspace getWorkspace() {
|
||||
|
@ -109,4 +111,10 @@ public class CRoot extends CResource implements ICRoot {
|
|||
protected CElementInfo createElementInfo () {
|
||||
return new CRootInfo(this);
|
||||
}
|
||||
|
||||
// CHECKPOINT: Roots will return the hashcode of their resource
|
||||
public int hashCode() {
|
||||
return resource.hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
package org.eclipse.cdt.internal.core.model;
|
||||
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2002,2003 Rational Software Corporation and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Common Public License v0.5
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/cpl-v05.html
|
||||
*
|
||||
* Contributors:
|
||||
* Rational Software - Initial API and implementation
|
||||
***********************************************************************/
|
||||
|
||||
import org.eclipse.cdt.core.model.CModelException;
|
||||
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.ITranslationUnit;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
|
||||
/**
|
||||
* Commits the contents of a working copy translation unit to its original
|
||||
* element and resource, bringing the C Model up-to-date with the current
|
||||
* contents of the working copy.
|
||||
*
|
||||
* <p>It is possible that the contents of the
|
||||
* original resource have changed since the working copy was created,
|
||||
* in which case there is an update conflict. This operation allows
|
||||
* for two settings to resolve conflict set by the <code>fForce</code> flag:<ul>
|
||||
* <li>force flag is <code>false</code> - in this case a <code>CModelException</code>
|
||||
* is thrown</li>
|
||||
* <li>force flag is <code>true</code> - in this case the contents of
|
||||
* the working copy are applied to the underlying resource even though
|
||||
* the working copy was created before a subsequent change in the
|
||||
* resource</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>The default conflict resolution setting is the force flag is <code>false</code>
|
||||
*
|
||||
* A CModelOperation exception is thrown either if the commit could not be
|
||||
* performed.
|
||||
*
|
||||
* This class is similar to the JDT CommitWorkingCopyOperation class.
|
||||
*/
|
||||
|
||||
public class CommitWorkingCopyOperation extends CModelOperation {
|
||||
/**
|
||||
* Constructs an operation to commit the contents of a working copy
|
||||
* to its original translation unit.
|
||||
*/
|
||||
|
||||
public CommitWorkingCopyOperation(ITranslationUnit element, boolean force) {
|
||||
super(new ICElement[] {element}, force);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see org.eclipse.cdt.internal.core.model.CModelOperation#executeOperation()
|
||||
*/
|
||||
protected void executeOperation() throws CModelException {
|
||||
try {
|
||||
beginTask("workingCopy.commit", 2); //$NON-NLS-1$
|
||||
WorkingCopy copy = (WorkingCopy)getElementToProcess();
|
||||
ITranslationUnit original = (ITranslationUnit) copy.getOriginalElement();
|
||||
|
||||
|
||||
// creates the delta builder (this remembers the content of the cu)
|
||||
if (!original.isOpen()) {
|
||||
// force opening so that the delta builder can get the old info
|
||||
original.open(null);
|
||||
}
|
||||
CElementDeltaBuilder deltaBuilder = new CElementDeltaBuilder(original);
|
||||
|
||||
// save the cu
|
||||
IBuffer originalBuffer = original.getBuffer();
|
||||
if (originalBuffer == null) return;
|
||||
char[] originalContents = originalBuffer.getCharacters();
|
||||
boolean hasSaved = false;
|
||||
try {
|
||||
IBuffer copyBuffer = copy.getBuffer();
|
||||
if (copyBuffer == null) return;
|
||||
originalBuffer.setContents(copyBuffer.getCharacters());
|
||||
original.save(fMonitor, fForce);
|
||||
this.hasModifiedResource = true;
|
||||
hasSaved = true;
|
||||
} finally {
|
||||
if (!hasSaved){
|
||||
// restore original buffer contents since something went wrong
|
||||
originalBuffer.setContents(originalContents);
|
||||
}
|
||||
}
|
||||
// make sure working copy is in sync
|
||||
copy.updateTimeStamp((TranslationUnit)original);
|
||||
copy.makeConsistent(this);
|
||||
worked(1);
|
||||
|
||||
if (deltaBuilder != null) {
|
||||
// build the deltas
|
||||
deltaBuilder.buildDeltas();
|
||||
|
||||
// add the deltas to the list of deltas created during this operation
|
||||
if (deltaBuilder.delta != null) {
|
||||
addDelta(deltaBuilder.delta);
|
||||
}
|
||||
}
|
||||
worked(1);
|
||||
} finally {
|
||||
done();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Possible failures: <ul>
|
||||
* <li>INVALID_ELEMENT_TYPES - the Translation unit supplied to this
|
||||
* operation is not a working copy
|
||||
* <li>ELEMENT_NOT_PRESENT - the Translation unit the working copy is
|
||||
* based on no longer exists.
|
||||
* <li>UPDATE_CONFLICT - the original Translation unit has changed since
|
||||
* the working copy was created and the operation specifies no force
|
||||
* </ul>
|
||||
*/
|
||||
|
||||
public ICModelStatus verify() {
|
||||
|
||||
IWorkingCopy wc = (IWorkingCopy) getElementToProcess();
|
||||
if (!wc.isWorkingCopy()) {
|
||||
return new CModelStatus(ICModelStatusConstants.INVALID_ELEMENT_TYPES, wc);
|
||||
}
|
||||
|
||||
try {
|
||||
ITranslationUnit original= (ITranslationUnit)wc.getOriginalElement();
|
||||
IResource resource = original.getResource();
|
||||
if (!wc.isBasedOn(resource) && !fForce) {
|
||||
return new CModelStatus(ICModelStatusConstants.UPDATE_CONFLICT);
|
||||
}
|
||||
} catch (CModelException e){
|
||||
// unable to get the underlying resource
|
||||
return new CModelStatus(ICModelStatusConstants.INVALID_RESOURCE);
|
||||
}
|
||||
// no read-only check, since some repository adapters can change the flag on save
|
||||
// operation.
|
||||
return CModelStatus.VERIFIED_OK;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
package org.eclipse.cdt.internal.core.model;
|
||||
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2002,2003 Rational Software Corporation and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Common Public License v0.5
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/cpl-v05.html
|
||||
*
|
||||
* Contributors:
|
||||
* Rational Software - Initial API and implementation
|
||||
***********************************************************************/
|
||||
|
||||
import org.eclipse.cdt.core.model.CModelException;
|
||||
import org.eclipse.cdt.core.model.ICOpenable;
|
||||
import org.eclipse.cdt.internal.core.util.LRUCache;
|
||||
import org.eclipse.cdt.internal.core.util.OverflowingLRUCache;
|
||||
|
||||
/**
|
||||
* An LRU cache of <code>CElements</code>.
|
||||
*
|
||||
* This class is similar to the JDT ElementCache class.
|
||||
*/
|
||||
public class ElementCache extends OverflowingLRUCache {
|
||||
|
||||
/**
|
||||
* Constructs a new element cache of the given size.
|
||||
*/
|
||||
public ElementCache(int size) {
|
||||
super(size);
|
||||
}
|
||||
/**
|
||||
* Constructs a new element cache of the given size.
|
||||
*/
|
||||
public ElementCache(int size, int overflow) {
|
||||
super(size, overflow);
|
||||
}
|
||||
/**
|
||||
* Returns true if the element is successfully closed and
|
||||
* removed from the cache, otherwise false.
|
||||
*
|
||||
* <p>NOTE: this triggers an external removal of this element
|
||||
* by closing the element.
|
||||
*/
|
||||
protected boolean close(LRUCacheEntry entry) {
|
||||
ICOpenable element = (ICOpenable) entry._fKey;
|
||||
try {
|
||||
if (element.hasUnsavedChanges()) {
|
||||
return false;
|
||||
} /*else {
|
||||
// We must close an entire JarPackageFragmentRoot at once.
|
||||
if (element instanceof JarPackageFragment) {
|
||||
JarPackageFragment packageFragment= (JarPackageFragment) element;
|
||||
JarPackageFragmentRoot root = (JarPackageFragmentRoot) packageFragment.getParent();
|
||||
root.close();
|
||||
}*/ else {
|
||||
element.close();
|
||||
}
|
||||
return true;
|
||||
// }
|
||||
} catch (CModelException npe) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Returns a new instance of the reciever.
|
||||
*/
|
||||
protected LRUCache newInstance(int size, int overflow) {
|
||||
return new ElementCache(size, overflow);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,259 @@
|
|||
package org.eclipse.cdt.internal.core.model;
|
||||
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2002,2003 Rational Software Corporation and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Common Public License v0.5
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/cpl-v05.html
|
||||
*
|
||||
* Contributors:
|
||||
* Rational Software - Initial API and implementation
|
||||
***********************************************************************/
|
||||
|
||||
import org.eclipse.cdt.core.model.CModelException;
|
||||
import org.eclipse.cdt.core.model.ICOpenable;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
|
||||
/**
|
||||
* A buffer contains the text contents of a resource. It is not language-specific.
|
||||
* The contents may be in the process of being edited, differing from the actual contents of the
|
||||
* underlying resource. A buffer has an owner, which is an
|
||||
* <code>IOpenable</code>. If a buffer does not have an underlying resource,
|
||||
* saving the buffer has no effect. Buffers can be read-only.
|
||||
* <p>
|
||||
* This interface is similar to the JDT IBuffer interface.
|
||||
*/
|
||||
|
||||
public interface IBuffer {
|
||||
|
||||
/**
|
||||
* Adds the given listener for changes to this buffer.
|
||||
* Has no effect if an identical listener is already registered or if the buffer
|
||||
* is closed.
|
||||
*
|
||||
* @param listener the listener of buffer changes
|
||||
*/
|
||||
public void addBufferChangedListener(IBufferChangedListener listener);
|
||||
/**
|
||||
* Appends the given character array to the contents of the buffer.
|
||||
* This buffer will now have unsaved changes.
|
||||
* Any client can append to the contents of the buffer, not just the owner of the buffer.
|
||||
* Reports a buffer changed event.
|
||||
* <p>
|
||||
* Has no effect if this buffer is read-only.
|
||||
* <p>
|
||||
* A <code>RuntimeException</code> might be thrown if the buffer is closed.
|
||||
*
|
||||
* @param text the given character array to append to contents of the buffer
|
||||
*/
|
||||
public void append(char[] text);
|
||||
/**
|
||||
* Appends the given string to the contents of the buffer.
|
||||
* This buffer will now have unsaved changes.
|
||||
* Any client can append to the contents of the buffer, not just the owner of the buffer.
|
||||
* Reports a buffer changed event.
|
||||
* <p>
|
||||
* Has no effect if this buffer is read-only.
|
||||
* <p>
|
||||
* A <code>RuntimeException</code> might be thrown if the buffer is closed.
|
||||
*
|
||||
* @param text the <code>String</code> to append to the contents of the buffer
|
||||
*/
|
||||
public void append(String text);
|
||||
/**
|
||||
* Closes the buffer. Any unsaved changes are lost. Reports a buffer changed event
|
||||
* with a 0 offset and a 0 length. When this event is fired, the buffer should already
|
||||
* be closed.
|
||||
* <p>
|
||||
* Further operations on the buffer are not allowed, except for close. If an
|
||||
* attempt is made to close an already closed buffer, the second attempt has no effect.
|
||||
*/
|
||||
public void close();
|
||||
/**
|
||||
* Returns the character at the given position in this buffer.
|
||||
* <p>
|
||||
* A <code>RuntimeException</code> might be thrown if the buffer is closed.
|
||||
*
|
||||
* @param position a zero-based source offset in this buffer
|
||||
* @return the character at the given position in this buffer
|
||||
*/
|
||||
public char getChar(int position);
|
||||
/**
|
||||
* Returns the contents of this buffer as a character array, or <code>null</code> if
|
||||
* the buffer has not been initialized.
|
||||
* <p>
|
||||
* Callers should make no assumption about whether the returned character array
|
||||
* is or is not the genuine article or a copy. In other words, if the client
|
||||
* wishes to change this array, they should make a copy. Likewise, if the
|
||||
* client wishes to hang on to the array in its current state, they should
|
||||
* make a copy.
|
||||
* </p>
|
||||
* <p>
|
||||
* A <code>RuntimeException</code> might be thrown if the buffer is closed.
|
||||
*
|
||||
* @return the characters contained in this buffer
|
||||
*/
|
||||
public char[] getCharacters();
|
||||
/**
|
||||
* Returns the contents of this buffer as a <code>String</code>. Like all strings,
|
||||
* the result is an immutable value object., It can also answer <code>null</code> if
|
||||
* the buffer has not been initialized.
|
||||
* <p>
|
||||
* A <code>RuntimeException</code> might be thrown if the buffer is closed.
|
||||
*
|
||||
* @return the contents of this buffer as a <code>String</code>
|
||||
*/
|
||||
public String getContents();
|
||||
/**
|
||||
* Returns number of characters stored in this buffer.
|
||||
* <p>
|
||||
* A <code>RuntimeException</code> might be thrown if the buffer is closed.
|
||||
*
|
||||
* @return the number of characters in this buffer
|
||||
*/
|
||||
public int getLength();
|
||||
/**
|
||||
* Returns the resource element owning of this buffer.
|
||||
*
|
||||
* @return the resource element owning this buffer
|
||||
*/
|
||||
public ICOpenable getOwner();
|
||||
/**
|
||||
* Returns the given range of text in this buffer.
|
||||
* <p>
|
||||
* A <code>RuntimeException</code> might be thrown if the buffer is closed.
|
||||
*
|
||||
* @param offset the zero-based starting offset
|
||||
* @param length the number of characters to retrieve
|
||||
* @return the given range of text in this buffer
|
||||
*/
|
||||
public String getText(int offset, int length);
|
||||
/**
|
||||
* Returns the underlying resource for which this buffer was opened,
|
||||
* or <code>null</code> if this buffer was not opened on a resource.
|
||||
*
|
||||
* @return the underlying resource for this buffer, or <code>null</code>
|
||||
* if none.
|
||||
*/
|
||||
public IResource getUnderlyingResource();
|
||||
/**
|
||||
* Returns whether this buffer has been modified since it
|
||||
* was opened or since it was last saved.
|
||||
* If a buffer does not have an underlying resource, this method always
|
||||
* returns <code>true</code>.
|
||||
*
|
||||
* @return a <code>boolean</code> indicating presence of unsaved changes (in
|
||||
* the absence of any underlying resource, it will always return <code>true</code>).
|
||||
*/
|
||||
public boolean hasUnsavedChanges();
|
||||
/**
|
||||
* Returns whether this buffer has been closed.
|
||||
*
|
||||
* @return a <code>boolean</code> indicating whether this buffer is closed.
|
||||
*/
|
||||
public boolean isClosed();
|
||||
/**
|
||||
* Returns whether this buffer is read-only.
|
||||
*
|
||||
* @return a <code>boolean</code> indicating whether this buffer is read-only
|
||||
*/
|
||||
public boolean isReadOnly();
|
||||
/**
|
||||
* Removes the given listener from this buffer.
|
||||
* Has no affect if an identical listener is not registered or if the buffer is closed.
|
||||
*
|
||||
* @param listener the listener
|
||||
*/
|
||||
public void removeBufferChangedListener(IBufferChangedListener listener);
|
||||
/**
|
||||
* Replaces the given range of characters in this buffer with the given text.
|
||||
* <code>position</code> and <code>position + length</code> must be in the range [0, getLength()].
|
||||
* <code>length</code> must not be negative.
|
||||
* <p>
|
||||
* A <code>RuntimeException</code> might be thrown if the buffer is closed.
|
||||
*
|
||||
* @param position the zero-based starting position of the affected text range in this buffer
|
||||
* @param length the length of the affected text range in this buffer
|
||||
* @param text the replacing text as a character array
|
||||
*/
|
||||
public void replace(int position, int length, char[] text);
|
||||
/**
|
||||
* Replaces the given range of characters in this buffer with the given text.
|
||||
* <code>position</code> and <code>position + length</code> must be in the range [0, getLength()].
|
||||
* <code>length</code> must not be negative.
|
||||
* <p>
|
||||
* A <code>RuntimeException</code> might be thrown if the buffer is closed.
|
||||
*
|
||||
* @param position the zero-based starting position of the affected text range in this buffer
|
||||
* @param length the length of the affected text range in this buffer
|
||||
* @param text the replacing text as a <code>String</code>
|
||||
*/
|
||||
public void replace(int position, int length, String text);
|
||||
/**
|
||||
* Saves the contents of this buffer to its underlying resource. If
|
||||
* successful, this buffer will have no unsaved changes.
|
||||
* The buffer is left open. Saving a buffer with no unsaved
|
||||
* changes has no effect - the underlying resource is not changed.
|
||||
* If the buffer does not have an underlying resource or is read-only, this
|
||||
* has no effect.
|
||||
* <p>
|
||||
* The <code>force</code> parameter controls how this method deals with
|
||||
* cases where the workbench is not completely in sync with the local file system.
|
||||
* If <code>false</code> is specified, this method will only attempt
|
||||
* to overwrite a corresponding file in the local file system provided
|
||||
* it is in sync with the workbench. This option ensures there is no
|
||||
* unintended data loss; it is the recommended setting.
|
||||
* However, if <code>true</code> is specified, an attempt will be made
|
||||
* to write a corresponding file in the local file system,
|
||||
* overwriting any existing one if need be.
|
||||
* In either case, if this method succeeds, the resource will be marked
|
||||
* as being local (even if it wasn't before).
|
||||
* <p>
|
||||
* A <code>RuntimeException</code> might be thrown if the buffer is closed.
|
||||
*
|
||||
* @param progress the progress monitor to notify
|
||||
* @param force a <code> boolean </code> flag indicating how to deal with resource
|
||||
* inconsistencies.
|
||||
*
|
||||
* @exception CModelException if an error occurs writing the buffer to
|
||||
* the underlying resource
|
||||
*
|
||||
* @see org.eclipse.core.resources.IFile#setContents(java.io.InputStream, boolean, boolean, org.eclipse.core.runtime.IProgressMonitor)
|
||||
*/
|
||||
public void save(IProgressMonitor progress, boolean force) throws CModelException;
|
||||
/**
|
||||
* Sets the contents of this buffer to the given character array.
|
||||
* This buffer will now have unsaved changes.
|
||||
* Any client can set the contents of the buffer, not just the owner of the buffer.
|
||||
* Reports a buffer changed event.
|
||||
* <p>
|
||||
* Equivalent to <code>replace(0,getLength(),contents)</code>.
|
||||
* </p>
|
||||
* <p>
|
||||
* Has no effect if this buffer is read-only.
|
||||
* <p>
|
||||
* A <code>RuntimeException</code> might be thrown if the buffer is closed.
|
||||
*
|
||||
* @param contents the new contents of this buffer as a character array
|
||||
*/
|
||||
public void setContents(char[] contents);
|
||||
/**
|
||||
* Sets the contents of this buffer to the given <code>String</code>.
|
||||
* This buffer will now have unsaved changes.
|
||||
* Any client can set the contents of the buffer, not just the owner of the buffer.
|
||||
* Reports a buffer changed event.
|
||||
* <p>
|
||||
* Equivalent to <code>replace(0,getLength(),contents)</code>.
|
||||
* </p>
|
||||
* <p>
|
||||
* Has no effect if this buffer is read-only.
|
||||
* <p>
|
||||
* A <code>RuntimeException</code> might be thrown if the buffer is closed.
|
||||
*
|
||||
* @param contents the new contents of this buffer as a <code>String</code>
|
||||
*/
|
||||
public void setContents(String contents);
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package org.eclipse.cdt.internal.core.model;
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2002,2003 Rational Software Corporation and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Common Public License v0.5
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/cpl-v05.html
|
||||
*
|
||||
* Contributors:
|
||||
* Rational Software - Initial API and implementation
|
||||
***********************************************************************/
|
||||
|
||||
/**
|
||||
* A listener, which gets notified when the contents of a specific buffer
|
||||
* have changed, or when the buffer is closed.
|
||||
* When a buffer is closed, the listener is notified <em>after</em> the buffer has been closed.
|
||||
* A listener is not notified when a buffer is saved.
|
||||
* <p>
|
||||
* This interface may be implemented by clients.
|
||||
* </p>
|
||||
*
|
||||
* This interface is similar to the JDT IBufferChangedListener interface
|
||||
*/
|
||||
public interface IBufferChangedListener {
|
||||
/**
|
||||
* Notifies that the given event has occurred.
|
||||
*
|
||||
* @param event the change event
|
||||
*/
|
||||
public void bufferChanged(BufferChangedEvent event);
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package org.eclipse.cdt.internal.core.model;
|
||||
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2002,2003 Rational Software Corporation and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Common Public License v0.5
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/cpl-v05.html
|
||||
*
|
||||
* Contributors:
|
||||
* Rational Software - Initial API and implementation
|
||||
***********************************************************************/
|
||||
|
||||
import org.eclipse.cdt.core.model.ICOpenable;
|
||||
/**
|
||||
* A factory that creates <code>IBuffer</code>s for CFiles.
|
||||
* <p>
|
||||
* This interface may be implemented by clients.
|
||||
* </p>
|
||||
*
|
||||
* This interface is similar to the JDT IBufferFactory interface.
|
||||
*/
|
||||
public interface IBufferFactory {
|
||||
|
||||
/**
|
||||
* Creates a buffer for the given owner.
|
||||
* The new buffer will be initialized with the contents of the owner
|
||||
* if and only if it was not already initialized by the factory (a buffer is uninitialized if
|
||||
* its content is <code>null</code>).
|
||||
*
|
||||
* @param owner the owner of the buffer
|
||||
* @see IBuffer
|
||||
*/
|
||||
IBuffer createBuffer(ICOpenable owner);
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
package org.eclipse.cdt.internal.core.model;
|
||||
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2002,2003 Rational Software Corporation and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Common Public License v0.5
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/cpl-v05.html
|
||||
*
|
||||
* Contributors:
|
||||
* Rational Software - Initial API and implementation
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
import org.eclipse.cdt.core.model.CModelException;
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||
import org.eclipse.core.resources.IMarker;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
|
||||
/**
|
||||
* <p> A working copy of a C element acts just like a regular element (handle),
|
||||
* except it is not attached to an underlying resource. A working copy is not
|
||||
* visible to the rest of the C model. Changes in a working copy's buffer are
|
||||
* not realized in a resource. To bring the C model up-to-date with a working
|
||||
* copy's contents, an explicit commit must be performed on the working copy.
|
||||
* Other operations performed on a working copy update the contents of the
|
||||
* working copy's buffer but do not commit the contents of the working copy.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note: The contents of a working copy is determined when a working
|
||||
* copy is created, based on the current content of the element the working
|
||||
* copy is created from. If a working copy is an <code>ICFile</code> and is
|
||||
* explicitly closed, the working copy's buffer will be thrown away. However,
|
||||
* clients should not explicitly open and close working copies.
|
||||
* </p>
|
||||
* <p>
|
||||
* The client that creates a working copy is responsible for
|
||||
* destroying the working copy. The C model will never automatically destroy or
|
||||
* close a working copy. (Note that destroying a working copy does not commit it
|
||||
* to the model, it only frees up the memory occupied by the element). After a
|
||||
* working copy is destroyed, the working copy cannot be accessed again. Non-
|
||||
* handle methods will throw a <code>CModelException</code> indicating the
|
||||
* C element does not exist.
|
||||
* </p>
|
||||
* <p>
|
||||
* A working copy cannot be created from another working copy.
|
||||
* Calling <code>getWorkingCopy</code> on a working copy returns the receiver.
|
||||
* </p>
|
||||
*/
|
||||
public interface IWorkingCopy extends ITranslationUnit{
|
||||
/**
|
||||
* Commits the contents of this working copy to its original element
|
||||
* and underlying resource, bringing the C model up-to-date with the current
|
||||
* contents of the working copy.
|
||||
*
|
||||
* <p>It is possible that the contents of the original resource have changed
|
||||
* since this working copy was created, in which case there is an update conflict.
|
||||
* The value of the <code>force</code> parameter effects the resolution of
|
||||
* such a conflict:<ul>
|
||||
* <li> <code>true</code> - in this case the contents of this working copy are applied to
|
||||
* the underlying resource even though this working copy was created before
|
||||
* a subsequent change in the resource</li>
|
||||
* <li> <code>false</code> - in this case a <code>CModelException</code> is
|
||||
* thrown</li>
|
||||
* </ul>
|
||||
*/
|
||||
void commit(boolean force, IProgressMonitor monitor) throws CModelException;
|
||||
/**
|
||||
* Destroys this working copy, closing its buffer and discarding
|
||||
* its structure. Subsequent attempts to access non-handle information
|
||||
* for this working copy will result in <code>CModelException</code>s. Has
|
||||
* no effect if this element is not a working copy.
|
||||
* <p>
|
||||
* If this working copy is shared, it is destroyed only when the number of calls to
|
||||
* <code>destroy()</code> is the same as the number of calls to <code>
|
||||
* getSharedWorkingCopy(IProgressMonitor, IBufferFactory)</code>.
|
||||
* A REMOVED CElementDelta is then reported on this working copy.
|
||||
*/
|
||||
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Returns the original element this working copy was created from,
|
||||
* or <code>null</code> if this is not a working copy.
|
||||
*/
|
||||
ITranslationUnit getOriginalElement();
|
||||
|
||||
/**
|
||||
* Returns whether this working copy's original element's content
|
||||
* has not changed since the inception of this working copy.
|
||||
*
|
||||
* @return true if this working copy's original element's content
|
||||
* has not changed since the inception of this working copy, false otherwise
|
||||
*/
|
||||
boolean isBasedOn(IResource resource);
|
||||
|
||||
/**
|
||||
* Reconciles the contents of this working copy.
|
||||
* It performs the reconciliation by locally caching the contents of
|
||||
* the working copy, updating the contents, then creating a delta
|
||||
* over the cached contents and the new contents, and finally firing
|
||||
* this delta.
|
||||
* <p>
|
||||
* If the working copy hasn't changed, then no problem will be detected,
|
||||
* this is equivalent to <code>IWorkingCopy#reconcile(false, null)</code>.
|
||||
* <p>
|
||||
*/
|
||||
IMarker[] reconcile() throws CModelException;
|
||||
|
||||
/**
|
||||
* Reconciles the contents of this working copy.
|
||||
* It performs the reconciliation by locally caching the contents of
|
||||
* the working copy, updating the contents, then creating a delta
|
||||
* over the cached contents and the new contents, and finally firing
|
||||
* this delta.
|
||||
* <p>
|
||||
* The boolean argument allows to force problem detection even if the
|
||||
* working copy is already consistent.
|
||||
*/
|
||||
void reconcile(boolean forceProblemDetection, IProgressMonitor monitor) throws CModelException;
|
||||
/**
|
||||
* Restores the contents of this working copy to the current contents of
|
||||
* this working copy's original element. Has no effect if this element
|
||||
* is not a working copy.
|
||||
*/
|
||||
void restore() throws CModelException;
|
||||
}
|
|
@ -5,15 +5,15 @@ package org.eclipse.cdt.internal.core.model;
|
|||
* All Rights Reserved.
|
||||
*/
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.eclipse.cdt.core.model.CModelException;
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.core.model.IParent;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
import org.eclipse.core.resources.ResourcesPlugin;
|
||||
import org.eclipse.core.runtime.IPath;
|
||||
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.core.model.IParent;
|
||||
import org.eclipse.cdt.core.model.CModelException;
|
||||
|
||||
public abstract class Parent extends CElement implements IParent {
|
||||
|
||||
protected IResource resource;
|
||||
|
@ -64,6 +64,24 @@ public abstract class Parent extends CElement implements IParent {
|
|||
return getElementInfo().getChildren();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the children of a certain type
|
||||
* @param type
|
||||
* @return ArrayList
|
||||
*/
|
||||
public ArrayList getChildrenOfType(int type){
|
||||
ICElement[] children = getChildren();
|
||||
int size = children.length;
|
||||
ArrayList list = new ArrayList(size);
|
||||
for (int i = 0; i < size; ++i) {
|
||||
CElement elt = (CElement)children[i];
|
||||
if (elt.getElementType() == type) {
|
||||
list.add(elt);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public boolean hasChildren () {
|
||||
return getElementInfo().hasChildren();
|
||||
}
|
||||
|
|
|
@ -5,16 +5,16 @@ package org.eclipse.cdt.internal.core.model;
|
|||
* All Rights Reserved.
|
||||
*/
|
||||
|
||||
import org.eclipse.cdt.core.model.CModelException;
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.core.model.ICOpenable;
|
||||
import org.eclipse.cdt.core.model.ISourceManipulation;
|
||||
import org.eclipse.cdt.core.model.ISourceRange;
|
||||
import org.eclipse.cdt.core.model.ISourceReference;
|
||||
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||
import org.eclipse.cdt.core.model.ISourceManipulation;
|
||||
import org.eclipse.cdt.core.model.ISourceReference;
|
||||
import org.eclipse.cdt.core.model.ISourceRange;
|
||||
import org.eclipse.cdt.core.model.CModelException;
|
||||
|
||||
/**
|
||||
* Abstract class for C elements which implement ISourceReference.
|
||||
*/
|
||||
|
@ -105,6 +105,21 @@ public class SourceManipulation extends Parent implements ISourceManipulation, I
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first parent of the element that is an instance of
|
||||
* ICOpenable.
|
||||
*/
|
||||
public ICOpenable getOpenableParent() {
|
||||
ICElement current = getParent();
|
||||
while (current != null){
|
||||
if (current instanceof ICOpenable){
|
||||
return (ICOpenable) current;
|
||||
}
|
||||
current = current.getParent();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ISourceReference
|
||||
*/
|
||||
|
|
|
@ -7,21 +7,25 @@ package org.eclipse.cdt.internal.core.model;
|
|||
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.cdt.core.model.CModelException;
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.core.model.IInclude;
|
||||
import org.eclipse.cdt.core.model.IParent;
|
||||
import org.eclipse.cdt.core.model.ISourceRange;
|
||||
import org.eclipse.cdt.core.model.ISourceReference;
|
||||
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||
import org.eclipse.cdt.core.model.IUsing;
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
import org.eclipse.core.runtime.IPath;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.core.model.IInclude;
|
||||
import org.eclipse.cdt.core.model.IUsing;
|
||||
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||
import org.eclipse.cdt.core.model.ISourceReference;
|
||||
import org.eclipse.cdt.core.model.ISourceRange;
|
||||
import org.eclipse.cdt.core.model.CModelException;
|
||||
|
||||
|
||||
/**
|
||||
* @see ITranslationUnit
|
||||
*/
|
||||
public class TranslationUnit extends CFile implements ITranslationUnit {
|
||||
|
||||
|
@ -180,4 +184,259 @@ public class TranslationUnit extends CFile implements ITranslationUnit {
|
|||
protected CElementInfo createElementInfo () {
|
||||
return new TranslationUnitInfo(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.cdt.internal.core.model.CFile#buildStructure(CFileInfo, IProgressMonitor)
|
||||
*/
|
||||
protected void buildStructure(CFileInfo info, IProgressMonitor monitor) throws CModelException {
|
||||
if (monitor != null && monitor.isCanceled()) return;
|
||||
|
||||
// remove existing (old) infos
|
||||
removeInfo();
|
||||
|
||||
HashMap newElements = new HashMap(11);
|
||||
info.setIsStructureKnown(generateInfos(info, monitor, newElements, getResource()));
|
||||
CModelManager.getDefault().getElementsOutOfSynchWithBuffers().remove(this);
|
||||
for (Iterator iter = newElements.keySet().iterator(); iter.hasNext();) {
|
||||
ICElement key = (ICElement) iter.next();
|
||||
Object value = newElements.get(key);
|
||||
CModelManager.getDefault().putInfo(key, value);
|
||||
}
|
||||
// problem detection
|
||||
if (monitor != null && monitor.isCanceled()) return;
|
||||
|
||||
//IProblemRequestor problemRequestor = this.getProblemRequestor();
|
||||
//if (problemRequestor != null && problemRequestor.isActive()){
|
||||
// problemRequestor.beginReporting();
|
||||
// CompilationUnitProblemFinder.process(this, problemRequestor, monitor);
|
||||
// problemRequestor.endReporting();
|
||||
//}
|
||||
|
||||
// add the info for this at the end, to ensure that a getInfo cannot reply null in case the LRU cache needs
|
||||
// to be flushed. Might lead to performance issues.
|
||||
CModelManager.getDefault().putInfo(this, info);
|
||||
|
||||
}
|
||||
/**
|
||||
* Returns true if this handle represents the same Java element
|
||||
* as the given handle.
|
||||
*
|
||||
* <p>Compilation units must also check working copy state;
|
||||
*
|
||||
* @see Object#equals(java.lang.Object)
|
||||
*/
|
||||
public boolean equals(Object o) {
|
||||
return super.equals(o) && !((ITranslationUnit)o).isWorkingCopy();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see IWorkingCopy#findSharedWorkingCopy(IBufferFactory)
|
||||
*/
|
||||
public IWorkingCopy findSharedWorkingCopy(IBufferFactory factory) {
|
||||
|
||||
// if factory is null, default factory must be used
|
||||
if (factory == null) factory = BufferManager.getDefaultBufferManager();
|
||||
|
||||
// In order to be shared, working copies have to denote the same translation unit
|
||||
// AND use the same buffer factory.
|
||||
// Assuming there is a little set of buffer factories, then use a 2 level Map cache.
|
||||
Map sharedWorkingCopies = CModelManager.getDefault().sharedWorkingCopies;
|
||||
|
||||
Map perFactoryWorkingCopies = (Map) sharedWorkingCopies.get(factory);
|
||||
if (perFactoryWorkingCopies == null) return null;
|
||||
return (WorkingCopy)perFactoryWorkingCopies.get(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* To be removed with the new model builder in place
|
||||
* @param newElements
|
||||
* @param element
|
||||
*/
|
||||
private void getNewElements(Map newElements, CElement element){
|
||||
Object info = element.getElementInfo();
|
||||
if(info != null){
|
||||
if(element instanceof IParent){
|
||||
ICElement[] children = ((CElementInfo)info).getChildren();
|
||||
int size = children.length;
|
||||
for (int i = 0; i < size; ++i) {
|
||||
CElement child = (CElement) children[i];
|
||||
getNewElements(newElements, child);
|
||||
}
|
||||
}
|
||||
}
|
||||
newElements.put(element, info);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.cdt.internal.core.model.CResource#generateInfos(CResourceInfo, IProgressMonitor, Map, IResource)
|
||||
*/
|
||||
protected boolean generateInfos(CResourceInfo info, IProgressMonitor pm, Map newElements, IResource underlyingResource) throws CModelException {
|
||||
// put the info now, because getting the contents requires it
|
||||
CModelManager.getDefault().putInfo(this, info);
|
||||
TranslationUnitInfo unitInfo = (TranslationUnitInfo) info;
|
||||
|
||||
// generate structure
|
||||
this.parse();
|
||||
|
||||
// this is temporary until the New Model Builder is implemented
|
||||
getNewElements(newElements, this);
|
||||
///////////////////////////////////////////////////////////////
|
||||
|
||||
if (isWorkingCopy()) {
|
||||
ITranslationUnit original = (ITranslationUnit) ((IWorkingCopy)this).getOriginalElement();
|
||||
// might be IResource.NULL_STAMP if original does not exist
|
||||
unitInfo.fTimestamp = ((IFile) original.getResource()).getModificationStamp();
|
||||
}
|
||||
|
||||
return unitInfo.isStructureKnown();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.cdt.core.model.ITranslationUnit#getContents()
|
||||
*/
|
||||
public char[] getContents() {
|
||||
try {
|
||||
IBuffer buffer = this.getBuffer();
|
||||
return buffer == null ? null : buffer.getCharacters();
|
||||
} catch (CModelException e) {
|
||||
return new char[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.cdt.core.model.ITranslationUnit#getSharedWorkingCopy(IProgressMonitor, IBufferFactory)
|
||||
*/
|
||||
public IWorkingCopy getSharedWorkingCopy(IProgressMonitor monitor,IBufferFactory factory)
|
||||
throws CModelException {
|
||||
|
||||
// if factory is null, default factory must be used
|
||||
if (factory == null) factory = BufferManager.getDefaultBufferManager();
|
||||
|
||||
CModelManager manager = CModelManager.getDefault();
|
||||
|
||||
// In order to be shared, working copies have to denote the same translation unit
|
||||
// AND use the same buffer factory.
|
||||
// Assuming there is a little set of buffer factories, then use a 2 level Map cache.
|
||||
Map sharedWorkingCopies = manager.sharedWorkingCopies;
|
||||
|
||||
Map perFactoryWorkingCopies = (Map) sharedWorkingCopies.get(factory);
|
||||
if (perFactoryWorkingCopies == null){
|
||||
perFactoryWorkingCopies = new HashMap();
|
||||
sharedWorkingCopies.put(factory, perFactoryWorkingCopies);
|
||||
}
|
||||
WorkingCopy workingCopy = (WorkingCopy)perFactoryWorkingCopies.get(this);
|
||||
if (workingCopy != null) {
|
||||
workingCopy.useCount++;
|
||||
return workingCopy;
|
||||
|
||||
} else {
|
||||
workingCopy = (WorkingCopy)this.getWorkingCopy(monitor, factory);
|
||||
perFactoryWorkingCopies.put(this, workingCopy);
|
||||
|
||||
// report added java delta
|
||||
// CElementDelta delta = new CElementDelta(this.getCModel());
|
||||
// delta.added(workingCopy);
|
||||
// manager.fire(delta, CModelManager.DEFAULT_CHANGE_EVENT);
|
||||
|
||||
return workingCopy;
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @see org.eclipse.cdt.core.model.ITranslationUnit#getWorkingCopy()
|
||||
*/
|
||||
public IWorkingCopy getWorkingCopy()throws CModelException{
|
||||
return this.getWorkingCopy(null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @see org.eclipse.cdt.core.model.ITranslationUnit#getWorkingCopy()
|
||||
*/
|
||||
public IWorkingCopy getWorkingCopy(IProgressMonitor monitor, IBufferFactory factory)throws CModelException{
|
||||
WorkingCopy workingCopy = new WorkingCopy(getParent(), getFile(), factory);
|
||||
// open the working copy now to ensure contents are that of the current state of this element
|
||||
workingCopy.open(monitor);
|
||||
return workingCopy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this element may have an associated source buffer.
|
||||
*/
|
||||
protected boolean hasBuffer() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.cdt.core.model.ICOpenable#isConsistent()
|
||||
*/
|
||||
public boolean isConsistent() throws CModelException {
|
||||
return CModelManager.getDefault().getElementsOutOfSynchWithBuffers().get(this) == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.cdt.internal.core.model.CResource#isSourceElement()
|
||||
*/
|
||||
protected boolean isSourceElement() {
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* @see org.eclipse.cdt.core.model.ITranslationUnit#isWorkingCopy()
|
||||
*/
|
||||
public boolean isWorkingCopy() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.cdt.core.model.ICOpenable#makeConsistent(IProgressMonitor)
|
||||
*/
|
||||
public void makeConsistent(IProgressMonitor pm) throws CModelException {
|
||||
if (!isConsistent()) {
|
||||
// create a new info and make it the current info
|
||||
CFileInfo info = (CFileInfo) createElementInfo();
|
||||
buildStructure(info, pm);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.cdt.internal.core.model.CResource#openBuffer(IProgressMonitor)
|
||||
*/
|
||||
protected IBuffer openBuffer(IProgressMonitor pm) throws CModelException {
|
||||
|
||||
// create buffer - translation units only use default buffer factory
|
||||
BufferManager bufManager = getBufferManager();
|
||||
IBuffer buffer = getBufferFactory().createBuffer(this);
|
||||
if (buffer == null)
|
||||
return null;
|
||||
|
||||
// set the buffer source
|
||||
if (buffer.getCharacters() == null){
|
||||
IResource file = this.getResource();
|
||||
if (file != null && file.getType() == IResource.FILE) {
|
||||
buffer.setContents(Util.getResourceContentsAsCharArray((IFile)file));
|
||||
}
|
||||
}
|
||||
|
||||
// add buffer to buffer cache
|
||||
bufManager.addBuffer(buffer);
|
||||
|
||||
// listen to buffer changes
|
||||
buffer.addBufferChangedListener(this);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the buffer contents of this element.
|
||||
*/
|
||||
public void parse(){
|
||||
try{
|
||||
getTranslationUnitInfo().parse(this.getBuffer().getContents());
|
||||
} catch (CModelException e){
|
||||
// error getting the buffer
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -5,21 +5,27 @@ package org.eclipse.cdt.internal.core.model;
|
|||
* All Rights Reserved.
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringBufferInputStream;
|
||||
|
||||
import org.eclipse.cdt.core.CCorePlugin;
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.core.model.ISourceRange;
|
||||
import org.eclipse.cdt.internal.core.parser.Parser;
|
||||
import org.eclipse.cdt.internal.parser.CStructurizer;
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.IPath;
|
||||
|
||||
/**
|
||||
* The Element Info of a Translation Unit.
|
||||
*/
|
||||
class TranslationUnitInfo extends CFileInfo {
|
||||
|
||||
/**
|
||||
* Timestamp of original resource at the time this element
|
||||
* was opened or last updated.
|
||||
*/
|
||||
protected long fTimestamp;
|
||||
|
||||
protected TranslationUnitInfo (CElement element) {
|
||||
super(element);
|
||||
}
|
||||
|
@ -29,27 +35,8 @@ class TranslationUnitInfo extends CFileInfo {
|
|||
}
|
||||
|
||||
protected ICElement [] getChildren() {
|
||||
if (hasChanged()) {
|
||||
InputStream in = null;
|
||||
try {
|
||||
IResource res = getElement().getUnderlyingResource();
|
||||
if (res != null && res.getType() == IResource.FILE) {
|
||||
in = ((IFile)res).getContents();
|
||||
parse(in);
|
||||
}
|
||||
} catch (CoreException e) {
|
||||
//e.printStackTrace();
|
||||
} finally {
|
||||
if (in != null) {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return super.getChildren();
|
||||
// CHECKPOINT: replacing the parsing done here before
|
||||
return fChildren;
|
||||
}
|
||||
|
||||
protected void parse(InputStream in) {
|
||||
|
@ -70,6 +57,15 @@ class TranslationUnitInfo extends CFileInfo {
|
|||
}
|
||||
}
|
||||
|
||||
protected void parse(String buf) {
|
||||
// CHECKPOINT: Parsing a string using the StringBufferInputStream
|
||||
// FIXME: quick fix for the IBinary which uses fake translationUnit
|
||||
if (buf != null) {
|
||||
StringBufferInputStream in = new StringBufferInputStream (buf);
|
||||
parse (in);
|
||||
}
|
||||
}
|
||||
|
||||
/* Overide the SourceManipulation for the range. */
|
||||
protected ISourceRange getSourceRange() {
|
||||
IPath location = ((TranslationUnit)getElement()).getLocation();
|
||||
|
|
|
@ -5,14 +5,19 @@ package org.eclipse.cdt.internal.core.model;
|
|||
* All Rights Reserved.
|
||||
*/
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
import org.eclipse.cdt.core.CCorePlugin;
|
||||
import org.eclipse.cdt.core.model.CModelException;
|
||||
import org.eclipse.cdt.core.model.ICModelStatusConstants;
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
|
||||
public class Util {
|
||||
|
||||
|
@ -114,4 +119,51 @@ public class Util {
|
|||
boolean force = true;
|
||||
file.setContents(stream, force, true, null); // record history
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given file's contents as a character array.
|
||||
*/
|
||||
public static char[] getResourceContentsAsCharArray(IFile file) throws CModelException {
|
||||
return getResourceContentsAsCharArray(file, null);
|
||||
}
|
||||
|
||||
public static char[] getResourceContentsAsCharArray(IFile file, String encoding) throws CModelException {
|
||||
InputStream stream= null;
|
||||
try {
|
||||
stream = new BufferedInputStream(file.getContents(true));
|
||||
} catch (CoreException e) {
|
||||
throw new CModelException(e, ICModelStatusConstants.ELEMENT_DOES_NOT_EXIST);
|
||||
}
|
||||
try {
|
||||
return Util.getInputStreamAsCharArray(stream, -1, encoding);
|
||||
} catch (IOException e) {
|
||||
throw new CModelException(e, ICModelStatusConstants.IO_EXCEPTION);
|
||||
} finally {
|
||||
try {
|
||||
stream.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a log entry
|
||||
*/
|
||||
public static void log(Throwable e, String message) {
|
||||
IStatus status= new Status(
|
||||
IStatus.ERROR,
|
||||
CCorePlugin.getDefault().getDescriptor().getUniqueIdentifier(),
|
||||
IStatus.ERROR,
|
||||
message,
|
||||
e);
|
||||
|
||||
CCorePlugin.getDefault().getLog().log(status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines two hash codes to make a new one.
|
||||
*/
|
||||
public static int combineHashCodes(int hashCode1, int hashCode2) {
|
||||
return hashCode1 * 17 + hashCode2;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,379 @@
|
|||
package org.eclipse.cdt.internal.core.model;
|
||||
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2002,2003 Rational Software Corporation and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Common Public License v0.5
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/cpl-v05.html
|
||||
*
|
||||
* Contributors:
|
||||
* Rational Software - Initial API and implementation
|
||||
***********************************************************************/
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.cdt.core.model.CModelException;
|
||||
import org.eclipse.cdt.core.model.ICElement;
|
||||
import org.eclipse.cdt.core.model.ICModelStatusConstants;
|
||||
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IMarker;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.IPath;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
|
||||
/**
|
||||
* Implementation of a working copy translation unit. A working copy maintains
|
||||
* the timestamp of the resource it was created from.
|
||||
*/
|
||||
public class WorkingCopy extends TranslationUnit implements IWorkingCopy {
|
||||
|
||||
/**
|
||||
* If set, this is the factory that will be used to create the buffer.
|
||||
*/
|
||||
protected IBufferFactory bufferFactory;
|
||||
/**
|
||||
* A counter of the number of time clients have asked for this
|
||||
* working copy. It is set to 1, if the working
|
||||
* copy is not managed. When destroyed, this counter is
|
||||
* set to 0. Once destroyed, this working copy cannot be opened
|
||||
* and non-handle info can not be accessed. This is
|
||||
* never true if this translation unit is not a working copy.
|
||||
*/
|
||||
protected int useCount = 1;
|
||||
|
||||
/**
|
||||
* Creates a working copy of this element
|
||||
*/
|
||||
public WorkingCopy(ICElement parent, IFile file, IBufferFactory bufferFactory) {
|
||||
super(parent, file);
|
||||
this.bufferFactory =
|
||||
bufferFactory == null ?
|
||||
getBufferManager() :
|
||||
bufferFactory;
|
||||
}
|
||||
|
||||
public WorkingCopy(ICElement parent, IPath path, IBufferFactory bufferFactory) {
|
||||
super(parent, path);
|
||||
this.bufferFactory =
|
||||
bufferFactory == null ?
|
||||
getBufferManager() :
|
||||
bufferFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.cdt.internal.core.model.IWorkingCopy#commit(boolean, org.eclipse.core.runtime.IProgressMonitor)
|
||||
*/
|
||||
public void commit(boolean force, IProgressMonitor monitor)
|
||||
throws CModelException {
|
||||
ITranslationUnit original = (ITranslationUnit)this.getOriginalElement();
|
||||
if (original.exists()) {
|
||||
CommitWorkingCopyOperation op= new CommitWorkingCopyOperation(this, force);
|
||||
runOperation(op, monitor);
|
||||
} else {
|
||||
String contents = this.getSource();
|
||||
if (contents == null) return;
|
||||
try {
|
||||
byte[] bytes = contents.getBytes();
|
||||
ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
|
||||
IFile originalRes = (IFile)original.getResource();
|
||||
if (originalRes.exists()) {
|
||||
originalRes.setContents(
|
||||
stream,
|
||||
force ? IResource.FORCE | IResource.KEEP_HISTORY : IResource.KEEP_HISTORY,
|
||||
null);
|
||||
} else {
|
||||
originalRes.create(
|
||||
stream,
|
||||
force,
|
||||
monitor);
|
||||
}
|
||||
} catch (CoreException e) {
|
||||
throw new CModelException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new element info for this element.
|
||||
*/
|
||||
protected CElementInfo createElementInfo() {
|
||||
return new WorkingCopyInfo(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.cdt.internal.core.model.IWorkingCopy#destroy()
|
||||
*/
|
||||
public void destroy() {
|
||||
if (--this.useCount > 0) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
close();
|
||||
|
||||
// if original element is not on classpath flush it from the cache
|
||||
ICElement originalElement = this.getOriginalElement();
|
||||
if (!this.getParent().exists()) {
|
||||
((TranslationUnit)originalElement).close();
|
||||
}
|
||||
|
||||
// remove working copy from the cache
|
||||
CModelManager manager = CModelManager.getDefault();
|
||||
|
||||
// In order to be shared, working copies have to denote the same compilation unit
|
||||
// AND use the same buffer factory.
|
||||
// Assuming there is a little set of buffer factories, then use a 2 level Map cache.
|
||||
Map sharedWorkingCopies = manager.sharedWorkingCopies;
|
||||
|
||||
Map perFactoryWorkingCopies = (Map) sharedWorkingCopies.get(this.bufferFactory);
|
||||
if (perFactoryWorkingCopies != null){
|
||||
if (perFactoryWorkingCopies.remove(originalElement) != null) {
|
||||
|
||||
// report removed java delta
|
||||
//CElementDelta delta = new CElementDelta(this.getCoreModel());
|
||||
//delta.removed(this);
|
||||
//manager.fire(delta, CModelManager.DEFAULT_CHANGE_EVENT);
|
||||
}
|
||||
}
|
||||
} catch (CModelException e) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.cdt.core.model.ICElement#exists()
|
||||
*/
|
||||
public boolean exists() {
|
||||
// working copy always exists in the model until it is detroyed
|
||||
return this.useCount != 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Answers custom buffer factory
|
||||
*/
|
||||
public IBufferFactory getBufferFactory(){
|
||||
|
||||
return this.bufferFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Working copies must be identical to be equal.
|
||||
*
|
||||
* @see Object#equals
|
||||
*/
|
||||
public boolean equals(Object o) {
|
||||
return this == o;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.cdt.internal.core.model.IWorkingCopy#getOriginalElement()
|
||||
*/
|
||||
public ITranslationUnit getOriginalElement() {
|
||||
return new TranslationUnit(getParent(), getFile());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.cdt.core.model.ITranslationUnit#getSharedWorkingCopy(IProgressMonitor, IBufferFactory)
|
||||
*/
|
||||
public IWorkingCopy getSharedWorkingCopy(IProgressMonitor monitor,IBufferFactory factory)
|
||||
throws CModelException{
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* @see org.eclipse.cdt.core.model.ITranslationUnit#getWorkingCopy()
|
||||
*/
|
||||
public IWorkingCopy getWorkingCopy() {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see IWorkingCopy
|
||||
*/
|
||||
public IWorkingCopy getWorkingCopy(IProgressMonitor monitor, IBufferFactory factory){
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see IWorkingCopy
|
||||
*/
|
||||
public boolean isBasedOn(IResource resource) {
|
||||
if (resource.getType() != IResource.FILE) {
|
||||
return false;
|
||||
}
|
||||
if (this.useCount == 0) {
|
||||
return false;
|
||||
}
|
||||
// if resource got deleted, then #getModificationStamp() will answer IResource.NULL_STAMP, which is always different from the cached
|
||||
// timestamp
|
||||
return ((TranslationUnitInfo) getElementInfo()).fTimestamp == ((IFile) resource).getModificationStamp();
|
||||
}
|
||||
/**
|
||||
* @see org.eclipse.cdt.core.model.ITranslationUnit#isWorkingCopy()
|
||||
*/
|
||||
public boolean isWorkingCopy() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ICFile
|
||||
* @see IWorkingCopy
|
||||
*
|
||||
* @exception CModelException attempting to open a read only element for
|
||||
* something other than navigation or if this is a working copy being
|
||||
* opened after it has been destroyed.
|
||||
*/
|
||||
public void open(IProgressMonitor pm) throws CModelException {
|
||||
if (this.useCount == 0) { // was destroyed
|
||||
throw newNotPresentException();
|
||||
} else {
|
||||
super.open(pm);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @see org.eclipse.cdt.internal.core.model.CFile#openBuffer(IProgressMonitor)
|
||||
*/
|
||||
protected IBuffer openBuffer(IProgressMonitor pm) throws CModelException {
|
||||
|
||||
if (this.useCount == 0) throw newNotPresentException();
|
||||
|
||||
// create buffer - working copies may use custom buffer factory
|
||||
IBuffer buffer = getBufferFactory().createBuffer(this);
|
||||
if (buffer == null)
|
||||
return null;
|
||||
|
||||
// set the buffer source if needed
|
||||
if (buffer.getCharacters() == null){
|
||||
ITranslationUnit original= (ITranslationUnit)this.getOriginalElement();
|
||||
IBuffer originalBuffer = null;
|
||||
try {
|
||||
originalBuffer = original.getBuffer();
|
||||
} catch (CModelException e) {
|
||||
// original element does not exist: create an empty working copy
|
||||
if (!e.getCModelStatus().doesNotExist()) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
if (originalBuffer != null) {
|
||||
char[] originalContents = originalBuffer.getCharacters();
|
||||
if (originalContents != null) {
|
||||
buffer.setContents((char[])originalContents.clone());
|
||||
}
|
||||
} else {
|
||||
// initialize buffer
|
||||
buffer.setContents(new char[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// add buffer to buffer cache
|
||||
this.getBufferManager().addBuffer(buffer);
|
||||
|
||||
// listen to buffer changes
|
||||
buffer.addBufferChangedListener(this);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see org.eclipse.cdt.internal.core.model.IWorkingCopy#reconcile()
|
||||
*/
|
||||
public IMarker[] reconcile() throws CModelException {
|
||||
reconcile(false, null);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.eclipse.cdt.internal.core.model.IWorkingCopy#reconcile(boolean, org.eclipse.core.runtime.IProgressMonitor)
|
||||
*/
|
||||
public void reconcile(boolean forceProblemDetection, IProgressMonitor monitor)
|
||||
throws CModelException {
|
||||
|
||||
if (this.useCount == 0) throw newNotPresentException(); //was destroyed
|
||||
|
||||
if (monitor != null){
|
||||
if (monitor.isCanceled()) return;
|
||||
monitor.beginTask("element.reconciling", 10); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
boolean wasConsistent = isConsistent();
|
||||
CElementDeltaBuilder deltaBuilder = null;
|
||||
|
||||
try {
|
||||
// create the delta builder (this remembers the current content of the cu)
|
||||
if (!wasConsistent){
|
||||
deltaBuilder = new CElementDeltaBuilder(this);
|
||||
|
||||
// update the element infos with the content of the working copy
|
||||
this.makeConsistent(monitor);
|
||||
deltaBuilder.buildDeltas();
|
||||
|
||||
}
|
||||
|
||||
if (monitor != null) monitor.worked(2);
|
||||
|
||||
// force problem detection? - if structure was consistent
|
||||
if (forceProblemDetection && wasConsistent){
|
||||
if (monitor != null && monitor.isCanceled()) return;
|
||||
|
||||
//IProblemRequestor problemRequestor = this.getProblemRequestor();
|
||||
//if (problemRequestor != null && problemRequestor.isActive()){
|
||||
// problemRequestor.beginReporting();
|
||||
// CompilationUnitProblemFinder.process(this, problemRequestor, monitor);
|
||||
// problemRequestor.endReporting();
|
||||
//}
|
||||
}
|
||||
|
||||
// fire the deltas
|
||||
//if (deltaBuilder != null){
|
||||
// if ((deltaBuilder.delta != null) && (deltaBuilder.delta.getAffectedChildren().length > 0)) {
|
||||
// CModelManager.getDefault().fire(deltaBuilder.delta, ElementChangedEvent.POST_RECONCILE);
|
||||
// }
|
||||
//}
|
||||
} finally {
|
||||
if (monitor != null) monitor.done();
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* @see org.eclipse.cdt.internal.core.model.IWorkingCopy#restore()
|
||||
*/
|
||||
public void restore() throws CModelException{
|
||||
if (this.useCount == 0) throw newNotPresentException(); //was destroyed
|
||||
|
||||
TranslationUnit original = (TranslationUnit) getOriginalElement();
|
||||
IBuffer buffer = this.getBuffer();
|
||||
if (buffer == null) return;
|
||||
buffer.setContents(original.getContents());
|
||||
updateTimeStamp(original);
|
||||
makeConsistent(null);
|
||||
}
|
||||
/**
|
||||
* @see org.eclipse.cdt.core.model.ICFile#save(IProgressMonitor, boolean)
|
||||
*/
|
||||
public void save(IProgressMonitor pm, boolean force) throws CModelException {
|
||||
if (isReadOnly()) {
|
||||
throw new CModelException(new CModelStatus(ICModelStatusConstants.READ_ONLY, this));
|
||||
}
|
||||
// computes fine-grain deltas in case the working copy is being reconciled already (if not it would miss one iteration of deltas).
|
||||
this.reconcile();
|
||||
}
|
||||
/**
|
||||
* @param original
|
||||
* @throws CModelException
|
||||
*/
|
||||
protected void updateTimeStamp(TranslationUnit original) throws CModelException {
|
||||
long timeStamp =
|
||||
((IFile) original.getResource()).getModificationStamp();
|
||||
if (timeStamp == IResource.NULL_STAMP) {
|
||||
throw new CModelException(
|
||||
new CModelStatus(ICModelStatusConstants.INVALID_RESOURCE));
|
||||
}
|
||||
((TranslationUnitInfo) getElementInfo()).fTimestamp = timeStamp;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package org.eclipse.cdt.internal.core.model;
|
||||
/**********************************************************************
|
||||
* Copyright (c) 2002,2003 Rational Software Corporation and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Common Public License v0.5
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/cpl-v05.html
|
||||
*
|
||||
* Contributors:
|
||||
* Rational Software - Initial API and implementation
|
||||
***********************************************************************/
|
||||
|
||||
/**
|
||||
* The Element Info of a Working Copy.
|
||||
*/
|
||||
public class WorkingCopyInfo extends TranslationUnitInfo {
|
||||
|
||||
public WorkingCopyInfo (CElement element) {
|
||||
super(element);
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Reference in a new issue