blob: 820d7dfe1e123b8a7f0b8c4f80424c767c0ae316 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2015 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.jface.text.projection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentInformationMapping;
import org.eclipse.jface.text.IDocumentListener;
import org.eclipse.jface.text.ISlaveDocumentManager;
import org.eclipse.jface.text.ISlaveDocumentManagerExtension;
/**
* A <code>ProjectionDocumentManager</code> is one particular implementation
* of {@link org.eclipse.jface.text.ISlaveDocumentManager}. This manager
* creates so called projection documents (see
* {@link org.eclipse.jface.text.projection.ProjectionDocument}as slave
* documents for given master documents.
* <p>
* A projection document represents a particular projection of the master
* document and is accordingly adapted to changes of the master document. Vice
* versa, the master document is accordingly adapted to changes of its slave
* documents. The manager does not maintain any particular management structure
* but utilizes mechanisms given by {@link org.eclipse.jface.text.IDocument}
* such as position categories and position updaters.
* <p>
* Clients can instantiate this class. This class is not intended to be
* subclassed.</p>
*
* @since 3.0
* @noextend This class is not intended to be subclassed by clients.
*/
public class ProjectionDocumentManager implements IDocumentListener, ISlaveDocumentManager, ISlaveDocumentManagerExtension {
/** Registry for master documents and their projection documents. */
private Map<IDocument, List<ProjectionDocument>> fProjectionRegistry= new HashMap<>();
/**
* Registers the given projection document for the given master document.
*
* @param master the master document
* @param projection the projection document
*/
private void add(IDocument master, ProjectionDocument projection) {
List<ProjectionDocument> list= fProjectionRegistry.get(master);
if (list == null) {
list= new ArrayList<>(1);
fProjectionRegistry.put(master, list);
}
list.add(projection);
}
/**
* Unregisters the given projection document from its master.
*
* @param master the master document
* @param projection the projection document
*/
private void remove(IDocument master, ProjectionDocument projection) {
List<ProjectionDocument> list= fProjectionRegistry.get(master);
if (list != null) {
list.remove(projection);
if (list.size() == 0)
fProjectionRegistry.remove(master);
}
}
/**
* Returns whether the given document is a master document.
*
* @param master the document
* @return <code>true</code> if the given document is a master document known to this manager
*/
private boolean hasProjection(IDocument master) {
return (fProjectionRegistry.get(master) != null);
}
/**
* Returns an iterator enumerating all projection documents registered for the given document or
* <code>null</code> if the document is not a known master document.
*
* @param master the document
* @return an iterator for all registered projection documents or <code>null</code>
*/
private Iterator<ProjectionDocument> getProjectionsIterator(IDocument master) {
List<ProjectionDocument> list= fProjectionRegistry.get(master);
if (list != null)
return list.iterator();
return null;
}
/**
* Informs all projection documents of the master document that issued the given document event.
*
* @param about indicates whether the change is about to happen or happened already
* @param masterEvent the document event which will be processed to inform the projection documents
*/
protected void fireDocumentEvent(boolean about, DocumentEvent masterEvent) {
IDocument master= masterEvent.getDocument();
Iterator<ProjectionDocument> e= getProjectionsIterator(master);
if (e == null)
return;
while (e.hasNext()) {
ProjectionDocument document= e.next();
if (about)
document.masterDocumentAboutToBeChanged(masterEvent);
else
document.masterDocumentChanged(masterEvent);
}
}
@Override
public void documentChanged(DocumentEvent event) {
fireDocumentEvent(false, event);
}
@Override
public void documentAboutToBeChanged(DocumentEvent event) {
fireDocumentEvent(true, event);
}
@Override
public IDocumentInformationMapping createMasterSlaveMapping(IDocument slave) {
if (slave instanceof ProjectionDocument) {
ProjectionDocument projectionDocument= (ProjectionDocument) slave;
return projectionDocument.getDocumentInformationMapping();
}
return null;
}
@Override
public IDocument createSlaveDocument(IDocument master) {
if (!hasProjection(master))
master.addDocumentListener(this);
ProjectionDocument slave= createProjectionDocument(master);
add(master, slave);
return slave;
}
/**
* Factory method for projection documents.
*
* @param master the master document
* @return the newly created projection document
*/
protected ProjectionDocument createProjectionDocument(IDocument master) {
return new ProjectionDocument(master);
}
@Override
public void freeSlaveDocument(IDocument slave) {
if (slave instanceof ProjectionDocument) {
ProjectionDocument projectionDocument= (ProjectionDocument) slave;
IDocument master= projectionDocument.getMasterDocument();
remove(master, projectionDocument);
projectionDocument.dispose();
if (!hasProjection(master))
master.removeDocumentListener(this);
}
}
@Override
public IDocument getMasterDocument(IDocument slave) {
if (slave instanceof ProjectionDocument)
return ((ProjectionDocument) slave).getMasterDocument();
return null;
}
@Override
public boolean isSlaveDocument(IDocument document) {
return (document instanceof ProjectionDocument);
}
@Override
public void setAutoExpandMode(IDocument slave, boolean autoExpanding) {
if (slave instanceof ProjectionDocument)
((ProjectionDocument) slave).setAutoExpandMode(autoExpanding);
}
@Override
public IDocument[] getSlaveDocuments(IDocument master) {
List<ProjectionDocument> list= fProjectionRegistry.get(master);
if (list != null) {
IDocument[] result= new IDocument[list.size()];
list.toArray(result);
return result;
}
return null;
}
}