diff -r 7a902c74231a editor.completion/src/org/netbeans/api/editor/completion/Completion.java --- a/editor.completion/src/org/netbeans/api/editor/completion/Completion.java Tue Dec 11 13:22:22 2012 +0100 +++ b/editor.completion/src/org/netbeans/api/editor/completion/Completion.java Tue Dec 11 17:01:43 2012 +0100 @@ -158,5 +158,17 @@ public void hideAll() { CompletionImpl.get().hideAll(); } + + /** + * Workaround for http://netbeans.org/bugzilla/show_bug.cgi?id=223290 . + * + * Client needs to explicitly repaint its CompletionItem-s when their full + * state is computation is finished in a background thread. + * + * Called by reflection. + */ + private void repaintCompletionView() { + CompletionImpl.get().repaintCompletionView(); + } } diff -r 7a902c74231a editor.completion/src/org/netbeans/modules/editor/completion/CompletionImpl.java --- a/editor.completion/src/org/netbeans/modules/editor/completion/CompletionImpl.java Tue Dec 11 13:22:22 2012 +0100 +++ b/editor.completion/src/org/netbeans/modules/editor/completion/CompletionImpl.java Tue Dec 11 17:01:43 2012 +0100 @@ -1545,6 +1545,16 @@ } // .......................................................................... + + /** + * Workaround for http://netbeans.org/bugzilla/show_bug.cgi?id=223290 . + * + * Client needs to explicitly repaint its CompletionItem-s when their full + * state is computation is finished in a background thread. + */ + public void repaintCompletionView() { + layout.repaintCompletionView(); + } private final class CompletionShowAction extends AbstractAction { private int queryType; diff -r 7a902c74231a editor.completion/src/org/netbeans/modules/editor/completion/CompletionLayout.java --- a/editor.completion/src/org/netbeans/modules/editor/completion/CompletionLayout.java Tue Dec 11 13:22:22 2012 +0100 +++ b/editor.completion/src/org/netbeans/modules/editor/completion/CompletionLayout.java Tue Dec 11 17:01:43 2012 +0100 @@ -47,6 +47,7 @@ import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; +import java.awt.EventQueue; import java.awt.Rectangle; import java.awt.Toolkit; import java.awt.event.ActionEvent; @@ -300,6 +301,14 @@ return completionPopup; } + void repaintCompletionView() { + assert EventQueue.isDispatchThread(); + JComponent completionView = completionPopup.completionScrollPane; + if(completionView != null && completionView.isVisible()) { + completionView.repaint(); + } + } + private static final class CompletionPopup extends CompletionLayoutPopup { private CompletionScrollPane completionScrollPane; diff -r 7a902c74231a html.editor/src/org/netbeans/modules/html/editor/api/completion/HtmlCompletionItem.java --- a/html.editor/src/org/netbeans/modules/html/editor/api/completion/HtmlCompletionItem.java Tue Dec 11 13:22:22 2012 +0100 +++ b/html.editor/src/org/netbeans/modules/html/editor/api/completion/HtmlCompletionItem.java Tue Dec 11 17:01:43 2012 +0100 @@ -58,7 +58,12 @@ import org.netbeans.modules.editor.indent.api.Indent; import org.netbeans.spi.editor.completion.*; import java.awt.Color; +import java.awt.EventQueue; import java.awt.event.KeyEvent; +import java.beans.FeatureDescriptor; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.lang.reflect.Method; import javax.swing.text.BadLocationException; import javax.swing.text.JTextComponent; import org.netbeans.modules.html.editor.lib.api.model.HtmlTagAttribute; @@ -66,13 +71,15 @@ import org.netbeans.modules.html.editor.javadoc.HelpManager; import org.netbeans.spi.editor.completion.support.AsyncCompletionTask; import org.netbeans.spi.editor.completion.support.CompletionUtilities; +import org.openide.explorer.propertysheet.PropertySheet; +import org.openide.util.Exceptions; import org.openide.util.ImageUtilities; import org.openide.xml.XMLUtil; /** * Code completion result item base class * - * @author Dusan Balek, Marek Fukala + * @author Dusan Balek, Marek Fukala */ public class HtmlCompletionItem implements CompletionItem { @@ -82,11 +89,11 @@ public static HtmlCompletionItem createTag(HtmlTag tag, String name, int substitutionOffset, String helpId, boolean possible) { return new Tag(tag, name, substitutionOffset, helpId, possible); } - + public static HtmlCompletionItem createEndTag(HtmlTag tag, String name, int substitutionOffset, String helpId, int order, EndTag.Type type) { return new EndTag(tag, name, substitutionOffset, helpId, order, type); } - + public static HtmlCompletionItem createEndTag(String name, int substitutionOffset, String helpId, int order, EndTag.Type type) { return new EndTag(name, substitutionOffset, helpId, order, type); } @@ -122,8 +129,6 @@ public static HtmlCompletionItem createGoUpFileCompletionItem(int substitutionOffset, Color color, ImageIcon icon) { return new GoUpFileAttributeValue(substitutionOffset, color, icon); } - - //------------------------------------------ protected int substitutionOffset; protected String text, helpId; @@ -178,7 +183,7 @@ } int caretOffset = component.getSelectionEnd(); int len = caretOffset - substitutionOffset; - if(len >= 0) { + if (len >= 0) { substituteText(component, len); } } @@ -189,9 +194,9 @@ return 0; //default } - /** - * Subclasses may override to customize the completed text - * if they do not want to override the substituteText method. + /** + * Subclasses may override to customize the completed text if they do not + * want to override the substituteText method. */ protected String getSubstituteText() { return getItemText(); @@ -211,7 +216,6 @@ result[0] = true; doc.runAtomic(new Runnable() { - @Override public void run() { try { @@ -223,7 +227,7 @@ doc.insertString(substitutionOffset, substituteText, null); } else { c.setCaretPosition(c.getCaret().getDot() + substituteText.length() - len); - } + } } catch (BadLocationException ex) { result[0] = false; } @@ -251,7 +255,6 @@ indent.lock(); try { doc.runAtomic(new Runnable() { - @Override public void run() { try { @@ -260,7 +263,7 @@ indent.reindent(startOffset, endOffset); } catch (BadLocationException ex) { //ignore - } + } } }); } finally { @@ -313,7 +316,8 @@ return this.helpId; } - /** Returns a url or null, if the help is not URL or the help is not defined. + /** + * Returns a url or null, if the help is not URL or the help is not defined. */ public URL getHelpURL() { if (helpId == null || helpId.equals("")) { @@ -326,8 +330,10 @@ return null; } - /** Returns help for the item. It can be only url. If the item doesn't have a help - * than returns null. The class can overwrite this method and compounds the help realtime. + /** + * Returns help for the item. It can be only url. If the item doesn't have a + * help than returns null. The class can overwrite this method and compounds + * the help realtime. */ public String getHelp() { return HelpManager.getDefault().getHelp(helpId); @@ -384,24 +390,20 @@ hash = 97 * hash + (this.helpId != null ? this.helpId.hashCode() : 0); return hash; } - - //------------------------------------------------------------------------------ - /** - * Completion item representing a JSP tag including its prefix eg. + /** + * Completion item representing a JSP tag including its prefix eg. + * */ public static class Tag extends HtmlCompletionItem { private static final ImageIcon HTML_TAG_ICON = - ImageUtilities.loadImageIcon("org/netbeans/modules/csl/source/resources/icons/html_element.png", false); // NOI18N - + ImageUtilities.loadImageIcon("org/netbeans/modules/csl/source/resources/icons/html_element.png", false); // NOI18N private static final ImageIcon SVG_TAG_ICON = - ImageUtilities.loadImageIcon("org/netbeans/modules/csl/source/resources/icons/class.png", false); // NOI18N - + ImageUtilities.loadImageIcon("org/netbeans/modules/csl/source/resources/icons/class.png", false); // NOI18N private static final ImageIcon MATHML_TAG_ICON = - ImageUtilities.loadImageIcon("org/netbeans/modules/html/editor/resources/mathml.png", false); // NOI18N - + ImageUtilities.loadImageIcon("org/netbeans/modules/html/editor/resources/mathml.png", false); // NOI18N private String GRAY_COLOR_CODE = hexColorCode(Color.GRAY); private boolean possible; private HtmlTag tag; @@ -435,9 +437,9 @@ @Override protected String getLeftHtmlText() { - return possible ? - "<" + getItemText() + ">" : //NOI18N - "<" + getItemText() + ">"; //NOI18N + return possible + ? "<" + getItemText() + ">" : //NOI18N + "<" + getItemText() + ">"; //NOI18N } @Override @@ -465,24 +467,23 @@ @Override public boolean hasHelp() { - return tag != null && tag.getHelp() != null || super.hasHelp(); + return tag != null && tag.getHelp() != null || super.hasHelp(); } - - } /** - * Completion item representing a JSP tag including its prefix eg. + * Completion item representing a JSP tag including its prefix eg. + * */ public static class EndTag extends HtmlCompletionItem { - + public enum Type { + DEFAULT(hexColorCode(Color.BLUE), false, DEFAULT_SORT_PRIORITY), //NOI18N OPTIONAL_EXISTING(hexColorCode(Color.GRAY), false, DEFAULT_SORT_PRIORITY), OPTIONAL_MISSING(hexColorCode(Color.BLUE), false, DEFAULT_SORT_PRIORITY - 10), //NOI18N REQUIRED_EXISTING(hexColorCode(Color.GRAY), false, DEFAULT_SORT_PRIORITY), REQUIRED_MISSING(hexColorCode(Color.BLUE), false, DEFAULT_SORT_PRIORITY - 10); //NOI18N - private String colorCode; private boolean bold; private int sortPriority; @@ -492,9 +493,7 @@ this.bold = bold; this.sortPriority = sortPriority; } - } - private int orderIndex; private Type type; private HtmlTag tag; @@ -519,7 +518,7 @@ } else { char[] result = new char[Integer.toString(Integer.MAX_VALUE).length()]; char[] orderIndexChars = Integer.toString(orderIndex).toCharArray(); - Arrays.fill(result,'0'); //NOI18N + Arrays.fill(result, '0'); //NOI18N System.arraycopy(orderIndexChars, 0, result, result.length - orderIndexChars.length, orderIndexChars.length); return new String(result); @@ -547,7 +546,6 @@ public boolean hasHelp() { return tag != null && tag.getHelp() != null || super.hasHelp(); } - } public static class AutocompleteEndTag extends EndTag { @@ -565,7 +563,6 @@ public boolean instantSubstitution(JTextComponent component) { return false; } - } /** @@ -604,7 +601,9 @@ } } - /** Item representing a JSP attribute value. */ + /** + * Item representing a JSP attribute value. + */ public static class AttributeValue extends HtmlCompletionItem { private boolean addQuotation; @@ -618,8 +617,6 @@ protected String getSubstituteText() { return addQuotation ? "\"" + super.getSubstituteText() + "\"" : super.getSubstituteText(); } - - } public static class Attribute extends HtmlCompletionItem { @@ -627,7 +624,6 @@ private boolean required; private boolean autocompleteQuotes; private HtmlTagAttribute attr; - protected static final String ATTR_NAME_COLOR = hexColorCode(Color.green.darker()); public Attribute(HtmlTagAttribute attr, String value, int offset, boolean required, String helpId) { @@ -664,18 +660,16 @@ "" + getItemText() + "" + //NOI18N (required ? "" : ""); //NOI18N } - + @Override public boolean hasHelp() { return attr != null && attr.getHelp() != null || super.hasHelp(); } - } public static class BooleanAttribute extends HtmlCompletionItem { private boolean required; - protected static final String ATTR_NAME_COLOR = hexColorCode(Color.green.darker()); public BooleanAttribute(String value, int offset, boolean required, String helpId) { @@ -691,11 +685,14 @@ } } - /** Item representing a File attribute */ - public static class FileAttributeValue extends HtmlCompletionItem { + /** + * Item representing a File attribute + */ + public static class FileAttributeValue extends HtmlCompletionItem implements PropertyChangeListener, LazyCompletionItem { private javax.swing.ImageIcon icon; private Color color; + private boolean visible = false; FileAttributeValue(String text, int substitutionOffset, Color color, javax.swing.ImageIcon icon) { super(text, substitutionOffset); @@ -712,6 +709,47 @@ protected String getLeftHtmlText() { return "" + getItemText() + ""; //NOI18N } + + private void iconLoaded(ImageIcon icon) { + this.icon = icon; + if(visible) { + repaintCompletionView_EDT(); + } + } + + private void repaintCompletionView_EDT() { + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + repaintCompletionView(); + } + }); + } + + private static void repaintCompletionView() { + try { + Completion completion = Completion.get(); + Class clz = completion.getClass(); + Method method = clz.getDeclaredMethod("repaintCompletionView"); //NOI18N + method.setAccessible(true); + method.invoke(completion); + } catch (Exception e) { + //ignore + } + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if(evt.getPropertyName().equals("iconLoaded")) { //NOI18N + iconLoaded((ImageIcon)evt.getNewValue()); + } + } + + @Override + public boolean accept() { + visible = true; + return true; + } } public static class GoUpFileAttributeValue extends FileAttributeValue { diff -r 7a902c74231a web.common/src/org/netbeans/modules/web/common/api/FileReferenceCompletion.java --- a/web.common/src/org/netbeans/modules/web/common/api/FileReferenceCompletion.java Tue Dec 11 13:22:22 2012 +0100 +++ b/web.common/src/org/netbeans/modules/web/common/api/FileReferenceCompletion.java Tue Dec 11 17:01:43 2012 +0100 @@ -42,6 +42,8 @@ package org.netbeans.modules.web.common.api; import java.awt.Color; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; @@ -57,7 +59,9 @@ import org.openide.filesystems.FileSystem; import org.openide.loaders.DataObject; import org.openide.loaders.DataObjectNotFoundException; +import org.openide.util.Exceptions; import org.openide.util.ImageUtilities; +import org.openide.util.RequestProcessor; /** * @@ -65,6 +69,8 @@ */ public abstract class FileReferenceCompletion implements ValueCompletion { + private static RequestProcessor RP = new RequestProcessor(); + private static final ImageIcon PACKAGE_ICON = ImageUtilities.loadImageIcon("org/openide/loaders/defaultFolder.gif", false); // NOI18N @@ -139,19 +145,32 @@ Enumeration files = folder.getChildren(false); while (files.hasMoreElements()) { - FileObject file = files.nextElement(); + final FileObject file = files.nextElement(); String fname = file.getNameExt(); if (fname.startsWith(prefix) && !"cvs".equalsIgnoreCase(fname)) { if (file.isFolder()) { resFolders.put(file.getNameExt(), createFileItem(offset, file.getNameExt() + "/", java.awt.Color.BLUE, PACKAGE_ICON)); } else { - java.awt.Image icon = getIcon(file); - if (icon != null) { - resFiles.put(file.getNameExt(), createFileItem(offset, file.getNameExt(), java.awt.Color.BLACK, new javax.swing.ImageIcon(icon))); + T fileItem = createFileItem(offset, file.getNameExt(), java.awt.Color.BLACK, null); + if(fileItem instanceof PropertyChangeListener) { //"bit" hacky :-) + //lazy load icons + final PropertyChangeListener plistener = (PropertyChangeListener)fileItem; + RP.post(new Runnable() { + @Override + public void run() { + ImageIcon icon = new ImageIcon(getIcon(file)); + plistener.propertyChange( + new PropertyChangeEvent(this, "iconLoaded", null, icon)); //NOI18N + } + + }); } else { - resFiles.put(file.getNameExt(), createFileItem(offset, file.getNameExt(), java.awt.Color.BLACK, null)); + //direct icons load + ImageIcon icon = new ImageIcon(getIcon(file)); + fileItem = createFileItem(offset, file.getNameExt(), java.awt.Color.BLACK, icon); } + resFiles.put(file.getNameExt(), fileItem); } } }