/*
* Copyright (c) 2012 Sam Harwell, Tunnel Vision Laboratories LLC
* All rights reserved.
*
* The source code of this document is proprietary work, and is not licensed for
* distribution. For information about licensing, contact Sam Harwell at:
* sam@tunnelvisionlabs.com
*/
package org.antlr.netbeans.parsing.spi.impl;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
import org.antlr.netbeans.editor.text.VersionedDocument;
import org.antlr.netbeans.editor.text.VersionedDocumentUtilities;
import org.antlr.netbeans.parsing.spi.ParseContext;
import org.antlr.netbeans.parsing.spi.ParserTaskScheduler;
import org.netbeans.api.editor.EditorRegistry;
import org.openide.util.WeakSet;
import org.openide.util.lookup.ServiceProvider;
/**
* A task scheduler which schedules tasks when the content of a document changes.
*
* @author Sam Harwell
*/
@ServiceProvider(service=ParserTaskScheduler.class)
public class DocumentContentParserTaskScheduler extends ParserTaskScheduler {
private final Map<Document, Set<JTextComponent>> documents = new WeakHashMap<>();
private final EditorRegistryListener editorRegistryListener = new EditorRegistryListener();
private final DocumentListener documentListener = new DocumentListenerImpl();
@Override
protected void initializeImpl() {
EditorRegistry.addPropertyChangeListener(editorRegistryListener);
}
private class EditorRegistryListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName() == null
|| evt.getPropertyName().equals(EditorRegistry.FOCUSED_DOCUMENT_PROPERTY)
|| evt.getPropertyName().equals(EditorRegistry.FOCUS_GAINED_PROPERTY)) {
JTextComponent editor = EditorRegistry.focusedComponent();
if (editor == null) {
return;
}
Document document = editor.getDocument();
Set<JTextComponent> components;
synchronized (documents) {
components = documents.get(document);
if (components == null) {
components = new WeakSet<>();
documents.put(document, components);
document.addDocumentListener(documentListener);
VersionedDocument versionedDocument = VersionedDocumentUtilities.getVersionedDocument(document);
ParseContext context = new ParseContext(DocumentContentParserTaskScheduler.this.getClass(), versionedDocument);
schedule(context);
}
}
components.add(editor);
} else if (evt.getPropertyName().equals(EditorRegistry.COMPONENT_REMOVED_PROPERTY)) {
JTextComponent editor = (JTextComponent)evt.getOldValue();
if (editor == null) {
return;
}
Document document = editor.getDocument();
synchronized (documents) {
Set<JTextComponent> components = documents.get(document);
if (components != null && components.remove(editor)) {
if (components.isEmpty()) {
document.removeDocumentListener(documentListener);
documents.remove(document);
}
}
}
}
}
}
private class DocumentListenerImpl implements DocumentListener {
@Override
public void insertUpdate(DocumentEvent e) {
VersionedDocument document = VersionedDocumentUtilities.getVersionedDocument(e.getDocument());
ParseContext context = new ParseContext(DocumentContentParserTaskScheduler.this.getClass(), document);
schedule(context);
}
@Override
public void removeUpdate(DocumentEvent e) {
VersionedDocument document = VersionedDocumentUtilities.getVersionedDocument(e.getDocument());
ParseContext context = new ParseContext(DocumentContentParserTaskScheduler.this.getClass(), document);
schedule(context);
}
@Override
public void changedUpdate(DocumentEvent e) {
VersionedDocument document = VersionedDocumentUtilities.getVersionedDocument(e.getDocument());
ParseContext context = new ParseContext(DocumentContentParserTaskScheduler.this.getClass(), document);
schedule(context);
}
}
}