1 19 20 package org.netbeans.lib.editor.codetemplates; 21 22 import java.util.ArrayList ; 23 import java.util.Collection ; 24 import java.util.Iterator ; 25 import java.util.List ; 26 import javax.swing.event.ChangeEvent ; 27 import javax.swing.event.ChangeListener ; 28 import javax.swing.text.AbstractDocument ; 29 import javax.swing.text.BadLocationException ; 30 import javax.swing.text.Document ; 31 import javax.swing.text.JTextComponent ; 32 import org.netbeans.editor.BaseDocument; 33 import org.netbeans.editor.SettingsUtil; 34 import org.netbeans.editor.Utilities; 35 import org.netbeans.editor.ext.ExtSettingsDefaults; 36 import org.netbeans.editor.ext.ExtSettingsNames; 37 import org.netbeans.lib.editor.codetemplates.api.CodeTemplate; 38 import org.netbeans.lib.editor.codetemplates.spi.CodeTemplateFilter; 39 import org.netbeans.spi.editor.completion.CompletionProvider; 40 import org.netbeans.spi.editor.completion.CompletionResultSet; 41 import org.netbeans.spi.editor.completion.CompletionTask; 42 import org.netbeans.spi.editor.completion.support.AsyncCompletionQuery; 43 import org.netbeans.spi.editor.completion.support.AsyncCompletionTask; 44 45 50 public final class CodeTemplateCompletionProvider implements CompletionProvider { 51 52 public CompletionTask createTask(int type, JTextComponent component) { 53 return type != COMPLETION_QUERY_TYPE || isAbbrevDisabled(component) ? null : new AsyncCompletionTask(new Query(), component); 54 } 55 56 public int getAutoQueryTypes(JTextComponent component, String typedText) { 57 return 0; 58 } 59 60 private static boolean isAbbrevDisabled(JTextComponent component) { 61 return org.netbeans.editor.Abbrev.isAbbrevDisabled(component); 62 } 63 64 private static final class Query extends AsyncCompletionQuery 65 implements ChangeListener { 66 67 private JTextComponent component; 68 69 private int queryCaretOffset; 70 private int queryAnchorOffset; 71 private List queryResult; 72 73 private String filterPrefix; 74 75 protected void prepareQuery(JTextComponent component) { 76 this.component = component; 77 } 78 79 protected boolean canFilter(JTextComponent component) { 80 int caretOffset = component.getSelectionStart(); 81 Document doc = component.getDocument(); 82 filterPrefix = null; 83 if (caretOffset >= queryCaretOffset) { 84 if (queryAnchorOffset < queryCaretOffset) { 85 try { 86 filterPrefix = doc.getText(queryAnchorOffset, caretOffset - queryAnchorOffset); 87 if (!isJavaIdentifierPart(filterPrefix)) { 88 filterPrefix = null; 89 } 90 } catch (BadLocationException e) { 91 } 93 } 94 } 95 return (filterPrefix != null); 96 } 97 98 protected void filter(CompletionResultSet resultSet) { 99 if (filterPrefix != null && queryResult != null) { 100 resultSet.addAllItems(getFilteredData(queryResult, filterPrefix)); 101 } 102 resultSet.finish(); 103 } 104 105 private boolean isJavaIdentifierPart(CharSequence text) { 106 for (int i = 0; i < text.length(); i++) { 107 if (!(Character.isJavaIdentifierPart(text.charAt(i))) ) { 108 return false; 109 } 110 } 111 return true; 112 } 113 114 private Collection getFilteredData(Collection data, String prefix) { 115 List ret = new ArrayList (); 116 for (Iterator it = data.iterator(); it.hasNext();) { 117 CodeTemplateCompletionItem itm = (CodeTemplateCompletionItem) it.next(); 118 if (itm.getInsertPrefix().toString().startsWith(prefix)) 119 ret.add(itm); 120 } 121 return ret; 122 } 123 124 protected void query(CompletionResultSet resultSet, Document doc, int caretOffset) { 125 CodeTemplateManagerOperation op = CodeTemplateManagerOperation.get(doc); 126 String identifierBeforeCursor = null; 127 if (doc instanceof AbstractDocument ) { 128 AbstractDocument adoc = (AbstractDocument )doc; 129 adoc.readLock(); 130 try { 131 if (adoc instanceof BaseDocument) { 132 identifierBeforeCursor = Utilities.getIdentifierBefore( 133 (BaseDocument)adoc, caretOffset); 134 } 135 } catch (BadLocationException e) { 136 } finally { 138 adoc.readUnlock(); 139 } 140 } 141 142 op.waitLoaded(); 143 144 queryCaretOffset = caretOffset; 145 queryAnchorOffset = (identifierBeforeCursor != null) ? caretOffset - identifierBeforeCursor.length() : caretOffset; 146 if (identifierBeforeCursor != null) { 147 boolean ignoreCase = !SettingsUtil.getBoolean(component.getUI().getEditorKit(component).getClass(), ExtSettingsNames.COMPLETION_CASE_SENSITIVE, 148 ExtSettingsDefaults.defaultCompletionCaseSensitive); 149 Collection cts = op.findByParametrizedText(identifierBeforeCursor, ignoreCase); 150 Collection filters = op.getTemplateFilters(component, queryAnchorOffset); 151 queryResult = new ArrayList (cts.size()); 152 for (Iterator it = cts.iterator(); it.hasNext();) { 153 CodeTemplate ct = (CodeTemplate)it.next(); 154 if (accept(ct, filters)) 155 queryResult.add(new CodeTemplateCompletionItem(ct)); 156 } 157 resultSet.addAllItems(queryResult); 158 } 159 resultSet.setAnchorOffset(queryAnchorOffset); 160 resultSet.finish(); 161 } 162 163 public void stateChanged(ChangeEvent evt) { 164 synchronized (this) { 165 notify(); 166 } 167 } 168 169 private static boolean accept(CodeTemplate template, Collection filters) { 170 for(Iterator it = filters.iterator(); it.hasNext();) { 171 CodeTemplateFilter filter = (CodeTemplateFilter)it.next(); 172 if (!filter.accept(template)) 173 return false; 174 } 175 return true; 176 } 177 178 } 179 180 } 181 | Popular Tags |