- Add asset code completion

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@10089 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
nor..67 12 years ago
parent bcedc37037
commit e51b39a628
  1. 4
      sdk/jme3-core/src/com/jme3/gde/core/assets/ProjectAssetManager.java
  2. 375
      sdk/jme3-core/src/com/jme3/gde/core/completion/AssetCompletionProvider.java

@ -298,6 +298,10 @@ public class ProjectAssetManager extends DesktopAssetManager {
return this;
}
public String[] getModels() {
return filesWithSuffix("j3o");
}
public String[] getMaterials() {
return filesWithSuffix("j3m");
}

@ -0,0 +1,375 @@
/*
* Copyright (c) 2003-2012 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.jme3.gde.core.completion;
import com.jme3.gde.core.assets.ProjectAssetManager;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.ImageIcon;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.Element;
import javax.swing.text.JTextComponent;
import javax.swing.text.StyledDocument;
import org.netbeans.api.editor.completion.Completion;
import org.netbeans.api.editor.mimelookup.MimeRegistration;
import org.netbeans.api.project.FileOwnerQuery;
import org.netbeans.api.project.Project;
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.netbeans.spi.editor.completion.support.CompletionUtilities;
import org.openide.filesystems.FileObject;
import org.openide.loaders.DataObject;
import org.openide.util.Exceptions;
import org.openide.util.ImageUtilities;
/**
*
* @author normenhansen
*/
@MimeRegistration(mimeType = "text/x-java", service = CompletionProvider.class)
public class AssetCompletionProvider implements CompletionProvider {
private static ImageIcon assetIcon =
new ImageIcon(ImageUtilities.loadImage("com/jme3/gde/core/assets/nodes/icons/assets.gif"));
private static ImageIcon modelIcon =
new ImageIcon(ImageUtilities.loadImage("com/jme3/gde/core/assets/nodes/icons/model.gif"));
private static ImageIcon materialIcon =
new ImageIcon(ImageUtilities.loadImage("com/jme3/gde/core/assets/nodes/icons/material.gif"));
private static ImageIcon matDefIcon =
new ImageIcon(ImageUtilities.loadImage("com/jme3/gde/core/assets/jme-logo.png"));
private static ImageIcon textureIcon =
new ImageIcon(ImageUtilities.loadImage("com/jme3/gde/core/assets/nodes/icons/image.gif"));
private enum AssetType {
Invalid, Model, Material, MatDef, Texture, Asset
}
public AssetCompletionProvider() {
}
@Override
public CompletionTask createTask(int queryType, JTextComponent jtc) {
if (queryType != CompletionProvider.COMPLETION_QUERY_TYPE) {
return null;
}
return new AsyncCompletionTask(new AsyncCompletionQuery() {
@Override
protected void query(CompletionResultSet completionResultSet, Document document, int caretOffset) {
ProjectAssetManager manager = getProjectAssetManager(document);
if (manager == null) {
Logger.getLogger(AssetCompletionProvider.class.getName()).log(Level.FINE, "No assetManager found");
completionResultSet.finish();
return;
}
AssetType type = determineType(document, caretOffset);
String filter = null;
int startOffset = caretOffset - 1;
try {
final StyledDocument bDoc = (StyledDocument) document;
final int lineStartOffset = getRowFirstNonWhite(bDoc, caretOffset);
final char[] line = bDoc.getText(lineStartOffset, caretOffset - lineStartOffset).toCharArray();
final int whiteOffset = indexOfInsertion(line);
filter = new String(line, whiteOffset + 1, line.length - whiteOffset - 1);
if (whiteOffset > 0) {
startOffset = lineStartOffset + whiteOffset + 1;
} else {
startOffset = lineStartOffset;
}
} catch (BadLocationException ex) {
Exceptions.printStackTrace(ex);
}
Logger.getLogger(AssetCompletionProvider.class.getName()).log(Level.FINE, "Searching with filter {0}", filter);
switch (type) {
case Model:
for (String string : manager.getModels()) {
if (string.startsWith(filter)) {
completionResultSet.addItem(new AssetCompletionItem(type, string, startOffset, caretOffset));
Logger.getLogger(AssetCompletionProvider.class.getName()).log(Level.FINE, "Added item {0}", string);
}
}
break;
case Material:
for (String string : manager.getMaterials()) {
if (string.startsWith(filter)) {
completionResultSet.addItem(new AssetCompletionItem(type, string, startOffset, caretOffset));
Logger.getLogger(AssetCompletionProvider.class.getName()).log(Level.FINE, "Added item {0}", string);
}
}
break;
case MatDef:
for (String string : manager.getMatDefs()) {
if (string.startsWith(filter)) {
completionResultSet.addItem(new AssetCompletionItem(type, string, startOffset, caretOffset));
Logger.getLogger(AssetCompletionProvider.class.getName()).log(Level.FINE, "Added item {0}", string);
}
}
break;
case Texture:
for (String string : manager.getTextures()) {
if (string.startsWith(filter)) {
completionResultSet.addItem(new AssetCompletionItem(type, string, startOffset, caretOffset));
Logger.getLogger(AssetCompletionProvider.class.getName()).log(Level.FINE, "Added item {0}", string);
}
}
break;
case Invalid:
Logger.getLogger(AssetCompletionProvider.class.getName()).log(Level.FINE, "Not a valid code line for assets");
break;
}
completionResultSet.finish();
}
}, jtc);
}
@Override
public int getAutoQueryTypes(JTextComponent component, String string) {
return 0;
}
private AssetType determineType(Document document, int caretOffset) {
try {
final StyledDocument bDoc = (StyledDocument) document;
final int lineStartOffset = getRowFirstNonWhite(bDoc, caretOffset);
final String line = bDoc.getText(lineStartOffset, caretOffset - lineStartOffset).trim();
//TODO: more intelligence! :)
if (line.endsWith(".loadModel(\"")) {
return AssetType.Model;
} else if (hasLastCommand(line, ".loadMaterial(\"")) {
return AssetType.Material;
} else if (hasLastCommand(line, ".loadTexture(\"")) {
return AssetType.Texture;
} else if (hasLastCommand(line, "new Material(")) {
return AssetType.MatDef;
}
} catch (BadLocationException ex) {
Exceptions.printStackTrace(ex);
}
return AssetType.Invalid;
}
private boolean hasLastCommand(String line, String command) {
int idx = line.lastIndexOf(command);
if (idx != -1) {
int bIdx = line.indexOf(")", idx);
if (bIdx == -1) {
return true;
}
}
return false;
}
private ProjectAssetManager getProjectAssetManager(Document doc) {
Object sdp = doc.getProperty(Document.StreamDescriptionProperty);
if (sdp instanceof FileObject) {
Logger.getLogger(AssetCompletionProvider.class.getName()).log(Level.FINE, "Check FileObject for Project..");
FileObject fobj = (FileObject) sdp;
Project proj = FileOwnerQuery.getOwner(fobj);
if (proj != null) {
Logger.getLogger(AssetCompletionProvider.class.getName()).log(Level.FINE, "Project found, return ProjectAssetManager");
return proj.getLookup().lookup(ProjectAssetManager.class);
}
}
if (sdp instanceof DataObject) {
Logger.getLogger(AssetCompletionProvider.class.getName()).log(Level.FINE, "Check DataObject for Project..");
DataObject dobj = (DataObject) sdp;
FileObject fobj = dobj.getPrimaryFile();
Project proj = FileOwnerQuery.getOwner(fobj);
if (proj != null) {
Logger.getLogger(AssetCompletionProvider.class.getName()).log(Level.FINE, "Project found, return ProjectAssetManager");
return proj.getLookup().lookup(ProjectAssetManager.class);
}
}
Logger.getLogger(AssetCompletionProvider.class.getName()).log(Level.FINE, "No Project found");
return null;
}
private static int getRowFirstNonWhite(StyledDocument doc, int offset)
throws BadLocationException {
Element lineElement = doc.getParagraphElement(offset);
int start = lineElement.getStartOffset();
while (start + 1 < lineElement.getEndOffset()) {
try {
if (doc.getText(start, 1).charAt(0) != ' ') {
break;
}
} catch (BadLocationException ex) {
throw (BadLocationException) new BadLocationException(
"calling getText(" + start + ", " + (start + 1)
+ ") on doc of length: " + doc.getLength(), start).initCause(ex);
}
start++;
}
return start;
}
private static int indexOfWhite(char[] line) {
int i = line.length;
while (--i > -1) {
final char c = line[i];
if (Character.isWhitespace(c)) {
return i;
}
}
return -1;
}
private static int indexOfInsertion(char[] line) {
int i = line.length;
while (--i > -1) {
final char c = line[i];
if (c == '"') {
return i;
}
}
return 0;
}
public static class AssetCompletionItem implements CompletionItem {
private AssetType type;
private String text;
private static Color fieldColor = Color.decode("0x0000B2");
private int dotOffset;
private int caretOffset;
public AssetCompletionItem(AssetType type, String text, int dotOffset, int caretOffset) {
this.type = type;
this.text = text;
this.caretOffset = caretOffset;
this.dotOffset = dotOffset;
}
@Override
public int getPreferredWidth(Graphics graphics, Font font) {
return CompletionUtilities.getPreferredWidth(text, null, graphics, font);
}
@Override
public void render(Graphics g, Font defaultFont, Color defaultColor,
Color backgroundColor, int width, int height, boolean selected) {
ImageIcon icon = null;
switch (type) {
case Model:
icon = modelIcon;
break;
case Material:
icon = materialIcon;
break;
case MatDef:
icon = matDefIcon;
break;
case Texture:
icon = textureIcon;
break;
case Asset:
icon = assetIcon;
break;
case Invalid:
break;
}
CompletionUtilities.renderHtml(icon, text, null, g, defaultFont,
(selected ? Color.white : fieldColor), width, height, selected);
}
@Override
public CharSequence getSortText() {
return text;
}
@Override
public CharSequence getInsertPrefix() {
return text;
}
@Override
public void defaultAction(JTextComponent component) {
try {
StyledDocument doc = (StyledDocument) component.getDocument();
//Here we remove the characters starting at the start offset
//and ending at the point where the caret is currently found:
doc.remove(dotOffset, caretOffset - dotOffset);
doc.insertString(dotOffset, text, null);
Completion.get().hideAll();
} catch (BadLocationException ex) {
Exceptions.printStackTrace(ex);
}
}
public void processKeyEvent(KeyEvent evt) {
}
@Override
public CompletionTask createDocumentationTask() {
// return new AsyncCompletionTask(new AsyncCompletionQuery() {
// @Override
// protected void query(CompletionResultSet completionResultSet, Document document, int i) {
// completionResultSet.setDocumentation(new CountriesCompletionDocumentation(CountriesCompletionItem.this));
// completionResultSet.finish();
// }
// });
return null;
}
@Override
public CompletionTask createToolTipTask() {
// return new AsyncCompletionTask(new AsyncCompletionQuery() {
// @Override
// protected void query(CompletionResultSet completionResultSet, Document document, int i) {
// JToolTip toolTip = new JToolTip();
// toolTip.setTipText("Press Enter to insert \"" + text + "\"");
// completionResultSet.setToolTip(toolTip);
// completionResultSet.finish();
// }
// });
return null;
}
public boolean instantSubstitution(JTextComponent component) {
return false;
}
public int getSortPriority() {
return 0;
}
}
}
Loading…
Cancel
Save