blob: 2e2c5c057ab1deddb59dd8250b791b8758365403 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.javafx2.editor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import javax.swing.text.AbstractDocument;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
import javax.xml.parsers.SAXParserFactory;
import org.netbeans.api.editor.mimelookup.MimeLookup;
import org.netbeans.api.editor.mimelookup.MimeRegistration;
import org.netbeans.api.java.source.ClasspathInfo;
import org.netbeans.api.java.source.CompilationController;
import org.netbeans.api.java.source.JavaSource.Phase;
import org.netbeans.api.lexer.TokenHierarchy;
import org.netbeans.editor.BaseDocument;
import org.netbeans.modules.java.source.parsing.ClasspathInfoProvider;
import org.netbeans.modules.javafx2.editor.completion.impl.Completer;
import org.netbeans.modules.javafx2.editor.completion.impl.CompletionContext;
import org.netbeans.modules.javafx2.editor.completion.model.FxmlParserResult;
import org.netbeans.modules.parsing.api.ParserManager;
import org.netbeans.modules.parsing.api.ResultIterator;
import org.netbeans.modules.parsing.api.Source;
import org.netbeans.modules.parsing.api.Task;
import org.netbeans.modules.parsing.api.UserTask;
import org.netbeans.modules.parsing.spi.ParseException;
import org.netbeans.modules.parsing.spi.Parser;
import org.netbeans.spi.editor.completion.CompletionItem;
import org.netbeans.spi.editor.completion.CompletionProvider;
import org.netbeans.spi.editor.completion.CompletionResultSet;
import org.netbeans.spi.editor.completion.CompletionTask;
import org.netbeans.spi.editor.completion.support.AsyncCompletionQuery;
import org.netbeans.spi.editor.completion.support.AsyncCompletionTask;
import org.openide.util.Exceptions;
/**
*
* @author sdedic
*/
@MimeRegistration(mimeType=JavaFXEditorUtils.FXML_MIME_TYPE, service=CompletionProvider.class)
public class FXMLCompletion2 implements CompletionProvider {
@Override
public CompletionTask createTask(int queryType, JTextComponent component) {
if (component == null) {
return null;
}
return new AsyncCompletionTask(new Q(component, queryType), component);
}
@Override
public int getAutoQueryTypes(JTextComponent component, String typedText) {
return 0;
}
public static List<CompletionItem> testQuery(Source s, Document doc, int queryType, int caretOffset) throws ParseException {
Q q = new Q(null, queryType);
ClasspathInfo cpInfo = ClasspathInfo.create(doc);
UserTask t = q.createTask(cpInfo, null, null, doc, caretOffset, queryType);
ParserManager.parse(Collections.singleton(s), t);
return q.items;
}
public static class Q extends AsyncCompletionQuery {
private JTextComponent component;
private int queryType;
private List<CompletionItem> items = Collections.emptyList();
private boolean additionalItems;
public Q(JTextComponent component, int queryType) {
this.component = component;
this.queryType = queryType;
}
private Task createTask(ClasspathInfo cpInfo, JTextComponent component,
CompletionResultSet rs, Document doc, int caretOffset, int qT) {
return new Task(cpInfo,
component,
rs,
doc, caretOffset, qT);
}
@Override
public void query(CompletionResultSet resultSet, Document doc, int caretOffset) {
try {
ClasspathInfo cpInfo = ClasspathInfo.create(doc);
ParserManager.parse(Collections.singleton(Source.create(doc)),
createTask(cpInfo,
component,
resultSet,
doc, caretOffset, queryType)
);
resultSet.setHasAdditionalItems(additionalItems);
resultSet.addAllItems(items);
resultSet.finish();
} catch (ParseException ex) {
Exceptions.printStackTrace(ex);
}
}
public List<CompletionItem> getItems() {
return items;
}
private class Task extends UserTask implements ClasspathInfoProvider {
private CompletionResultSet resultSet;
private Document doc;
private int caretOffset;
private JTextComponent component;
private ClasspathInfo cpInfo;
private int queryType;
private boolean fxmlParsing = true;
private CompletionContext ctx;
private CompilationController cc;
private FxmlParserResult fxmlResult;
public Task(ClasspathInfo cpInfo, JTextComponent component, CompletionResultSet resultSet, Document doc, int caretOffset, int queryType) {
this.resultSet = resultSet;
this.doc = doc;
this.caretOffset = caretOffset;
this.component = component;
this.cpInfo = cpInfo;
this.queryType = queryType;
}
@Override
public void run(ResultIterator resultIterator) throws Exception {
if (fxmlParsing) {
Parser.Result result = resultIterator.getParserResult(caretOffset);
fxmlResult = FxmlParserResult.get(result);
if (fxmlResult == null) {
return;
}
fxmlParsing = false;
// next round, with Java parser to get access to java typesystem
ParserManager.parse(JavaFXEditorUtils.JAVA_MIME_TYPE, this);
return;
}
Parser.Result result = resultIterator.getParserResult();
// [NETBEANS-4832] CompController (not CompInfo) for module info (partial fix)
cc = CompilationController.get(result);
cc.toPhase(Phase.ELEMENTS_RESOLVED);
ctx = new CompletionContext(doc, caretOffset, queryType);
// initialize the Context under read lock, it moves through TokenHierarchy back & forward
if (doc instanceof AbstractDocument) {
((AbstractDocument)doc).readLock();
}
// bug in parsing API: snapshot source not modified just after modification to the source file
try {
TokenHierarchy<?> th = TokenHierarchy.get(doc);
ctx.init(th, cc, fxmlResult);
} finally {
if (doc instanceof AbstractDocument) {
((AbstractDocument)doc).readUnlock();
}
}
items = new ArrayList<CompletionItem>();
Collection<? extends Completer.Factory> completers = MimeLookup.getLookup(JavaFXEditorUtils.FXML_MIME_TYPE).lookupAll(Completer.Factory.class);
for (Iterator<? extends Completer.Factory> it = completers.iterator(); it.hasNext(); ) {
Completer.Factory f = it.next();
Completer c = f.createCompleter(ctx);
if (c != null) {
List<? extends CompletionItem> newItems = c.complete();
if (newItems != null) {
items.addAll(newItems);
additionalItems |= c.hasMoreItems();
}
}
}
}
public ClasspathInfo getClasspathInfo() {
return cpInfo;
}
}
}
}