/*
* 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.works.editor.antlr4.completion;
import com.tvl.api.editor.completion.Completion;
import com.tvl.spi.editor.completion.CompletionController;
import com.tvl.spi.editor.completion.CompletionItem;
import com.tvl.spi.editor.completion.CompletionTask;
import com.tvl.spi.editor.completion.support.CompletionUtilities;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.util.Locale;
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.JTextComponent;
import org.antlr.netbeans.editor.text.DocumentSnapshot;
import org.antlr.netbeans.editor.text.SnapshotPositionRegion;
import org.antlr.netbeans.editor.text.TrackingPositionRegion;
import org.antlr.netbeans.editor.text.VersionedDocument;
import org.antlr.netbeans.editor.text.VersionedDocumentUtilities;
import org.netbeans.api.annotations.common.NonNull;
import org.netbeans.editor.BaseDocument;
import org.netbeans.editor.GuardedDocument;
/**
*
* @author Sam Harwell
*/
public abstract class AbstractCompletionItem implements CompletionItem {
// -J-Dorg.antlr.works.editor.antlr4.completion.AbstractCompletionItem.level=FINE
private static final Logger LOGGER = Logger.getLogger(AbstractCompletionItem.class.getName());
protected static final Object CT_HANDLER_DOC_PROPERTY = "code-template-insert-handler"; // NOI18N
public static final String COLOR_END = "</font>"; //NOI18N
public static final String STRIKE = "<s>"; //NOI18N
public static final String STRIKE_END = "</s>"; //NOI18N
public static final String BOLD = "<b>"; //NOI18N
public static final String BOLD_END = "</b>"; //NOI18N
protected AbstractCompletionItem() {
}
public boolean allowInitialSelection() {
return true;
}
@Override
public final void defaultAction(JTextComponent component) {
throw new UnsupportedOperationException(String.format("This functionality is handled by %s.", BaseCompletionController.class.getSimpleName())); //NOI18N
}
public void defaultAction(@NonNull JTextComponent component, @NonNull BaseCompletionController controller, boolean isSelected) {
Completion.get().hideDocumentation();
Completion.get().hideCompletion();
if (!isSelected) {
return;
}
TrackingPositionRegion applicableTo = controller.getApplicableTo();
if (applicableTo == null) {
return;
}
Document document = component.getDocument();
if (document == null) {
return;
}
VersionedDocument textBuffer = VersionedDocumentUtilities.getVersionedDocument(document);
DocumentSnapshot snapshot = textBuffer.getCurrentSnapshot();
SnapshotPositionRegion replacementSpan = applicableTo.getRegion(snapshot);
substituteText(component, replacementSpan.getStart().getOffset(), replacementSpan.getLength(), getInsertPrefix().toString());
BaseCompletionController.addRecentCompletion(getInsertPrefix().toString());
}
@Override
public final void processKeyEvent(KeyEvent evt) {
throw new UnsupportedOperationException(String.format("This functionality is handled by %s.", BaseCompletionController.class.getSimpleName())); //NOI18N
}
public void processKeyEvent(KeyEvent evt, BaseCompletionController controller, boolean isSelected) {
//if (evt.getID() == KeyEvent.KEY_TYPED) {
// if (!AbstractCompletionProvider.autoPopupOnIdentifierPart()
// && evt.getModifiers() == 0
// && AbstractCompletionProvider.getCompletionSelectors().indexOf(evt.getKeyChar()) >= 0) {
// throw new UnsupportedOperationException("Not supported yet.");
// }
//} else if (evt.getID() == KeyEvent.KEY_PRESSED && evt.getKeyCode() == KeyEvent.VK_ENTER && evt.isControlDown()) {
// throw new UnsupportedOperationException("Not supported yet.");
//} else if (evt.getID() == KeyEvent.KEY_PRESSED && evt.getKeyCode() == KeyEvent.VK_ENTER && evt.isAltDown()) {
// throw new UnsupportedOperationException("Not supported yet.");
//}
JTextComponent comp = controller.getComponent();
boolean compEditable = (comp != null && comp.isEditable());
Document doc = comp != null ? comp.getDocument() : null;
boolean guardedPos = doc instanceof GuardedDocument && ((GuardedDocument)doc).isPosGuarded(comp.getSelectionEnd());
if (evt.getKeyCode() == KeyEvent.VK_TAB && doc.getProperty(CT_HANDLER_DOC_PROPERTY) == null) {
evt.consume();
if (guardedPos) {
Toolkit.getDefaultToolkit().beep();
} else if (compEditable && evt.getID() == KeyEvent.KEY_PRESSED) {
controller.defaultAction(this, true);
evt.consume();
}
return;
}
if (evt.getID() == KeyEvent.KEY_TYPED && !Character.isJavaIdentifierPart(evt.getKeyChar())) {
Completion.get().hideCompletion();
}
}
@Override
public int getPreferredWidth(Graphics g, Font defaultFont) {
return CompletionUtilities.getPreferredWidth(getLeftHtmlText(), getRightHtmlText(), g, defaultFont);
}
@Override
public final void render(Graphics g, Font defaultFont, Color defaultColor, Color backgroundColor, int width, int height, boolean selected) {
throw new UnsupportedOperationException(String.format("This functionality is handled by %s.", BaseCompletionController.class.getSimpleName())); //NOI18N
}
public void render(CompletionController controller, Graphics g, Font defaultFont, Color foregroundColor, Color backgroundColor, Color selectedForegroundColor, Color selectedBackgroundColor, int width, int height, boolean isBestMatch, boolean isSelected) {
CompletionUtilities.renderHtml(getIcon(), getLeftHtmlText(), getRightHtmlText(), g, defaultFont, foregroundColor, selectedBackgroundColor, width, height, isBestMatch, isSelected);
}
@Override
public CompletionTask createDocumentationTask() {
return null;
}
@Override
public CompletionTask createToolTipTask() {
return null;
}
@Override
public final boolean instantSubstitution(JTextComponent component) {
throw new UnsupportedOperationException(String.format("This functionality is handled by %s.", BaseCompletionController.class.getSimpleName())); //NOI18N
}
public boolean instantSubstitution(@NonNull JTextComponent component, @NonNull BaseCompletionController controller) {
if (controller.getApplicableTo() == null) {
return false;
}
defaultAction(component, controller, true);
return true;
}
// @Override
// public int getSortPriority() {
// throw new UnsupportedOperationException("Not supported yet.");
// }
//
// @Override
// public CharSequence getSortText() {
// throw new UnsupportedOperationException("Not supported yet.");
// }
//
// @Override
// public CharSequence getInsertPrefix() {
// throw new UnsupportedOperationException("Not supported yet.");
// }
@Override
public final CharSequence getSortText() {
return getSortTextImpl().toLowerCase(Locale.getDefault());
}
protected abstract String getSortTextImpl();
protected ImageIcon getIcon() {
return null;
}
protected String getLeftHtmlText() {
return null;
}
protected String getRightHtmlText() {
return null;
}
protected void substituteText(final JTextComponent component, final int offset, final int length, final String replacement) {
final BaseDocument document = (BaseDocument)component.getDocument();
document.runAtomic (new Runnable () {
@Override
public void run () {
try {
if (document.getText(offset, length).equals(replacement)) {
component.setCaretPosition(offset + replacement.length());
return;
}
document.remove(offset, length);
document.insertString(offset, replacement, null);
// component.setCaretPosition(offset + replacement.length());
} catch (BadLocationException e) {
// Can't update
LOGGER.log(Level.WARNING, e.getMessage(), e);
}
}
});
}
}