blob: c95d9b6dbbd8acd238ce38a8ca2e3e53e7a926a3 [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2000, 2005 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
****************************************************************************/
package org.eclipse.gmf.runtime.diagram.ui.resources.editor.document;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* Abstract implementation of <code>IDocument</code>. This class
* provides implementation for registering <code>IDocumentListener</code>s.
* Additionally it also handles firing of <code>DocumentEvent</code> to
* the document listeners.
*/
public abstract class AbstractDocument
implements IDocument {
/**
* Content of this document.
*/
protected Object content;
/**
* The current modification stamp.
*/
private long fModificationStamp= IDocument.UNKNOWN_MODIFICATION_STAMP;
/**
* @see org.eclipse.gmf.runtime.diagram.ui.editor.IDocument#getModificationStamp()
*/
public long getModificationStamp() {
return fModificationStamp;
}
/** The registered document listeners */
private List fDocumentListeners;
/** The registered pre-notified document listeners */
private List fPrenotifiedDocumentListeners;
/**
* Indicates whether the notification of listeners has been stopped.
*/
private int fStoppedListenerNotification= 0;
/**
* The document event to be sent after listener notification has been resumed.
*/
private DocumentEvent fDeferredDocumentEvent;
/**
* Initializes document listeners, positions, and position updaters.
* Must be called inside the constructor after the implementation plug-ins
* have been set.
*/
protected void completeInitialization() {
fDocumentListeners= new ArrayList();
fPrenotifiedDocumentListeners= new ArrayList();
}
/**
* @see org.eclipse.gmf.runtime.diagram.ui.editor.IDocument#addDocumentListener(org.eclipse.gmf.runtime.diagram.ui.editor.IDocumentListener)
*/
public void addDocumentListener(IDocumentListener listener) {
assert listener != null;
if (! fDocumentListeners.contains(listener))
fDocumentListeners.add(listener);
}
/**
* @see org.eclipse.gmf.runtime.diagram.ui.editor.IDocument#removeDocumentListener(org.eclipse.gmf.runtime.diagram.ui.editor.IDocumentListener)
*/
public void removeDocumentListener(IDocumentListener listener) {
assert listener != null;
fDocumentListeners.remove(listener);
}
/**
* @see org.eclipse.gmf.runtime.diagram.ui.editor.IDocument#addPrenotifiedDocumentListener(org.eclipse.gmf.runtime.diagram.ui.editor.IDocumentListener)
*/
public void addPrenotifiedDocumentListener(IDocumentListener listener) {
assert listener != null;
if (! fPrenotifiedDocumentListeners.contains(listener))
fPrenotifiedDocumentListeners.add(listener);
}
/**
* @see org.eclipse.gmf.runtime.diagram.ui.editor.IDocument#removePrenotifiedDocumentListener(org.eclipse.gmf.runtime.diagram.ui.editor.IDocumentListener)
*/
public void removePrenotifiedDocumentListener(
IDocumentListener listener) {
assert listener != null;
fPrenotifiedDocumentListeners.remove(listener);
}
/**
* @see org.eclipse.gmf.runtime.diagram.ui.editor.IDocument#getContent()
*/
public Object getContent() {
return content;
}
/**
* @see org.eclipse.gmf.runtime.diagram.ui.editor.IDocument#setContent(java.lang.Object)
*/
public void setContent(Object documentContent) {
setContent(documentContent, getNextModificationStamp());
}
/**
* @see org.eclipse.gmf.runtime.diagram.ui.editor.IDocument#setContent(java.lang.Object, long)
*/
public void setContent(Object documentContent, long modificationStamp) {
DocumentEvent eventToBeFired = null;
if (content != documentContent) {
DocumentEvent changed= new DocumentEvent(this, DocumentEvent.CONTENT_REPLACED, documentContent);
DocumentEvent changing= new DocumentEvent(this, DocumentEvent.CONTENT_REPLACED, content);
fireDocumentAboutToBeChanged(changed);
content = documentContent;
fModificationStamp= modificationStamp;
changed.fModificationStamp= fModificationStamp;
changing.fModificationStamp = fModificationStamp;
eventToBeFired = changing;
fireDocumentChanged(changing);
}
else {
eventToBeFired = new DocumentEvent(this, DocumentEvent.CONTENT_MODIFIED, documentContent);
fireDocumentChanged(eventToBeFired);
}
}
private long getNextModificationStamp() {
if (fModificationStamp == Long.MAX_VALUE || fModificationStamp == IDocument.UNKNOWN_MODIFICATION_STAMP)
return 0;
return fModificationStamp + 1;
}
/**
* Fires the given document event to all registers document listeners informing them
* about the forthcoming document manipulation. Uses a robust iterator.
*
* @param event the event to be sent out
*/
protected void fireDocumentAboutToBeChanged(DocumentEvent event) {
if (fPrenotifiedDocumentListeners.size() > 0) {
List list= new ArrayList(fPrenotifiedDocumentListeners);
Iterator e= list.iterator();
while (e.hasNext()) {
IDocumentListener l= (IDocumentListener) e.next();
l.documentAboutToBeChanged(event);
}
}
if (fDocumentListeners.size() > 0) {
List list= new ArrayList(fDocumentListeners);
Iterator e= list.iterator();
while (e.hasNext()) {
IDocumentListener l= (IDocumentListener) e.next();
l.documentAboutToBeChanged(event);
}
}
}
/**
* Updates the internal document structures and informs all document listeners
* if listener notification has been enabled. Otherwise it remembers the event
* to be sent to the listeners on resume.
*
* @param event the document event to be sent out
*/
protected void fireDocumentChanged(DocumentEvent event) {
if (fStoppedListenerNotification == 0)
doFireDocumentChanged(event);
else
fDeferredDocumentEvent= event;
}
/**
* Notifies all listeners about the given document change. Uses a robust
* iterator.
* <p>
* Executes all registered post notification replace operation.
* <p>
* This method will be renamed to <code>doFireDocumentChanged</code>.
*
* @param event the event to be sent out
*/
protected void doFireDocumentChanged(DocumentEvent event) {
if (fPrenotifiedDocumentListeners.size() > 0) {
List list= new ArrayList(fPrenotifiedDocumentListeners);
Iterator e= list.iterator();
while (e.hasNext()) {
IDocumentListener l= (IDocumentListener) e.next();
l.documentChanged(event);
}
}
if (fDocumentListeners.size() > 0) {
List list= new ArrayList(fDocumentListeners);
Iterator e= list.iterator();
while (e.hasNext()) {
IDocumentListener l= (IDocumentListener) e.next();
l.documentChanged(event);
}
}
}
/**
* @see org.eclipse.gmf.runtime.diagram.ui.editor.IDocument#resumeListenerNotification()
*/
public void resumeListenerNotification() {
-- fStoppedListenerNotification;
if (fStoppedListenerNotification == 0) {
resumeDocumentListenerNotification();
}
}
/**
* @see org.eclipse.gmf.runtime.diagram.ui.editor.IDocument#stopListenerNotification()
*/
public void stopListenerNotification() {
++ fStoppedListenerNotification;
}
/**
* Resumes the document listener notification by sending out the remembered
* partition changed and document event.
*/
private void resumeDocumentListenerNotification() {
if (fDeferredDocumentEvent != null) {
DocumentEvent event= fDeferredDocumentEvent;
fDeferredDocumentEvent= null;
doFireDocumentChanged(event);
}
}
}